X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fusb-uhci.c;h=a78dbcaf63e679ac55d1c8f3fc11fd93454ec6b0;hb=72b5e45550e5dc439681cd90a9b6220ac20d0254;hp=f666ab7c3d32e4c2bf455bb23fc80f3cc22131a1;hpb=190cc622a2f57ca21d8ffc85be94c32fb518b04d;p=seabios.git diff --git a/src/usb-uhci.c b/src/usb-uhci.c index f666ab7..a78dbca 100644 --- a/src/usb-uhci.c +++ b/src/usb-uhci.c @@ -12,7 +12,6 @@ #include "pci_regs.h" // PCI_BASE_ADDRESS_4 #include "usb.h" // struct usb_s #include "farptr.h" // GET_FLATPTR -#include "usb-hub.h" // struct usbhub_s struct usb_uhci_s { struct usb_s usb; @@ -26,55 +25,59 @@ struct usb_uhci_s { * Root hub ****************************************************************/ -static void -init_uhci_port(void *data) +// Check if device attached to a given port +static int +uhci_hub_detect(struct usbhub_s *hub, u32 port) { - struct usbhub_s *hub = data; - u32 port = hub->port; // XXX - find better way to pass port struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb); u16 ioport = cntl->iobase + USBPORTSC1 + port * 2; u16 status = inw(ioport); if (!(status & USBPORTSC_CCS)) // No device - goto done; + return -1; // XXX - if just powered up, need to wait for USB_TIME_ATTDB? - // Reset port + // Begin reset on port outw(USBPORTSC_PR, ioport); msleep(USB_TIME_DRSTR); - mutex_lock(&cntl->usb.resetlock); + return 0; +} + +// Reset device on port +static int +uhci_hub_reset(struct usbhub_s *hub, u32 port) +{ + struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb); + u16 ioport = cntl->iobase + USBPORTSC1 + port * 2; + + // Finish reset on port outw(0, ioport); udelay(6); // 64 high-speed bit times - status = inw(ioport); + u16 status = inw(ioport); if (!(status & USBPORTSC_CCS)) // No longer connected - goto resetfail; + return -1; outw(USBPORTSC_PE, ioport); - struct usb_pipe *pipe = usb_set_address( - hub, port, !!(status & USBPORTSC_LSDA)); - if (!pipe) - goto resetfail; - mutex_unlock(&cntl->usb.resetlock); - - // Configure port - int count = configure_usb_device(pipe); - free_pipe(pipe); - if (! count) - // Disable port - outw(0, ioport); - hub->devcount += count; -done: - hub->threads--; - return; - -resetfail: + return !!(status & USBPORTSC_LSDA); +} + +// Disable port +static void +uhci_hub_disconnect(struct usbhub_s *hub, u32 port) +{ + struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb); + u16 ioport = cntl->iobase + USBPORTSC1 + port * 2; outw(0, ioport); - mutex_unlock(&cntl->usb.resetlock); - goto done; } +static struct usbhub_op_s uhci_HubOp = { + .detect = uhci_hub_detect, + .reset = uhci_hub_reset, + .disconnect = uhci_hub_disconnect, +}; + // Find any devices connected to the root hub. static int check_uhci_ports(struct usb_uhci_s *cntl) @@ -83,17 +86,9 @@ check_uhci_ports(struct usb_uhci_s *cntl) struct usbhub_s hub; memset(&hub, 0, sizeof(hub)); hub.cntl = &cntl->usb; - hub.threads = 2; - - // Launch a thread for every port. - run_thread(init_uhci_port, &hub); - hub.port = 1; - run_thread(init_uhci_port, &hub); - - // Wait for threads to complete. - while (hub.threads) - yield(); - + hub.portcount = 2; + hub.op = &uhci_HubOp; + usb_enumerate(&hub); return hub.devcount; } @@ -184,18 +179,24 @@ fail: } void -uhci_init(u16 bdf, int busid) +uhci_init(struct pci_device *pci, int busid) { if (! CONFIG_USB_UHCI) return; + u16 bdf = pci->bdf; struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl)); + if (!cntl) { + warn_noalloc(); + return; + } memset(cntl, 0, sizeof(*cntl)); cntl->usb.busid = busid; + cntl->usb.pci = pci; cntl->usb.type = USB_TYPE_UHCI; cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4) & PCI_BASE_ADDRESS_IO_MASK); - dprintf(3, "UHCI init on dev %02x:%02x.%x (io=%x)\n" + dprintf(1, "UHCI init on dev %02x:%02x.%x (io=%x)\n" , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf) , pci_bdf_to_fn(bdf), cntl->iobase); @@ -211,26 +212,13 @@ uhci_init(u16 bdf, int busid) * End point communication ****************************************************************/ -static int -wait_qh(struct usb_uhci_s *cntl, struct uhci_qh *qh) -{ - // XXX - 500ms just a guess - u64 end = calc_future_tsc(500); - for (;;) { - if (qh->element & UHCI_PTR_TERM) - return 0; - if (check_time(end)) { - warn_timeout(); - struct uhci_td *td = (void*)(qh->element & ~UHCI_PTR_BITS); - dprintf(1, "Timeout on wait_qh %p (td=%p s=%x c=%x/%x)\n" - , qh, td, td->status - , inw(cntl->iobase + USBCMD) - , inw(cntl->iobase + USBSTS)); - return -1; - } - yield(); - } -} +struct uhci_pipe { + struct uhci_qh qh; + struct uhci_td *next_td; + struct usb_pipe pipe; + u16 iobase; + u8 toggle; +}; // Wait for next USB frame to start - for ensuring safe memory release. static void @@ -242,7 +230,7 @@ uhci_waittick(u16 iobase) for (;;) { if (inw(iobase + USBFRNUM) != startframe) break; - if (check_time(end)) { + if (check_tsc(end)) { warn_timeout(); return; } @@ -250,13 +238,29 @@ uhci_waittick(u16 iobase) } } -struct uhci_pipe { - struct uhci_qh qh; - struct uhci_td *next_td; - struct usb_pipe pipe; - u16 iobase; - u8 toggle; -}; +static int +wait_pipe(struct uhci_pipe *pipe, int timeout) +{ + u64 end = calc_future_tsc(timeout); + for (;;) { + u32 el_link = GET_FLATPTR(pipe->qh.element); + if (el_link & UHCI_PTR_TERM) + return 0; + if (check_tsc(end)) { + warn_timeout(); + u16 iobase = GET_FLATPTR(pipe->iobase); + struct uhci_td *td = (void*)(el_link & ~UHCI_PTR_BITS); + dprintf(1, "Timeout on wait_pipe %p (td=%p s=%x c=%x/%x)\n" + , pipe, (void*)el_link, GET_FLATPTR(td->status) + , inw(iobase + USBCMD) + , inw(iobase + USBSTS)); + SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM); + uhci_waittick(iobase); + return -1; + } + yield(); + } +} void uhci_free_pipe(struct usb_pipe *p) @@ -330,8 +334,6 @@ uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize return -1; dprintf(5, "uhci_control %p\n", p); struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe); - struct usb_uhci_s *cntl = container_of( - pipe->pipe.cntl, struct usb_uhci_s, usb); int maxpacket = pipe->pipe.maxpacket; int lowspeed = pipe->pipe.speed; @@ -375,11 +377,7 @@ uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize // Transfer data barrier(); pipe->qh.element = (u32)&tds[0]; - int ret = wait_qh(cntl, &pipe->qh); - if (ret) { - pipe->qh.element = UHCI_PTR_TERM; - uhci_waittick(pipe->iobase); - } + int ret = wait_pipe(pipe, 500); free(tds); return ret; } @@ -422,7 +420,7 @@ wait_td(struct uhci_td *td) status = td->status; if (!(status & TD_CTRL_ACTIVE)) break; - if (check_time(end)) { + if (check_tsc(end)) { warn_timeout(); return -1; } @@ -486,16 +484,8 @@ uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) data += transfer; datasize -= transfer; } - int i; - for (i=0; itoggle, !!toggle); - return 0; + return wait_pipe(pipe, 5000); fail: dprintf(1, "uhci_send_bulk failed\n"); SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);