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

📄 usb-ohci.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
					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;    	 		/* 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 = bus_to_virt (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;				--(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]) {			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 (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 = readl (&ohci->regs->roothub.a) & RH_A_NDP; 	if (num_ports > MAX_ROOT_PORTS) {		err ("bogus NDP=%d for OHCI usb-%s", num_ports,			ohci->ohci_dev->slot_name);		err ("rereads as NDP=%d",			readl (&ohci->regs->roothub.a) & RH_A_NDP);		/* retry later; "should not happen" */		return 0;	}	*(__u8 *) data = (readl (&ohci->regs->roothub.status) & (RH_HS_LPSC | RH_HS_OCIC))		? 1: 0;	ret = *(__u8 *) data;	for ( i = 0; i < num_ports; i++) {		*(__u8 *) (data + (i + 1) / 8) |= 			((readl (&ohci->regs->roothub.portstatus[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 (len, min (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;#ifdef DEBUG			urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));#endif			if (urb->complete)				urb->complete (urb);		}	} out:	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;		__u32 datab[4];	__u8  * data_buf = (__u8 *) 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);	dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq,		bmRType_bReq, 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_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 & ~(RH_HS_CRWE | RH_HS_DRWE));				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_HS_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 & RH_PS_CCS)						    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 & RH_PS_CCS)						    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 */					len = usb_root_hub_string (wValue & 0xff,						(int)(long) ohci->regs, "OHCI",						data, wLength);					if (len > 0) {						data_buf = data;						OK (min (leni, len));					}					// else fallthrough				default: 					status = TD_CC_STALL;			}			break;				case RH_GET_DESCRIPTOR | RH_CLASS:		    {			    __u32 temp = readl (&ohci->regs->roothub.a);			    data_buf [0] = 9;		// min length;			    data_buf [1] = 0x29;			    data_buf [2] = temp & RH_A_NDP;			    data_buf [3] = 0;			    if (temp & RH_A_PSM) 	/* per-port power switching? */				data_buf [3] |= 0x1;			    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */				data_buf [3] |= 0x10;			    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */				data_buf [3] |= 0x8;			    datab [1] = 0;			    data_buf [5] = (temp & RH_A_POTPGT) >> 24;			    temp = readl (&ohci->regs->roothub.b);			    data_buf [7] = temp & RH_B_DR;			    if (data_buf [2] < 7) {				data_buf [8] = 0xff;			    } else {				data_buf [0] += 2;				data_buf [8] = (temp & RH_B_DR) >> 8;				data_buf [10] = data_buf [9] = 0xff;			    }							    len = min (leni, min (data_buf [0], wLength));			    OK (len);			} 		case RH_GET_CONFIGURATION: 	*(__u8 *) data_buf = 0x01; OK (1);

⌨️ 快捷键说明

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