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

📄 usb-ohci.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				default: 					status = TD_CC_STALL;			}			break;				case RH_GET_DESCRIPTOR | RH_CLASS:			*(__u8 *)  (data_buf+1) = 0x29;			*(__u32 *) (data_buf+2) = cpu_to_le32 (readl (&ohci->regs->roothub.a));  	 		*(__u8 *)  data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */				 			len = min (leni, min(*(__u8 *) data_buf, wLength));			*(__u8 *) (data_buf+6) = 0; /* Root Hub needs no current from bus */			if (*(__u8 *) (data_buf+2) < 8) { /* less than 8 Ports */				*(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff; 				*(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16; 			} else {				*(__u32 *) (data_buf+7) = cpu_to_le32 (readl(&ohci->regs->roothub.b)); 			}			OK (len);  		case RH_GET_CONFIGURATION: 	*(__u8 *) data_buf = 0x01; OK (1);		case RH_SET_CONFIGURATION: 	WR_RH_STAT (0x10000); OK (0);		default: 			status = TD_CC_STALL;	}		dbg("USB HC roothubstat1: %x", readl ( &(ohci->regs->roothub.portstatus[0]) ));	dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));	len = min(len, leni);	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	if (urb->complete) urb->complete (urb);	return 0;}/*-------------------------------------------------------------------------*/static int rh_unlink_urb (urb_t * urb){	ohci_t * ohci = urb->dev->bus->hcpriv; 	ohci->rh.send = 0;	del_timer (&ohci->rh.rh_int_timer);	return 0;} /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*//* reset the HC not the BUS */static void hc_reset (ohci_t * ohci){	int timeout = 30;	int smm_timeout = 50; /* 0,5 sec */	 		if (readl (&ohci->regs->control) & 0x100) { /* SMM owns the HC */		writel (0x08, &ohci->regs->cmdstatus); /* request ownership */		dbg("USB HC TakeOver from SMM");		while (readl (&ohci->regs->control) & 0x100) {			wait_ms (10);			if (--smm_timeout == 0) {				err("USB HC TakeOver failed!");				break;			}		}	}				writel ((1 << 31), &ohci->regs->intrdisable); /* Disable HC interrupts */	dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));  	/* this seems to be needed for the lucent controller on powerbooks.. */	writel (0, &ohci->regs->control);           /* Move USB to reset state */      		writel (1,  &ohci->regs->cmdstatus);	   /* HC Reset */	while ((readl (&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */		if (--timeout == 0) {			err("USB HC reset timed out!");			return;		}			udelay (1);	}	 }/*-------------------------------------------------------------------------*//* Start an OHCI controller, set the BUS operational * enable interrupts  * connect the virtual root hub */static int hc_start (ohci_t * ohci){	unsigned int mask;  	unsigned int fminterval;  	struct usb_device  * usb_dev;	struct ohci_device * dev;		/* 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);	/* Choose the interrupts we care about now, others later on demand */	mask = OHCI_INTR_MIE | OHCI_INTR_WDH | OHCI_INTR_SO;		writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */	writel (mask, &ohci->regs->intrenable);	writel (mask, &ohci->regs->intrstatus);#ifdef OHCI_USE_NPS	writel ((readl(&ohci->regs->roothub.a) | 0x200) & ~0x100,		&ohci->regs->roothub.a);	writel (0x10000, &ohci->regs->roothub.status);	mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);#endif /* OHCI_USE_NPS */ 	/* connect the virtual root hub */		usb_dev = usb_alloc_dev (NULL, ohci->bus);	if (!usb_dev) return -1;	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); 		return -1;	}		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_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);	}/*-------------------------------------------------------------------------*//* allocate OHCI */static ohci_t * hc_alloc_ohci (void * mem_base){	int i;	ohci_t * ohci;	struct usb_bus * bus;	ohci = (ohci_t *) __get_free_pages (GFP_KERNEL, 1);	if (!ohci)		return NULL;			memset (ohci, 0, sizeof (ohci_t));		ohci->irq = -1;	ohci->regs = mem_base;   	/* for load ballancing of 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;		/* end of control and bulk lists */	 	ohci->ed_isotail     = NULL;	ohci->ed_controltail = NULL;	ohci->ed_bulktail    = NULL;	bus = usb_alloc_bus (&sohci_device_operations);	if (!bus) {		free_pages ((unsigned long) ohci, 1);		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");	/* disconnect all devices */    	if (ohci->bus->root_hub) usb_disconnect (&ohci->bus->root_hub);		hc_reset (ohci);	writel (OHCI_USB_RESET, &ohci->regs->control);	wait_ms (10);		if (ohci->irq >= 0) {		free_irq (ohci->irq, ohci);		ohci->irq = -1;	}	usb_deregister_bus (ohci->bus);	usb_free_bus (ohci->bus);    	/* unmap the IO address space */	iounmap (ohci->regs);       	free_pages ((unsigned long) ohci, 1);	}/*-------------------------------------------------------------------------*//* Increment the module usage count, start the control thread and * return success. */ static int hc_found_ohci (int irq, void * mem_base){	ohci_t * ohci;	dbg("USB HC found: irq= %d membase= %lx", irq, (unsigned long) mem_base);    	ohci = hc_alloc_ohci (mem_base);	if (!ohci) {		return -ENOMEM;	}		INIT_LIST_HEAD (&ohci->ohci_hcd_list);	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);		hc_reset (ohci);	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-usb", ohci) == 0) {		ohci->irq = irq;     		hc_start (ohci);		return 0; 	}	 	err("request interrupt %d failed", irq);	hc_release_ohci (ohci);	return -EBUSY;}/*-------------------------------------------------------------------------*/ static int hc_start_ohci (struct pci_dev * dev){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)	unsigned long mem_base = dev->resource[0].start;#else	unsigned long mem_base = dev->base_address[0];	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV;	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;#endif		pci_set_master (dev);	mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);	if (!mem_base) {		err("Error mapping OHCI memory");		return -EFAULT;	}	return hc_found_ohci (dev->irq, (void *) mem_base);} /*-------------------------------------------------------------------------*/#ifdef CONFIG_PMAC_PBOOK/* On Powerbooks, put the controller into suspend mode when going * to sleep, and do a resume when waking up. */static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when){	struct list_head * ohci_l;	ohci_t * ohci;       	for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {	ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);		switch (when) {		case PBOOK_SLEEP_NOW:			disable_irq (ohci->irq);			writel (ohci->hc_control = OHCI_USB_SUSPEND, &ohci->regs->control);			wait_ms (10);			break;		case PBOOK_WAKE: 			writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);			wait_ms (20);			writel (ohci->hc_control = 0xBF, &ohci->regs->control);			enable_irq (ohci->irq);			break;		}	}	return PBOOK_SLEEP_OK;}static struct pmu_sleep_notifier ohci_sleep_notifier = {       ohci_sleep_notify, SLEEP_LEVEL_MISC,};#endif /* CONFIG_PMAC_PBOOK *//*-------------------------------------------------------------------------*/ #ifdef CONFIG_APMstatic int handle_apm_event (apm_event_t event) {	static int down = 0;	ohci_t * ohci;	struct list_head * ohci_l;		switch (event) {	case APM_SYS_SUSPEND:	case APM_USER_SUSPEND:		if (down) {			dbg("received extra suspend event");			break;		}		for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {			ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);			dbg("USB-Bus suspend: %p", ohci);			writel (ohci->hc_control = 0xFF, &ohci->regs->control);		}		wait_ms (10);		down = 1;		break;	case APM_NORMAL_RESUME:	case APM_CRITICAL_RESUME:		if (!down) {			dbg("received bogus resume event");			break;		}		for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {			ohci = list_entry(ohci_l, ohci_t, ohci_hcd_list);			dbg("USB-Bus resume: %p", ohci);			writel (ohci->hc_control = 0x7F, &ohci->regs->control);		}				wait_ms (20);		for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {			ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);			writel (ohci->hc_control = 0xBF, &ohci->regs->control);		}		down = 0;		break;	}	return 0;}#endif/*-------------------------------------------------------------------------*/#define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310 int ohci_hcd_init (void) {	int ret = -ENODEV;	struct pci_dev * dev = NULL; 	while ((dev = pci_find_class (PCI_CLASS_SERIAL_USB_OHCI, dev))) { 		if (hc_start_ohci(dev) >= 0) ret = 0;	}    #ifdef CONFIG_APM	apm_register_callback (&handle_apm_event);#endif#ifdef CONFIG_PMAC_PBOOK	pmu_register_sleep_notifier (&ohci_sleep_notifier);#endif      return ret;}/*-------------------------------------------------------------------------*/#ifdef MODULEint init_module (void) {	return ohci_hcd_init ();}/*-------------------------------------------------------------------------*/void cleanup_module (void) {		ohci_t * ohci;	#ifdef CONFIG_APM	apm_unregister_callback (&handle_apm_event);#endif#ifdef CONFIG_PMAC_PBOOK	pmu_unregister_sleep_notifier (&ohci_sleep_notifier);#endif  	while (!list_empty (&ohci_hcd_list)) {		ohci = list_entry (ohci_hcd_list.next, ohci_t, ohci_hcd_list);		list_del (&ohci->ohci_hcd_list);		INIT_LIST_HEAD (&ohci->ohci_hcd_list);		hc_release_ohci (ohci);	}		}#endif //MODULE

⌨️ 快捷键说明

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