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

📄 uhci.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	return ret;}/* * Return the result of a transfer * * MUST be called with urb_list_lock acquired */static void uhci_transfer_result(struct uhci *uhci, struct urb *urb){	int ret = -EINVAL;	unsigned long flags;	struct urb_priv *urbp;	/* The root hub is special */	if (urb->dev == uhci->rh.dev)		return;	spin_lock_irqsave(&urb->lock, flags);	urbp = (struct urb_priv *)urb->hcpriv;	if (urb->status != -EINPROGRESS) {		info("uhci_transfer_result: called for URB %p not in flight?", urb);		goto out;	}	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;	if (ret == -EINPROGRESS)		goto out;	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)			goto out_complete;		/* 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);	}	/* Remove it from uhci->urb_list */	list_del_init(&urb->urb_list);out_complete:	uhci_add_complete(urb);out:	spin_unlock_irqrestore(&urb->lock, flags);}/* * MUST be called with urb->lock acquired */static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb){	struct list_head *head, *tmp;	struct urb_priv *urbp = urb->hcpriv;	int prevactive = 1;	/* We can get called when urbp allocation fails, so check */	if (!urbp)		return;	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */	/*	 * Now we need to find out what the last successful toggle was	 * so we can update the local data toggle for the next transfer	 *	 * There's 3 way's the last successful completed TD is found:	 *	 * 1) The TD is NOT active and the actual length < expected length	 * 2) The TD is NOT active and it's the last TD in the chain	 * 3) The TD is active and the previous TD is NOT active	 *	 * Control and Isochronous ignore the toggle, so this is safe	 * for all types	 */	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) &&		    (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);		else if ((td->status & TD_CTRL_ACTIVE) && !prevactive)			usb_settoggle(urb->dev, uhci_endpoint(td->info),				uhci_packetout(td->info),				uhci_toggle(td->info));		prevactive = td->status & TD_CTRL_ACTIVE;	}	uhci_delete_queued_urb(uhci, urb);	/* The interrupt loop will reclaim the QH's */	uhci_remove_qh(uhci, urbp->qh);	urbp->qh = NULL;}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;	spin_lock_irqsave(&uhci->urb_list_lock, flags);	spin_lock(&urb->lock);	/* 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) {		spin_unlock(&urb->lock);		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);		return 0;	}	list_del_init(&urb->urb_list);	uhci_unlink_generic(uhci, urb);	/* Short circuit the virtual root hub */	if (urb->dev == uhci->rh.dev) {		rh_unlink_urb(urb);		spin_unlock(&urb->lock);		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);		uhci_call_completion(urb);	} else {		if (urb->transfer_flags & USB_ASYNC_UNLINK) {			urbp->status = urb->status = -ECONNABORTED;			spin_lock(&uhci->urb_remove_list_lock);			/* If we're the first, set the next interrupt bit */			if (list_empty(&uhci->urb_remove_list))				uhci_set_next_interrupt(uhci);						list_add(&urb->urb_list, &uhci->urb_remove_list);			spin_unlock(&uhci->urb_remove_list_lock);			spin_unlock(&urb->lock);			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);		} else {			urb->status = -ENOENT;			spin_unlock(&urb->lock);			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);			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;	int count = 0;	uhci_dec_fsbr(uhci, urb);	urbp->fsbr_timeout = 1;	/*	 * Ideally we would want to fix qh->element as well, but it's	 * read/write by the HC, so that can introduce a race. It's not	 * really worth the hassle	 */	head = &urbp->td_list;	tmp = head->next;	while (tmp != head) {		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);		tmp = tmp->next;		/*		 * Make sure we don't do the last one (since it'll have the		 * TERM bit set) as well as we skip every so many TD's to		 * make sure it doesn't hog the bandwidth		 */		if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))			td->link |= UHCI_PTR_DEPTH;		count++;	}	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){	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;	unsigned int io_addr = uhci->io_addr;	unsigned long flags;	int i, len = 1;	__u16 data = 0;	spin_lock_irqsave(&urb->lock, flags);	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;	spin_unlock_irqrestore(&urb->lock, flags);	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 *up = (struct urb_priv *)u->hcpriv;		tmp = tmp->next;		spin_lock(&u->lock);		/* Check if the FSBR timed out */		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))			uhci_fsbr_timeout(uhci, u);		/* Check if the URB timed out */		if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {			list_del(&u->urb_list);			list_add_tail(&u->urb_list, &list);		}		spin_unlock(&u->lock);	}	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);	}	/* Really disable FSBR */	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {		uhci->fsbrtimeout = 0;		uhci->skel_term_qh->link = UHCI_PTR_TERM;	}	/* 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;	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)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->bRequestType | cmd->bRequest << 8;	wValue = le16_to_cpu(cmd->wValue);	wIndex = le16_to_cpu(cmd->wIndex);	wLength = le16_to_cpu(cmd->wLength);	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);

⌨️ 快捷键说明

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