[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.109.4.1

1.109.4.1! rmind       1: /*     $NetBSD$        */
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.109.4.1! rmind      39: __KERNEL_RCSID(0, "$NetBSD$");
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.109.4.1! rmind      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.109.4.1! rmind      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 */
                     71:        u_int8_t                *sc_statusbuf;
1.84      drochner   72:        u_int8_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);
                    190:        DPRINTFN(1,("usb_init_hub: getting hub descriptor\n"));
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.87      drochner  262:                  USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_statusbuf,
                    263:                  sc->sc_statuslen, uhub_intr, USBD_DEFAULT_INTERVAL);
1.33      augustss  264:        if (err) {
1.98      cube      265:                aprint_error_dev(self, "cannot open interrupt pipe\n");
1.18      augustss  266:                goto bad;
1.1       augustss  267:        }
                    268:
1.11      augustss  269:        /* Wait with power off for a while. */
1.13      augustss  270:        usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
1.11      augustss  271:
1.105     dyoung    272:        usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, sc->sc_dev);
1.37      augustss  273:
1.42      augustss  274:        /*
                    275:         * To have the best chance of success we do things in the exact same
                    276:         * order as Windoze98.  This should not be necessary, but some
                    277:         * devices do not follow the USB specs to the letter.
                    278:         *
                    279:         * These are the events on the bus when a hub is attached:
                    280:         *  Get device and config descriptors (see attach code)
                    281:         *  Get hub descriptor (see above)
                    282:         *  For all ports
                    283:         *     turn on power
                    284:         *     wait for power to become stable
                    285:         * (all below happens in explore code)
                    286:         *  For all ports
                    287:         *     clear C_PORT_CONNECTION
                    288:         *  For all ports
                    289:         *     get port status
                    290:         *     if device connected
1.57      augustss  291:         *        wait 100 ms
1.42      augustss  292:         *        turn on reset
                    293:         *        wait
                    294:         *        clear C_PORT_RESET
                    295:         *        get port status
                    296:         *        proceed with device attachment
                    297:         */
                    298:
1.83      drochner  299: #if 0
1.78      christos  300:        if (UHUB_IS_HIGH_SPEED(sc) && nports > 0) {
1.70      augustss  301:                tts = malloc((UHUB_IS_SINGLE_TT(sc) ? 1 : nports) *
                    302:                             sizeof (struct usbd_tt), M_USBDEV, M_NOWAIT);
                    303:                if (!tts)
                    304:                        goto bad;
                    305:        }
1.83      drochner  306: #endif
1.42      augustss  307:        /* Set up data structures */
1.11      augustss  308:        for (p = 0; p < nports; p++) {
                    309:                struct usbd_port *up = &hub->ports[p];
1.70      augustss  310:                up->device = NULL;
1.11      augustss  311:                up->parent = dev;
                    312:                up->portno = p+1;
1.42      augustss  313:                if (dev->self_powered)
                    314:                        /* Self powered hub, give ports maximum current. */
                    315:                        up->power = USB_MAX_POWER;
                    316:                else
                    317:                        up->power = USB_MIN_POWER;
1.67      petrov    318:                up->restartcnt = 0;
1.72      joff      319:                up->reattach = 0;
1.83      drochner  320: #if 0
1.70      augustss  321:                if (UHUB_IS_HIGH_SPEED(sc)) {
                    322:                        up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
                    323:                        up->tt->hub = hub;
                    324:                } else {
                    325:                        up->tt = NULL;
                    326:                }
1.83      drochner  327: #endif
1.42      augustss  328:        }
                    329:
                    330:        /* XXX should check for none, individual, or ganged power? */
                    331:
                    332:        pwrdly = dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR
                    333:            + USB_EXTRA_POWER_UP_TIME;
                    334:        for (port = 1; port <= nports; port++) {
                    335:                /* Turn the power on. */
                    336:                err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
1.33      augustss  337:                if (err)
1.98      cube      338:                        aprint_error_dev(self, "port %d power on failed, %s\n",
                    339:                            port, usbd_errstr(err));
1.42      augustss  340:                DPRINTF(("usb_init_port: turn on port %d power\n", port));
1.94      jmcneill  341:        }
                    342:
                    343:        /* Wait for stable power if we are not a root hub */
                    344:        if (dev->powersrc->parent != NULL)
1.42      augustss  345:                usbd_delay_ms(dev, pwrdly);
                    346:
                    347:        /* The usual exploration will finish the setup. */
                    348:
1.1       augustss  349:        sc->sc_running = 1;
1.11      augustss  350:
1.92      jmcneill  351:        if (!pmf_device_register(self, NULL, NULL))
                    352:                aprint_error_dev(self, "couldn't establish power handler\n");
                    353:
1.107     dyoung    354:        return;
1.11      augustss  355:
1.18      augustss  356:  bad:
1.84      drochner  357:        if (sc->sc_status)
                    358:                free(sc->sc_status, M_USBDEV);
1.101     drochner  359:        if (sc->sc_statusbuf)
                    360:                free(sc->sc_statusbuf, M_USBDEV);
1.70      augustss  361:        if (hub)
                    362:                free(hub, M_USBDEV);
                    363:        dev->hub = NULL;
1.107     dyoung    364:        return;
1.11      augustss  365: }
                    366:
1.1       augustss  367: usbd_status
1.45      augustss  368: uhub_explore(usbd_device_handle dev)
1.1       augustss  369: {
                    370:        usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
1.11      augustss  371:        struct uhub_softc *sc = dev->hub->hubsoftc;
1.1       augustss  372:        struct usbd_port *up;
1.33      augustss  373:        usbd_status err;
1.56      augustss  374:        int speed;
1.1       augustss  375:        int port;
1.72      joff      376:        int change, status, reconnect;
1.1       augustss  377:
1.11      augustss  378:        DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
1.1       augustss  379:
                    380:        if (!sc->sc_running)
                    381:                return (USBD_NOT_STARTED);
                    382:
                    383:        /* Ignore hubs that are too deep. */
                    384:        if (dev->depth > USB_HUB_MAX_DEPTH)
                    385:                return (USBD_TOO_DEEP);
                    386:
1.101     drochner  387:        if (PORTSTAT_ISSET(sc, 0)) { /* hub status change */
                    388:                usb_hub_status_t hs;
                    389:
                    390:                err = usbd_get_hub_status(dev, &hs);
                    391:                if (err) {
                    392:                        DPRINTF(("%s: get hub status failed, err=%d\n",
                    393:                                 device_xname(sc->sc_dev), err));
                    394:                } else {
                    395:                        /* just acknowledge */
                    396:                        status = UGETW(hs.wHubStatus);
                    397:                        change = UGETW(hs.wHubChange);
                    398:                        if (change & UHS_LOCAL_POWER)
                    399:                                usbd_clear_hub_feature(dev,
                    400:                                                       UHF_C_HUB_LOCAL_POWER);
                    401:                        if (change & UHS_OVER_CURRENT)
                    402:                                usbd_clear_hub_feature(dev,
                    403:                                                       UHF_C_HUB_OVER_CURRENT);
                    404:                }
                    405:        }
                    406:
1.84      drochner  407:        for (port = 1; port <= hd->bNbrPorts; port++) {
1.1       augustss  408:                up = &dev->hub->ports[port-1];
1.87      drochner  409:
                    410:                /* reattach is needed after firmware upload */
                    411:                reconnect = up->reattach;
                    412:                up->reattach = 0;
                    413:
                    414:                status = change = 0;
                    415:
                    416:                /* don't check if no change summary notification */
                    417:                if (PORTSTAT_ISSET(sc, port) || reconnect) {
                    418:                        err = usbd_get_port_status(dev, port, &up->status);
                    419:                        if (err) {
                    420:                                DPRINTF(("uhub_explore: get port stat failed, "
                    421:                                         "error=%s\n", usbd_errstr(err)));
                    422:                                continue;
                    423:                        }
                    424:                        status = UGETW(up->status.wPortStatus);
                    425:                        change = UGETW(up->status.wPortChange);
1.101     drochner  426: #if 0
                    427:                        printf("%s port %d: s/c=%x/%x\n",
                    428:                               device_xname(sc->sc_dev), port, status, change);
                    429: #endif
1.87      drochner  430:                }
                    431:                if (!change && !reconnect) {
                    432:                        /* No status change, just do recursive explore. */
                    433:                        if (up->device != NULL && up->device->hub != NULL)
                    434:                                up->device->hub->explore(up->device);
1.1       augustss  435:                        continue;
                    436:                }
1.87      drochner  437:
1.11      augustss  438:                if (change & UPS_C_PORT_ENABLED) {
1.35      augustss  439:                        DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
1.11      augustss  440:                        usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
1.68      mycroft   441:                        if (change & UPS_C_CONNECT_STATUS) {
                    442:                                /* Ignore the port error if the device
                    443:                                   vanished. */
                    444:                        } else if (status & UPS_PORT_ENABLED) {
1.98      cube      445:                                aprint_error_dev(sc->sc_dev,
                    446:                                    "illegal enable change, port %d\n", port);
1.11      augustss  447:                        } else {
                    448:                                /* Port error condition. */
1.47      augustss  449:                                if (up->restartcnt) /* no message first time */
1.98      cube      450:                                        aprint_error_dev(sc->sc_dev,
                    451:                                            "port error, restarting port %d\n",
                    452:                                            port);
1.47      augustss  453:
                    454:                                if (up->restartcnt++ < USBD_RESTART_MAX)
1.11      augustss  455:                                        goto disco;
1.47      augustss  456:                                else
1.98      cube      457:                                        aprint_error_dev(sc->sc_dev,
                    458:                                            "port error, giving up port %d\n",
                    459:                                            port);
1.11      augustss  460:                        }
                    461:                }
1.87      drochner  462:
                    463:                /* XXX handle overcurrent and resume events! */
                    464:
                    465:                if (!(change & UPS_C_CONNECT_STATUS))
1.1       augustss  466:                        continue;
1.42      augustss  467:
                    468:                /* We have a connect status change, handle it. */
                    469:
1.1       augustss  470:                DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
                    471:                         dev->address, port));
                    472:                usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
                    473:                /*
                    474:                 * If there is already a device on the port the change status
                    475:                 * must mean that is has disconnected.  Looking at the
                    476:                 * current connect status is not enough to figure this out
                    477:                 * since a new unit may have been connected before we handle
                    478:                 * the disconnect.
                    479:                 */
