diff options
Diffstat (limited to 'sys/dev/usb/uhub.c')
-rw-r--r-- | sys/dev/usb/uhub.c | 310 |
1 files changed, 125 insertions, 185 deletions
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c index 6b859b9..015dce9 100644 --- a/sys/dev/usb/uhub.c +++ b/sys/dev/usb/uhub.c @@ -1,4 +1,4 @@ -/* $NetBSD: uhub.c,v 1.26 1999/09/05 19:32:18 augustss Exp $ */ +/* $NetBSD: uhub.c,v 1.32 1999/10/13 08:10:56 augustss Exp $ */ /* $FreeBSD$ */ /* @@ -52,9 +52,10 @@ #elif defined(__FreeBSD__) #include <sys/module.h> #include <sys/bus.h> +#include "bus_if.h" #endif -#include "bus_if.h" +#include <machine/bus.h> #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> @@ -78,22 +79,23 @@ struct uhub_softc { u_char sc_running; }; -usbd_status uhub_init_port __P((struct usbd_port *)); -void uhub_disconnect_port __P((struct usbd_port *up)); -usbd_status uhub_explore __P((usbd_device_handle hub)); -void uhub_intr __P((usbd_request_handle, usbd_private_handle, usbd_status)); +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)); #if defined(__FreeBSD__) static bus_child_detached_t uhub_child_detached; #endif -/* We need two attachment points: + +/* + * We need two attachment points: * hub to usb and hub to hub * Every other driver only connects to hubs */ #if defined(__NetBSD__) || defined(__OpenBSD__) -USB_DECLARE_DRIVER(uhub); +USB_DECLARE_DRIVER(uhub) /* Create the driver instance for the hub connected to hub case */ struct cfattach uhub_uhub_ca = { @@ -101,8 +103,9 @@ struct cfattach uhub_uhub_ca = { uhub_detach, uhub_activate }; #elif defined(__FreeBSD__) -USB_DECLARE_DRIVER_INIT(uhub, DEVMETHOD(bus_child_detached, uhub_child_detached)); - +USB_DECLARE_DRIVER_INIT(uhub, + DEVMETHOD(bus_child_detached, uhub_child_detached)); + /* Create the driver instance for the hub connected to usb case. */ devclass_t uhubroot_devclass; @@ -121,7 +124,6 @@ static driver_t uhubroot_driver = { }; #endif - USB_MATCH(uhub) { USB_MATCH_START(uhub, uaa); @@ -132,7 +134,7 @@ USB_MATCH(uhub) * The subclass for hubs seems to be 0 for some and 1 for others, * so we just ignore the subclass. */ - if (uaa->iface == 0 && dd->bDeviceClass == UCLASS_HUB) + if (uaa->iface == NULL && dd->bDeviceClass == UCLASS_HUB) return (UMATCH_DEVCLASS_DEVSUBCLASS); return (UMATCH_NONE); } @@ -142,7 +144,7 @@ USB_ATTACH(uhub) USB_ATTACH_START(uhub, sc, uaa); usbd_device_handle dev = uaa->device; char devinfo[1024]; - usbd_status r; + usbd_status err; struct usbd_hub *hub; usb_device_request_t req; usb_hub_descriptor_t hubdesc; @@ -156,10 +158,10 @@ USB_ATTACH(uhub) USB_ATTACH_SETUP; printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); - r = usbd_set_config_index(dev, 0, 1); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_set_config_index(dev, 0, 1); + if (err) { DPRINTF(("%s: configuration failed, error=%s\n", - USBDEVNAME(sc->sc_dev), usbd_errstr(r))); + USBDEVNAME(sc->sc_dev), usbd_errstr(err))); USB_ATTACH_ERROR_RETURN; } @@ -176,15 +178,15 @@ USB_ATTACH(uhub) USETW(req.wIndex, 0); USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE); DPRINTFN(1,("usb_init_hub: getting hub descriptor\n")); - r = usbd_do_request(dev, &req, &hubdesc); + err = usbd_do_request(dev, &req, &hubdesc); nports = hubdesc.bNbrPorts; - if (r == USBD_NORMAL_COMPLETION && nports > 7) { + if (!err && nports > 7) { USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8); - r = usbd_do_request(dev, &req, &hubdesc); + err = usbd_do_request(dev, &req, &hubdesc); } - if (r != USBD_NORMAL_COMPLETION) { + if (err) { DPRINTF(("%s: getting hub descriptor failed, error=%s\n", - USBDEVNAME(sc->sc_dev), usbd_errstr(r))); + USBDEVNAME(sc->sc_dev), usbd_errstr(err))); USB_ATTACH_ERROR_RETURN; } @@ -194,11 +196,10 @@ USB_ATTACH(uhub) printf("%s: %d port%s with %d removable, %s powered\n", USBDEVNAME(sc->sc_dev), nports, nports != 1 ? "s" : "", nremov, dev->self_powered ? "self" : "bus"); - hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port), M_USBDEV, M_NOWAIT); - if (hub == 0) + if (hub == NULL) USB_ATTACH_ERROR_RETURN; dev->hub = hub; dev->hub->hubsoftc = sc; @@ -211,7 +212,7 @@ USB_ATTACH(uhub) dev->powersrc->parent ? dev->powersrc->parent->self_powered : 0)); - if (!dev->self_powered && dev->powersrc->parent && + if (!dev->self_powered && dev->powersrc->parent != NULL && !dev->powersrc->parent->self_powered) { printf("%s: bus powered hub connected to bus powered hub, " "ignored\n", USBDEVNAME(sc->sc_dev)); @@ -219,13 +220,13 @@ USB_ATTACH(uhub) } /* Set up interrupt pipe. */ - r = usbd_device2interface_handle(dev, 0, &iface); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_device2interface_handle(dev, 0, &iface); + if (err) { printf("%s: no interface handle\n", USBDEVNAME(sc->sc_dev)); goto bad; } ed = usbd_interface2endpoint_descriptor(iface, 0); - if (ed == 0) { + if (ed == NULL) { printf("%s: no endpoint descriptor\n", USBDEVNAME(sc->sc_dev)); goto bad; } @@ -234,11 +235,10 @@ USB_ATTACH(uhub) goto bad; } - r = usbd_open_pipe_intr(iface, ed->bEndpointAddress,USBD_SHORT_XFER_OK, - &sc->sc_ipipe, sc, sc->sc_status, - sizeof(sc->sc_status), - uhub_intr); - if (r != USBD_NORMAL_COMPLETION) { + 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); + if (err) { printf("%s: cannot open interrupt pipe\n", USBDEVNAME(sc->sc_dev)); goto bad; @@ -252,16 +252,16 @@ USB_ATTACH(uhub) up->device = 0; up->parent = dev; up->portno = p+1; - r = uhub_init_port(up); - if (r != USBD_NORMAL_COMPLETION) + err = uhub_init_port(up); + if (err) printf("%s: init of port %d failed\n", - USBDEVNAME(sc->sc_dev), up->portno); + USBDEVNAME(sc->sc_dev), up->portno); } sc->sc_running = 1; USB_ATTACH_SUCCESS_RETURN; -bad: + bad: free(hub, M_USBDEV); dev->hub = 0; USB_ATTACH_ERROR_RETURN; @@ -273,12 +273,12 @@ uhub_init_port(up) { int port = up->portno; usbd_device_handle dev = up->parent; - usbd_status r; + usbd_status err; u_int16_t pstatus; - r = usbd_get_port_status(dev, port, &up->status); - if (r != USBD_NORMAL_COMPLETION) - return (r); + 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", @@ -295,9 +295,9 @@ usbd_clear_port_feature(dev, port, UHF_C_PORT_OVER_CURRENT); #endif /* then turn the power on. */ - r = usbd_set_port_feature(dev, port, UHF_PORT_POWER); - if (r != USBD_NORMAL_COMPLETION) - return (r); + 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), @@ -306,9 +306,9 @@ usbd_clear_port_feature(dev, port, UHF_C_PORT_OVER_CURRENT); usbd_delay_ms(dev, dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR); /* Get the port status again. */ - r = usbd_get_port_status(dev, port, &up->status); - if (r != USBD_NORMAL_COMPLETION) - return (r); + 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), @@ -341,7 +341,7 @@ uhub_explore(dev) usb_hub_descriptor_t *hd = &dev->hub->hubdesc; struct uhub_softc *sc = dev->hub->hubsoftc; struct usbd_port *up; - usbd_status r; + usbd_status err; int port; int change, status; @@ -356,11 +356,10 @@ uhub_explore(dev) for(port = 1; port <= hd->bNbrPorts; port++) { up = &dev->hub->ports[port-1]; - r = usbd_get_port_status(dev, port, &up->status); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_get_port_status(dev, port, &up->status); + if (err) { DPRINTF(("uhub_explore: get port status failed, " - "error=%s\n", - usbd_errstr(r))); + "error=%s\n", usbd_errstr(err))); continue; } status = UGETW(up->status.wPortStatus); @@ -404,13 +403,11 @@ uhub_explore(dev) * the disconnect. */ disco: - if (up->device) { + if (up->device != NULL) { /* Disconnected */ DPRINTF(("uhub_explore: device %d disappeared " - "on port %d\n", - up->device->address, port)); - uhub_disconnect_port(up); - + "on port %d\n", up->device->address, port)); + usb_disconnect_port(up, USBDEV(sc->sc_dev)); usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION); } @@ -429,32 +426,26 @@ uhub_explore(dev) continue; /* Get device info and set its address. */ - r = usbd_new_device(USBDEV(sc->sc_dev), dev->bus, - dev->depth + 1, status & UPS_LOW_SPEED, - port, up); + err = usbd_new_device(USBDEV(sc->sc_dev), dev->bus, + dev->depth + 1, status & UPS_LOW_SPEED, + port, up); /* XXX retry a few times? */ - if (r != USBD_NORMAL_COMPLETION) { + if (err) { DPRINTFN(-1,("uhub_explore: usb_new_device failed, " - "error=%s\n", usbd_errstr(r))); + "error=%s\n", usbd_errstr(err))); /* Avoid addressing problems by disabling. */ /* usbd_reset_port(dev, port, &up->status); */ -/* XXX - * What should we do. The device may or may not be at its - * assigned address. In any case we'd like to ignore it. - */ - if (r == USBD_SET_ADDR_FAILED || 1) {/* XXX */ - /* The unit refused to accept a new - * address, and since we cannot leave - * at 0 we have to disable the port - * instead. */ - printf("%s: device problem, disabling " - "port %d\n", - USBDEVNAME(sc->sc_dev), port); - usbd_clear_port_feature(dev, port, - UHF_PORT_ENABLE); - /* Make sure we don't try to restart it. */ - up->restartcnt = USBD_RESTART_MAX; - } + + /* + * The unit refused to accept a new address, or had + * some other serious problem. Since we cannot leave + * at 0 we have to disable the port instead. + */ + printf("%s: device problem, disabling port %d\n", + USBDEVNAME(sc->sc_dev), port); + usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE); + /* Make sure we don't try to restart it infinitely. */ + up->restartcnt = USBD_RESTART_MAX; } else { if (up->device->hub) up->device->hub->explore(up->device); @@ -463,112 +454,31 @@ uhub_explore(dev) return (USBD_NORMAL_COMPLETION); } -/* - * The general mechanism for detaching drivers works as follows: Each - * driver is responsible for maintaining a reference count on the - * number of outstanding references to its softc (e.g. from - * processing hanging in a read or write). The detach method of the - * driver decrements this counter and flags in the softc that the - * driver is dying and then wakes any sleepers. It then sleeps on the - * softc. Each place that can sleep must maintain the reference - * count. When the reference count drops to -1 (0 is the normal value - * of the reference count) the a wakeup on the softc is performed - * signaling to the detach waiter that all references are gone. - */ - -/* - * Called from process context when we discover that a port has - * been disconnected. - */ -void -uhub_disconnect_port(up) - struct usbd_port *up; -{ - usbd_device_handle dev = up->device; - int i; - - DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", - up, dev, up->portno)); - - if (!dev) /* not even generic device was attached */ - return; - - if (!dev->cdesc) { - /* Partially attached device, just drop it. */ - dev->bus->devices[dev->address] = 0; - up->device = 0; - return; - } - - if (dev->subdevs) { - for (i = 0; dev->subdevs[i]; i++) { - if (!dev->subdevs[i]) /* skip empty elements */ - continue; - - printf("%s: at %s port %d (addr %d) disconnected\n", - USBDEVPTRNAME(dev->subdevs[i]), - USBDEVPTRNAME(up->parent->subdevs[0]), - up->portno, dev->address); #if defined(__NetBSD__) || defined(__OpenBSD__) - config_detach(dev->subdevs[i], DETACH_FORCE); -#elif defined(__FreeBSD__) - device_delete_child(device_get_parent(dev->subdevs[i]), - dev->subdevs[i]); -#endif - } - } - - dev->bus->devices[dev->address] = 0; - up->device = 0; - usb_free_device(dev); -} - -#if defined(__FreeBSD__) -/* Called when a device has been detached from it */ -static void -uhub_child_detached(self, child) - device_t self; - device_t child; -{ - struct uhub_softc *sc = device_get_softc(self); - usbd_device_handle dev = sc->sc_hub; - struct usbd_port *up; - int nports; - int port; - int i; - - if (!dev->hub) - /* should never happen; children are only created after init */ - panic("hub not fully initialised, but child deleted?"); - - nports = dev->hub->hubdesc.bNbrPorts; - for (port = 0; port < nports; port++) { - up = &dev->hub->ports[port]; - if (up->device && up->device->subdevs) { - for (i = 0; up->device->subdevs[i]; i++) { - if (up->device->subdevs[i] == child) { - up->device->subdevs[i] = NULL; - return; - } - } - } - } -} -#endif - - -#if defined(__NetBSD__) int uhub_activate(self, act) device_ptr_t self; enum devact act; { + struct uhub_softc *sc = (struct uhub_softc *)self; + usbd_device_handle devhub = sc->sc_hub; + usbd_device_handle dev; + int nports, port, i; + switch (act) { case DVACT_ACTIVATE: return (EOPNOTSUPP); break; case DVACT_DEACTIVATE: + nports = devhub->hub->hubdesc.bNbrPorts; + for(port = 0; port < nports; port++) { + dev = devhub->hub->ports[port].device; + if (dev != NULL) { + for (i = 0; dev->subdevs[i]; i++) + config_deactivate(dev->subdevs[i]); + } + } break; } return (0); @@ -583,16 +493,16 @@ USB_DETACH(uhub) { USB_DETACH_START(uhub, sc); usbd_device_handle dev = sc->sc_hub; - struct usbd_port *up; + struct usbd_port *rup; int port, nports; #if defined(__NetBSD__) || defined(__OpenBSD__) - DPRINTF(("uhub_detach: sc=%port flags=%d\n", sc, flags)); + DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags)); #elif defined(__FreeBSD__) DPRINTF(("uhub_detach: sc=%port\n", sc)); #endif - if (!dev->hub) /* Must be partially working */ + if (dev->hub == NULL) /* Must be partially working */ return (0); usbd_abort_pipe(sc->sc_ipipe); @@ -600,21 +510,51 @@ USB_DETACH(uhub) nports = dev->hub->hubdesc.bNbrPorts; for(port = 0; port < nports; port++) { - up = &dev->hub->ports[port]; - if (up->device) { - DPRINTF(("uhub_detach: device %d disappeared " - "on port %d\n", - up->device->address, port)); - uhub_disconnect_port(up); - } + rup = &dev->hub->ports[port]; + if (rup->device) + usb_disconnect_port(rup, self); } free(dev->hub, M_USBDEV); - dev->hub = 0; + dev->hub = NULL; return (0); } +#if defined(__FreeBSD__) +/* Called when a device has been detached from it */ +static void +uhub_child_detached(self, child) + device_t self; + device_t child; +{ + struct uhub_softc *sc = device_get_softc(self); + usbd_device_handle devhub = sc->sc_hub; + usbd_device_handle dev; + int nports; + int port; + int i; + + if (!devhub->hub) + /* should never happen; children are only created after init */ + panic("hub not fully initialised, but child deleted?"); + + nports = devhub->hub->hubdesc.bNbrPorts; + for (port = 0; port < nports; port++) { + dev = devhub->hub->ports[port].device; + if (dev && dev->subdevs) { + for (i = 0; dev->subdevs[i]; i++) { + if (dev->subdevs[i] == child) { + dev->subdevs[i] = NULL; + return; + } + } + } + } +} +#endif + + /* * Hub interrupt. * This an indication that some port has changed status. @@ -622,8 +562,8 @@ USB_DETACH(uhub) * to be explored again. */ void -uhub_intr(reqh, addr, status) - usbd_request_handle reqh; +uhub_intr(xfer, addr, status) + usbd_xfer_handle xfer; usbd_private_handle addr; usbd_status status; { |