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

📄 usb-uhci.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
{	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 len = 1;	int i;	uhci_t *uhci = urb->dev->bus->hcpriv;	unsigned int io_addr = uhci->io_addr;	__u16 data = 0;	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;	urb->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);		urb->complete (urb);	}	return 0;}/*-------------------------------------------------------------------------*//* Virtual Root Hub INTs are polled by this timer every "intervall" ms */_static int rh_init_int_timer (struct urb *urb);_static void rh_int_timer_do (unsigned long ptr){	int len;	struct urb *urb = (struct urb*) ptr;	uhci_t *uhci = urb->dev->bus->hcpriv;	if (uhci->rh.send) {		len = rh_send_irq (urb);		if (len > 0) {			urb->actual_length = len;			if (urb->complete)				urb->complete (urb);		}	}	rh_init_int_timer (urb);}/*-------------------------------------------------------------------------*//* Root Hub INTs are polled by this timer, polling interval 20ms */_static int rh_init_int_timer (struct urb *urb){	uhci_t *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 * 20) / 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 usb_device *usb_dev = urb->dev;	uhci_t *uhci = usb_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) {		dbg("Root-Hub submit IRQ: every %d ms", urb->interval);		uhci->rh.urb = urb;		uhci->rh.send = 1;		uhci->rh.interval = urb->interval;		rh_init_int_timer (urb);		return 0;	}	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;	dbg("Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x",	     uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, wLength);	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);			uhci_wait_ms (10);			uhci->rh.c_p_r[wIndex - 1] = 1;			CLR_RH_PORTSTAT (USBPORTSC_PR);			udelay (10);			SET_RH_PORTSTAT (USBPORTSC_PE);			uhci_wait_ms (10);			SET_RH_PORTSTAT (0xa);			OK (0);		case (RH_PORT_POWER):			OK (0);	/* port power ** */		case (RH_PORT_ENABLE):			SET_RH_PORTSTAT (USBPORTSC_PE);			OK (0);		}		break;	case RH_SET_ADDRESS:		uhci->rh.devnum = wValue;		OK (0);	case RH_GET_DESCRIPTOR:		switch ((wValue & 0xff00) >> 8) {		case (0x01):	/* device descriptor */			len = min_t(unsigned int, leni,				  min_t(unsigned int,				      sizeof (root_hub_dev_des), wLength));			memcpy (data, root_hub_dev_des, len);			OK (len);		case (0x02):	/* configuration descriptor */			len = min_t(unsigned int, leni,				  min_t(unsigned int,				      sizeof (root_hub_config_des), wLength));			memcpy (data, root_hub_config_des, len);			OK (len);		case (0x03):	/* string descriptors */			len = usb_root_hub_string (wValue & 0xff,			        uhci->io_addr, "UHCI",				data, wLength);			if (len > 0) {				OK(min_t(int, leni, len));			} else 				stat = -EPIPE;		}		break;	case RH_GET_DESCRIPTOR | RH_CLASS:		root_hub_hub_des[2] = uhci->rh.numports;		len = min_t(unsigned int, leni,			  min_t(unsigned int, sizeof (root_hub_hub_des), wLength));		memcpy (data, root_hub_hub_des, len);		OK (len);	case RH_GET_CONFIGURATION:		*(__u8 *) data = 0x01;		OK (1);	case RH_SET_CONFIGURATION:		OK (0);	default:		stat = -EPIPE;	}	dbg("Root-Hub stat port1: %x port2: %x",	     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));	urb->actual_length = len;	urb->status = stat;	urb->dev=NULL;	if (urb->complete)		urb->complete (urb);	return 0;}/*-------------------------------------------------------------------------*/_static int rh_unlink_urb (struct urb *urb){	uhci_t *uhci = urb->dev->bus->hcpriv;	if (uhci->rh.urb==urb) {		dbg("Root-Hub unlink IRQ");		uhci->rh.send = 0;		del_timer (&uhci->rh.rh_int_timer);	}	return 0;}/*-------------------------------------------------------------------*//* * Map status to standard result codes * * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status) * <dir_out> is True for output TDs and False for input TDs. */_static int uhci_map_status (int status, int dir_out){	if (!status)		return 0;	if (status & TD_CTRL_BITSTUFF)	/* Bitstuff error */		return -EPROTO;	if (status & TD_CTRL_CRCTIMEO) {	/* CRC/Timeout */		if (dir_out)			return -ETIMEDOUT;		else			return -EILSEQ;	}	if (status & TD_CTRL_NAK)	/* NAK */		return -ETIMEDOUT;	if (status & TD_CTRL_BABBLE)	/* Babble */		return -EOVERFLOW;	if (status & TD_CTRL_DBUFERR)	/* Buffer error */		return -ENOSR;	if (status & TD_CTRL_STALLED)	/* Stalled */		return -EPIPE;	if (status & TD_CTRL_ACTIVE)	/* Active */		return 0;	return -EPROTO;}/* * Only the USB core should call uhci_alloc_dev and uhci_free_dev */_static int uhci_alloc_dev (struct usb_device *usb_dev){	return 0;}_static void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_all){	unsigned long flags;	struct list_head *p;	struct list_head *p2;	struct urb *urb;	spin_lock_irqsave (&s->urb_list_lock, flags);	p = s->urb_list.prev;		while (p != &s->urb_list) {		p2 = p;		p = p->prev ;		urb = list_entry (p2, struct urb, urb_list);		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);				//urb->transfer_flags |=USB_ASYNC_UNLINK; 					if (remove_all || (usb_dev == urb->dev)) {			spin_unlock_irqrestore (&s->urb_list_lock, flags);			warn("forced removing of queued URB %p due to disconnect",urb);			uhci_unlink_urb(urb);			urb->dev = NULL; // avoid further processing of this URB			spin_lock_irqsave (&s->urb_list_lock, flags);			p = s->urb_list.prev;			}	}	spin_unlock_irqrestore (&s->urb_list_lock, flags);}_static int uhci_free_dev (struct usb_device *usb_dev){	uhci_t *s;		if(!usb_dev || !usb_dev->bus || !usb_dev->bus->hcpriv)		return -EINVAL;		s=(uhci_t*) usb_dev->bus->hcpriv;		uhci_unlink_urbs(s, usb_dev, 0);	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 *usb_dev){	return UHCI_GET_CURRENT_FRAME ((uhci_t*) usb_dev->bus->hcpriv);}struct usb_operations uhci_device_operations ={	uhci_alloc_dev,	uhci_free_dev,	uhci_get_current_frame_number,	uhci_submit_urb,	uhci_unlink_urb};_static void correct_data_toggles(struct urb *urb){	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));	while(urb) {		urb_priv_t *priv=urb->hcpriv;				uhci_desc_t *qh = list_entry (priv->desc_list.next, uhci_desc_t, desc_list);		struct list_head *p = qh->vertical.next;		uhci_desc_t *td;		dbg("URB to correct %p\n", urb);			for (; p != &qh->vertical; p = p->next) {			td = list_entry (p, uhci_desc_t, vertical);			td->hw.td.info^=cpu_to_le32(1<<TD_TOKEN_TOGGLE);		}		urb=priv->next_queued_urb;	}}/*  * For IN-control transfers, process_transfer gets a bit more complicated, * since there are devices that return less data (eg. strings) than they * have announced. This leads to a queue abort due to the short packet, * the status stage is not executed. If this happens, the status stage * is manually re-executed. * mode: PROCESS_TRANSFER_REGULAR: regular (unlink QH) *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb) */_static int process_transfer (uhci_t *s, struct urb *urb, int mode){	int ret = 0;	urb_priv_t *urb_priv = urb->hcpriv;	struct list_head *qhl = urb_priv->desc_list.next;	uhci_desc_t *qh = list_entry (qhl, uhci_desc_t, desc_list);	struct list_head *p = qh->vertical.next;	uhci_desc_t *desc= list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);	uhci_desc_t *last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);	int data_toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));	// save initial data_toggle	int maxlength; 	// extracted and remapped info from TD	int actual_length;	int status = 0;	//dbg("process_transfer: urb %p, urb_priv %p, qh %p last_desc %p\n",urb,urb_priv, qh, last_desc);	/* if the status phase has been retriggered and the	   queue is empty or the last status-TD is inactive, the retriggered	   status stage is completed	 */	if (urb_priv->flags && 	    ((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) || !is_td_

⌨️ 快捷键说明

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