[BACK]Return to uhub.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / usb

Annotation of src/sys/dev/usb/uhub.c, Revision 1.126.2.1

1.126.2.1! skrll       1: /*     $NetBSD: uhub.c,v 1.126 2014/08/13 06:26:32 skrll Exp $ */
1.34      augustss    2: /*     $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $       */
1.1       augustss    3:
                      4: /*
1.74      mycroft     5:  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
1.1       augustss    6:  * All rights reserved.
                      7:  *
1.6       augustss    8:  * This code is derived from software contributed to The NetBSD Foundation
1.44      augustss    9:  * by Lennart Augustsson (lennart@augustsson.net) at
1.6       augustss   10:  * Carlstedt Research & Technology.
1.1       augustss   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:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     22:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     23:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     24:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     25:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     26:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     27:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     28:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     29:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     30:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     31:  * POSSIBILITY OF SUCH DAMAGE.
1.15      augustss   32:  */
                     33:
                     34: /*
1.64      ichiro     35:  * USB spec: http://www.usb.org/developers/docs/usbspec.zip
1.1       augustss   36:  */
1.53      lukem      37:
                     38: #include <sys/cdefs.h>
1.126.2.1! skrll      39: __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126 2014/08/13 06:26:32 skrll Exp $");
1.1       augustss   40:
                     41: #include <sys/param.h>
                     42: #include <sys/systm.h>
                     43: #include <sys/kernel.h>
                     44: #include <sys/malloc.h>
                     45: #include <sys/device.h>
1.34      augustss   46: #include <sys/proc.h>
1.28      augustss   47:
1.90      ad         48: #include <sys/bus.h>
1.1       augustss   49:
                     50: #include <dev/usb/usb.h>
                     51: #include <dev/usb/usbdi.h>
                     52: #include <dev/usb/usbdi_util.h>
                     53: #include <dev/usb/usbdivar.h>
                     54:
1.32      augustss   55: #ifdef UHUB_DEBUG
1.111     dyoung     56: #define DPRINTF(x)     if (uhubdebug) printf x
                     57: #define DPRINTFN(n,x)  if (uhubdebug>(n)) printf x
1.63      dsainty    58: int    uhubdebug = 0;
1.1       augustss   59: #else
                     60: #define DPRINTF(x)
                     61: #define DPRINTFN(n,x)
                     62: #endif
                     63:
                     64: struct uhub_softc {
1.111     dyoung     65:        device_t                sc_dev;         /* base device */
1.11      augustss   66:        usbd_device_handle      sc_hub;         /* USB device */
1.86      drochner   67:        int                     sc_proto;       /* device protocol */
1.11      augustss   68:        usbd_pipe_handle        sc_ipipe;       /* interrupt pipe */
1.87      drochner   69:
                     70:        /* XXX second buffer needed because we can't suspend pipes yet */
1.126.2.1! skrll      71:        uint8_t                 *sc_statusbuf;
        !            72:        uint8_t                 *sc_status;
1.87      drochner   73:        size_t                  sc_statuslen;
                     74:        int                     sc_explorepending;
1.101     drochner   75:        int             sc_isehciroothub; /* see comment in uhub_intr() */
1.87      drochner   76:
1.11      augustss   77:        u_char                  sc_running;
1.1       augustss   78: };
1.87      drochner   79:
1.86      drochner   80: #define UHUB_IS_HIGH_SPEED(sc) ((sc)->sc_proto != UDPROTO_FSHUB)
                     81: #define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
1.1       augustss   82:
1.87      drochner   83: #define PORTSTAT_ISSET(sc, port) \
                     84:        ((sc)->sc_status[(port) / 8] & (1 << ((port) % 8)))
                     85:
1.45      augustss   86: Static usbd_status uhub_explore(usbd_device_handle hub);
                     87: Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status);
1.1       augustss   88:
1.32      augustss   89:
1.58      augustss   90: /*
1.32      augustss   91:  * We need two attachment points:
                     92:  * hub to usb and hub to hub
                     93:  * Every other driver only connects to hubs
                     94:  */
1.1       augustss   95:
1.98      cube       96: int uhub_match(device_t, cfdata_t, void *);
1.95      dyoung     97: void uhub_attach(device_t, device_t, void *);
1.103     kent       98: int uhub_rescan(device_t, const char *, const int *);
1.95      dyoung     99: void uhub_childdet(device_t, device_t);
                    100: int uhub_detach(device_t, int);
                    101: extern struct cfdriver uhub_cd;
1.104     dyoung    102: CFATTACH_DECL3_NEW(uhub, sizeof(struct uhub_softc), uhub_match,
1.108     dyoung    103:     uhub_attach, uhub_detach, NULL, uhub_rescan, uhub_childdet,
1.104     dyoung    104:     DVF_DETACH_SHUTDOWN);
1.99      drochner  105: CFATTACH_DECL2_NEW(uroothub, sizeof(struct uhub_softc), uhub_match,
1.108     dyoung    106:     uhub_attach, uhub_detach, NULL, uhub_rescan, uhub_childdet);
1.1       augustss  107:
1.109     pooka     108: /*
                    109:  * Setting this to 1 makes sure than an uhub attaches even at higher
                    110:  * priority than ugen when ugen_override is set to 1.  This allows to
                    111:  * probe the whole USB bus and attach functions with ugen.
                    112:  */
                    113: int uhub_ubermatch = 0;
                    114:
1.105     dyoung    115: int
                    116: uhub_match(device_t parent, cfdata_t match, void *aux)
1.1       augustss  117: {
1.107     dyoung    118:        struct usb_attach_arg *uaa = aux;
1.109     pooka     119:        int matchvalue;
                    120:
                    121:        if (uhub_ubermatch)
                    122:                matchvalue = UMATCH_HIGHEST+1;
                    123:        else
                    124:                matchvalue = UMATCH_DEVCLASS_DEVSUBCLASS;
1.58      augustss  125:
1.88      drochner  126:        DPRINTFN(5,("uhub_match, uaa=%p\n", uaa));
1.58      augustss  127:        /*
1.1       augustss  128:         * The subclass for hubs seems to be 0 for some and 1 for others,
                    129:         * so we just ignore the subclass.
                    130:         */
1.86      drochner  131:        if (uaa->class == UDCLASS_HUB)
1.109     pooka     132:                return (matchvalue);
1.1       augustss  133:        return (UMATCH_NONE);
                    134: }
                    135:
1.105     dyoung    136: void
                    137: uhub_attach(device_t parent, device_t self, void *aux)
1.1       augustss  138: {
1.107     dyoung    139:        struct uhub_softc *sc = device_private(self);
                    140:        struct usb_attach_arg *uaa = aux;
1.1       augustss  141:        usbd_device_handle dev = uaa->device;
1.76      augustss  142:        char *devinfop;
1.33      augustss  143:        usbd_status err;
1.70      augustss  144:        struct usbd_hub *hub = NULL;
1.1       augustss  145:        usb_device_request_t req;
                    146:        usb_hub_descriptor_t hubdesc;
1.42      augustss  147:        int p, port, nports, nremov, pwrdly;
1.1       augustss  148:        usbd_interface_handle iface;
                    149:        usb_endpoint_descriptor_t *ed;
1.83      drochner  150: #if 0 /* notyet */
1.70      augustss  151:        struct usbd_tt *tts = NULL;
1.83      drochner  152: #endif
1.58      augustss  153:
1.1       augustss  154:        DPRINTFN(1,("uhub_attach\n"));
1.98      cube      155:        sc->sc_dev = self;
1.1       augustss  156:        sc->sc_hub = dev;
1.86      drochner  157:        sc->sc_proto = uaa->proto;
1.76      augustss  158:
                    159:        devinfop = usbd_devinfo_alloc(dev, 1);
1.96      jmcneill  160:        aprint_naive("\n");
                    161:        aprint_normal(": %s\n", devinfop);
1.76      augustss  162:        usbd_devinfo_free(devinfop);
1.1       augustss  163:
1.75      augustss  164:        if (dev->depth > 0 && UHUB_IS_HIGH_SPEED(sc)) {
1.98      cube      165:                aprint_normal_dev(self, "%s transaction translator%s\n",
1.70      augustss  166:                       UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple",
                    167:                       UHUB_IS_SINGLE_TT(sc) ? "" : "s");
1.69      augustss  168:        }
                    169:
1.33      augustss  170:        err = usbd_set_config_index(dev, 0, 1);
                    171:        if (err) {
1.21      augustss  172:                DPRINTF(("%s: configuration failed, error=%s\n",
1.105     dyoung    173:                    device_xname(sc->sc_dev), usbd_errstr(err)));
1.107     dyoung    174:                return;
1.1       augustss  175:        }
                    176:
                    177:        if (dev->depth > USB_HUB_MAX_DEPTH) {
1.98      cube      178:                aprint_error_dev(self,
                    179:                    "hub depth (%d) exceeded, hub ignored\n",
                    180:                    USB_HUB_MAX_DEPTH);
1.107     dyoung    181:                return;
1.1       augustss  182:        }
                    183:
                    184:        /* Get hub descriptor. */
                    185:        req.bmRequestType = UT_READ_CLASS_DEVICE;
                    186:        req.bRequest = UR_GET_DESCRIPTOR;
1.65      toshii    187:        USETW2(req.wValue, UDESC_HUB, 0);
1.1       augustss  188:        USETW(req.wIndex, 0);
                    189:        USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
1.119     skrll     190:        DPRINTFN(1,("%s: getting hub descriptor\n", __func__));
1.33      augustss  191:        err = usbd_do_request(dev, &req, &hubdesc);
1.11      augustss  192:        nports = hubdesc.bNbrPorts;
1.33      augustss  193:        if (!err && nports > 7) {
1.11      augustss  194:                USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
1.33      augustss  195:                err = usbd_do_request(dev, &req, &hubdesc);
1.11      augustss  196:        }
1.33      augustss  197:        if (err) {
1.21      augustss  198:                DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
1.105     dyoung    199:                    device_xname(sc->sc_dev), usbd_errstr(err)));
1.107     dyoung    200:                return;
1.1       augustss  201:        }
                    202:
1.11      augustss  203:        for (nremov = 0, port = 1; port <= nports; port++)
                    204:                if (!UHD_NOT_REMOV(&hubdesc, port))
                    205:                        nremov++;
1.98      cube      206:        aprint_verbose_dev(self, "%d port%s with %d removable, %s powered\n",
                    207:            nports, nports != 1 ? "s" : "", nremov,
                    208:            dev->self_powered ? "self" : "bus");
1.11      augustss  209:
1.70      augustss  210:        if (nports == 0) {
1.98      cube      211:                aprint_debug_dev(self, "no ports, hub ignored\n");
1.70      augustss  212:                goto bad;
                    213:        }
                    214:
1.1       augustss  215:        hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
1.18      augustss  216:                     M_USBDEV, M_NOWAIT);
1.33      augustss  217:        if (hub == NULL)
1.107     dyoung    218:                return;
1.1       augustss  219:        dev->hub = hub;
1.11      augustss  220:        dev->hub->hubsoftc = sc;
1.1       augustss  221:        hub->explore = uhub_explore;
                    222:        hub->hubdesc = hubdesc;
1.58      augustss  223:
1.1       augustss  224:        /* Set up interrupt pipe. */
1.33      augustss  225:        err = usbd_device2interface_handle(dev, 0, &iface);
                    226:        if (err) {
1.98      cube      227:                aprint_error_dev(self, "no interface handle\n");
1.18      augustss  228:                goto bad;
1.1       augustss  229:        }
1.83      drochner  230:
                    231:        if (UHUB_IS_HIGH_SPEED(sc) && !UHUB_IS_SINGLE_TT(sc)) {
                    232:                err = usbd_set_interface(iface, 1);
                    233:                if (err)
1.98      cube      234:                        aprint_error_dev(self, "can't enable multiple TTs\n");
1.83      drochner  235:        }
                    236:
1.1       augustss  237:        ed = usbd_interface2endpoint_descriptor(iface, 0);
1.33      augustss  238:        if (ed == NULL) {
1.98      cube      239:                aprint_error_dev(self, "no endpoint descriptor\n");
1.18      augustss  240:                goto bad;
1.1       augustss  241:        }
                    242:        if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
1.98      cube      243:                aprint_error_dev(self, "bad interrupt endpoint\n");
1.18      augustss  244:                goto bad;
1.1       augustss  245:        }
                    246:
1.87      drochner  247:        sc->sc_statuslen = (nports + 1 + 7) / 8;
                    248:        sc->sc_statusbuf = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
                    249:        if (!sc->sc_statusbuf)
                    250:                goto bad;
                    251:        sc->sc_status = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
1.84      drochner  252:        if (!sc->sc_status)
                    253:                goto bad;
1.101     drochner  254:        if (device_is_a(device_parent(device_parent(sc->sc_dev)), "ehci"))
                    255:                sc->sc_isehciroothub = 1;
1.84      drochner  256:
1.87      drochner  257:        /* force initial scan */
                    258:        memset(sc->sc_status, 0xff, sc->sc_statuslen);
                    259:        sc->sc_explorepending = 1;
                    260:
1.33      augustss  261:        err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
1.122     jmcneill  262:                  USBD_SHORT_XFER_OK|USBD_MPSAFE, &sc->sc_ipipe, sc,
                    263:                  sc->sc_statusbuf, sc->sc_statuslen,
                    264:                  uhub_intr, USBD_DEFAULT_INTERVAL);
1.33      augustss  265:        if (err) {
1.98      cube      266:                aprint_error_dev(self, "cannot open interrupt pipe\n");
1.18      augustss  267:                goto bad;
1.1       augustss  268:        }
                    269:
1.11      augustss  270:        /* Wait with power off for a while. */
1.13      augustss  271:        usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
1.11      augustss  272:
1.105     dyoung    273:        usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, sc->sc_dev);
1.37      augustss  274:
1.42      augustss  275:        /*
                    276:         * To have the best chance of success we do things in the exact same
1.123     jakllsch  277:         * order as Windows 98.  This should not be necessary, but some
1.42      augustss  278:         * devices do not follow the USB specs to the letter.
                    279:         *
                    280:         * These are the events on the bus when a hub is attached:
                    281:         *  Get device and config descriptors (see attach code)
                    282:         *  Get hub descriptor (see above)
                    283:         *  For all ports
                    284:         *     turn on power
                    285:         *     wait for power to become stable
                    286:         * (all below happens in explore code)
                    287:         *  For all ports
                    288:         *     clear C_PORT_CONNECTION
                    289:         *  For all ports
                    290:         *     get port status
                    291:         *     if device connected
1.57      augustss  292:         *        wait 100 ms
1.42      augustss  293:         *        turn on reset
                    294:         *        wait
                    295:         *        clear C_PORT_RESET
                    296:         *        get port status
                    297:         *        proceed with device attachment
                    298:         */
                    299:
1.83      drochner  300: #if 0
1.78      christos  301:        if (UHUB_IS_HIGH_SPEED(sc) && nports > 0) {
1.70      augustss  302:                tts = malloc((UHUB_IS_SINGLE_TT(sc) ? 1 : nports) *
                    303:                             sizeof (struct usbd_tt), M_USBDEV, M_NOWAIT);
                    304:                if (!tts)
                    305:                        goto bad;
                    306:        }
1.83      drochner  307: #endif
1.42      augustss  308:        /* Set up data structures */
1.11      augustss  309:        for (p = 0; p < nports; p++) {
                    310:                struct usbd_port *up = &hub->ports[p];
1.70      augustss  311:                up->device = NULL;
1.11      augustss  312:                up->parent = dev;
                    313:                up->portno = p+1;
1.42      augustss  314:                if (dev->self_powered)
                    315:                        /* Self powered hub, give ports maximum current. */
                    316:                        up->power = USB_MAX_POWER;
                    317:                else
                    318:                        up->power = USB_MIN_POWER;
1.67      petrov    319:                up->restartcnt = 0;
1.72      joff      320:                up->reattach = 0;
1.83      drochner  321: #if 0
1.70      augustss  322:                if (UHUB_IS_HIGH_SPEED(sc)) {
                    323:                        up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
                    324:                        up->tt->hub = hub;
                    325:                } else {
                    326:                        up->tt = NULL;
                    327:                }
1.83      drochner  328: #endif
1.42      augustss  329:        }
                    330:
                    331:        /* XXX should check for none, individual, or ganged power? */
                    332:
                    333:        pwrdly = dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR
                    334:            + USB_EXTRA_POWER_UP_TIME;
                    335:        for (port = 1; port <= nports; port++) {
                    336:                /* Turn the power on. */
                    337:                err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
1.33      augustss  338:                if (err)
1.98      cube      339:                        aprint_error_dev(self, "port %d power on failed, %s\n",
                    340:                            port, usbd_errstr(err));
1.42      augustss  341:                DPRINTF(("usb_init_port: turn on port %d power\n", port));
1.94      jmcneill  342:        }
                    343:
                    344:        /* Wait for stable power if we are not a root hub */
                    345:        if (dev->powersrc->parent != NULL)
1.42      augustss  346:                usbd_delay_ms(dev, pwrdly);
                    347:
                    348:        /* The usual exploration will finish the setup. */
                    349:
1.1       augustss  350:        sc->sc_running = 1;
1.11      augustss  351:
1.92      jmcneill  352:        if (!pmf_device_register(self, NULL, NULL))
                    353:                aprint_error_dev(self, "couldn't establish power handler\n");
                    354:
1.107     dyoung    355:        return;
1.11      augustss  356:
1.18      augustss  357:  bad:
1.84      drochner  358:        if (sc->sc_status)
                    359:                free(sc->sc_status, M_USBDEV);