1.11      augustss  480:        disco:
1.33      augustss  481:                if (up->device != NULL) {
1.1       augustss  482:                        /* Disconnected */
1.35      augustss  483:                        DPRINTF(("uhub_explore: device addr=%d disappeared "
1.31      augustss  484:                                 "on port %d\n", up->device->address, port));
1.108     dyoung    485:                        usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
1.58      augustss  486:                        usbd_clear_port_feature(dev, port,
1.1       augustss  487:                                                UHF_C_PORT_CONNECTION);
                    488:                }
1.35      augustss  489:                if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
1.42      augustss  490:                        /* Nothing connected, just ignore it. */
1.35      augustss  491:                        DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
                    492:                                    "_STATUS\n", port));
1.1       augustss  493:                        continue;
1.35      augustss  494:                }
1.1       augustss  495:
                    496:                /* Connected */
1.42      augustss  497:
                    498:                if (!(status & UPS_PORT_POWER))
1.98      cube      499:                        aprint_normal_dev(sc->sc_dev,
                    500:                            "strange, connected port %d has no power\n", port);
1.42      augustss  501:
1.1       augustss  502:                /* Wait for maximum device power up time. */
1.13      augustss  503:                usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
1.11      augustss  504:
1.1       augustss  505:                /* Reset port, which implies enabling it. */
1.35      augustss  506:                if (usbd_reset_port(dev, port, &up->status)) {
1.98      cube      507:                        aprint_error_dev(sc->sc_dev,
                    508:                            "port %d reset failed\n", port);
1.54      augustss  509:                        continue;
                    510:                }
                    511:                /* Get port status again, it might have changed during reset */
                    512:                err = usbd_get_port_status(dev, port, &up->status);
                    513:                if (err) {
                    514:                        DPRINTF(("uhub_explore: get port status failed, "
                    515:                                 "error=%s\n", usbd_errstr(err)));
                    516:                        continue;
                    517:                }
                    518:                status = UGETW(up->status.wPortStatus);
                    519:                change = UGETW(up->status.wPortChange);
                    520:                if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
                    521:                        /* Nothing connected, just ignore it. */
                    522: #ifdef DIAGNOSTIC
1.98      cube      523:                        aprint_debug_dev(sc->sc_dev,
                    524:                            "port %d, device disappeared after reset\n", port);
1.54      augustss  525: #endif
1.1       augustss  526:                        continue;
1.35      augustss  527:                }
1.109.4.1! rmind     528:                if (!(status & UPS_PORT_ENABLED)) {
        !           529:                        /* Not allowed send/receive packet. */
        !           530: #ifdef DIAGNOSTIC
        !           531:                        printf("%s: port %d, device not enable\n",
        !           532:                               device_xname(sc->sc_dev), port);
        !           533: #endif
        !           534:                        continue;
        !           535:                }
1.1       augustss  536:
1.56      augustss  537:                /* Figure out device speed */
                    538:                if (status & UPS_HIGH_SPEED)
                    539:                        speed = USB_SPEED_HIGH;
                    540:                else if (status & UPS_LOW_SPEED)
                    541:                        speed = USB_SPEED_LOW;
                    542:                else
                    543:                        speed = USB_SPEED_FULL;
1.1       augustss  544:                /* Get device info and set its address. */
1.105     dyoung    545:                err = usbd_new_device(sc->sc_dev, dev->bus,
1.56      augustss  546:                          dev->depth + 1, speed, port, up);
1.1       augustss  547:                /* XXX retry a few times? */
1.33      augustss  548:                if (err) {
1.10      drochner  549:                        DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
1.33      augustss  550:                                     "error=%s\n", usbd_errstr(err)));
1.1       augustss  551:                        /* Avoid addressing problems by disabling. */
                    552:                        /* usbd_reset_port(dev, port, &up->status); */
1.30      augustss  553:
1.58      augustss  554:                        /*
1.30      augustss  555:                         * The unit refused to accept a new address, or had
                    556:                         * some other serious problem.  Since we cannot leave
                    557:                         * at 0 we have to disable the port instead.
                    558:                         */
1.98      cube      559:                        aprint_error_dev(sc->sc_dev,
                    560:                            "device problem, disabling port %d\n", port);
1.30      augustss  561:                        usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
1.1       augustss  562:                } else {
1.47      augustss  563:                        /* The port set up succeeded, reset error count. */
                    564:                        up->restartcnt = 0;
                    565:
1.34      augustss  566:                        if (up->device->hub)
1.11      augustss  567:                                up->device->hub->explore(up->device);
1.1       augustss  568:                }
                    569:        }
1.87      drochner  570:        /* enable status change notifications again */
1.101     drochner  571:        if (!sc->sc_isehciroothub)
                    572:                memset(sc->sc_status, 0, sc->sc_statuslen);
1.87      drochner  573:        sc->sc_explorepending = 0;
1.1       augustss  574:        return (USBD_NORMAL_COMPLETION);
                    575: }
                    576:
1.18      augustss  577: /*
                    578:  * Called from process context when the hub is gone.
                    579:  * Detach all devices on active ports.
                    580:  */
1.105     dyoung    581: int
                    582: uhub_detach(device_t self, int flags)
1.18      augustss  583: {
1.107     dyoung    584:        struct uhub_softc *sc = device_private(self);
1.39      augustss  585:        struct usbd_hub *hub = sc->sc_hub->hub;
1.18      augustss  586:        struct usbd_port *rup;
1.108     dyoung    587:        int nports, port, rc;
1.18      augustss  588:
                    589:        DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
                    590:
1.39      augustss  591:        if (hub == NULL)                /* Must be partially working */
1.18      augustss  592:                return (0);
                    593:
1.39      augustss  594:        nports = hub->hubdesc.bNbrPorts;
1.32      augustss  595:        for(port = 0; port < nports; port++) {
1.39      augustss  596:                rup = &hub->ports[port];
1.108     dyoung    597:                if (rup->device == NULL)
                    598:                        continue;
                    599:                if ((rc = usb_disconnect_port(rup, self, flags)) != 0)
                    600:                        return rc;
1.18      augustss  601:        }
1.58      augustss  602:
1.108     dyoung    603:        pmf_device_deregister(self);
                    604:        usbd_abort_pipe(sc->sc_ipipe);
                    605:        usbd_close_pipe(sc->sc_ipipe);
                    606:
1.105     dyoung    607:        usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub, sc->sc_dev);
1.37      augustss  608:
1.83      drochner  609: #if 0
1.70      augustss  610:        if (hub->ports[0].tt)
                    611:                free(hub->ports[0].tt, M_USBDEV);
1.83      drochner  612: #endif
1.71      augustss  613:        free(hub, M_USBDEV);
1.39      augustss  614:        sc->sc_hub->hub = NULL;
1.84      drochner  615:        if (sc->sc_status)
                    616:                free(sc->sc_status, M_USBDEV);
1.101     drochner  617:        if (sc->sc_statusbuf)
                    618:                free(sc->sc_statusbuf, M_USBDEV);
1.18      augustss  619:
                    620:        return (0);
                    621: }
1.34      augustss  622:
1.103     kent      623: int
                    624: uhub_rescan(device_t self, const char *ifattr, const int *locators)
                    625: {
                    626:        struct uhub_softc *sc = device_private(self);
                    627:        struct usbd_hub *hub = sc->sc_hub->hub;
                    628:        usbd_device_handle dev;
                    629:        int port, err;
                    630:
                    631:        for (port = 0; port < hub->hubdesc.bNbrPorts; port++) {
                    632:                dev = hub->ports[port].device;
                    633:                if (dev == NULL)
                    634:                        continue;
1.105     dyoung    635:                err = usbd_reattach_device(sc->sc_dev, dev, port, locators);
1.103     kent      636:        }
                    637:        return 0;
                    638: }
                    639:
1.34      augustss  640: /* Called when a device has been detached from it */
1.95      dyoung    641: void
                    642: uhub_childdet(device_t self, device_t child)
1.34      augustss  643: {
1.95      dyoung    644:        struct uhub_softc *sc = device_private(self);
                    645:        usbd_device_handle devhub = sc->sc_hub;
                    646:        usbd_device_handle dev;
                    647:        int nports;
                    648:        int port;
                    649:        int i;
                    650:
                    651:        if (!devhub->hub)
                    652:                /* should never happen; children are only created after init */
                    653:                panic("hub not fully initialised, but child deleted?");
                    654:
                    655:        nports = devhub->hub->hubdesc.bNbrPorts;
                    656:        for (port = 0; port < nports; port++) {
                    657:                dev = devhub->hub->ports[port].device;
1.99      drochner  658:                if (!dev)
1.95      dyoung    659:                        continue;
1.99      drochner  660:                for (i = 0; i < dev->subdevlen; i++) {
1.95      dyoung    661:                        if (dev->subdevs[i] == child) {
                    662:                                dev->subdevs[i] = NULL;
1.102     drochner  663:                                dev->nifaces_claimed--;
1.95      dyoung    664:                        }
                    665:                }
                    666:        }
1.34      augustss  667: }
                    668:
1.18      augustss  669:
                    670: /*
                    671:  * Hub interrupt.
                    672:  * This an indication that some port has changed status.
                    673:  * Notify the bus event handler thread that we need
                    674:  * to be explored again.
                    675:  */
1.1       augustss  676: void
1.105     dyoung    677: uhub_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
1.1       augustss  678: {
                    679:        struct uhub_softc *sc = addr;
                    680:
1.11      augustss  681:        DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
1.87      drochner  682:
1.50      augustss  683:        if (status == USBD_STALLED)
1.9       augustss  684:                usbd_clear_endpoint_stall_async(sc->sc_ipipe);
1.87      drochner  685:        else if (status == USBD_NORMAL_COMPLETION &&
                    686:                 !sc->sc_explorepending) {
                    687:                /*
                    688:                 * Make sure the status is not overwritten in between.
                    689:                 * XXX we should suspend the pipe instead
                    690:                 */
                    691:                memcpy(sc->sc_status, sc->sc_statusbuf, sc->sc_statuslen);
                    692:                sc->sc_explorepending = 1;
1.50      augustss  693:                usb_needs_explore(sc->sc_hub);
1.87      drochner  694:        }
1.89      drochner  695:        /*
                    696:         * XXX workaround for broken implementation of the interrupt
                    697:         * pipe in EHCI root hub emulation which doesn't resend
                    698:         * status change notifications until handled: force a rescan
                    699:         * of the ports we touched in the last run
                    700:         */
                    701:        if (status == USBD_NORMAL_COMPLETION && sc->sc_explorepending &&
1.101     drochner  702:            sc->sc_isehciroothub)
1.89      drochner  703:                usb_needs_explore(sc->sc_hub);
1.1       augustss  704: }

CVSweb <webmaster@jp.NetBSD.org>