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

📄 usb-ohci.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				wmb();				writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */			}			break;		case PIPE_INTERRUPT:			info = usb_pipeout (urb->pipe)? 				TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;			td_fill (ohci, info, data, data_len, urb, cnt++);			break;		case PIPE_CONTROL:			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;			td_fill (ohci, info,				pci_map_single (ohci->ohci_dev,					urb->setup_packet, 8,					PCI_DMA_TODEVICE),				8, urb, cnt++); 			if (data_len > 0) {  				info = usb_pipeout (urb->pipe)? 					TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;				/* NOTE:  mishandles transfers >8K, some >4K */				td_fill (ohci, info, data, data_len, urb, cnt++);  			} 			info = usb_pipeout (urb->pipe)?  				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;			td_fill (ohci, info, data, 0, urb, cnt++);			if (!ohci->sleeping) {				// BUSHI				wmb();				writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */			}			break;		case PIPE_ISOCHRONOUS:			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {				td_fill (ohci, TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 					data + urb->iso_frame_desc[cnt].offset, 					urb->iso_frame_desc[cnt].length, urb, cnt); 			}			break;	} 	if (urb_priv->length != cnt) 		dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);}/*-------------------------------------------------------------------------* * Done List handling functions *-------------------------------------------------------------------------*//* calculate the transfer length and update the urb */static void dl_transfer_length(td_t * td){	__u32 tdINFO, tdBE, tdCBP; 	__u16 tdPSW; 	urb_t * urb = td->urb; 	urb_priv_t * urb_priv = urb->hcpriv;	int dlen = 0;	int cc = 0;		tdINFO = le32_to_cpup (&td->hwINFO);  	tdBE   = le32_to_cpup (&td->hwBE);  	tdCBP  = le32_to_cpup (&td->hwCBP);  	if (tdINFO & TD_ISO) { 		tdPSW = le16_to_cpu (td->hwPSW[0]); 		cc = (tdPSW >> 12) & 0xF;		if (cc < 0xE)  {			if (usb_pipeout(urb->pipe)) {				dlen = urb->iso_frame_desc[td->index].length;			} else {				dlen = tdPSW & 0x3ff;			}			urb->actual_length += dlen;			urb->iso_frame_desc[td->index].actual_length = dlen;			if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))				cc = TD_CC_NOERROR;					 			urb->iso_frame_desc[td->index].status = cc_to_error[cc];		}	} else { /* BULK, INT, CONTROL DATA */		if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL && 				((td->index == 0) || (td->index == urb_priv->length - 1)))) { 			if (tdBE != 0) { 				if (td->hwCBP == 0)					urb->actual_length += tdBE - td->data_dma + 1;  				else					urb->actual_length += tdCBP - td->data_dma;			}  		}  	}}/* handle an urb that is being unlinked */static void dl_del_urb (urb_t * urb){	wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;	urb_rm_priv_locked (urb);	if (urb->transfer_flags & USB_ASYNC_UNLINK) {		urb->status = -ECONNRESET;		if (urb->complete)			urb->complete (urb);	} else {		urb->status = -ENOENT;		/* unblock sohci_unlink_urb */		if (wait_head)			wake_up (wait_head);	}}/*-------------------------------------------------------------------------*//* replies to the request have to be on a FIFO basis so * we reverse the reversed done-list */ static td_t * dl_reverse_done_list (ohci_t * ohci){	__u32 td_list_hc;	td_t * td_rev = NULL;	td_t * td_list = NULL;  	urb_priv_t * urb_priv = NULL;  	unsigned long flags;  	  	spin_lock_irqsave (&usb_ed_lock, flags);  		td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;	ohci->hcca->done_head = 0;		while (td_list_hc) {				td_list = dma_to_td (ohci, td_list_hc);		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;			dbg(" USB-error/status: %x : %p", 					TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);			if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {				if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {					td_list->ed->hwHeadP = 						(urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |									(td_list->ed->hwHeadP & cpu_to_le32 (0x2));					urb_priv->td_cnt += urb_priv->length - td_list->index - 1;				} else 					td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);			}		}		td_list->next_dl_td = td_rev;			td_rev = td_list;		td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;		}		spin_unlock_irqrestore (&usb_ed_lock, flags);	return td_list;}/*-------------------------------------------------------------------------*//* there are some pending requests to remove  * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev) * - some URBs/TDs if urb_priv->state == URB_DEL */ static void dl_del_list (ohci_t  * ohci, unsigned int frame){	unsigned long flags;	ed_t * ed;	__u32 edINFO;	__u32 tdINFO;	td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;	__u32 * td_p;	int ctrl = 0, bulk = 0;	spin_lock_irqsave (&usb_ed_lock, flags);	for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {		tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);		edINFO = le32_to_cpup (&ed->hwINFO);		td_p = &ed->hwHeadP;		for (td = tdHeadP; td != tdTailP; td = td_next) { 			urb_t * urb = td->urb;			urb_priv_t * urb_priv = td->urb->hcpriv;						td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);			if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {				tdINFO = le32_to_cpup (&td->hwINFO);				if (TD_CC_GET (tdINFO) < 0xE)					dl_transfer_length (td);				*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));				/* URB is done; clean up */				if (++(urb_priv->td_cnt) == urb_priv->length)					dl_del_urb (urb);			} else {				td_p = &td->hwNextTD;			}		}		if (ed->state & ED_DEL) { /* set by sohci_free_dev */			struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);			td_free (ohci, tdTailP); /* free dummy td */   	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 			ed->state = ED_NEW;			hash_free_ed(ohci, ed);   	 		/* if all eds are removed wake up sohci_free_dev */   	 		if (!--dev->ed_cnt) {				wait_queue_head_t *wait_head = dev->wait;				dev->wait = 0;				if (wait_head)					wake_up (wait_head);			}   	 	} else {   	 		ed->state &= ~ED_URB_DEL;			tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);			if (tdHeadP == tdTailP) {				if (ed->state == ED_OPER)					ep_unlink(ohci, ed);				td_free (ohci, tdTailP);				ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);				ed->state = ED_NEW;				hash_free_ed(ohci, ed);				--(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt;			} else   	 			ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);   	 	}		switch (ed->type) {			case PIPE_CONTROL:				ctrl = 1;				break;			case PIPE_BULK:				bulk = 1;				break;		}   	}   		/* maybe reenable control and bulk lists */ 	if (!ohci->disabled) {		if (ctrl) 	/* reset control list */			writel (0, &ohci->regs->ed_controlcurrent);		if (bulk)	/* reset bulk list */			writel (0, &ohci->regs->ed_bulkcurrent);		if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {			if (ohci->ed_controltail)				ohci->hc_control |= OHCI_CTRL_CLE;			if (ohci->ed_bulktail)				ohci->hc_control |= OHCI_CTRL_BLE;			writel (ohci->hc_control, &ohci->regs->control);   		}	}   	ohci->ed_rm_list[frame] = NULL;   	spin_unlock_irqrestore (&usb_ed_lock, flags);}  		/*-------------------------------------------------------------------------*//* td done list */static void dl_done_list (ohci_t * ohci, td_t * td_list){  	td_t * td_list_next = NULL;	ed_t * ed;	int cc = 0;	urb_t * urb;	urb_priv_t * urb_priv; 	__u32 tdINFO, edHeadP, edTailP; 	 	unsigned long flags; 	  	while (td_list) {   		td_list_next = td_list->next_dl_td;   		  		urb = td_list->urb;  		urb_priv = urb->hcpriv;  		tdINFO = le32_to_cpup (&td_list->hwINFO);  		   		ed = td_list->ed;   		   		dl_transfer_length(td_list); 			  		/* error code of transfer */  		cc = TD_CC_GET (tdINFO);  		if (cc == TD_CC_STALL)			usb_endpoint_halt(urb->dev,				usb_pipeendpoint(urb->pipe),				usb_pipeout(urb->pipe));  		  		if (!(urb->transfer_flags & USB_DISABLE_SPD)				&& (cc == TD_DATAUNDERRUN))			cc = TD_CC_NOERROR;  		if (++(urb_priv->td_cnt) == urb_priv->length) {			if ((ed->state & (ED_OPER | ED_UNLINK))					&& (urb_priv->state != URB_DEL)) {  				urb->status = cc_to_error[cc];  				sohci_return_urb (ohci, urb);  			} else {				spin_lock_irqsave (&usb_ed_lock, flags);  				dl_del_urb (urb);				spin_unlock_irqrestore (&usb_ed_lock, flags);			}  		}  		  		spin_lock_irqsave (&usb_ed_lock, flags);  		if (ed->state != ED_NEW) {   			edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;  			edTailP = le32_to_cpup (&ed->hwTailP);			/* unlink eds if they are not busy */     			if ((edHeadP == edTailP) && (ed->state == ED_OPER))      				ep_unlink (ohci, ed);     		}	     		spin_unlock_irqrestore (&usb_ed_lock, flags);     	    		td_list = td_list_next;  	}  }/*-------------------------------------------------------------------------* * Virtual Root Hub  *-------------------------------------------------------------------------*/ /* Device descriptor */static __u8 root_hub_dev_des[] ={	0x12,       /*  __u8  bLength; */	0x01,       /*  __u8  bDescriptorType; Device */	0x10,	    /*  __u16 bcdUSB; v1.1 */	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, 5 Remote-wakwup, 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 */ 	0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ 	0x00,	0xff        /*  __u8  ep_bInterval; 255 ms */};/* Hub class-specific descriptor is constructed dynamically *//*-------------------------------------------------------------------------*//* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */  static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len){	int num_ports;	int i;	int ret;	int len;	__u8 data[8];	num_ports = roothub_a (ohci) & RH_A_NDP; #ifdef CONFIG_ARCH_S3C2410	if ((ohci->rh.devnum == 1) // Root Hub			&& (num_ports > CONFIG_MAX_ROOT_PORTS))		num_ports = CONFIG_MAX_ROOT_PORTS;#endif	if (num_ports > MAX_ROOT_PORTS) {		err ("bogus NDP=%d for OHCI usb-%s", num_ports,			ohci->slot_name);		err ("rereads as NDP=%d",			readl (&ohci->regs->roothub.a) & RH_A_NDP);		/* retry later; "should not happen" */		return 0;	}	*(__u8 *) data = (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))		? 1: 0;	ret = *(__u8 *) data;	for ( i = 0; i < num_ports; i++) {		*(__u8 *) (data + (i + 1) / 8) |= 			((roothub_portstatus (ohci, i) &				(RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))			    ? 1: 0) << ((i + 1) % 8);		ret += *(__u8 *) (data + (i + 1) / 8);	}	len = i/8 + 1;  	if (ret > 0) { 		memcpy(rh_data, data,		       min_t(unsigned int, len,			   min_t(unsigned int, rh_len, sizeof(data))));		return len;	}	return 0;}/*-------------------------------------------------------------------------*//* Virtual Root Hub INTs are polled by this timer every "interval" ms */ static void rh_int_timer_do (unsigned long ptr){	int len; 	urb_t * urb = (urb_t *) ptr;	ohci_t * ohci = urb->dev->bus->hcpriv;	if (ohci->disabled)		return;	/* ignore timers firing during PM suspend, etc */	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER)		goto out;	if(ohci->rh.send) { 		len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);		if (len > 0) {			urb->actual_length = len;

⌨️ 快捷键说明

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