1.101     drochner  360:        if (sc->sc_statusbuf)
                    361:                free(sc->sc_statusbuf, M_USBDEV);
1.70      augustss  362:        if (hub)
                    363:                free(hub, M_USBDEV);
                    364:        dev->hub = NULL;
1.107     dyoung    365:        return;
1.11      augustss  366: }
                    367:
1.1       augustss  368: usbd_status
1.45      augustss  369: uhub_explore(usbd_device_handle dev)
1.1       augustss  370: {
                    371:        usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
1.11      augustss  372:        struct uhub_softc *sc = dev->hub->hubsoftc;
1.1       augustss  373:        struct usbd_port *up;
1.33      augustss  374:        usbd_status err;
1.56      augustss  375:        int speed;
1.1       augustss  376:        int port;
1.72      joff      377:        int change, status, reconnect;
1.1       augustss  378:
1.11      augustss  379:        DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
1.1       augustss  380:
                    381:        if (!sc->sc_running)
                    382:                return (USBD_NOT_STARTED);
                    383:
                    384:        /* Ignore hubs that are too deep. */
                    385:        if (dev->depth > USB_HUB_MAX_DEPTH)
                    386:                return (USBD_TOO_DEEP);
                    387:
1.101     drochner  388:        if (PORTSTAT_ISSET(sc, 0)) { /* hub status change */
                    389:                usb_hub_status_t hs;
                    390:
                    391:                err = usbd_get_hub_status(dev, &hs);
                    392:                if (err) {
                    393:                        DPRINTF(("%s: get hub status failed, err=%d\n",
                    394:                                 device_xname(sc->sc_dev), err));
                    395:                } else {
                    396:                        /* just acknowledge */
                    397:                        status = UGETW(hs.wHubStatus);
                    398:                        change = UGETW(hs.wHubChange);
                    399:                        if (change & UHS_LOCAL_POWER)
                    400:                                usbd_clear_hub_feature(dev,
                    401:                                                       UHF_C_HUB_LOCAL_POWER);
                    402:                        if (change & UHS_OVER_CURRENT)
                    403:                                usbd_clear_hub_feature(dev,
                    404:                                                       UHF_C_HUB_OVER_CURRENT);
                    405:                }
                    406:        }
                    407:
1.84      drochner  408:        for (port = 1; port <= hd->bNbrPorts; port++) {
1.1       augustss  409:                up = &dev->hub->ports[port-1];
1.87      drochner  410:
                    411:                /* reattach is needed after firmware upload */
                    412:                reconnect = up->reattach;
                    413:                up->reattach = 0;
                    414:
                    415:                status = change = 0;
                    416:
                    417:                /* don't check if no change summary notification */
                    418:                if (PORTSTAT_ISSET(sc, port) || reconnect) {
                    419:                        err = usbd_get_port_status(dev, port, &up->status);
                    420:                        if (err) {
                    421:                                DPRINTF(("uhub_explore: get port stat failed, "
                    422:                                         "error=%s\n", usbd_errstr(err)));
                    423:                                continue;
                    424:                        }
                    425:                        status = UGETW(up->status.wPortStatus);
                    426:                        change = UGETW(up->status.wPortChange);
1.101     drochner  427: #if 0
                    428:                        printf("%s port %d: s/c=%x/%x\n",
                    429:                               device_xname(sc->sc_dev), port, status, change);
                    430: #endif
1.87      drochner  431:                }
                    432:                if (!change && !reconnect) {
                    433:                        /* No status change, just do recursive explore. */
                    434:                        if (up->device != NULL && up->device->hub != NULL)
                    435:                                up->device->hub->explore(up->device);
1.1       augustss  436:                        continue;
                    437:                }
1.87      drochner  438:
1.11      augustss  439:                if (change & UPS_C_PORT_ENABLED) {
1.35      augustss  440:                        DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
1.11      augustss  441:                        usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
1.68      mycroft   442:                        if (change & UPS_C_CONNECT_STATUS) {
                    443:                                /* Ignore the port error if the device
                    444:                                   vanished. */
                    445:                        } else if (status & UPS_PORT_ENABLED) {
1.98      cube      446:                                aprint_error_dev(sc->sc_dev,
                    447:                                    "illegal enable change, port %d\n", port);
1.11      augustss  448:                        } else {
                    449:                                /* Port error condition. */
1.47      augustss  450:                                if (up->restartcnt) /* no message first time */
1.98      cube      451:                                        aprint_error_dev(sc->sc_dev,
                    452:                                            "port error, restarting port %d\n",
                    453:                                            port);
1.47      augustss  454:
                    455:                                if (up->restartcnt++ < USBD_RESTART_MAX)
1.11      augustss  456:                                        goto disco;
1.47      augustss  457:                                else
1.98      cube      458:                                        aprint_error_dev(sc->sc_dev,
                    459:                                            "port error, giving up port %d\n",
                    460:                                            port);
1.11      augustss  461:                        }
                    462:                }
1.87      drochner  463:
                    464:                /* XXX handle overcurrent and resume events! */
                    465:
1.116     jakllsch  466:                if (!reconnect && !(change & UPS_C_CONNECT_STATUS)) {
                    467:                        /* No status change, just do recursive explore. */
                    468:                        if (up->device != NULL && up->device->hub != NULL)
                    469:                                up->device->hub->explore(up->device);
1.1       augustss  470:                        continue;
1.116     jakllsch  471:                }
1.42      augustss  472:
                    473:                /* We have a connect status change, handle it. */
                    474:
1.1       augustss  475:                DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
                    476:                         dev->address, port));
                    477:                usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
                    478:                /*
                    479:                 * If there is already a device on the port the change status
                    480:                 * must mean that is has disconnected.  Looking at the
                    481:                 * current connect status is not enough to figure this out
                    482:                 * since a new unit may have been connected before we handle
                    483:                 * the disconnect.
                    484:                 */
1.11      augustss  485:        disco:
1.33      augustss  486:                if (up->device != NULL) {
1.1       augustss  487:                        /* Disconnected */
1.35      augustss  488:                        DPRINTF(("uhub_explore: device addr=%d disappeared "
1.31      augustss  489:                                 "on port %d\n", up->device->address, port));
1.108     dyoung    490:                        usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
1.58      augustss  491:                        usbd_clear_port_feature(dev, port,
1.1       augustss  492:                                                UHF_C_PORT_CONNECTION);
                    493:                }
1.35      augustss  494:                if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
1.42      augustss  495:                        /* Nothing connected, just ignore it. */
1.35      augustss  496:                        DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
                    497:                                    "_STATUS\n", port));
1.1       augustss  498:                        continue;
1.35      augustss  499:                }
1.1       augustss  500:
                    501:                /* Connected */
1.42      augustss  502:
                    503:                if (!(status & UPS_PORT_POWER))
1.98      cube      504:                        aprint_normal_dev(sc->sc_dev,
                    505:                            "strange, connected port %d has no power\n", port);
1.42      augustss  506:
1.1       augustss  507:                /* Wait for maximum device power up time. */
1.13      augustss  508:                usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
1.11      augustss  509:
1.1       augustss  510:                /* Reset port, which implies enabling it. */
1.35      augustss  511:                if (usbd_reset_port(dev, port, &up->status)) {
1.98      cube      512:                        aprint_error_dev(sc->sc_dev,
                    513:                            "port %d reset failed\n", port);
1.54      augustss  514:                        continue;
                    515:                }
                    516:                /* Get port status again, it might have changed during reset */
                    517:                err = usbd_get_port_status(dev, port, &up->status);
                    518:                if (err) {
                    519:                        DPRINTF(("uhub_explore: get port status failed, "
                    520:                                 "error=%s\n", usbd_errstr(err)));
                    521:                        continue;
                    522:                }
                    523:                status = UGETW(up->status.wPortStatus);
                    524:                change = UGETW(up->status.wPortChange);
                    525:                if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
                    526:                        /* Nothing connected, just ignore it. */
                    527: #ifdef DIAGNOSTIC
1.98      cube      528:                        aprint_debug_dev(sc->sc_dev,
                    529:                            "port %d, device disappeared after reset\n", port);
1.54      augustss  530: #endif
1.1       augustss  531:                        continue;
1.35      augustss  532:                }
1.110     kiyohara  533:                if (!(status & UPS_PORT_ENABLED)) {
                    534:                        /* Not allowed send/receive packet. */
                    535: #ifdef DIAGNOSTIC
1.115     sborrill  536:                        printf("%s: port %d, device not enabled\n",
1.112     dyoung    537:                               device_xname(sc->sc_dev), port);
1.110     kiyohara  538: #endif
                    539:                        continue;
                    540:                }
1.1       augustss  541:
1.56      augustss  542:                /* Figure out device speed */
1.126     skrll     543: #if 0
1.125     skrll     544:                if (status & UPS_SUPER_SPEED)
                    545:                        speed = USB_SPEED_SUPER;
1.126     skrll     546:                else
                    547: #endif
                    548:                if (status & UPS_HIGH_SPEED)
1.56      augustss  549:                        speed = USB_SPEED_HIGH;
                    550:                else if (status & UPS_LOW_SPEED)
                    551:                        speed = USB_SPEED_LOW;
                    552:                else
                    553:                        speed = USB_SPEED_FULL;
1.1       augustss  554:                /* Get device info and set its address. */
1.105     dyoung    555:                err = usbd_new_device(sc->sc_dev, dev->bus,
1.56      augustss  556:                          dev->depth + 1, speed, port, up);
1.1       augustss  557:                /* XXX retry a few times? */
1.33      augustss  558:                if (err) {
1.114     matt      559:                        DPRINTFN(-1,("uhub_explore: usbd_new_device failed, "
1.33      augustss  560:                                     "error=%s\n", usbd_errstr(err)));
1.1       augustss  561:                        /* Avoid addressing problems by disabling. */
                    562:                        /* usbd_reset_port(dev, port, &up->status); */
1.30      augustss  563:
1.58      augustss  564:                        /*
1.30      augustss  565:                         * The unit refused to accept a new address, or had
                    566:                         * some other serious problem.  Since we cannot leave
                    567:                         * at 0 we have to disable the port instead.
                    568:                         */
1.98      cube      569:                        aprint_error_dev(sc->sc_dev,
                    570:                            "device problem, disabling port %d\n", port);
1.30      augustss  571:                        usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
1.1       augustss  572:                } else {
1.47      augustss  573:                        /* The port set up succeeded, reset error count. */
                    574:                        up->restartcnt = 0;
                    575:
1.34      augustss  576:                        if (up->device->hub)
1.11      augustss  577:                                up->device->hub->explore(up->device);
1.1       augustss  578:                }
                    579:        }
1.87      drochner  580:        /* enable status change notifications again */
1.101     drochner  581:        if (!sc->sc_isehciroothub)
                    582:                memset(sc->sc_status, 0, sc->sc_statuslen);
1.87      drochner  583:        sc->sc_explorepending = 0;
1.1       augustss  584:        return (USBD_NORMAL_COMPLETION);
                    585: }
                    586:
1.18      augustss  587: /*
                    588:  * Called from process context when the hub is gone.
                    589:  * Detach all devices on active ports.
                    590:  */
1.105     dyoung    591: int
                    592: uhub_detach(device_t self, int flags)
1.18      augustss  593: {
1.107     dyoung    594:        struct uhub_softc *sc = device_private(self);
1.39      augustss  595:        struct usbd_hub *hub = sc->sc_hub->hub;
1.18      augustss  596:        struct usbd_port *rup;
1.108     dyoung    597:        int nports, port, rc;
1.18      augustss  598:
                    599:        DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
                    600:
1.39      augustss  601:        if (hub == NULL)                /* Must be partially working */
1.18      augustss  602:                return (0);
                    603:
1.117     mrg       604:        /* XXXSMP usb */
                    605:        KERNEL_LOCK(1, curlwp);
                    606:
1.39      augustss  607:        nports = hub->hubdesc.bNbrPorts;
1.32      augustss  608:        for(port = 0; port < nports; port++) {
1.39      augustss  609:                rup = &hub->ports[port];
1.108     dyoung    610:                if (rup->device == NULL)
                    611:                        continue;
1.117     mrg       612:                if ((rc = usb_disconnect_port(rup, self, flags)) != 0) {
                    613:                        /* XXXSMP usb */
                    614:                        KERNEL_UNLOCK_ONE(curlwp);
                    615:
1.108     dyoung    616:                        return rc;
1.117     mrg       617:                }
1.18      augustss  618:        }
1.58      augustss  619:
1.108     dyoung    620:        pmf_device_deregister(self);
                    621:        usbd_abort_pipe(sc->sc_ipipe);
                    622:        usbd_close_pipe(sc->sc_ipipe);
                    623:
1.105     dyoung    624:        usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub, sc->sc_dev);
1.37      augustss  625:
1.83      drochner  626: #if 0
1.70      augustss  627:        if (hub->ports[0].tt)
                    628:                free(hub->ports[0].tt, M_USBDEV);
1.83      drochner  629: #endif
1.71      augustss  630:        free(hub, M_USBDEV);
1.39      augustss  631:        sc->sc_hub->hub = NULL;
1.84      drochner  632:        if (sc->sc_status)
                    633:                free(sc->sc_status, M_USBDEV);
1.101     drochner  634:        if (sc->sc_statusbuf)
                    635:                free(sc->sc_statusbuf, M_USBDEV);
1.18      augustss  636:
1.117     mrg       637:        /* XXXSMP usb */
                    638:        KERNEL_UNLOCK_ONE(curlwp);
                    639:
1.18      augustss  640:        return (0);
                    641: }
1.34      augustss  642:
1.103     kent      643: int
                    644: uhub_rescan(device_t self, const char *ifattr, const int *locators)
                    645: {
                    646:        struct uhub_softc *sc = device_private(self);
                    647:        struct usbd_hub *hub = sc->sc_hub->hub;
                    648:        usbd_device_handle dev;
1.124     martin    649:        int port;
1.103     kent      650:
                    651:        for (port = 0; port < hub->hubdesc.bNbrPorts; port++) {
                    652:                dev = hub->ports[port].device;
                    653:                if (dev == NULL)
                    654:                        continue;
1.124     martin    655:                usbd_reattach_device(sc->sc_dev, dev, port, locators);
1.103     kent      656:        }
                    657:        return 0;
                    658: }
                    659:
1.34      augustss  660: /* Called when a device has been detached from it */
1.95      dyoung    661: void
                    662: uhub_childdet(device_t self, device_t child)
1.34      augustss  663: {
1.95      dyoung    664:        struct uhub_softc *sc = device_private(self);
                    665:        usbd_device_handle devhub = sc->sc_hub;
                    666:        usbd_device_handle dev;
                    667:        int nports;
                    668:        int port;
                    669:        int i;
                    670:
                    671:        if (!devhub->hub)
                    672:                /* should never happen; children are only created after init */
                    673:                panic("hub not fully initialised, but child deleted?");
                    674:
                    675:        nports = devhub->hub->hubdesc.bNbrPorts;
                    676:        for (port = 0; port < nports; port++) {
                    677:                dev = devhub->hub->ports[port].device;
1.118     gsutre    678:                if (!dev || dev->subdevlen == 0)
1.95      dyoung    679:                        continue;
1.99      drochner  680:                for (i = 0; i < dev->subdevlen; i++) {
1.95      dyoung    681:                        if (dev->subdevs[i] == child) {
                    682:                                dev->subdevs[i] = NULL;
1.102     drochner  683:                                dev->nifaces_claimed--;
1.95      dyoung    684:                        }
                    685:                }
1.113     jmcneill  686:                if (dev->nifaces_claimed == 0) {
                    687:                        free(dev->subdevs, M_USB);
                    688:                        dev->subdevs = NULL;
                    689:                        dev->subdevlen = 0;
                    690:                }
1.95      dyoung    691:        }
1.34      augustss  692: }
                    693:
1.18      augustss  694:
                    695: /*
                    696:  * Hub interrupt.
                    697:  * This an indication that some port has changed status.
                    698:  * Notify the bus event handler thread that we need
                    699:  * to be explored again.
                    700:  */
1.1       augustss  701: void
1.105     dyoung    702: uhub_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
1.1       augustss  703: {
                    704:        struct uhub_softc *sc = addr;
                    705:
1.11      augustss  706:        DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
1.87      drochner  707:
1.50      augustss  708:        if (status == USBD_STALLED)
1.9       augustss  709:                usbd_clear_endpoint_stall_async(sc->sc_ipipe);
1.87      drochner  710:        else if (status == USBD_NORMAL_COMPLETION &&
                    711:                 !sc->sc_explorepending) {
                    712:                /*
                    713:                 * Make sure the status is not overwritten in between.
                    714:                 * XXX we should suspend the pipe instead
                    715:                 */
                    716:                memcpy(sc->sc_status, sc->sc_statusbuf, sc->sc_statuslen);
                    717:                sc->sc_explorepending = 1;
1.50      augustss  718:                usb_needs_explore(sc->sc_hub);
1.87      drochner  719:        }
1.89      drochner  720:        /*
                    721:         * XXX workaround for broken implementation of the interrupt
                    722:         * pipe in EHCI root hub emulation which doesn't resend
                    723:         * status change notifications until handled: force a rescan
                    724:         * of the ports we touched in the last run
                    725:         */
                    726:        if (status == USBD_NORMAL_COMPLETION && sc->sc_explorepending &&
1.101     drochner  727:            sc->sc_isehciroothub)
1.89      drochner  728:                usb_needs_explore(sc->sc_hub);
1.1       augustss  729: }

CVSweb <webmaster@jp.NetBSD.org>