The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/uhub.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: uhub.c,v 1.65.2.2 2004/07/02 17:17:52 he Exp $ */
    2 /*      $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $       */
    3 
    4 /*
    5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Lennart Augustsson (lennart@augustsson.net) at
   10  * Carlstedt Research & Technology.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *        This product includes software developed by the NetBSD
   23  *        Foundation, Inc. and its contributors.
   24  * 4. Neither the name of The NetBSD Foundation nor the names of its
   25  *    contributors may be used to endorse or promote products derived
   26  *    from this software without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   38  * POSSIBILITY OF SUCH DAMAGE.
   39  */
   40 
   41 /*
   42  * USB spec: http://www.usb.org/developers/docs/usbspec.zip
   43  */
   44 
   45 #include <sys/cdefs.h>
   46 __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.65.2.2 2004/07/02 17:17:52 he Exp $");
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/kernel.h>
   51 #include <sys/malloc.h>
   52 #if defined(__NetBSD__) || defined(__OpenBSD__)
   53 #include <sys/device.h>
   54 #include <sys/proc.h>
   55 #elif defined(__FreeBSD__)
   56 #include <sys/module.h>
   57 #include <sys/bus.h>
   58 #include "bus_if.h"
   59 #endif
   60 
   61 #include <machine/bus.h>
   62 
   63 #include <dev/usb/usb.h>
   64 #include <dev/usb/usbdi.h>
   65 #include <dev/usb/usbdi_util.h>
   66 #include <dev/usb/usbdivar.h>
   67 
   68 #define UHUB_INTR_INTERVAL 255  /* ms */
   69 
   70 #ifdef UHUB_DEBUG
   71 #define DPRINTF(x)      if (uhubdebug) logprintf x
   72 #define DPRINTFN(n,x)   if (uhubdebug>(n)) logprintf x
   73 int     uhubdebug = 0;
   74 #else
   75 #define DPRINTF(x)
   76 #define DPRINTFN(n,x)
   77 #endif
   78 
   79 struct uhub_softc {
   80         USBBASEDEVICE           sc_dev;         /* base device */
   81         usbd_device_handle      sc_hub;         /* USB device */
   82         usbd_pipe_handle        sc_ipipe;       /* interrupt pipe */
   83         u_int8_t                sc_status[1];   /* XXX more ports */
   84         u_char                  sc_running;
   85 };
   86 
   87 Static usbd_status uhub_explore(usbd_device_handle hub);
   88 Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status);
   89 
   90 #if defined(__FreeBSD__)
   91 Static bus_child_detached_t uhub_child_detached;
   92 #endif
   93 
   94 
   95 /*
   96  * We need two attachment points:
   97  * hub to usb and hub to hub
   98  * Every other driver only connects to hubs
   99  */
  100 
  101 #if defined(__NetBSD__) || defined(__OpenBSD__)
  102 USB_DECLARE_DRIVER(uhub);
  103 
  104 /* Create the driver instance for the hub connected to hub case */
  105 CFATTACH_DECL(uhub_uhub, sizeof(struct uhub_softc),
  106     uhub_match, uhub_attach, uhub_detach, uhub_activate);
  107 #elif defined(__FreeBSD__)
  108 USB_DECLARE_DRIVER_INIT(uhub,
  109                         DEVMETHOD(bus_child_detached, uhub_child_detached));
  110 
  111 /* Create the driver instance for the hub connected to usb case. */
  112 devclass_t uhubroot_devclass;
  113 
  114 Static device_method_t uhubroot_methods[] = {
  115         DEVMETHOD(device_probe, uhub_match),
  116         DEVMETHOD(device_attach, uhub_attach),
  117 
  118         /* detach is not allowed for a root hub */
  119         {0,0}
  120 };
  121 
  122 Static  driver_t uhubroot_driver = {
  123         "uhub",
  124         uhubroot_methods,
  125         sizeof(struct uhub_softc)
  126 };
  127 #endif
  128 
  129 USB_MATCH(uhub)
  130 {
  131         USB_MATCH_START(uhub, uaa);
  132         usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
  133 
  134         DPRINTFN(5,("uhub_match, dd=%p\n", dd));
  135         /*
  136          * The subclass for hubs seems to be 0 for some and 1 for others,
  137          * so we just ignore the subclass.
  138          */
  139         if (uaa->iface == NULL && dd->bDeviceClass == UDCLASS_HUB)
  140                 return (UMATCH_DEVCLASS_DEVSUBCLASS);
  141         return (UMATCH_NONE);
  142 }
  143 
  144 USB_ATTACH(uhub)
  145 {
  146         USB_ATTACH_START(uhub, sc, uaa);
  147         usbd_device_handle dev = uaa->device;
  148         char devinfo[1024];
  149         usbd_status err;
  150         struct usbd_hub *hub;
  151         usb_device_request_t req;
  152         usb_hub_descriptor_t hubdesc;
  153         int p, port, nports, nremov, pwrdly;
  154         usbd_interface_handle iface;
  155         usb_endpoint_descriptor_t *ed;
  156 
  157         DPRINTFN(1,("uhub_attach\n"));
  158         sc->sc_hub = dev;
  159         usbd_devinfo(dev, 1, devinfo);
  160         USB_ATTACH_SETUP;
  161         printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
  162 
  163         err = usbd_set_config_index(dev, 0, 1);
  164         if (err) {
  165                 DPRINTF(("%s: configuration failed, error=%s\n",
  166                          USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
  167                 USB_ATTACH_ERROR_RETURN;
  168         }
  169 
  170         if (dev->depth > USB_HUB_MAX_DEPTH) {
  171                 printf("%s: hub depth (%d) exceeded, hub ignored\n",
  172                        USBDEVNAME(sc->sc_dev), USB_HUB_MAX_DEPTH);
  173                 USB_ATTACH_ERROR_RETURN;
  174         }
  175 
  176         /* Get hub descriptor. */
  177         req.bmRequestType = UT_READ_CLASS_DEVICE;
  178         req.bRequest = UR_GET_DESCRIPTOR;
  179         USETW2(req.wValue, UDESC_HUB, 0);
  180         USETW(req.wIndex, 0);
  181         USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
  182         DPRINTFN(1,("usb_init_hub: getting hub descriptor\n"));
  183         err = usbd_do_request(dev, &req, &hubdesc);
  184         nports = hubdesc.bNbrPorts;
  185         if (!err && nports > 7) {
  186                 USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
  187                 err = usbd_do_request(dev, &req, &hubdesc);
  188         }
  189         if (err) {
  190                 DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
  191                          USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
  192                 USB_ATTACH_ERROR_RETURN;
  193         }
  194 
  195         for (nremov = 0, port = 1; port <= nports; port++)
  196                 if (!UHD_NOT_REMOV(&hubdesc, port))
  197                         nremov++;
  198         printf("%s: %d port%s with %d removable, %s powered\n",
  199                USBDEVNAME(sc->sc_dev), nports, nports != 1 ? "s" : "",
  200                nremov, dev->self_powered ? "self" : "bus");
  201 
  202         hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
  203                      M_USBDEV, M_NOWAIT);
  204         if (hub == NULL)
  205                 USB_ATTACH_ERROR_RETURN;
  206         dev->hub = hub;
  207         dev->hub->hubsoftc = sc;
  208         hub->explore = uhub_explore;
  209         hub->hubdesc = hubdesc;
  210 
  211         DPRINTFN(1,("usbhub_init_hub: selfpowered=%d, parent=%p, "
  212                     "parent->selfpowered=%d\n",
  213                  dev->self_powered, dev->powersrc->parent,
  214                  dev->powersrc->parent ?
  215                  dev->powersrc->parent->self_powered : 0));
  216 
  217         if (!dev->self_powered && dev->powersrc->parent != NULL &&
  218             !dev->powersrc->parent->self_powered) {
  219                 printf("%s: bus powered hub connected to bus powered hub, "
  220                        "ignored\n", USBDEVNAME(sc->sc_dev));
  221                 goto bad;
  222         }
  223 
  224         /* Set up interrupt pipe. */
  225         err = usbd_device2interface_handle(dev, 0, &iface);
  226         if (err) {
  227                 printf("%s: no interface handle\n", USBDEVNAME(sc->sc_dev));
  228                 goto bad;
  229         }
  230         ed = usbd_interface2endpoint_descriptor(iface, 0);
  231         if (ed == NULL) {
  232                 printf("%s: no endpoint descriptor\n", USBDEVNAME(sc->sc_dev));
  233                 goto bad;
  234         }
  235         if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
  236                 printf("%s: bad interrupt endpoint\n", USBDEVNAME(sc->sc_dev));
  237                 goto bad;
  238         }
  239 
  240         err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
  241                   USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status,
  242                   sizeof(sc->sc_status), uhub_intr, UHUB_INTR_INTERVAL);
  243         if (err) {
  244                 printf("%s: cannot open interrupt pipe\n",
  245                        USBDEVNAME(sc->sc_dev));
  246                 goto bad;
  247         }
  248 
  249         /* Wait with power off for a while. */
  250         usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
  251 
  252         usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, USBDEV(sc->sc_dev));
  253 
  254         /*
  255          * To have the best chance of success we do things in the exact same
  256          * order as Windoze98.  This should not be necessary, but some
  257          * devices do not follow the USB specs to the letter.
  258          *
  259          * These are the events on the bus when a hub is attached:
  260          *  Get device and config descriptors (see attach code)
  261          *  Get hub descriptor (see above)
  262          *  For all ports
  263          *     turn on power
  264          *     wait for power to become stable
  265          * (all below happens in explore code)
  266          *  For all ports
  267          *     clear C_PORT_CONNECTION
  268          *  For all ports
  269          *     get port status
  270          *     if device connected
  271          *        wait 100 ms
  272          *        turn on reset
  273          *        wait
  274          *        clear C_PORT_RESET
  275          *        get port status
  276          *        proceed with device attachment
  277          */
  278 
  279         /* Set up data structures */
  280         for (p = 0; p < nports; p++) {
  281                 struct usbd_port *up = &hub->ports[p];
  282                 up->device = 0;
  283                 up->parent = dev;
  284                 up->portno = p+1;
  285                 if (dev->self_powered)
  286                         /* Self powered hub, give ports maximum current. */
  287                         up->power = USB_MAX_POWER;
  288                 else
  289                         up->power = USB_MIN_POWER;
  290                 up->restartcnt = 0;
  291         }
  292 
  293         /* XXX should check for none, individual, or ganged power? */
  294 
  295         pwrdly = dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR
  296             + USB_EXTRA_POWER_UP_TIME;
  297         for (port = 1; port <= nports; port++) {
  298                 /* Turn the power on. */
  299                 err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
  300                 if (err)
  301                         printf("%s: port %d power on failed, %s\n",
  302                                USBDEVNAME(sc->sc_dev), port,
  303                                usbd_errstr(err));
  304                 DPRINTF(("usb_init_port: turn on port %d power\n", port));
  305                 /* Wait for stable power. */
  306                 usbd_delay_ms(dev, pwrdly);
  307         }
  308 
  309         /* The usual exploration will finish the setup. */
  310 
  311         sc->sc_running = 1;
  312 
  313         USB_ATTACH_SUCCESS_RETURN;
  314 
  315  bad:
  316         free(hub, M_USBDEV);
  317         dev->hub = 0;
  318         USB_ATTACH_ERROR_RETURN;
  319 }
  320 
  321 usbd_status
  322 uhub_explore(usbd_device_handle dev)
  323 {
  324         usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
  325         struct uhub_softc *sc = dev->hub->hubsoftc;
  326         struct usbd_port *up;
  327         usbd_status err;
  328         int speed;
  329         int port;
  330         int change, status;
  331 
  332         DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
  333 
  334         if (!sc->sc_running)
  335                 return (USBD_NOT_STARTED);
  336 
  337         /* Ignore hubs that are too deep. */
  338         if (dev->depth > USB_HUB_MAX_DEPTH)
  339                 return (USBD_TOO_DEEP);
  340 
  341         for(port = 1; port <= hd->bNbrPorts; port++) {
  342                 up = &dev->hub->ports[port-1];
  343                 err = usbd_get_port_status(dev, port, &up->status);
  344                 if (err) {
  345                         DPRINTF(("uhub_explore: get port status failed, "
  346                                  "error=%s\n", usbd_errstr(err)));
  347                         continue;
  348                 }
  349                 status = UGETW(up->status.wPortStatus);
  350                 change = UGETW(up->status.wPortChange);
  351                 DPRINTFN(3,("uhub_explore: %s port %d status 0x%04x 0x%04x\n",
  352                             USBDEVNAME(sc->sc_dev), port, status, change));
  353                 if (change & UPS_C_PORT_ENABLED) {
  354                         DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
  355                         usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
  356                         if (change & UPS_C_CONNECT_STATUS) {
  357                                 /* Ignore the port error if the device
  358                                    vanished. */
  359                         } else if (status & UPS_PORT_ENABLED) {
  360                                 printf("%s: illegal enable change, port %d\n",
  361                                        USBDEVNAME(sc->sc_dev), port);
  362                         } else {
  363                                 /* Port error condition. */
  364                                 if (up->restartcnt) /* no message first time */
  365                                         printf("%s: port error, restarting "
  366                                                "port %d\n",
  367                                                USBDEVNAME(sc->sc_dev), port);
  368 
  369                                 if (up->restartcnt++ < USBD_RESTART_MAX)
  370                                         goto disco;
  371                                 else
  372                                         printf("%s: port error, giving up "
  373                                                "port %d\n",
  374                                                USBDEVNAME(sc->sc_dev), port);
  375                         }
  376                 }
  377                 if (!(change & UPS_C_CONNECT_STATUS)) {
  378                         DPRINTFN(3,("uhub_explore: port=%d !C_CONNECT_"
  379                                     "STATUS\n", port));
  380                         /* No status change, just do recursive explore. */
  381                         if (up->device != NULL && up->device->hub != NULL)
  382                                 up->device->hub->explore(up->device);
  383 #if 0 && defined(DIAGNOSTIC)
  384                         if (up->device == NULL &&
  385                             (status & UPS_CURRENT_CONNECT_STATUS))
  386                                 printf("%s: connected, no device\n",
  387                                        USBDEVNAME(sc->sc_dev));
  388 #endif
  389                         continue;
  390                 }
  391 
  392                 /* We have a connect status change, handle it. */
  393 
  394                 DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
  395                          dev->address, port));
  396                 usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
  397                 /*usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);*/
  398                 /*
  399                  * If there is already a device on the port the change status
  400                  * must mean that is has disconnected.  Looking at the
  401                  * current connect status is not enough to figure this out
  402                  * since a new unit may have been connected before we handle
  403                  * the disconnect.
  404                  */
  405         disco:
  406                 if (up->device != NULL) {
  407                         /* Disconnected */
  408                         DPRINTF(("uhub_explore: device addr=%d disappeared "
  409                                  "on port %d\n", up->device->address, port));
  410                         usb_disconnect_port(up, USBDEV(sc->sc_dev));
  411                         usbd_clear_port_feature(dev, port,
  412                                                 UHF_C_PORT_CONNECTION);
  413                 }
  414                 if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
  415                         /* Nothing connected, just ignore it. */
  416                         DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
  417                                     "_STATUS\n", port));
  418                         continue;
  419                 }
  420 
  421                 /* Connected */
  422 
  423                 if (!(status & UPS_PORT_POWER))
  424                         printf("%s: strange, connected port %d has no power\n",
  425                                USBDEVNAME(sc->sc_dev), port);
  426 
  427                 /* Wait for maximum device power up time. */
  428                 usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
  429 
  430                 /* Reset port, which implies enabling it. */
  431                 if (usbd_reset_port(dev, port, &up->status)) {
  432                         printf("%s: port %d reset failed\n",
  433                                USBDEVNAME(sc->sc_dev), port);
  434                         continue;
  435                 }
  436                 /* Get port status again, it might have changed during reset */
  437                 err = usbd_get_port_status(dev, port, &up->status);
  438                 if (err) {
  439                         DPRINTF(("uhub_explore: get port status failed, "
  440                                  "error=%s\n", usbd_errstr(err)));
  441                         continue;
  442                 }
  443                 status = UGETW(up->status.wPortStatus);
  444                 change = UGETW(up->status.wPortChange);
  445                 if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
  446                         /* Nothing connected, just ignore it. */
  447 #ifdef DIAGNOSTIC
  448                         printf("%s: port %d, device disappeared after reset\n",
  449                                USBDEVNAME(sc->sc_dev), port);
  450 #endif
  451                         continue;
  452                 }
  453 
  454                 /* Figure out device speed */
  455                 if (status & UPS_HIGH_SPEED)
  456                         speed = USB_SPEED_HIGH;
  457                 else if (status & UPS_LOW_SPEED)
  458                         speed = USB_SPEED_LOW;
  459                 else
  460                         speed = USB_SPEED_FULL;
  461                 /* Get device info and set its address. */
  462                 err = usbd_new_device(USBDEV(sc->sc_dev), dev->bus,
  463                           dev->depth + 1, speed, port, up);
  464                 /* XXX retry a few times? */
  465                 if (err) {
  466                         DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
  467                                      "error=%s\n", usbd_errstr(err)));
  468                         /* Avoid addressing problems by disabling. */
  469                         /* usbd_reset_port(dev, port, &up->status); */
  470 
  471                         /*
  472                          * The unit refused to accept a new address, or had
  473                          * some other serious problem.  Since we cannot leave
  474                          * at 0 we have to disable the port instead.
  475                          */
  476                         printf("%s: device problem, disabling port %d\n",
  477                                USBDEVNAME(sc->sc_dev), port);
  478                         usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
  479                 } else {
  480                         /* The port set up succeeded, reset error count. */
  481                         up->restartcnt = 0;
  482 
  483                         if (up->device->hub)
  484                                 up->device->hub->explore(up->device);
  485                 }
  486         }
  487         return (USBD_NORMAL_COMPLETION);
  488 }
  489 
  490 #if defined(__NetBSD__) || defined(__OpenBSD__)
  491 int
  492 uhub_activate(device_ptr_t self, enum devact act)
  493 {
  494         struct uhub_softc *sc = (struct uhub_softc *)self;
  495         struct usbd_hub *hub = sc->sc_hub->hub;
  496         usbd_device_handle dev;
  497         int nports, port, i;
  498 
  499         switch (act) {
  500         case DVACT_ACTIVATE:
  501                 return (EOPNOTSUPP);
  502 
  503         case DVACT_DEACTIVATE:
  504                 if (hub == NULL) /* malfunctioning hub */
  505                         break;
  506                 nports = hub->hubdesc.bNbrPorts;
  507                 for(port = 0; port < nports; port++) {
  508                         dev = hub->ports[port].device;
  509                         if (dev != NULL && dev->subdevs != NULL) {
  510                                 for (i = 0; dev->subdevs[i] != NULL; i++)
  511                                         config_deactivate(dev->subdevs[i]);
  512                         }
  513                 }
  514                 break;
  515         }
  516         return (0);
  517 }
  518 #endif
  519 
  520 /*
  521  * Called from process context when the hub is gone.
  522  * Detach all devices on active ports.
  523  */
  524 USB_DETACH(uhub)
  525 {
  526         USB_DETACH_START(uhub, sc);
  527         struct usbd_hub *hub = sc->sc_hub->hub;
  528         struct usbd_port *rup;
  529         int port, nports;
  530 
  531 #if defined(__NetBSD__) || defined(__OpenBSD__)
  532         DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
  533 #elif defined(__FreeBSD__)
  534         DPRINTF(("uhub_detach: sc=%port\n", sc));
  535 #endif
  536 
  537         if (hub == NULL)                /* Must be partially working */
  538                 return (0);
  539 
  540         usbd_abort_pipe(sc->sc_ipipe);
  541         usbd_close_pipe(sc->sc_ipipe);
  542 
  543         nports = hub->hubdesc.bNbrPorts;
  544         for(port = 0; port < nports; port++) {
  545                 rup = &hub->ports[port];
  546                 if (rup->device)
  547                         usb_disconnect_port(rup, self);
  548         }
  549 
  550         usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub,
  551                            USBDEV(sc->sc_dev));
  552 
  553         free(hub, M_USBDEV);
  554         sc->sc_hub->hub = NULL;
  555 
  556         return (0);
  557 }
  558 
  559 #if defined(__FreeBSD__)
  560 /* Called when a device has been detached from it */
  561 Static void
  562 uhub_child_detached(device_t self, device_t child)
  563 {
  564        struct uhub_softc *sc = device_get_softc(self);
  565        usbd_device_handle devhub = sc->sc_hub;
  566        usbd_device_handle dev;
  567        int nports;
  568        int port;
  569        int i;
  570 
  571        if (!devhub->hub)
  572                /* should never happen; children are only created after init */
  573                panic("hub not fully initialised, but child deleted?");
  574 
  575        nports = devhub->hub->hubdesc.bNbrPorts;
  576        for (port = 0; port < nports; port++) {
  577                dev = devhub->hub->ports[port].device;
  578                if (dev && dev->subdevs) {
  579                        for (i = 0; dev->subdevs[i]; i++) {
  580                                if (dev->subdevs[i] == child) {
  581                                        dev->subdevs[i] = NULL;
  582                                        return;
  583                                }
  584                        }
  585                }
  586        }
  587 }
  588 #endif
  589 
  590 
  591 /*
  592  * Hub interrupt.
  593  * This an indication that some port has changed status.
  594  * Notify the bus event handler thread that we need
  595  * to be explored again.
  596  */
  597 void
  598 uhub_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
  599 {
  600         struct uhub_softc *sc = addr;
  601 
  602         DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
  603         if (status == USBD_STALLED)
  604                 usbd_clear_endpoint_stall_async(sc->sc_ipipe);
  605         else if (status == USBD_NORMAL_COMPLETION)
  606                 usb_needs_explore(sc->sc_hub);
  607 }
  608 
  609 #if defined(__FreeBSD__)
  610 DRIVER_MODULE(uhub, usb, uhubroot_driver, uhubroot_devclass, 0, 0);
  611 DRIVER_MODULE(uhub, uhub, uhub_driver, uhub_devclass, usbd_driver_load, 0);
  612 #endif

Cache object: 20272e15fe3fb8ecf1d9b487dd4304d3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.