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

📄 usb-ohci.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		td_list = (td_t *) bus_to_virt (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;	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 = bus_to_virt (le32_to_cpup (&ed->hwTailP) & 0xfffffff0);		tdHeadP = bus_to_virt (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 = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);			if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {				*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));				if(++ (urb_priv->td_cnt) == urb_priv->length) 					urb_rm_priv (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]);   	 		OHCI_FREE (tdTailP); /* free dummy td */   	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);    	 		ed->state = ED_NEW;    	 		/* if all eds are removed wake up sohci_free_dev */   	 		if ((! --dev->ed_cnt) && dev->wait) {   	 			add_wait_queue (&op_wakeup, dev->wait); 				wake_up (&op_wakeup);			}   	 	}   	 	else {   	 		ed->state &= ~ED_URB_DEL;   	 		ed->hwINFO  &=  ~cpu_to_le32 (OHCI_ED_SKIP);   	 	}   	 	   	 	if ((ed->type & 3) == CTRL) ctrl |= 1;  		if ((ed->type & 3) == BULK) bulk |= 1;     	}   	   	if (ctrl) writel (0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */   	if (bulk) writel (0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */	if (!ohci->ed_rm_list[!frame]) 		/* start CTRL u. BULK list */   		writel (ohci->hc_control |= (0x03<<4), &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 dlen = 0;	int cc = 0;	urb_t * urb;	urb_priv_t * urb_priv; 	__u32 tdINFO, tdBE, tdCBP, edHeadP, edTailP; 	__u16 tdPSW; 	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);  		tdBE   = le32_to_cpup (&td_list->hwBE);  		tdCBP  = le32_to_cpup (&td_list->hwCBP);  		   		ed = td_list->ed;   		  		if (td_list->type & ST_ADDR)   			urb->actual_length = 0;  			 		if (td_list->type & ADD_LEN) { /* accumulate length of multi td transfers */ 			if (tdINFO & TD_ISO) { 				tdPSW = le16_to_cpu (td_list->hwPSW[0]); 				cc = (tdPSW >> 12) & 0xF;				if (cc < 0xE)  {					if (usb_pipeout(urb->pipe)) {						dlen = urb->iso_frame_desc[td_list->index].length;					} else {						dlen = tdPSW & 0x3ff;					}					urb->actual_length += dlen;					urb->iso_frame_desc[td_list->index].actual_length = dlen;					if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))						cc = TD_CC_NOERROR;					 					urb->iso_frame_desc[td_list->index].status = cc_to_error[cc];				} 			} else { 				if (tdBE != 0) { 					if (td_list->hwCBP == 0)						urb->actual_length = bus_to_virt (tdBE) - urb->transfer_buffer + 1;  					else						urb->actual_length = bus_to_virt (tdCBP) - urb->transfer_buffer;  			    }  			}  		}  		/* error code of transfer */  		cc = TD_CC_GET (tdINFO);  		if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))						cc = TD_CC_NOERROR;  		if (++(urb_priv->td_cnt) == urb_priv->length) {  			if (urb_priv->state != URB_DEL && !(ed->state & ED_DEL) && ed->state != ED_NEW) {   				urb->status = cc_to_error[cc];  				sohci_return_urb (urb);  			} else {  				urb_rm_priv (urb);  			}  		}  		  		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);     		if((edHeadP == edTailP) && (ed->state == ED_OPER))      			ep_unlink (ohci, ed); /* unlink eds if they are not busy */     		     	}	     	spin_unlock_irqrestore (&usb_ed_lock, flags);     	    	td_list = td_list_next;  	}  }/*-------------------------------------------------------------------------* * 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; */	0x00,       /*  __u8  iProduct; */	0x00,       /*  __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 */ 	0x08,       /*  __u16 ep_wMaxPacketSize; 8 Bytes */ 	0x00,	0xff        /*  __u8  ep_bInterval; 255 ms */};/* For OHCI we need just the  2nd Byte, so we don't need this constant byte-array static __u8 root_hub_hub_des[] ={ 	0x00,       *  __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; *** 8 Ports max *** *	0xff        *  __u8  PortPwrCtrlMask; *** 8 ports max *** *};*//*-------------------------------------------------------------------------*//* 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 = readl (&ohci->regs->roothub.a) & 0xff; 	*(__u8 *) data = (readl (&ohci->regs->roothub.status) & 0x00030000) > 0? 1: 0;	ret = *(__u8 *) data;	for ( i = 0; i < num_ports; i++) {		*(__u8 *) (data + (i + 1) / 8) |= 			((readl (&ohci->regs->roothub.portstatus[i]) & 0x001f0000) > 0? 1: 0) << ((i + 1) % 8);		ret += *(__u8 *) (data + (i + 1) / 8);	}	len = i/8 + 1;  	if (ret > 0) { 		memcpy (rh_data, data, min (len, min (rh_len, sizeof(data))));		return len;	}	return 0;}/*-------------------------------------------------------------------------*//* Virtual Root Hub INTs are polled by this timer every "intervall" 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->rh.send) { 		len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);		if (len > 0) {			urb->actual_length = len;#ifdef DEBUG			urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));#endif			if (urb->complete) urb->complete (urb);		}	}		rh_init_int_timer (urb);}/*-------------------------------------------------------------------------*//* Root Hub INTs are polled by this timer */static int rh_init_int_timer (urb_t * urb) {	ohci_t * ohci = urb->dev->bus->hcpriv;	ohci->rh.interval = urb->interval;	init_timer (&ohci->rh.rh_int_timer);	ohci->rh.rh_int_timer.function = rh_int_timer_do;	ohci->rh.rh_int_timer.data = (unsigned long) urb;	ohci->rh.rh_int_timer.expires = 			jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;	add_timer (&ohci->rh.rh_int_timer);		return 0;}/*-------------------------------------------------------------------------*/#define OK(x) 				len = (x); break#define WR_RH_STAT(x) 		writel((x), &ohci->regs->roothub.status)#define WR_RH_PORTSTAT(x) 	writel((x), &ohci->regs->roothub.portstatus[wIndex-1])#define RD_RH_STAT			readl(&ohci->regs->roothub.status)#define RD_RH_PORTSTAT		readl(&ohci->regs->roothub.portstatus[wIndex-1])/* request to virtual root hub */static int rh_submit_urb (urb_t * urb){	struct usb_device * usb_dev = urb->dev;	ohci_t * ohci = usb_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 = TD_CC_NOERROR;		__u8 datab[16];	__u8  * data_buf = datab;	 	__u16 bmRType_bReq;	__u16 wValue; 	__u16 wIndex;	__u16 wLength;	if (usb_pipeint(pipe)) {			ohci->rh.urb =  urb;		ohci->rh.send = 1;		ohci->rh.interval = urb->interval;		rh_init_int_timer(urb);		urb->status = cc_to_error [TD_CC_NOERROR];				return 0;	}	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);	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_buf = cpu_to_le16 (1); OK (2);		case RH_GET_STATUS | RH_INTERFACE: 	 						*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);		case RH_GET_STATUS | RH_ENDPOINT:	 						*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);   		case RH_GET_STATUS | RH_CLASS: 								*(__u32 *) data_buf = cpu_to_le32 (RD_RH_STAT & 0x7fff7fff); OK (4);		case RH_GET_STATUS | RH_OTHER | RH_CLASS: 					*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); 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_LOCAL_POWER:					OK(0);				case (RH_C_HUB_OVER_CURRENT): 						WR_RH_STAT(RH_PS_OCIC); OK (0);			}			break;				case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:			switch (wValue) {				case (RH_PORT_ENABLE): 									WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);				case (RH_PORT_SUSPEND):									WR_RH_PORTSTAT (RH_PS_POCI); OK (0);				case (RH_PORT_POWER):									WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);				case (RH_C_PORT_CONNECTION):							WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);				case (RH_C_PORT_ENABLE):								WR_RH_PORTSTAT (RH_PS_PESC); OK (0);				case (RH_C_PORT_SUSPEND):								WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);				case (RH_C_PORT_OVER_CURRENT):							WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);				case (RH_C_PORT_RESET):									WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); 			}			break; 		case RH_SET_FEATURE | RH_OTHER | RH_CLASS:			switch (wValue) {				case (RH_PORT_SUSPEND):									WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); 				case (RH_PORT_RESET): /* BUG IN HUP CODE *********/						if((RD_RH_PORTSTAT &1) != 0)  WR_RH_PORTSTAT (RH_PS_PRS ); OK (0);				case (RH_PORT_POWER):									WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); 				case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/						if((RD_RH_PORTSTAT &1) != 0)  WR_RH_PORTSTAT (RH_PS_PES ); OK (0);			}			break;		case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0);		case RH_GET_DESCRIPTOR:			switch ((wValue & 0xff00) >> 8) {				case (0x01): /* device descriptor */					len = min (leni, min (sizeof (root_hub_dev_des), wLength));					data_buf = root_hub_dev_des; OK(len);				case (0x02): /* configuration descriptor */					len = min (leni, min (sizeof (root_hub_config_des), wLength));					data_buf = root_hub_config_des; OK(len);				case (0x03): /* string descriptors */

⌨️ 快捷键说明

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