📄 ehci-hcd-fotg2xx.c
字号:
readl (&ehci->regs->command); /* unblock posted write */ bh = 0;#ifdef EHCI_VERBOSE_DEBUG /* unrequested/ignored: Port Change Detect, Frame List Rollover */ dbg_status (ehci, "irq", status);#endif /* INT, ERR, and IAA interrupt rates can be throttled */ /* normal [4.15.1.2] or error [4.15.1.1] completion */ if (likely ((status & (STS_INT|STS_ERR)) != 0)) { if (likely ((status & STS_ERR) == 0)) COUNT (ehci->stats.normal); else COUNT (ehci->stats.error); bh = 1; } /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { COUNT (ehci->stats.reclaim); ehci->reclaim_ready = 1; bh = 1; } /* PCI errors [4.15.2.4] */ if (unlikely ((status & STS_FATAL) != 0)) { ehci_err (ehci, "fatal error\n");dead: ehci_reset (ehci); /* generic layer kills/unlinks all urbs, then * uses ehci_stop to clean up the rest */ bh = 1; } if (bh) ehci_work (ehci, regs);done: spin_unlock (&ehci->lock);}/*-------------------------------------------------------------------------*//* * non-error returns are a promise to giveback() the urb later * we drop ownership so next owner (or urb unlink) can get it * * urb + dev is in hcd_dev.urb_list * we're queueing TDs onto software and hardware lists * * hcd-specific init for hcpriv hasn't been done yet * * NOTE: control, bulk, and interrupt share the same code to append TDs * to a (possibly active) QH, and the same QH scanning code. */static int ehci_urb_enqueue ( struct usb_hcd *hcd, struct urb *urb, int mem_flags) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct list_head qtd_list; urb->transfer_flags &= ~EHCI_STATE_UNLINK; INIT_LIST_HEAD (&qtd_list); switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: default: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; return submit_async (ehci, urb, &qtd_list, mem_flags); case PIPE_INTERRUPT: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; return intr_submit (ehci, urb, &qtd_list, mem_flags); case PIPE_ISOCHRONOUS: if (urb->dev->speed == USB_SPEED_HIGH) return itd_submit (ehci, urb, mem_flags);#ifdef have_split_iso else return sitd_submit (ehci, urb, mem_flags);#else dbg ("no split iso support yet"); return -ENOSYS;#endif /* have_split_iso */ }}/* remove from hardware lists * completions normally happen asynchronously */static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb){ struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_qh *qh; unsigned long flags; spin_lock_irqsave (&ehci->lock, flags); switch (usb_pipetype (urb->pipe)) { // case PIPE_CONTROL: // case PIPE_BULK: default: qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; /* if we need to use IAA and it's busy, defer */ if (qh->qh_state == QH_STATE_LINKED && ehci->reclaim && HCD_IS_RUNNING (ehci->hcd.state) ) { struct ehci_qh *last; for (last = ehci->reclaim; last->reclaim; last = last->reclaim) continue; qh->qh_state = QH_STATE_UNLINK_WAIT; last->reclaim = qh; /* bypass IAA if the hc can't care */ } else if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim) end_unlink_async (ehci, NULL); /* something else might have unlinked the qh by now */ if (qh->qh_state == QH_STATE_LINKED) start_unlink_async (ehci, qh); break; case PIPE_INTERRUPT: qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; if (qh->qh_state == QH_STATE_LINKED) { /* messy, can spin or block a microframe ... */ intr_deschedule (ehci, qh, 1); /* qh_state == IDLE */ } qh_completions (ehci, qh, NULL); /* reschedule QH iff another request is queued */ if (!list_empty (&qh->qtd_list) && HCD_IS_RUNNING (ehci->hcd.state)) { int status; status = qh_schedule (ehci, qh); spin_unlock_irqrestore (&ehci->lock, flags); if (status != 0) { // shouldn't happen often, but ... // FIXME kill those tds' urbs err ("can't reschedule qh %p, err %d", qh, status); } return status; } break; case PIPE_ISOCHRONOUS: // itd or sitd ... // wait till next completion, do it then. // completion irqs can wait up to 1024 msec, urb->transfer_flags |= EHCI_STATE_UNLINK; break; } spin_unlock_irqrestore (&ehci->lock, flags); return 0;}/*-------------------------------------------------------------------------*/// bulk qh holds the data togglestatic void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev){ struct hcd_dev *dev = (struct hcd_dev *)udev->hcpriv; struct ehci_hcd *ehci = hcd_to_ehci (hcd); int i; unsigned long flags; /* ASSERT: no requests/urbs are still linked (so no TDs) */ /* ASSERT: nobody can be submitting urbs for this any more */ dbg ("%s: free_config devnum %d", hcd_to_bus (hcd)->bus_name, udev->devnum); spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < 32; i++) { if (dev->ep [i]) { struct ehci_qh *qh; char *why; /* dev->ep never has ITDs or SITDs */ qh = (struct ehci_qh *) dev->ep [i]; /* detect/report non-recoverable errors */ if (in_interrupt ()) why = "disconnect() didn't"; else if ((qh->hw_info2 & cpu_to_le32 (0xffff)) != 0 && qh->qh_state != QH_STATE_IDLE) why = "(active periodic)"; else why = 0; if (why) { err ("dev %s-%s ep %d-%s error: %s", hcd_to_bus (hcd)->bus_name, udev->devpath, i & 0xf, (i & 0x10) ? "IN" : "OUT", why); BUG (); } dev->ep [i] = 0; if (qh->qh_state == QH_STATE_IDLE) goto idle; dbg ("free_config, async ep 0x%02x qh %p", i, qh); /* scan_async() empties the ring as it does its work, * using IAA, but doesn't (yet?) turn it off. if it * doesn't empty this qh, likely it's the last entry. */ while (qh->qh_state == QH_STATE_LINKED && ehci->reclaim && HCD_IS_RUNNING (ehci->hcd.state) ) { spin_unlock_irqrestore (&ehci->lock, flags); /* wait_ms() won't spin, we're a thread; * and we know IRQ/timer/... can progress */ wait_ms (1); spin_lock_irqsave (&ehci->lock, flags); } if (qh->qh_state == QH_STATE_LINKED) start_unlink_async (ehci, qh); while (qh->qh_state != QH_STATE_IDLE && ehci->hcd.state != USB_STATE_HALT) { spin_unlock_irqrestore (&ehci->lock, flags); wait_ms (1); spin_lock_irqsave (&ehci->lock, flags); }idle: qh_put (ehci, qh); } } spin_unlock_irqrestore (&ehci->lock, flags);}static const struct hc_driver ehci_driver = { description: hcd_name, /* * generic hardware linkage */ irq: ehci_irq, flags: HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations */ start: ehci_start,#ifdef CONFIG_PM suspend: ehci_suspend, resume: ehci_resume,#endif stop: ehci_stop, /* * memory lifecycle (except per-request) */ hcd_alloc: ehci_hcd_alloc, hcd_free: ehci_hcd_free, /* * managing i/o requests and associated device resources */ urb_enqueue: ehci_urb_enqueue, urb_dequeue: ehci_urb_dequeue, free_config: ehci_free_config, /* * scheduling support */ get_frame_number: ehci_get_frame, /* * root hub support */ hub_status_data: ehci_hub_status_data, hub_control: ehci_hub_control, disconnect_for_OTG: ehci_disconnect_for_OTG,//Faraday-EHCI(FOTG2XX)};/*-------------------------------------------------------------------------*/#if 0static const struct hc_driver ehci_driver = { .description = hcd_name, /* * generic hardware linkage */ .irq = ehci_irq, .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations */ .start = ehci_start,#ifdef CONFIG_PM .suspend = ehci_suspend, .resume = ehci_resume,#endif .stop = ehci_stop, /* * memory lifecycle (except per-request) */ .hcd_alloc = ehci_hcd_alloc, .hcd_free = ehci_hcd_free, /* * managing i/o requests and associated device resources */ .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .free_config = ehci_free_config, /* * scheduling support */ .get_frame_number = ehci_get_frame, /* * root hub support */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control,};/*-------------------------------------------------------------------------*//* EHCI spec says PCI is required. *//* PCI driver selection metadata; PCI hotplugging uses this */static const struct pci_device_id __devinitdata pci_ids [] = { { /* handle any USB 2.0 EHCI controller */ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x20), .class_mask = ~0, .driver_data = (unsigned long) &ehci_driver, /* no matter who makes it */ .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID,}, { /* end: all zeroes */ }};MODULE_DEVICE_TABLE (pci, pci_ids);/* pci driver glue; this is a "new style" PCI driver module */static struct pci_driver ehci_pci_driver = { .name = (char *) hcd_name, .id_table = pci_ids, .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove,#ifdef CONFIG_PM .suspend = usb_hcd_pci_suspend, .resume = usb_hcd_pci_resume,#endif};#endif#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESCMODULE_DESCRIPTION (DRIVER_INFO);MODULE_AUTHOR (DRIVER_AUTHOR);MODULE_LICENSE ("GPL");extern void usb_ehcd_FEHCI_probe (struct hc_driver *driver,int iType);static int __init init (void) { dbg (DRIVER_INFO); dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd", sizeof (struct ehci_qh), sizeof (struct ehci_qtd), sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); DBG_HOST_EHCI("### >>> &ehci_driver = 0x%x \n",&ehci_driver); usb_ehcd_FEHCI_probe((struct hc_driver*) &ehci_driver,1); return 0;}module_init (init);static void __exit cleanup (void) { #if 1 DBG_HOST_EHCI("### >>> Enter ehci-hcd.c file --> cleanup function \n");#else pci_unregister_driver (&ehci_pci_driver);#endif }module_exit (cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -