Index: usb.c =================================================================== RCS file: /cvs/src/sys/dev/usb/usb.c,v retrieving revision 1.35 diff -u -p -r1.35 usb.c --- usb.c 1 Nov 2006 03:37:24 -0000 1.35 +++ usb.c 11 Mar 2007 08:27:37 -0000 @@ -119,7 +119,8 @@ const struct cdevsw usb_cdevsw = { }; #endif -Static volatile int threads_pending = 0; +Static volatile int usb1_threads_pending = 0; +Static volatile int usb2_threads_pending = 0; Static void usb_discover(void *); Static void usb_create_event_thread(void *); @@ -249,7 +250,9 @@ usb_create_event_thread(void *arg) static int created = 0; if (sc->sc_bus->usbrev == USBREV_2_0) - threads_pending++; + usb2_threads_pending++; + else + usb1_threads_pending++; if (kthread_create(usb_event_thread, sc, &sc->sc_event_thread, "%s", sc->sc_dev.dv_xname)) @@ -307,9 +310,22 @@ usb_event_thread(void *arg) DPRINTF(("usb_event_thread: start\n")); + /* USB2 threads wait for USB1 threads to finish their power on. */ + while (sc->sc_bus->usbrev == USBREV_2_0 && usb1_threads_pending) + (void)tsleep((void *)&usb1_threads_pending, PWAIT, "pwron", 0); + + /* Power on ports. */ + sc->sc_bus->root_hub->hub->poweron(sc->sc_bus->root_hub); + + /* Wake up any USB2 threads waiting for their companions to poweron. */ + if (sc->sc_bus->usbrev != USBREV_2_0) { + usb1_threads_pending--; + wakeup((void *)&usb1_threads_pending); + } + /* USB1 threads wait for USB2 threads to finish their first probe. */ - while (sc->sc_bus->usbrev != USBREV_2_0 && threads_pending) - (void)tsleep((void *)&threads_pending, PWAIT, "config", 0); + while (sc->sc_bus->usbrev != USBREV_2_0 && usb2_threads_pending) + (void)tsleep((void *)&usb2_threads_pending, PWAIT, "config", 0); /* Make sure first discover does something. */ sc->sc_bus->needs_explore = 1; @@ -318,8 +334,8 @@ usb_event_thread(void *arg) /* Wake up any companions waiting for handover before their probes. */ if (sc->sc_bus->usbrev == USBREV_2_0) { - threads_pending--; - wakeup((void *)&threads_pending); + usb2_threads_pending--; + wakeup((void *)&usb2_threads_pending); } while (!sc->sc_dying) { Index: usbdivar.h =================================================================== RCS file: /cvs/src/sys/dev/usb/usbdivar.h,v retrieving revision 1.24 diff -u -p -r1.24 usbdivar.h --- usbdivar.h 31 May 2006 06:18:09 -0000 1.24 +++ usbdivar.h 11 Mar 2007 08:27:37 -0000 @@ -92,6 +92,7 @@ struct usbd_port { }; struct usbd_hub { + usbd_status (*poweron)(usbd_device_handle hub); usbd_status (*explore)(usbd_device_handle hub); void *hubsoftc; usb_hub_descriptor_t hubdesc; Index: uhub.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uhub.c,v retrieving revision 1.34 diff -u -p -r1.34 uhub.c --- uhub.c 26 Jun 2006 19:12:38 -0000 1.34 +++ uhub.c 11 Mar 2007 08:27:38 -0000 @@ -85,6 +85,7 @@ struct uhub_softc { #define UHUB_IS_HIGH_SPEED(sc) (UHUB_PROTO(sc) != UDPROTO_FSHUB) #define UHUB_IS_SINGLE_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBSTT) +Static usbd_status uhub_poweron(usbd_device_handle hub); Static usbd_status uhub_explore(usbd_device_handle hub); Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status); @@ -158,7 +159,7 @@ USB_ATTACH(uhub) struct usbd_hub *hub = NULL; usb_device_request_t req; usb_hub_descriptor_t hubdesc; - int p, port, nports, nremov, pwrdly; + int p, port, nports, nremov; usbd_interface_handle iface; usb_endpoint_descriptor_t *ed; struct usbd_tt *tts = NULL; @@ -282,9 +283,10 @@ USB_ATTACH(uhub) * These are the events on the bus when a hub is attached: * Get device and config descriptors (see attach code) * Get hub descriptor (see above) + * (below happens in poweron code, and is deferred for the root hub) * For all ports * turn on power - * wait for power to become stable + * Wait for power to become stable * (all below happens in explore code) * For all ports * clear C_PORT_CONNECTION @@ -326,21 +328,11 @@ USB_ATTACH(uhub) } } - /* XXX should check for none, individual, or ganged power? */ - - pwrdly = dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR - + USB_EXTRA_POWER_UP_TIME; - for (port = 1; port <= nports; port++) { - /* Turn the power on. */ - err = usbd_set_port_feature(dev, port, UHF_PORT_POWER); - if (err) - printf("%s: port %d power on failed, %s\n", - USBDEVNAME(sc->sc_dev), port, - usbd_errstr(err)); - DPRINTF(("usb_init_port: turn on port %d power\n", port)); - /* Wait for stable power. */ - usbd_delay_ms(dev, pwrdly); - } + /* Defer power on for the root hub until all controllers are ready. */ + if (dev->powersrc->parent == NULL) + hub->poweron = uhub_poweron; + else + uhub_poweron(dev); /* The usual exploration will finish the setup. */ @@ -353,6 +345,38 @@ USB_ATTACH(uhub) free(hub, M_USBDEV); dev->hub = NULL; USB_ATTACH_ERROR_RETURN; +} + +usbd_status +uhub_poweron(usbd_device_handle dev) +{ + usb_hub_descriptor_t *hd = &dev->hub->hubdesc; + struct uhub_softc *sc = dev->hub->hubsoftc; + usbd_status err; + int port; + + DPRINTFN(1,("uhub_poweron dev=%p\n", dev)); + + /* Ignore hubs that are too deep. */ + if (dev->depth > USB_HUB_MAX_DEPTH) + return (USBD_TOO_DEEP); + + /* Turn the power on for all ports. */ + for (port = 1; port <= hd->bNbrPorts; port++) { + DPRINTF(("uhub_poweron_reset: turn on hub %s port %d power\n", + USBDEVNAME(sc->sc_dev), port)); + err = usbd_set_port_feature(dev, port, UHF_PORT_POWER); + if (err) + printf("%s: port %d power on failed, %s\n", + USBDEVNAME(sc->sc_dev), port, + usbd_errstr(err)); + } + + /* Wait for stable power. */ + usbd_delay_ms(dev, hd->bPwrOn2PwrGood * UHD_PWRON_FACTOR + + USB_EXTRA_POWER_UP_TIME); + + return (USBD_NORMAL_COMPLETION); } usbd_status