X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fusb.c;h=1f69d16aa2b738d732125891d8aff0b50602f45a;hb=refs%2Fheads%2Fcoreboot;hp=8b3c36ed3b543e9932ef6bcd2568be53a0366eeb;hpb=190cc622a2f57ca21d8ffc85be94c32fb518b04d;p=seabios.git diff --git a/src/usb.c b/src/usb.c index 8b3c36e..1f69d16 100644 --- a/src/usb.c +++ b/src/usb.c @@ -94,7 +94,7 @@ alloc_bulk_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc) case USB_TYPE_UHCI: return uhci_alloc_bulk_pipe(&dummy); case USB_TYPE_OHCI: - return NULL; + return ohci_alloc_bulk_pipe(&dummy); case USB_TYPE_EHCI: return ehci_alloc_bulk_pipe(&dummy); } @@ -108,7 +108,7 @@ usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize) case USB_TYPE_UHCI: return uhci_send_bulk(pipe_fl, dir, data, datasize); case USB_TYPE_OHCI: - return -1; + return ohci_send_bulk(pipe_fl, dir, data, datasize); case USB_TYPE_EHCI: return ehci_send_bulk(pipe_fl, dir, data, datasize); } @@ -242,7 +242,7 @@ set_configuration(struct usb_pipe *pipe, u16 val) // Assign an address to a device in the default state on the given // controller. -struct usb_pipe * +static struct usb_pipe * usb_set_address(struct usbhub_s *hub, int port, int speed) { ASSERT32FLAT(); @@ -259,6 +259,7 @@ usb_set_address(struct usbhub_s *hub, int port, int speed) dummy.cntl = cntl; dummy.type = cntl->type; dummy.maxpacket = 8; + dummy.path = (u64)-1; cntl->defaultpipe = defpipe = alloc_default_control_pipe(&dummy); if (!defpipe) return NULL; @@ -294,12 +295,15 @@ usb_set_address(struct usbhub_s *hub, int port, int speed) defpipe->devaddr = cntl->maxaddr; struct usb_pipe *pipe = alloc_default_control_pipe(defpipe); defpipe->devaddr = 0; + if (hub->pipe) + pipe->path = hub->pipe->path; + pipe->path = (pipe->path << 8) | port; return pipe; } // Called for every found device - see if a driver is available for // this device and do setup if so. -int +static int configure_usb_device(struct usb_pipe *pipe) { ASSERT32FLAT(); @@ -325,11 +329,9 @@ configure_usb_device(struct usb_pipe *pipe) // Determine if a driver exists for this device - only look at the // first interface of the first configuration. struct usb_interface_descriptor *iface = (void*)(&config[1]); - if ((iface->bInterfaceClass != USB_CLASS_HID - || iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT - || iface->bInterfaceProtocol != USB_INTERFACE_PROTOCOL_KEYBOARD) - && (iface->bInterfaceClass != USB_CLASS_MASS_STORAGE) - && (iface->bInterfaceClass != USB_CLASS_HUB)) + if (iface->bInterfaceClass != USB_CLASS_HID + && iface->bInterfaceClass != USB_CLASS_MASS_STORAGE + && iface->bInterfaceClass != USB_CLASS_HUB) // Not a supported device. goto fail; @@ -345,7 +347,7 @@ configure_usb_device(struct usb_pipe *pipe) else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE) ret = usb_msc_init(pipe, iface, imax); else - ret = usb_keyboard_init(pipe, iface, imax); + ret = usb_hid_init(pipe, iface, imax); if (ret) goto fail; @@ -356,6 +358,66 @@ fail: return 0; } +static void +usb_init_hub_port(void *data) +{ + struct usbhub_s *hub = data; + u32 port = hub->port; // XXX - find better way to pass port + + // Detect if device present (and possibly start reset) + int ret = hub->op->detect(hub, port); + if (ret) + // No device present + goto done; + + // Reset port and determine device speed + mutex_lock(&hub->cntl->resetlock); + ret = hub->op->reset(hub, port); + if (ret < 0) + // Reset failed + goto resetfail; + + // Set address of port + struct usb_pipe *pipe = usb_set_address(hub, port, ret); + if (!pipe) { + hub->op->disconnect(hub, port); + goto resetfail; + } + mutex_unlock(&hub->cntl->resetlock); + + // Configure the device + int count = configure_usb_device(pipe); + free_pipe(pipe); + if (!count) + hub->op->disconnect(hub, port); + hub->devcount += count; +done: + hub->threads--; + return; + +resetfail: + mutex_unlock(&hub->cntl->resetlock); + goto done; +} + +void +usb_enumerate(struct usbhub_s *hub) +{ + u32 portcount = hub->portcount; + hub->threads = portcount; + + // Launch a thread for every port. + int i; + for (i=0; iport = i; + run_thread(usb_init_hub_port, hub); + } + + // Wait for threads to complete. + while (hub->threads) + yield(); +} + void usb_setup(void) { @@ -365,49 +427,42 @@ usb_setup(void) dprintf(3, "init usb\n"); - usb_keyboard_setup(); - // Look for USB controllers - int ehcibdf = -1; int count = 0; - int bdf, max; - foreachpci(bdf, max) { - u32 code = pci_config_readl(bdf, PCI_CLASS_REVISION) >> 8; - - if (code >> 8 != PCI_CLASS_SERIAL_USB) + struct pci_device *ehcipci = PCIDevices; + struct pci_device *pci; + foreachpci(pci) { + if (pci->class != PCI_CLASS_SERIAL_USB) continue; - if (bdf > ehcibdf) { + if (pci->bdf >= ehcipci->bdf) { // Check to see if this device has an ehci controller - ehcibdf = bdf; - u32 ehcicode = code; int found = 0; + ehcipci = pci; for (;;) { - if (ehcicode == PCI_CLASS_SERIAL_USB_EHCI) { + if (pci_classprog(ehcipci) == PCI_CLASS_SERIAL_USB_EHCI) { // Found an ehci controller. - int ret = ehci_init(ehcibdf, count++, bdf); + int ret = ehci_init(ehcipci, count++, pci); if (ret) // Error break; count += found; - bdf = ehcibdf; - code = 0; + pci = ehcipci; break; } - if (ehcicode >> 8 == PCI_CLASS_SERIAL_USB) + if (ehcipci->class == PCI_CLASS_SERIAL_USB) found++; - ehcibdf = pci_next(ehcibdf+1, &max); - if (ehcibdf < 0 - || pci_bdf_to_busdev(ehcibdf) != pci_bdf_to_busdev(bdf)) + ehcipci = ehcipci->next; + if (!ehcipci || (pci_bdf_to_busdev(ehcipci->bdf) + != pci_bdf_to_busdev(pci->bdf))) // No ehci controller found. break; - ehcicode = pci_config_readl(ehcibdf, PCI_CLASS_REVISION) >> 8; } } - if (code == PCI_CLASS_SERIAL_USB_UHCI) - uhci_init(bdf, count++); - else if (code == PCI_CLASS_SERIAL_USB_OHCI) - ohci_init(bdf, count++); + if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI) + uhci_init(pci, count++); + else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI) + ohci_init(pci, count++); } }