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

📄 usb-ohci.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#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		roothub_status(ohci)#define RD_RH_PORTSTAT		roothub_portstatus(ohci,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);	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_t(unsigned int,						  leni,						  min_t(unsigned int,						      sizeof (root_hub_dev_des),						      wLength));					data_buf = root_hub_dev_des; OK(len);				case (0x02): /* configuration descriptor */					len = min_t(unsigned int,						  leni,						  min_t(unsigned int,						      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_t(int, leni, len));					}					// else fallthrough				default: 					status = TD_CC_STALL;			}			break;				case RH_GET_DESCRIPTOR | RH_CLASS:		    {			    __u32 temp = roothub_a (ohci);			    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 = roothub_b (ohci);			    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_t(unsigned int, leni,				      min_t(unsigned int, data_buf [0], wLength));			    OK (len);			} 		case RH_GET_CONFIGURATION: 	*(__u8 *) data_buf = 0x01; OK (1);		case RH_SET_CONFIGURATION: 	WR_RH_STAT (0x10000); OK (0);		default: 			dbg ("unsupported root hub command");			status = TD_CC_STALL;	}	#ifdef	DEBUG	// ohci_dump_roothub (ohci, 0);#endif	len = min_t(int, len, leni);	if (data != data_buf)	    memcpy (data, data_buf, len);  	urb->actual_length = len;	urb->status = cc_to_error [status];	#ifdef DEBUG	urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));#endif	urb->hcpriv = NULL;	usb_dec_dev_use (usb_dev);	urb->dev = NULL;	if (urb->complete)	    	urb->complete (urb);	return 0;}/*-------------------------------------------------------------------------*/static int rh_unlink_urb (urb_t * urb){	ohci_t * ohci = urb->dev->bus->hcpriv; 	if (ohci->rh.urb == urb) {		ohci->rh.send = 0;		del_timer (&ohci->rh.rh_int_timer);		ohci->rh.urb = NULL;		urb->hcpriv = NULL;		usb_dec_dev_use(urb->dev);		urb->dev = NULL;		if (urb->transfer_flags & USB_ASYNC_UNLINK) {			urb->status = -ECONNRESET;			if (urb->complete)				urb->complete (urb);		} else			urb->status = -ENOENT;	}	return 0;} /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*//* reset the HC and BUS */static int hc_reset (ohci_t * ohci){	int timeout = 30;	int smm_timeout = 50; /* 0,5 sec */	 		if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */		dbg("USB HC TakeOver from SMM");		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {			wait_ms (10);			if (--smm_timeout == 0) {				err("USB HC TakeOver failed!");				return -1;			}		}	}				/* Disable HC interrupts */	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);	dbg("USB HC reset_hc usb-%s: ctrl = 0x%x ;",		ohci->slot_name,		readl (&ohci->regs->control));  	/* Reset USB (needed by some controllers) */	writel (0, &ohci->regs->control);      		/* HC Reset requires max 10 ms delay */	writel (OHCI_HCR,  &ohci->regs->cmdstatus);	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {		if (--timeout == 0) {			err("USB HC reset timed out!");			return -1;		}			udelay (1);	}	 	return 0;}/*-------------------------------------------------------------------------*//* Start an OHCI controller, set the BUS operational * enable interrupts  * connect the virtual root hub */static int hc_start (ohci_t * ohci){  	__u32 mask;  	unsigned int fminterval;  	struct usb_device  * usb_dev;	struct ohci_device * dev;		ohci->disabled = 1;	/* Tell the controller where the control and bulk lists are	 * The lists are empty now. */	 	writel (0, &ohci->regs->ed_controlhead);	writel (0, &ohci->regs->ed_bulkhead);		writel (ohci->hcca_dma, &ohci->regs->hcca); /* a reset clears this */     	fminterval = 0x2edf;	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);	fminterval |= ((((fminterval - 210) * 6) / 7) << 16); 	writel (fminterval, &ohci->regs->fminterval);		writel (0x628, &ohci->regs->lsthresh); 	/* start controller operations */ 	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;	ohci->disabled = 0; 	writel (ohci->hc_control, &ohci->regs->control); 	/* Choose the interrupts we care about now, others later on demand */	mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;	writel (mask, &ohci->regs->intrenable);	writel (mask, &ohci->regs->intrstatus);#ifdef	OHCI_USE_NPS	/* required for AMD-756 and some Mac platforms */	writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,		&ohci->regs->roothub.a);	writel (RH_HS_LPSC, &ohci->regs->roothub.status);#endif	/* OHCI_USE_NPS */	// POTPGT delay is bits 24-31, in 2 ms units.	mdelay ((roothub_a (ohci) >> 23) & 0x1fe); 	/* connect the virtual root hub */	ohci->rh.devnum = 0;	usb_dev = usb_alloc_dev (NULL, ohci->bus);	if (!usb_dev) {	    ohci->disabled = 1;	    return -ENOMEM;	}	dev = usb_to_ohci (usb_dev);	ohci->bus->root_hub = usb_dev;	usb_connect (usb_dev);	if (usb_new_device (usb_dev) != 0) {		usb_free_dev (usb_dev); 		ohci->disabled = 1;		return -ENODEV;	}		return 0;}/*-------------------------------------------------------------------------*//* called only from interrupt handler */static void check_timeouts (struct ohci *ohci){	spin_lock (&usb_ed_lock);	while (!list_empty (&ohci->timeout_list)) {		struct urb	*urb;		urb = list_entry (ohci->timeout_list.next, struct urb, urb_list);		if (time_after (jiffies, urb->timeout))			break;		list_del_init (&urb->urb_list);		if (urb->status != -EINPROGRESS)			continue;		urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;		spin_unlock (&usb_ed_lock);		// outside the interrupt handler (in a timer...)		// this reference would race interrupts		sohci_unlink_urb (urb);		spin_lock (&usb_ed_lock);	}	spin_unlock (&usb_ed_lock);}/*-------------------------------------------------------------------------*//* an interrupt happens */static void hc_interrupt (int irq, void * __ohci, struct pt_regs * k){	ohci_t * ohci = __ohci;	struct ohci_regs * regs = ohci->regs; 	int ints; 	if ((ohci->hcca->done_head != 0) && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {		ints =  OHCI_INTR_WDH;	} else if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0) {		return;	}//	printk("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));	if (ints & OHCI_INTR_UE) {		ohci->disabled++;		printk ("OHCI Unrecoverable Error, controller usb-%s disabled",			ohci->slot_name);		// e.g. due to PCI Master/Target Abort#ifdef	DEBUG		ohci_dump (ohci, 1);#else		// FIXME: be optimistic, hope that bug won't repeat often.		// Make some non-interrupt context restart the controller.		// Count and limit the retries though; either hardware or		// software errors can go forever...#endif		hc_reset (ohci);	}  	if (ints & OHCI_INTR_WDH) {		writel (OHCI_INTR_WDH, &regs->intrdisable);			dl_done_list (ohci, dl_reverse_done_list (ohci));		writel (OHCI_INTR_WDH, &regs->intrenable); 	}  	if (ints & OHCI_INTR_SO) {		printk("USB Schedule overrun\n");		writel (OHCI_INTR_SO, &regs->intrenable); 	 	}	// FIXME:  this assumes SOF (1/ms) interrupts don't get lost...	if (ints & OHCI_INTR_SF) { 		unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;		writel (OHCI_INTR_SF, &regs->intrdisable);			if (ohci->ed_rm_list[!frame] != NULL) {			dl_del_list (ohci, !frame);		}		if (ohci->ed_rm_list[frame] != NULL)			writel (OHCI_INTR_SF, &regs->intrenable);		}	if (!list_empty (&ohci->timeout_list)) {		check_timeouts (ohci);// FIXM

⌨️ 快捷键说明

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