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

📄 usb-ohci.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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(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->ohci_dev->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 (virt_to_bus (&ohci->hcca), &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	writel ((readl(&ohci->regs->roothub.a) | 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 ((readl(&ohci->regs->roothub.a) >> 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;}/*-------------------------------------------------------------------------*//* an interrupt happens */static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r){	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;	} 	// dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));	if (ints & OHCI_INTR_UE) {		ohci->disabled++;		err ("OHCI Unrecoverable Error, controller usb-%s disabled",			ohci->ohci_dev->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	}  	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) {		dbg("USB Schedule overrun");		writel (OHCI_INTR_SO, &regs->intrenable); 	 	}	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);		}	writel (ints, &regs->intrstatus);	writel (OHCI_INTR_MIE, &regs->intrenable);		/* FIXME:  check URB timeouts */}/*-------------------------------------------------------------------------*//* allocate OHCI */static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base){	ohci_t * ohci;	struct usb_bus * bus;	ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL);	if (!ohci)		return NULL;			memset (ohci, 0, sizeof (ohci_t));		ohci->disabled = 1;	ohci->irq = -1;	ohci->regs = mem_base;   	ohci->ohci_dev = dev;	dev->driver_data = ohci; 	INIT_LIST_HEAD (&ohci->ohci_hcd_list);	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);	bus = usb_alloc_bus (&sohci_device_operations);	if (!bus) {		kfree (ohci);		return NULL;	}	ohci->bus = bus;	bus->hcpriv = (void *) ohci;	return ohci;} /*-------------------------------------------------------------------------*//* De-allocate all resources.. */static void hc_release_ohci (ohci_t * ohci){		dbg ("USB HC release ohci usb-%s", ohci->ohci_dev->slot_name);	/* disconnect all devices */    	if (ohci->bus->root_hub)		usb_disconnect (&ohci->bus->root_hub);	if (!ohci->disabled)		hc_reset (ohci);		if (ohci->irq >= 0) {		free_irq (ohci->irq, ohci);		ohci->irq = -1;	}	ohci->ohci_dev->driver_data = 0;	usb_deregister_bus (ohci->bus);	usb_free_bus (ohci->bus);	list_del (&ohci->ohci_hcd_list);	INIT_LIST_HEAD (&ohci->ohci_hcd_list);    	/* unmap the IO address space */	iounmap (ohci->regs);       	kfree (ohci);}/*-------------------------------------------------------------------------*//* Increment the module usage count, start the control thread and * return success. */static struct pci_driver ohci_pci_driver; static int __devinithc_found_ohci (struct pci_dev *dev, int irq, void * mem_base){	ohci_t * ohci;	u8 latency, limit;	char buf[8], *bufp = buf;#ifndef __sparc__	sprintf(buf, "%d", irq);#else	bufp = __irq_itoa(irq);#endif	printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",		(unsigned long)	mem_base, bufp);	printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name);    	ohci = hc_alloc_ohci (dev, mem_base);	if (!ohci) {		return -ENOMEM;	}	/* bad pci latencies can contribute to overruns */ 	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);	if (latency) {		pci_read_config_byte (dev, PCI_MAX_LAT, &limit);		if (limit && limit < latency) {			dbg ("PCI latency reduced to max %d", limit);			pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);			ohci->pci_latency = limit;		} else {			/* it might already have been reduced */			ohci->pci_latency = latency;		}	}	if (hc_reset (ohci) < 0) {		hc_release_ohci (ohci);		return -ENODEV;	}	/* FIXME this is a second HC reset; why?? */	writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);	wait_ms (10);	usb_register_bus (ohci->bus);		if (request_irq (irq, hc_interrupt, SA_SHIRQ,			ohci_pci_driver.name, ohci) != 0) {		err ("request interrupt %s failed", bufp);		hc_release_ohci (ohci);		return -EBUSY;	}	ohci->irq = irq;     	if (hc_start (ohci) < 0) {		err ("can't start usb-%s", dev->slot_name);		hc_release_ohci (ohci);		return -EBUSY;	}#ifdef	DEBUG	ohci_dump (ohci, 1);#endif	return 0;}/*-------------------------------------------------------------------------*/#ifdef	CONFIG_PM/* controller died; cleanup debris, then restart *//* must not be called from interrupt context */static void hc_restart (ohci_t *ohci){	int temp;	int i;	if (ohci->pci_latency)		pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);	ohci->disabled = 1;	if (ohci->bus->root_hub)		usb_disconnect (&ohci->bus->root_hub);		/* empty the interrupt branches */	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;	for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;		/* no EDs to remove */	ohci->ed_rm_list [0] = NULL;	ohci->ed_rm_list [1] = NULL;	/* empty control and bulk lists */	 	ohci->ed_isotail     = NULL;	ohci->ed_controltail = NULL;	ohci->ed_bulktail    = NULL;	if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {		err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp);	} else		dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name);}#endif	/* CONFIG_PM *//*-------------------------------------------------------------------------*//* configured so that an OHCI device is always provided *//* always called with process context; sleeping is OK */static int __devinitohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id){	unsigned long mem_resource, mem_len;	void *mem_base;	if (pci_enable_device(dev) < 0)		return -ENODEV;		/* we read its hardware registers as memory */	mem_resource = pci_resource_start(dev, 0);	mem_len = pci_resource_len(dev, 0);	if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {		dbg ("controller already in use");		return -EBUSY;	}	mem_base = ioremap_nocache (mem_resource, mem_len);	if (!mem_base) {		err("Error mapping OHCI memory");		return -EFAULT;	}	/* controller writes into our memory */	pci_set_master (dev);	return hc_found_ohci (dev, dev->irq, mem_base);} /*-------------------------------------------------------------------------*//* may be called from interrupt context [interface spec] *//* may be called without controller present *//* may be called with controller, bus, and devices active */static void __devexitohci_pci_remove (struct pci_dev *dev){	ohci_t		*ohci = (ohci_t *) dev->driver_data;	dbg ("remove %s controller usb-%s%s%s",		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),		dev->slot_name,		ohci->disabled ? " (disabled)" : "",		in_interrupt () ? " in interrupt" : ""		);#ifdef	DEBUG	ohci_dump (ohci, 1);#endif	/* don't wake up sleeping controllers, or block in interrupt context */	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) {		dbg ("controller being disabled");		ohci->disabled = 1;	}	/* on return, USB will always be reset (if present) */	if (ohci->disabled)		writel (ohci->hc_control = OHCI_USB_RES

⌨️ 快捷键说明

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