diff options
author | n_hibma <n_hibma@FreeBSD.org> | 2000-05-14 19:39:10 +0000 |
---|---|---|
committer | n_hibma <n_hibma@FreeBSD.org> | 2000-05-14 19:39:10 +0000 |
commit | 6262213c44b6c2ee99819dc35cbb09f6703926a3 (patch) | |
tree | a207dc01b9d9f389a2be10c7ee8425dc38ad5720 /sys | |
parent | ba91f59db82c01480c50f2ee9fe90e87f7f7e0a4 (diff) | |
download | FreeBSD-src-6262213c44b6c2ee99819dc35cbb09f6703926a3.zip FreeBSD-src-6262213c44b6c2ee99819dc35cbb09f6703926a3.tar.gz |
Sync with NetBSD:
Make the behaviour more similar to what the Microsoft uhub driver
does.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/usb/uhub.c | 167 | ||||
-rw-r--r-- | sys/dev/usb/usb.h | 2 |
2 files changed, 81 insertions, 88 deletions
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c index 3f3e77f..3cd2a44 100644 --- a/sys/dev/usb/uhub.c +++ b/sys/dev/usb/uhub.c @@ -1,4 +1,4 @@ -/* $NetBSD: uhub.c,v 1.34 1999/11/18 23:32:29 augustss Exp $ */ +/* $NetBSD: uhub.c,v 1.44 2000/04/27 15:26:48 augustss Exp $ */ /* $FreeBSD$ */ /* @@ -39,7 +39,7 @@ */ /* - * USB spec: http://www.usb.org/cgi-usb/mailmerge.cgi/home/usb/docs/developers/cgiform.tpl + * USB spec: http://www.usb.org/developers/docs.htm */ #include <sys/param.h> @@ -62,10 +62,12 @@ #include <dev/usb/usbdi_util.h> #include <dev/usb/usbdivar.h> +#define UHUB_INTR_INTERVAL 255 /* ms */ + #ifdef UHUB_DEBUG #define DPRINTF(x) if (uhubdebug) logprintf x #define DPRINTFN(n,x) if (uhubdebug>(n)) logprintf x -int uhubdebug = 0; +int uhubdebug; #else #define DPRINTF(x) #define DPRINTFN(n,x) @@ -79,7 +81,6 @@ struct uhub_softc { u_char sc_running; }; -Static usbd_status uhub_init_port __P((struct usbd_port *)); Static usbd_status uhub_explore __P((usbd_device_handle hub)); Static void uhub_intr __P((usbd_xfer_handle, usbd_private_handle,usbd_status)); @@ -154,7 +155,7 @@ USB_ATTACH(uhub) struct usbd_hub *hub; usb_device_request_t req; usb_hub_descriptor_t hubdesc; - int p, port, nports, nremov; + int p, port, nports, nremov, pwrdly; usbd_interface_handle iface; usb_endpoint_descriptor_t *ed; @@ -243,7 +244,7 @@ USB_ATTACH(uhub) err = usbd_open_pipe_intr(iface, ed->bEndpointAddress, USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status, - sizeof(sc->sc_status), uhub_intr, USBD_DEFAULT_INTERVAL); + sizeof(sc->sc_status), uhub_intr, UHUB_INTR_INTERVAL); if (err) { printf("%s: cannot open interrupt pipe\n", USBDEVNAME(sc->sc_dev)); @@ -253,16 +254,61 @@ USB_ATTACH(uhub) /* Wait with power off for a while. */ usbd_delay_ms(dev, USB_POWER_DOWN_TIME); + /* + * To have the best chance of success we do things in the exact same + * order as Windoze98. This should not be necessary, but some + * devices do not follow the USB specs to the letter. + * + * 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) + * For all ports + * turn on power + * wait for power to become stable + * (all below happens in explore code) + * For all ports + * clear C_PORT_CONNECTION + * For all ports + * get port status + * if device connected + * turn on reset + * wait + * clear C_PORT_RESET + * get port status + * proceed with device attachment + */ + + /* Set up data structures */ for (p = 0; p < nports; p++) { struct usbd_port *up = &hub->ports[p]; up->device = 0; up->parent = dev; up->portno = p+1; - err = uhub_init_port(up); + if (dev->self_powered) + /* Self powered hub, give ports maximum current. */ + up->power = USB_MAX_POWER; + else + up->power = USB_MIN_POWER; + } + + /* 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: init of port %d failed\n", - USBDEVNAME(sc->sc_dev), up->portno); + 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); } + + /* The usual exploration will finish the setup. */ + sc->sc_running = 1; USB_ATTACH_SUCCESS_RETURN; @@ -274,73 +320,6 @@ USB_ATTACH(uhub) } usbd_status -uhub_init_port(up) - struct usbd_port *up; -{ - int port = up->portno; - usbd_device_handle dev = up->parent; - usbd_status err; - u_int16_t pstatus; - - err = usbd_get_port_status(dev, port, &up->status); - if (err) - return (err); - pstatus = UGETW(up->status.wPortStatus); - DPRINTF(("usbd_init_port: adding hub port=%d status=0x%04x " - "change=0x%04x\n", - port, pstatus, UGETW(up->status.wPortChange))); - if ((pstatus & UPS_PORT_POWER) == 0) { - /* Port lacks power, turn it on */ - - /* First let the device go through a good power cycle, */ - usbd_delay_ms(dev, USB_PORT_POWER_DOWN_TIME); - -#if 0 -usbd_clear_hub_feature(dev, UHF_C_HUB_OVER_CURRENT); -usbd_clear_port_feature(dev, port, UHF_C_PORT_OVER_CURRENT); -#endif - - /* then turn the power on. */ - err = usbd_set_port_feature(dev, port, UHF_PORT_POWER); - if (err) - return (err); - DPRINTF(("usb_init_port: turn on port %d power status=0x%04x " - "change=0x%04x\n", - port, UGETW(up->status.wPortStatus), - UGETW(up->status.wPortChange))); - /* Wait for stable power. */ - usbd_delay_ms(dev, dev->hub->hubdesc.bPwrOn2PwrGood * - UHD_PWRON_FACTOR); - /* Get the port status again. */ - err = usbd_get_port_status(dev, port, &up->status); - if (err) - return (err); - DPRINTF(("usb_init_port: after power on status=0x%04x " - "change=0x%04x\n", - UGETW(up->status.wPortStatus), - UGETW(up->status.wPortChange))); - -#if 0 -usbd_clear_hub_feature(dev, UHF_C_HUB_OVER_CURRENT); -usbd_clear_port_feature(dev, port, UHF_C_PORT_OVER_CURRENT); -usbd_get_port_status(dev, port, &up->status); -#endif - - pstatus = UGETW(up->status.wPortStatus); - if ((pstatus & UPS_PORT_POWER) == 0) - printf("%s: port %d did not power up\n", - USBDEVNAME(((struct uhub_softc *)dev->hub->hubsoftc)->sc_dev), port); - - } - if (dev->self_powered) - /* Self powered hub, give ports maximum current. */ - up->power = USB_MAX_POWER; - else - up->power = USB_MIN_POWER; - return (USBD_NORMAL_COMPLETION); -} - -usbd_status uhub_explore(dev) usbd_device_handle dev; { @@ -400,10 +379,13 @@ uhub_explore(dev) up->device->hub->explore(up->device); continue; } + + /* We have a connect status change, handle it. */ + DPRINTF(("uhub_explore: status change hub=%d port=%d\n", dev->address, port)); usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION); - usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE); + /*usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);*/ /* * If there is already a device on the port the change status * must mean that is has disconnected. Looking at the @@ -421,12 +403,18 @@ uhub_explore(dev) UHF_C_PORT_CONNECTION); } if (!(status & UPS_CURRENT_CONNECT_STATUS)) { + /* Nothing connected, just ignore it. */ DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT" "_STATUS\n", port)); continue; } /* Connected */ + + if (!(status & UPS_PORT_POWER)) + printf("%s: strange, connected port %d has no power\n", + USBDEVNAME(sc->sc_dev), port); + up->restartcnt = 0; /* Wait for maximum device power up time. */ @@ -434,8 +422,8 @@ uhub_explore(dev) /* Reset port, which implies enabling it. */ if (usbd_reset_port(dev, port, &up->status)) { - DPRINTF(("uhub_explore: port=%d reset failed\n", - port)); + printf("uhub_explore: port=%d reset failed\n", + port); continue; } @@ -475,7 +463,7 @@ uhub_activate(self, act) enum devact act; { struct uhub_softc *sc = (struct uhub_softc *)self; - usbd_device_handle devhub = sc->sc_hub; + struct usbd_hub *hub = sc->sc_hub->hub; usbd_device_handle dev; int nports, port, i; @@ -485,9 +473,11 @@ uhub_activate(self, act) break; case DVACT_DEACTIVATE: - nports = devhub->hub->hubdesc.bNbrPorts; + if (hub == NULL) /* malfunctioning hub */ + break; + nports = hub->hubdesc.bNbrPorts; for(port = 0; port < nports; port++) { - dev = devhub->hub->ports[port].device; + dev = hub->ports[port].device; if (dev != NULL) { for (i = 0; dev->subdevs[i]; i++) config_deactivate(dev->subdevs[i]); @@ -506,7 +496,7 @@ uhub_activate(self, act) USB_DETACH(uhub) { USB_DETACH_START(uhub, sc); - usbd_device_handle dev = sc->sc_hub; + struct usbd_hub *hub = sc->sc_hub->hub; struct usbd_port *rup; int port, nports; @@ -516,21 +506,22 @@ USB_DETACH(uhub) DPRINTF(("uhub_detach: sc=%port\n", sc)); #endif - if (dev->hub == NULL) /* Must be partially working */ + if (hub == NULL) /* Must be partially working */ return (0); usbd_abort_pipe(sc->sc_ipipe); usbd_close_pipe(sc->sc_ipipe); - nports = dev->hub->hubdesc.bNbrPorts; + nports = hub->hubdesc.bNbrPorts; for(port = 0; port < nports; port++) { - rup = &dev->hub->ports[port]; + rup = &hub->ports[port]; if (rup->device) usb_disconnect_port(rup, self); } - free(dev->hub, M_USBDEV); - dev->hub = NULL; + + free(hub, M_USBDEV); + sc->sc_hub->hub = NULL; return (0); } diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h index e9ddbb1..0d987d3 100644 --- a/sys/dev/usb/usb.h +++ b/sys/dev/usb/usb.h @@ -409,6 +409,7 @@ typedef struct { #define USB_RESUME_TIME (20*5) /* ms */ #define USB_RESUME_WAIT 10 /* ms */ #define USB_RESUME_RECOVERY 10 /* ms */ +#define USB_EXTRA_POWER_UP_TIME 0 /* ms */ #else /* Allow for marginal (i.e. non-conforming) devices. */ #define USB_PORT_RESET_DELAY 50 /* ms */ @@ -418,6 +419,7 @@ typedef struct { #define USB_RESUME_DELAY (50*5) /* ms */ #define USB_RESUME_WAIT 50 /* ms */ #define USB_RESUME_RECOVERY 50 /* ms */ +#define USB_EXTRA_POWER_UP_TIME 20 /* ms */ #endif #define USB_MIN_POWER 100 /* mA */ |