⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uhci.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (urb->status != -EINPROGRESS) {		info("uhci_transfer_result: called for URB %p not in flight?", urb);		spin_unlock_irqrestore(&urb->lock, flags);		return;	}	switch (usb_pipetype(urb->pipe)) {	case PIPE_CONTROL:		ret = uhci_result_control(urb);		break;	case PIPE_INTERRUPT:		ret = uhci_result_interrupt(urb);		break;	case PIPE_BULK:		ret = uhci_result_bulk(urb);		break;	case PIPE_ISOCHRONOUS:		ret = uhci_result_isochronous(urb);		break;	}	urbp->status = ret;	spin_unlock_irqrestore(&urb->lock, flags);	if (ret == -EINPROGRESS)		return;	switch (usb_pipetype(urb->pipe)) {	case PIPE_CONTROL:	case PIPE_BULK:	case PIPE_ISOCHRONOUS:		/* Release bandwidth for Interrupt or Isoc. transfers */		/* Spinlock needed ? */		if (urb->bandwidth)			usb_release_bandwidth(urb->dev, urb, 1);		uhci_unlink_generic(uhci, urb);		break;	case PIPE_INTERRUPT:		/* Interrupts are an exception */		if (urb->interval) {			uhci_add_complete(urb);			return;		/* <-- note return */		}		/* Release bandwidth for Interrupt or Isoc. transfers */		/* Spinlock needed ? */		if (urb->bandwidth)			usb_release_bandwidth(urb->dev, urb, 0);		uhci_unlink_generic(uhci, urb);		break;	default:		info("uhci_transfer_result: unknown pipe type %d for urb %p\n",			usb_pipetype(urb->pipe), urb);	}	list_del_init(&urb->urb_list);	uhci_add_complete(urb);}static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb){	struct list_head *head, *tmp;	struct urb_priv *urbp = urb->hcpriv;	/* We can get called when urbp allocation fails, so check */	if (!urbp)		return;	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */	head = &urbp->td_list;	tmp = head->next;	while (tmp != head) {		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);		tmp = tmp->next;		/* Control and Isochronous ignore the toggle, so this */		/* is safe for all types */		if ((!(td->status & TD_CTRL_ACTIVE) &&		    (uhci_actual_length(td->status) < uhci_expected_length(td->info)) ||		    tmp == head)) {			usb_settoggle(urb->dev, uhci_endpoint(td->info),				uhci_packetout(td->info),				uhci_toggle(td->info) ^ 1);		}	}	uhci_delete_queued_urb(uhci, urb);	/* The interrupt loop will reclaim the QH's */	uhci_remove_qh(uhci, urb);}static int uhci_unlink_urb(struct urb *urb){	struct uhci *uhci;	unsigned long flags;	struct urb_priv *urbp = urb->hcpriv;	if (!urb)		return -EINVAL;	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)		return -ENODEV;	uhci = (struct uhci *)urb->dev->bus->hcpriv;	/* Release bandwidth for Interrupt or Isoc. transfers */	/* Spinlock needed ? */	if (urb->bandwidth) {		switch (usb_pipetype(urb->pipe)) {		case PIPE_INTERRUPT:			usb_release_bandwidth(urb->dev, urb, 0);			break;		case PIPE_ISOCHRONOUS:			usb_release_bandwidth(urb->dev, urb, 1);			break;		default:			break;		}	}	if (urb->status != -EINPROGRESS)		return 0;	spin_lock_irqsave(&uhci->urb_list_lock, flags);	list_del_init(&urb->urb_list);	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);	uhci_unlink_generic(uhci, urb);	/* Short circuit the virtual root hub */	if (urb->dev == uhci->rh.dev) {		rh_unlink_urb(urb);		uhci_call_completion(urb);	} else {		if (urb->transfer_flags & USB_ASYNC_UNLINK) {			/* urb_list is available now since we called */			/*  uhci_unlink_generic already */			urbp->status = urb->status = -ECONNABORTED;			spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);			/* Check to see if the remove list is empty */			if (list_empty(&uhci->urb_remove_list))				uhci_set_next_interrupt(uhci);						list_add(&urb->urb_list, &uhci->urb_remove_list);			spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);		} else {			urb->status = -ENOENT;			if (in_interrupt()) {	/* wait at least 1 frame */				static int errorcount = 10;				if (errorcount--)					dbg("uhci_unlink_urb called from interrupt for urb %p", urb);				udelay(1000);			} else				schedule_timeout(1+1*HZ/1000); 			uhci_call_completion(urb);		}	}	return 0;}static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb){	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;	struct list_head *head, *tmp;	uhci_dec_fsbr(uhci, urb);	/* There is a race with updating IOC in here, but it's not worth */	/*  trying to fix since this is merely an optimization. The only */	/*  time we'd lose is if the status of the packet got updated */	/*  and we'd be turning on FSBR next frame anyway, so it's a wash */	urbp->fsbr_timeout = 1;	head = &urbp->td_list;	tmp = head->next;	while (tmp != head) {		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);		tmp = tmp->next;		if (td->status & TD_CTRL_ACTIVE) {			set_bit(TD_CTRL_IOC_BIT, &td->status);			break;		}	}	return 0;}/* * uhci_get_current_frame_number() * * returns the current frame number for a USB bus/controller. */static int uhci_get_current_frame_number(struct usb_device *dev){	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;	return inw(uhci->io_addr + USBFRNUM);}struct usb_operations uhci_device_operations = {	uhci_alloc_dev,	uhci_free_dev,	uhci_get_current_frame_number,	uhci_submit_urb,	uhci_unlink_urb};/* Virtual Root Hub */static __u8 root_hub_dev_des[] ={ 	0x12,			/*  __u8  bLength; */	0x01,			/*  __u8  bDescriptorType; Device */	0x00,			/*  __u16 bcdUSB; v1.0 */	0x01,	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */	0x00,			/*  __u8  bDeviceSubClass; */	0x00,			/*  __u8  bDeviceProtocol; */	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */	0x00,			/*  __u16 idVendor; */	0x00,	0x00,			/*  __u16 idProduct; */	0x00,	0x00,			/*  __u16 bcdDevice; */	0x00,	0x00,			/*  __u8  iManufacturer; */	0x02,			/*  __u8  iProduct; */	0x01,			/*  __u8  iSerialNumber; */	0x01			/*  __u8  bNumConfigurations; */};/* Configuration descriptor */static __u8 root_hub_config_des[] ={	0x09,			/*  __u8  bLength; */	0x02,			/*  __u8  bDescriptorType; Configuration */	0x19,			/*  __u16 wTotalLength; */	0x00,	0x01,			/*  __u8  bNumInterfaces; */	0x01,			/*  __u8  bConfigurationValue; */	0x00,			/*  __u8  iConfiguration; */	0x40,			/*  __u8  bmAttributes;					Bit 7: Bus-powered, 6: Self-powered,					Bit 5 Remote-wakeup, 4..0: resvd */	0x00,			/*  __u8  MaxPower; */	/* interface */	0x09,			/*  __u8  if_bLength; */	0x04,			/*  __u8  if_bDescriptorType; Interface */	0x00,			/*  __u8  if_bInterfaceNumber; */	0x00,			/*  __u8  if_bAlternateSetting; */	0x01,			/*  __u8  if_bNumEndpoints; */	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */	0x00,			/*  __u8  if_bInterfaceSubClass; */	0x00,			/*  __u8  if_bInterfaceProtocol; */	0x00,			/*  __u8  if_iInterface; */	/* endpoint */	0x07,			/*  __u8  ep_bLength; */	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */	0x03,			/*  __u8  ep_bmAttributes; Interrupt */	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */	0x00,	0xff			/*  __u8  ep_bInterval; 255 ms */};static __u8 root_hub_hub_des[] ={	0x09,			/*  __u8  bLength; */	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */	0x02,			/*  __u8  bNbrPorts; */	0x00,			/* __u16  wHubCharacteristics; */	0x00,	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */	0x00,			/*  __u8  bHubContrCurrent; 0 mA */	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */};/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */static int rh_send_irq(struct urb *urb){	int i, len = 1;	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	unsigned int io_addr = uhci->io_addr;	__u16 data = 0;	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;	for (i = 0; i < uhci->rh.numports; i++) {		data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);		len = (i + 1) / 8 + 1;	}	*(__u16 *) urb->transfer_buffer = cpu_to_le16(data);	urb->actual_length = len;	urbp->status = 0;	if ((data > 0) && (uhci->rh.send != 0)) {		dbg("root-hub INT complete: port1: %x port2: %x data: %x",			inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);		uhci_call_completion(urb);	}	return 0;}/* Virtual Root Hub INTs are polled by this timer every "interval" ms */static int rh_init_int_timer(struct urb *urb);static void rh_int_timer_do(unsigned long ptr){	struct urb *urb = (struct urb *)ptr;	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	struct list_head list, *tmp, *head;	unsigned long flags;	if (uhci->rh.send)		rh_send_irq(urb);	INIT_LIST_HEAD(&list);	spin_lock_irqsave(&uhci->urb_list_lock, flags);	head = &uhci->urb_list;	tmp = head->next;	while (tmp != head) {		struct urb *u = list_entry(tmp, struct urb, urb_list);		struct urb_priv *urbp = (struct urb_priv *)u->hcpriv;		tmp = tmp->next;		/* Check if the FSBR timed out */		if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT))			uhci_fsbr_timeout(uhci, u);		/* Check if the URB timed out */		if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) {			list_del(&u->urb_list);			list_add_tail(&u->urb_list, &list);		}	}	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);	head = &list;	tmp = head->next;	while (tmp != head) {		struct urb *u = list_entry(tmp, struct urb, urb_list);		tmp = tmp->next;		u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;		uhci_unlink_urb(u);	}	/* enter global suspend if nothing connected */	if (!uhci->is_suspended && !ports_active(uhci))		suspend_hc(uhci);	rh_init_int_timer(urb);}/* Root Hub INTs are polled by this timer */static int rh_init_int_timer(struct urb *urb){	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	uhci->rh.interval = urb->interval;	init_timer(&uhci->rh.rh_int_timer);	uhci->rh.rh_int_timer.function = rh_int_timer_do;	uhci->rh.rh_int_timer.data = (unsigned long)urb;	uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;	add_timer(&uhci->rh.rh_int_timer);	return 0;}#define OK(x)			len = (x); break#define CLR_RH_PORTSTAT(x) \	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \	status = (status & 0xfff5) & ~(x); \	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))#define SET_RH_PORTSTAT(x) \	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \	status = (status & 0xfff5) | (x); \	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))/* Root Hub Control Pipe */static int rh_submit_urb(struct urb *urb){	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	unsigned int pipe = urb->pipe;	devrequest *cmd = (devrequest *)urb->setup_packet;	void *data = urb->transfer_buffer;	int leni = urb->transfer_buffer_length;	int len = 0;	int status = 0;	int stat = 0;	int i;	unsigned int io_addr = uhci->io_addr;	__u16 cstatus;	__u16 bmRType_bReq;	__u16 wValue;	__u16 wIndex;	__u16 wLength;	if (usb_pipetype(pipe) == PIPE_INTERRUPT) {		uhci->rh.urb = urb;		uhci->rh.send = 1;		uhci->rh.interval = urb->interval;		rh_init_int_timer(urb);		return -EINPROGRESS;	}	bmRType_bReq = cmd->requesttype | cmd->request << 8;	wValue = le16_to_cpu(cmd->value);	wIndex = le16_to_cpu(cmd->index);	wLength = le16_to_cpu(cmd->length);	for (i = 0; i < 8; i++)		uhci->rh.c_p_r[i] = 0;	switch (bmRType_bReq) {		/* Request Destination:		   without flags: Device,		   RH_INTERFACE: interface,		   RH_ENDPOINT: endpoint,		   RH_CLASS means HUB here,		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here		*/	case RH_GET_STATUS:		*(__u16 *)data = cpu_to_le16(1);		OK(2);	case RH_GET_STATUS | RH_INTERFACE:		*(__u16 *)data = cpu_to_le16(0);		OK(2);	case RH_GET_STATUS | RH_ENDPOINT:		*(__u16 *)data = cpu_to_le16(0);		OK(2);	case RH_GET_STATUS | RH_CLASS:		*(__u32 *)data = cpu_to_le32(0);		OK(4);		/* hub power */	case RH_GET_STATUS | RH_OTHER | RH_CLASS:		status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |			((status & USBPORTSC_PEC) >> (3 - 1)) |			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));			status = (status & USBPORTSC_CCS) |			((status & USBPORTSC_PE) >> (2 - 1)) |			((status & USBPORTSC_SUSP) >> (12 - 2)) |			((status & USBPORTSC_PR) >> (9 - 4)) |			(1 << 8) |      /* power on */			((status & USBPORTSC_LSDA) << (-8 + 9));		*(__u16 *)data = cpu_to_le16(status);		*(__u16 *)(data + 2) = cpu_to_le16(cstatus);		OK(4);	case RH_CLEAR_FEATURE | RH_ENDPOINT:		switch (wValue) {		case RH_ENDPOINT_STALL:			OK(0);		}		break;	case RH_CLEAR_FEATURE | RH_CLASS:		switch (wValue) {		case RH_C_HUB_OVER_CURRENT:			OK(0);	/* hub power over current */		}		break;	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:		switch (wValue) {		case RH_PORT_ENABLE:			CLR_RH_PORTSTAT(USBPORTSC_PE);			OK(0);		case RH_PORT_SUSPEND:			CLR_RH_PORTSTAT(USBPORTSC_SUSP);			OK(0);		case RH_PORT_POWER:			OK(0);	/* port power */		case RH_C_PORT_CONNECTION:			SET_RH_PORTSTAT(USBPORTSC_CSC);			OK(0);		case RH_C_PORT_ENABLE:			SET_RH_PORTSTAT(USBPORTSC_PEC);			OK(0);		case RH_C_PORT_SUSPEND:			/*** WR_RH_PORTSTAT(RH_PS_PSSC); */			OK(0);		case RH_C_PORT_OVER_CURRENT:			OK(0);	/* port power over current */		case RH_C_PORT_RESET:			uhci->rh.c_p_r[wIndex - 1] = 0;			OK(0);		}		break;	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:		switch (wValue) {		case RH_PORT_SUSPEND:			SET_RH_PORTSTAT(USBPORTSC_SUSP);			OK(0);		case RH_PORT_RESET:			SET_RH_PORTSTAT(USBPORTSC_PR);			wait_ms(50);	/* USB v1.1 7.1.7.3 */			uhci->rh.c_p_r[wIndex - 1] = 1;			CLR_RH_PORTSTAT(USBPORTSC_PR);			udelay(10);			SET_RH_PORTSTAT(USBPORTSC_PE);			wait_ms(10);			SET_RH_PORTSTAT(0xa);			OK(0);		case RH_PORT_POWER:			OK(0); /* port power ** */		case RH_PORT_ENABLE:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -