// Check if need companion controllers for full/low speed devices static void ehci_note_port(struct usb_ehci_s *cntl) { if (--cntl->checkports) // Ports still being detected. return; if (! cntl->legacycount) // No full/low speed devices found. return; // Start companion controllers. int i; for (i=0; i<ARRAY_SIZE(cntl->companion); i++) { struct pci_device *pci = cntl->companion[i]; if (!pci) break; // ohci/uhci_setup call pci_config_X - don't run from irq handler. wait_preempt(); if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI) uhci_setup(pci, cntl->usb.busid + i); else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI) ohci_setup(pci, cntl->usb.busid + i); } }
int ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci) { if (! CONFIG_USB_EHCI) return -1; u16 bdf = pci->bdf; u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0); struct ehci_caps *caps = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK); u32 hcc_params = readl(&caps->hccparams); if (hcc_params & HCC_64BIT_ADDR) { dprintf(1, "No support for 64bit EHCI\n"); return -1; } struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl)); if (!cntl) { warn_noalloc(); return -1; } memset(cntl, 0, sizeof(*cntl)); cntl->usb.busid = busid; cntl->usb.pci = pci; cntl->usb.type = USB_TYPE_EHCI; cntl->caps = caps; cntl->regs = (void*)caps + readb(&caps->caplength); dprintf(1, "EHCI init on dev %02x:%02x.%x (regs=%p)\n" , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf) , pci_bdf_to_fn(bdf), cntl->regs); pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); // XXX - check for and disable SMM control? // Find companion controllers. int count = 0; for (;;) { if (!comppci || comppci == pci) break; if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_UHCI) cntl->companion[count++] = comppci; else if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_OHCI) cntl->companion[count++] = comppci; comppci = comppci->next; } run_thread(configure_ehci, cntl); return 0; }