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

1.126.2.19! skrll       1: /*     $NetBSD: uhub.c,v 1.126.2.18 2016/01/02 14:04:41 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.126.2.16  skrll       3: /*     $OpenBSD: uhub.c,v 1.86 2015/06/29 18:27:40 mpi Exp $ */
1.1       augustss    4:
                      5: /*
1.74      mycroft     6:  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
1.1       augustss    7:  * All rights reserved.
                      8:  *
1.6       augustss    9:  * This code is derived from software contributed to The NetBSD Foundation
1.44      augustss   10:  * by Lennart Augustsson (lennart@augustsson.net) at
1.6       augustss   11:  * Carlstedt Research & Technology.
1.1       augustss   12:  *
                     13:  * Redistribution and use in source and binary forms, with or without
                     14:  * modification, are permitted provided that the following conditions
                     15:  * are met:
                     16:  * 1. Redistributions of source code must retain the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer.
                     18:  * 2. Redistributions in binary form must reproduce the above copyright
                     19:  *    notice, this list of conditions and the following disclaimer in the
                     20:  *    documentation and/or other materials provided with the distribution.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     23:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     24:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     25:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     26:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     27:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     28:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     29:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     30:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     31:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     32:  * POSSIBILITY OF SUCH DAMAGE.
1.15      augustss   33:  */
                     34:
                     35: /*
1.64      ichiro     36:  * USB spec: http://www.usb.org/developers/docs/usbspec.zip
1.1       augustss   37:  */
1.53      lukem      38:
                     39: #include <sys/cdefs.h>
1.126.2.19! skrll      40: __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126.2.18 2016/01/02 14:04:41 skrll Exp $");
1.1       augustss   41:
                     42: #include <sys/param.h>
1.126.2.9  skrll      43:
1.126.2.10  skrll      44: #include <sys/bus.h>
1.126.2.9  skrll      45: #include <sys/device.h>
1.1       augustss   46: #include <sys/kernel.h>
1.126.2.3  skrll      47: #include <sys/kmem.h>
1.34      augustss   48: #include <sys/proc.h>
1.126.2.9  skrll      49: #include <sys/sysctl.h>
1.126.2.10  skrll      50: #include <sys/systm.h>
1.28      augustss   51:
1.1       augustss   52:
                     53: #include <dev/usb/usb.h>
                     54: #include <dev/usb/usbdi.h>
                     55: #include <dev/usb/usbdi_util.h>
                     56: #include <dev/usb/usbdivar.h>
1.126.2.9  skrll      57: #include <dev/usb/usbhist.h>
1.1       augustss   58:
1.126.2.9  skrll      59: #ifdef USB_DEBUG
                     60: #ifndef UHUB_DEBUG
                     61: #define uhubdebug 0
1.1       augustss   62: #else
1.126.2.9  skrll      63: static int uhubdebug = 0;
                     64:
                     65: SYSCTL_SETUP(sysctl_hw_uhub_setup, "sysctl hw.uhub setup")
                     66: {
                     67:        int err;
                     68:        const struct sysctlnode *rnode;
                     69:        const struct sysctlnode *cnode;
                     70:
                     71:        err = sysctl_createv(clog, 0, NULL, &rnode,
                     72:            CTLFLAG_PERMANENT, CTLTYPE_NODE, "uhub",
                     73:            SYSCTL_DESCR("uhub global controls"),
                     74:            NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
                     75:
                     76:        if (err)
                     77:                goto fail;
                     78:
                     79:        /* control debugging printfs */
                     80:        err = sysctl_createv(clog, 0, &rnode, &cnode,
                     81:            CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
                     82:            "debug", SYSCTL_DESCR("Enable debugging output"),
                     83:            NULL, 0, &uhubdebug, sizeof(uhubdebug), CTL_CREATE, CTL_EOL);
                     84:        if (err)
                     85:                goto fail;
                     86:
                     87:        return;
                     88: fail:
                     89:        aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
                     90: }
                     91:
                     92: #endif /* UHUB_DEBUG */
                     93: #endif /* USB_DEBUG */
                     94:
                     95: #define DPRINTF(FMT,A,B,C,D)   USBHIST_LOGN(uhubdebug,1,FMT,A,B,C,D)
                     96: #define DPRINTFN(N,FMT,A,B,C,D)        USBHIST_LOGN(uhubdebug,N,FMT,A,B,C,D)
                     97: #define UHUBHIST_FUNC() USBHIST_FUNC()
                     98: #define UHUBHIST_CALLED(name) USBHIST_CALLED(uhubdebug)
1.1       augustss   99:
                    100: struct uhub_softc {
1.111     dyoung    101:        device_t                sc_dev;         /* base device */
1.126.2.7  skrll     102:        struct usbd_device *    sc_hub;         /* USB device */
1.86      drochner  103:        int                     sc_proto;       /* device protocol */
1.126.2.7  skrll     104:        struct usbd_pipe *      sc_ipipe;       /* interrupt pipe */
1.87      drochner  105:
1.126.2.18  skrll     106:        kmutex_t                sc_lock;
                    107:
1.126.2.1  skrll     108:        uint8_t                 *sc_statusbuf;
1.126.2.12  skrll     109:        uint8_t                 *sc_statuspend;
1.126.2.1  skrll     110:        uint8_t                 *sc_status;
1.87      drochner  111:        size_t                  sc_statuslen;
                    112:        int                     sc_explorepending;
                    113:
1.11      augustss  114:        u_char                  sc_running;
1.1       augustss  115: };
1.87      drochner  116:
1.126.2.12  skrll     117: #define UHUB_IS_HIGH_SPEED(sc) \
                    118:     ((sc)->sc_proto == UDPROTO_HSHUBSTT || (sc)->sc_proto == UDPROTO_HSHUBMTT)
1.86      drochner  119: #define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
1.1       augustss  120:
1.87      drochner  121: #define PORTSTAT_ISSET(sc, port) \
                    122:        ((sc)->sc_status[(port) / 8] & (1 << ((port) % 8)))
                    123:
1.126.2.7  skrll     124: Static usbd_status uhub_explore(struct usbd_device *);
                    125: Static void uhub_intr(struct usbd_xfer *, void *, usbd_status);
1.1       augustss  126:
1.32      augustss  127:
1.58      augustss  128: /*
1.32      augustss  129:  * We need two attachment points:
                    130:  * hub to usb and hub to hub
                    131:  * Every other driver only connects to hubs
                    132:  */
1.1       augustss  133:
1.98      cube      134: int uhub_match(device_t, cfdata_t, void *);
1.95      dyoung    135: void uhub_attach(device_t, device_t, void *);
1.103     kent      136: int uhub_rescan(device_t, const char *, const int *);
1.95      dyoung    137: void uhub_childdet(device_t, device_t);
                    138: int uhub_detach(device_t, int);
                    139: extern struct cfdriver uhub_cd;
1.104     dyoung    140: CFATTACH_DECL3_NEW(uhub, sizeof(struct uhub_softc), uhub_match,
1.108     dyoung    141:     uhub_attach, uhub_detach, NULL, uhub_rescan, uhub_childdet,
1.104     dyoung    142:     DVF_DETACH_SHUTDOWN);
1.99      drochner  143: CFATTACH_DECL2_NEW(uroothub, sizeof(struct uhub_softc), uhub_match,
1.108     dyoung    144:     uhub_attach, uhub_detach, NULL, uhub_rescan, uhub_childdet);
1.1       augustss  145:
1.109     pooka     146: /*
                    147:  * Setting this to 1 makes sure than an uhub attaches even at higher
                    148:  * priority than ugen when ugen_override is set to 1.  This allows to
                    149:  * probe the whole USB bus and attach functions with ugen.
                    150:  */
                    151: int uhub_ubermatch = 0;
                    152:
1.126.2.12  skrll     153: static usbd_status
                    154: usbd_get_hub_desc(struct usbd_device *dev, usb_hub_descriptor_t *hd, int speed)
                    155: {
                    156:        usb_device_request_t req;
                    157:        usbd_status err;
                    158:        int nports;
                    159:
                    160:        UHUBHIST_FUNC(); UHUBHIST_CALLED();
                    161:
                    162:        /* don't issue UDESC_HUB to SS hub, or it would stall */
                    163:        if (dev->ud_depth != 0 && USB_IS_SS(dev->ud_speed)) {
                    164:                usb_hub_ss_descriptor_t hssd;
                    165:                int rmvlen;
                    166:
                    167:                memset(&hssd, 0, sizeof(hssd));
                    168:                req.bmRequestType = UT_READ_CLASS_DEVICE;
                    169:                req.bRequest = UR_GET_DESCRIPTOR;
                    170:                USETW2(req.wValue, UDESC_SS_HUB, 0);
                    171:                USETW(req.wIndex, 0);
                    172:                USETW(req.wLength, USB_HUB_SS_DESCRIPTOR_SIZE);
                    173:                DPRINTFN(1, "getting sshub descriptor", 0, 0, 0, 0);
                    174:                err = usbd_do_request(dev, &req, &hssd);
                    175:                nports = hssd.bNbrPorts;
                    176:                if (dev->ud_depth != 0 && nports > UHD_SS_NPORTS_MAX) {
                    177:                        DPRINTF("num of ports %d exceeds maxports %d",
                    178:                            nports, UHD_SS_NPORTS_MAX, 0, 0);
                    179:                        nports = hd->bNbrPorts = UHD_SS_NPORTS_MAX;
                    180:                }
                    181:                rmvlen = (nports + 7) / 8;
                    182:                hd->bDescLength = USB_HUB_DESCRIPTOR_SIZE +
                    183:                    (rmvlen > 1 ? rmvlen : 1) - 1;
                    184:                memcpy(hd->DeviceRemovable, hssd.DeviceRemovable, rmvlen);
                    185:                hd->bDescriptorType             = hssd.bDescriptorType;
                    186:                hd->bNbrPorts                   = hssd.bNbrPorts;
                    187:                hd->wHubCharacteristics[0]      = hssd.wHubCharacteristics[0];
                    188:                hd->wHubCharacteristics[1]      = hssd.wHubCharacteristics[1];
                    189:                hd->bPwrOn2PwrGood              = hssd.bPwrOn2PwrGood;
                    190:                hd->bHubContrCurrent            = hssd.bHubContrCurrent;
                    191:        } else {
                    192:                req.bmRequestType = UT_READ_CLASS_DEVICE;
                    193:                req.bRequest = UR_GET_DESCRIPTOR;
                    194:                USETW2(req.wValue, UDESC_HUB, 0);
                    195:                USETW(req.wIndex, 0);
                    196:                USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
                    197:                DPRINTFN(1, "getting hub descriptor", 0, 0, 0, 0);
                    198:                err = usbd_do_request(dev, &req, hd);
                    199:                nports = hd->bNbrPorts;
                    200:                if (!err && nports > 7) {
                    201:                        USETW(req.wLength,
                    202:                            USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
                    203:                        err = usbd_do_request(dev, &req, hd);
                    204:                }
                    205:        }
                    206:
                    207:        return err;
                    208: }
                    209:
                    210: static usbd_status
                    211: usbd_set_hub_depth(struct usbd_device *dev, int depth)
                    212: {
                    213:        usb_device_request_t req;
                    214:
                    215:        req.bmRequestType = UT_WRITE_CLASS_DEVICE;
                    216:        req.bRequest = UR_SET_HUB_DEPTH;
                    217:        USETW(req.wValue, depth);
                    218:        USETW(req.wIndex, 0);
                    219:        USETW(req.wLength, 0);
                    220:        return usbd_do_request(dev, &req, 0);
                    221: }
                    222:
1.105     dyoung    223: int
                    224: uhub_match(device_t parent, cfdata_t match, void *aux)
1.1       augustss  225: {
1.107     dyoung    226:        struct usb_attach_arg *uaa = aux;
1.109     pooka     227:        int matchvalue;
                    228:
1.126.2.9  skrll     229:        UHUBHIST_FUNC(); UHUBHIST_CALLED();
                    230:
1.109     pooka     231:        if (uhub_ubermatch)
                    232:                matchvalue = UMATCH_HIGHEST+1;
                    233:        else
                    234:                matchvalue = UMATCH_DEVCLASS_DEVSUBCLASS;
1.58      augustss  235:
1.126.2.9  skrll     236:        DPRINTFN(5, "uaa=%p", uaa, 0, 0, 0);
1.58      augustss  237:        /*
1.1       augustss  238:         * The subclass for hubs seems to be 0 for some and 1 for others,
                    239:         * so we just ignore the subclass.
                    240:         */
1.126.2.8  skrll     241:        if (uaa->uaa_class == UDCLASS_HUB)
1.126.2.4  skrll     242:                return matchvalue;
                    243:        return UMATCH_NONE;
1.1       augustss  244: }
                    245:
1.105     dyoung    246: void
                    247: uhub_attach(device_t parent, device_t self, void *aux)
1.1       augustss  248: {
1.107     dyoung    249:        struct uhub_softc *sc = device_private(self);
                    250:        struct usb_attach_arg *uaa = aux;
1.126.2.8  skrll     251:        struct usbd_device *dev = uaa->uaa_device;
1.76      augustss  252:        char *devinfop;
1.33      augustss  253:        usbd_status err;
1.70      augustss  254:        struct usbd_hub *hub = NULL;
1.1       augustss  255:        usb_hub_descriptor_t hubdesc;
1.42      augustss  256:        int p, port, nports, nremov, pwrdly;
1.126.2.7  skrll     257:        struct usbd_interface *iface;
1.1       augustss  258:        usb_endpoint_descriptor_t *ed;
1.83      drochner  259: #if 0 /* notyet */
1.70      augustss  260:        struct usbd_tt *tts = NULL;
1.83      drochner  261: #endif
1.58      augustss  262:
1.126.2.9  skrll     263:        UHUBHIST_FUNC(); UHUBHIST_CALLED();
                    264:
1.98      cube      265:        sc->sc_dev = self;
1.1       augustss  266:        sc->sc_hub = dev;
1.126.2.8  skrll     267:        sc->sc_proto = uaa->uaa_proto;
1.76      augustss  268:
                    269:        devinfop = usbd_devinfo_alloc(dev, 1);
1.96      jmcneill  270:        aprint_naive("\n");
                    271:        aprint_normal(": %s\n", devinfop);
1.76      augustss  272:        usbd_devinfo_free(devinfop);
1.1       augustss  273:
1.126.2.2  skrll     274:        if (dev->ud_depth > 0 && UHUB_IS_HIGH_SPEED(sc)) {
1.98      cube      275:                aprint_normal_dev(self, "%s transaction translator%s\n",
1.70      augustss  276:                       UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple",
                    277:                       UHUB_IS_SINGLE_TT(sc) ? "" : "s");
1.69      augustss  278:        }
                    279:
1.33      augustss  280:        err = usbd_set_config_index(dev, 0, 1);
                    281:        if (err) {
1.126.2.9  skrll     282:                DPRINTF("configuration failed, sc %p error %d", sc, err, 0, 0);
1.107     dyoung    283:                return;
1.1       augustss  284:        }
                    285:
1.126.2.2  skrll     286:        if (dev->ud_depth > USB_HUB_MAX_DEPTH) {
1.98      cube      287:                aprint_error_dev(self,
                    288:                    "hub depth (%d) exceeded, hub ignored\n",
                    289:                    USB_HUB_MAX_DEPTH);
1.107     dyoung    290:                return;
1.1       augustss  291:        }
                    292:
                    293:        /* Get hub descriptor. */
1.126.2.12  skrll     294:        memset(&hubdesc, 0, sizeof(hubdesc));
                    295:        err = usbd_get_hub_desc(dev, &hubdesc, dev->ud_speed);
1.11      augustss  296:        nports = hubdesc.bNbrPorts;
1.33      augustss  297:        if (err) {
1.126.2.17  skrll     298:                DPRINTF("getting hub descriptor failed, uhub%d error %d",
1.126.2.9  skrll     299:                    device_unit(self), err, 0, 0);
1.107     dyoung    300:                return;
1.1       augustss  301:        }
                    302:
1.11      augustss  303:        for (nremov = 0, port = 1; port <= nports; port++)
                    304:                if (!UHD_NOT_REMOV(&hubdesc, port))
                    305:                        nremov++;
1.98      cube      306:        aprint_verbose_dev(self, "%d port%s with %d removable, %s powered\n",
                    307:            nports, nports != 1 ? "s" : "", nremov,
1.126.2.2  skrll     308:            dev->ud_selfpowered ? "self" : "bus");
1.11      augustss  309:
1.70      augustss  310:        if (nports == 0) {
1.98      cube      311:                aprint_debug_dev(self, "no ports, hub ignored\n");
1.70      augustss  312:                goto bad;
                    313:        }
                    314:
1.126.2.3  skrll     315:        hub = kmem_alloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
                    316:            KM_SLEEP);
1.33      augustss  317:        if (hub == NULL)
1.107     dyoung    318:                return;
1.126.2.2  skrll     319:        dev->ud_hub = hub;
                    320:        dev->ud_hub->uh_hubsoftc = sc;
                    321:        hub->uh_explore = uhub_explore;
                    322:        hub->uh_hubdesc = hubdesc;
1.58      augustss  323:
1.126.2.12  skrll     324:        if (USB_IS_SS(dev->ud_speed) && dev->ud_depth != 0) {
                    325:                aprint_debug_dev(self, "setting hub depth %u\n",
                    326:                    dev->ud_depth-1);
                    327:                err = usbd_set_hub_depth(dev, dev->ud_depth - 1);
                    328:                if (err) {
                    329:                        aprint_error_dev(self, "can't set depth\n");
                    330:                        goto bad;
                    331:                }
                    332:        }
                    333:
1.1       augustss  334:        /* Set up interrupt pipe. */
1.33      augustss  335:        err = usbd_device2interface_handle(dev, 0, &iface);
                    336:        if (err) {
1.98      cube      337:                aprint_error_dev(self, "no interface handle\n");
1.18      augustss  338:                goto bad;
1.1       augustss  339:        }
1.83      drochner  340:
                    341:        if (UHUB_IS_HIGH_SPEED(sc) && !UHUB_IS_SINGLE_TT(sc)) {
                    342:                err = usbd_set_interface(iface, 1);
                    343:                if (err)
1.98      cube      344:                        aprint_error_dev(self, "can't enable multiple TTs\n");
1.83      drochner  345:        }
                    346:
1.1       augustss  347:        ed = usbd_interface2endpoint_descriptor(iface, 0);
1.33      augustss  348:        if (ed == NULL) {
1.98      cube      349:                aprint_error_dev(self, "no endpoint descriptor\n");
1.18      augustss  350:                goto bad;
1.1       augustss  351:        }
                    352:        if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
1.98      cube      353:                aprint_error_dev(self, "bad interrupt endpoint\n");
1.18      augustss  354:                goto bad;
1.1       augustss  355:        }
                    356:
1.87      drochner  357:        sc->sc_statuslen = (nports + 1 + 7) / 8;
1.126.2.3  skrll     358:        sc->sc_statusbuf = kmem_alloc(sc->sc_statuslen, KM_SLEEP);
1.87      drochner  359:        if (!sc->sc_statusbuf)
                    360:                goto bad;
1.126.2.12  skrll     361:        sc->sc_statuspend = kmem_zalloc(sc->sc_statuslen, KM_SLEEP);
                    362:        if (!sc->sc_statuspend)
                    363:                goto bad;
1.126.2.3  skrll     364:        sc->sc_status = kmem_alloc(sc->sc_statuslen, KM_SLEEP);
1.84      drochner  365:        if (!sc->sc_status)
                    366:                goto bad;
1.126.2.18  skrll     367:
                    368:        mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
                    369:        memset(sc->sc_statuspend, 0, sc->sc_statuslen);
1.84      drochner  370:
1.87      drochner  371:        /* force initial scan */
                    372:        memset(sc->sc_status, 0xff, sc->sc_statuslen);
                    373:        sc->sc_explorepending = 1;
                    374:
1.33      augustss  375:        err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
1.122     jmcneill  376:                  USBD_SHORT_XFER_OK|USBD_MPSAFE, &sc->sc_ipipe, sc,
                    377:                  sc->sc_statusbuf, sc->sc_statuslen,
                    378:                  uhub_intr, USBD_DEFAULT_INTERVAL);
1.33      augustss  379:        if (err) {
1.98      cube      380:                aprint_error_dev(self, "cannot open interrupt pipe\n");
1.18      augustss  381:                goto bad;
1.1       augustss  382:        }
                    383:
1.11      augustss  384:        /* Wait with power off for a while. */
1.13      augustss  385:        usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
1.11      augustss  386:
1.105     dyoung    387:        usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, sc->sc_dev);
1.37      augustss  388:
1.42      augustss  389:        /*
                    390:         * To have the best chance of success we do things in the exact same
1.123     jakllsch  391:         * order as Windows 98.  This should not be necessary, but some
1.42      augustss  392:         * devices do not follow the USB specs to the letter.
                    393:         *
                    394:         * These are the events on the bus when a hub is attached:
                    395:         *  Get device and config descriptors (see attach code)
                    396:         *  Get hub descriptor (see above)
                    397:         *  For all ports
                    398:         *     turn on power
                    399:         *     wait for power to become stable
                    400:         * (all below happens in explore code)
                    401:         *  For all ports
                    402:         *     clear C_PORT_CONNECTION
                    403:         *  For all ports
                    404:         *     get port status
                    405:         *     if device connected
1.57      augustss  406:         *        wait 100 ms
1.42      augustss  407:         *        turn on reset
                    408:         *        wait
                    409:         *        clear C_PORT_RESET
                    410:         *        get port status
                    411:         *        proceed with device attachment
                    412:         */
                    413:
1.83      drochner  414: #if 0
1.78      christos  415:        if (UHUB_IS_HIGH_SPEED(sc) && nports > 0) {
1.126.2.3  skrll     416:                tts = kmem_alloc((UHUB_IS_SINGLE_TT(sc) ? 1 : nports) *
1.126.2.15  skrll     417:                             sizeof(struct usbd_tt), KM_SLEEP);
1.70      augustss  418:                if (!tts)
                    419:                        goto bad;
                    420:        }
1.83      drochner  421: #endif
1.42      augustss  422:        /* Set up data structures */
1.11      augustss  423:        for (p = 0; p < nports; p++) {
1.126.2.2  skrll     424:                struct usbd_port *up = &hub->uh_ports[p];
                    425:                up->up_dev = NULL;
                    426:                up->up_parent = dev;
                    427:                up->up_portno = p+1;
                    428:                if (dev->ud_selfpowered)
1.42      augustss  429:                        /* Self powered hub, give ports maximum current. */
1.126.2.2  skrll     430:                        up->up_power = USB_MAX_POWER;
1.42      augustss  431:                else
1.126.2.2  skrll     432:                        up->up_power = USB_MIN_POWER;
                    433:                up->up_restartcnt = 0;
                    434:                up->up_reattach = 0;
1.83      drochner  435: #if 0
1.70      augustss  436:                if (UHUB_IS_HIGH_SPEED(sc)) {
                    437:                        up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
                    438:                        up->tt->hub = hub;
                    439:                } else {
                    440:                        up->tt = NULL;
                    441:                }
1.83      drochner  442: #endif
1.42      augustss  443:        }
                    444:
                    445:        /* XXX should check for none, individual, or ganged power? */
                    446:
1.126.2.2  skrll     447:        pwrdly = dev->ud_hub->uh_hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR
1.42      augustss  448:            + USB_EXTRA_POWER_UP_TIME;
                    449:        for (port = 1; port <= nports; port++) {
                    450:                /* Turn the power on. */
                    451:                err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
1.33      augustss  452:                if (err)
1.98      cube      453:                        aprint_error_dev(self, "port %d power on failed, %s\n",
                    454:                            port, usbd_errstr(err));
1.126.2.17  skrll     455:                DPRINTF("uhub%d turn on port %d power", device_unit(self),
1.126.2.9  skrll     456:                    port, 0, 0);
1.94      jmcneill  457:        }
                    458:
                    459:        /* Wait for stable power if we are not a root hub */
1.126.2.2  skrll     460:        if (dev->ud_powersrc->up_parent != NULL)
1.42      augustss  461:                usbd_delay_ms(dev, pwrdly);
                    462:
                    463:        /* The usual exploration will finish the setup. */
                    464:
1.1       augustss  465:        sc->sc_running = 1;
1.11      augustss  466:
1.92      jmcneill  467:        if (!pmf_device_register(self, NULL, NULL))
                    468:                aprint_error_dev(self, "couldn't establish power handler\n");
                    469:
1.107     dyoung    470:        return;
1.11      augustss  471:
1.18      augustss  472:  bad:
1.84      drochner  473:        if (sc->sc_status)
1.126.2.6  skrll     474:                kmem_free(sc->sc_status, sc->sc_statuslen);
1.126.2.12  skrll     475:        if (sc->sc_statuspend)
                    476:                kmem_free(sc->sc_statuspend, sc->sc_statuslen);
1.101     drochner  477:        if (sc->sc_statusbuf)
1.126.2.3  skrll     478:                kmem_free(sc->sc_statusbuf, sc->sc_statuslen);
1.70      augustss  479:        if (hub)
1.126.2.3  skrll     480:                kmem_free(hub,
                    481:                    sizeof(*hub) + (nports-1) * sizeof(struct usbd_port));
1.126.2.2  skrll     482:        dev->ud_hub = NULL;
1.107     dyoung    483:        return;
1.11      augustss  484: }
                    485:
1.1       augustss  486: usbd_status
1.126.2.7  skrll     487: uhub_explore(struct usbd_device *dev)
1.1       augustss  488: {
1.126.2.2  skrll     489:        usb_hub_descriptor_t *hd = &dev->ud_hub->uh_hubdesc;
                    490:        struct uhub_softc *sc = dev->ud_hub->uh_hubsoftc;
1.1       augustss  491:        struct usbd_port *up;
1.33      augustss  492:        usbd_status err;
1.56      augustss  493:        int speed;
1.1       augustss  494:        int port;
1.72      joff      495:        int change, status, reconnect;
1.1       augustss  496:
1.126.2.9  skrll     497:        UHUBHIST_FUNC(); UHUBHIST_CALLED();
                    498:
1.126.2.17  skrll     499:        DPRINTFN(10, "uhub%d dev=%p addr=%d speed=%u",
1.126.2.9  skrll     500:            device_unit(sc->sc_dev), dev, dev->ud_addr, dev->ud_speed);
1.1       augustss  501:
                    502:        if (!sc->sc_running)
1.126.2.4  skrll     503:                return USBD_NOT_STARTED;
1.1       augustss  504:
                    505:        /* Ignore hubs that are too deep. */
1.126.2.2  skrll     506:        if (dev->ud_depth > USB_HUB_MAX_DEPTH)
1.126.2.4  skrll     507:                return USBD_TOO_DEEP;
1.1       augustss  508:
1.101     drochner  509:        if (PORTSTAT_ISSET(sc, 0)) { /* hub status change */
                    510:                usb_hub_status_t hs;
                    511:
                    512:                err = usbd_get_hub_status(dev, &hs);
                    513:                if (err) {
1.126.2.17  skrll     514:                        DPRINTF("uhub%d get hub status failed, err %d",
1.126.2.9  skrll     515:                            device_unit(sc->sc_dev), err, 0, 0);
1.101     drochner  516:                } else {
                    517:                        /* just acknowledge */
                    518:                        status = UGETW(hs.wHubStatus);
                    519:                        change = UGETW(hs.wHubChange);
1.126.2.17  skrll     520:                        DPRINTF("uhub%d s/c=%x/%x", device_unit(sc->sc_dev),
1.126.2.9  skrll     521:                            status, change, 0);
                    522:
1.101     drochner  523:                        if (change & UHS_LOCAL_POWER)
                    524:                                usbd_clear_hub_feature(dev,
                    525:                                                       UHF_C_HUB_LOCAL_POWER);
                    526:                        if (change & UHS_OVER_CURRENT)
                    527:                                usbd_clear_hub_feature(dev,
                    528:                                                       UHF_C_HUB_OVER_CURRENT);
                    529:                }
                    530:        }
                    531:
1.84      drochner  532:        for (port = 1; port <= hd->bNbrPorts; port++) {
1.126.2.2  skrll     533:                up = &dev->ud_hub->uh_ports[port-1];
1.87      drochner  534:
                    535:                /* reattach is needed after firmware upload */
1.126.2.2  skrll     536:                reconnect = up->up_reattach;
                    537:                up->up_reattach = 0;
1.87      drochner  538:
                    539:                status = change = 0;
                    540:
                    541:                /* don't check if no change summary notification */
                    542:                if (PORTSTAT_ISSET(sc, port) || reconnect) {
1.126.2.2  skrll     543:                        err = usbd_get_port_status(dev, port, &up->up_status);
1.87      drochner  544:                        if (err) {
1.126.2.17  skrll     545:                                DPRINTF("uhub%d get port stat failed, err %d",
1.126.2.9  skrll     546:                                    device_unit(sc->sc_dev), err, 0, 0);
1.87      drochner  547:                                continue;
                    548:                        }
1.126.2.2  skrll     549:                        status = UGETW(up->up_status.wPortStatus);
                    550:                        change = UGETW(up->up_status.wPortChange);
1.126.2.9  skrll     551:
1.126.2.17  skrll     552:                        DPRINTF("uhub%d port %d: s/c=%x/%x",
1.126.2.9  skrll     553:                            device_unit(sc->sc_dev), port, status, change);
1.87      drochner  554:                }
                    555:                if (!change && !reconnect) {
                    556:                        /* No status change, just do recursive explore. */
1.126.2.2  skrll     557:                        if (up->up_dev != NULL && up->up_dev->ud_hub != NULL)
                    558:                                up->up_dev->ud_hub->uh_explore(up->up_dev);
1.1       augustss  559:                        continue;
                    560:                }
1.87      drochner  561:
1.11      augustss  562:                if (change & UPS_C_PORT_ENABLED) {
1.126.2.17  skrll     563:                        DPRINTF("uhub%d port %d C_PORT_ENABLED",
1.126.2.9  skrll     564:                            device_unit(sc->sc_dev), port, 0, 0);
1.11      augustss  565:                        usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
1.68      mycroft   566:                        if (change & UPS_C_CONNECT_STATUS) {
                    567:                                /* Ignore the port error if the device
                    568:                                   vanished. */
                    569:                        } else if (status & UPS_PORT_ENABLED) {
1.98      cube      570:                                aprint_error_dev(sc->sc_dev,
                    571:                                    "illegal enable change, port %d\n", port);
1.11      augustss  572:                        } else {
                    573:                                /* Port error condition. */
1.126.2.2  skrll     574:                                if (up->up_restartcnt) /* no message first time */
1.98      cube      575:                                        aprint_error_dev(sc->sc_dev,
                    576:                                            "port error, restarting port %d\n",
                    577:                                            port);
1.47      augustss  578:
1.126.2.2  skrll     579:                                if (up->up_restartcnt++ < USBD_RESTART_MAX)
1.11      augustss  580:                                        goto disco;
1.47      augustss  581:                                else
1.98      cube      582:                                        aprint_error_dev(sc->sc_dev,
                    583:                                            "port error, giving up port %d\n",
                    584:                                            port);
1.11      augustss  585:                        }
                    586:                }
1.126.2.13  skrll     587:                if (change & UPS_C_PORT_RESET) {
1.126.2.14  skrll     588:                        /*
                    589:                         * some xHCs set PortResetChange instead of CSC
                    590:                         * when port is reset.
                    591:                         */
                    592:                        if ((status & UPS_CURRENT_CONNECT_STATUS) != 0) {
                    593:                                change |= UPS_C_CONNECT_STATUS;
                    594:                        }
1.126.2.12  skrll     595:                        usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
1.126.2.13  skrll     596:                }
1.126.2.12  skrll     597:                if (change & UPS_C_BH_PORT_RESET) {
1.126.2.13  skrll     598:                        /*
                    599:                         * some xHCs set WarmResetChange instead of CSC
                    600:                         * when port is reset.
                    601:                         */
                    602:                        if ((status & UPS_CURRENT_CONNECT_STATUS) != 0) {
                    603:                                change |= UPS_C_CONNECT_STATUS;
                    604:                        }
1.126.2.12  skrll     605:                        usbd_clear_port_feature(dev, port,
                    606:                            UHF_C_BH_PORT_RESET);
                    607:                }
                    608:                if (change & UPS_C_PORT_LINK_STATE)
                    609:                        usbd_clear_port_feature(dev, port,
                    610:                            UHF_C_PORT_LINK_STATE);
                    611:                if (change & UPS_C_PORT_CONFIG_ERROR)
                    612:                        usbd_clear_port_feature(dev, port,
                    613:                            UHF_C_PORT_CONFIG_ERROR);
1.87      drochner  614:
                    615:                /* XXX handle overcurrent and resume events! */
                    616:
1.126.2.13  skrll     617:                if (!reconnect && !(change & UPS_C_CONNECT_STATUS)) {
1.116     jakllsch  618:                        /* No status change, just do recursive explore. */
1.126.2.2  skrll     619:                        if (up->up_dev != NULL && up->up_dev->ud_hub != NULL)
                    620:                                up->up_dev->ud_hub->uh_explore(up->up_dev);
1.1       augustss  621:                        continue;
1.116     jakllsch  622:                }
1.42      augustss  623:
                    624:                /* We have a connect status change, handle it. */
                    625:
1.126.2.17  skrll     626:                DPRINTF("uhub%d status change port %d", device_unit(sc->sc_dev),
                    627:                    port, 0, 0);
1.1       augustss  628:                usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
                    629:                /*
                    630:                 * If there is already a device on the port the change status
                    631:                 * must mean that is has disconnected.  Looking at the
                    632:                 * current connect status is not enough to figure this out
                    633:                 * since a new unit may have been connected before we handle
                    634:                 * the disconnect.
                    635:                 */
1.11      augustss  636:        disco:
1.126.2.2  skrll     637:                if (up->up_dev != NULL) {
1.1       augustss  638:                        /* Disconnected */
1.126.2.17  skrll     639:                        DPRINTF("uhub%d device addr=%d disappeared on port %d",
1.126.2.9  skrll     640:                            device_unit(sc->sc_dev), up->up_dev->ud_addr, port,
                    641:                            0);
                    642:
1.108     dyoung    643:                        usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
1.58      augustss  644:                        usbd_clear_port_feature(dev, port,
1.1       augustss  645:                                                UHF_C_PORT_CONNECTION);
1.126.2.12  skrll     646:                        continue;
1.1       augustss  647:                }
1.35      augustss  648:                if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
1.42      augustss  649:                        /* Nothing connected, just ignore it. */
1.126.2.17  skrll     650:                        DPRINTFN(3, "uhub%d port %d !CURRENT_CONNECT_STATUS",
1.126.2.9  skrll     651:                            device_unit(sc->sc_dev), port, 0, 0);
1.126.2.12  skrll     652:                        usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
                    653:                        usbd_clear_port_feature(dev, port,
                    654:                                                UHF_C_PORT_CONNECTION);
1.1       augustss  655:                        continue;
1.35      augustss  656:                }
1.1       augustss  657:
                    658:                /* Connected */
1.126.2.9  skrll     659:                DPRINTF("unit %d dev->speed=%u dev->depth=%u",
                    660:                    device_unit(sc->sc_dev), dev->ud_speed, dev->ud_depth, 0);
1.42      augustss  661:
1.1       augustss  662:                /* Wait for maximum device power up time. */
1.13      augustss  663:                usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
1.11      augustss  664:
1.1       augustss  665:                /* Reset port, which implies enabling it. */
1.126.2.2  skrll     666:                if (usbd_reset_port(dev, port, &up->up_status)) {
1.98      cube      667:                        aprint_error_dev(sc->sc_dev,
                    668:                            "port %d reset failed\n", port);
1.54      augustss  669:                        continue;
                    670:                }
                    671:                /* Get port status again, it might have changed during reset */
1.126.2.2  skrll     672:                err = usbd_get_port_status(dev, port, &up->up_status);
1.54      augustss  673:                if (err) {
1.126.2.17  skrll     674:                        DPRINTF("uhub%d port %d get port status failed, "
1.126.2.9  skrll     675:                            "err %d", device_unit(sc->sc_dev), port, err, 0);
1.54      augustss  676:                        continue;
                    677:                }
1.126.2.2  skrll     678:                status = UGETW(up->up_status.wPortStatus);
                    679:                change = UGETW(up->up_status.wPortChange);
1.126.2.11  skrll     680:                DPRINTF("hub %d port %d after reset: s/c=%x/%x",
                    681:                    device_unit(sc->sc_dev), port, status, change);
                    682:
1.54      augustss  683:                if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
                    684:                        /* Nothing connected, just ignore it. */
                    685: #ifdef DIAGNOSTIC
1.98      cube      686:                        aprint_debug_dev(sc->sc_dev,
                    687:                            "port %d, device disappeared after reset\n", port);
1.54      augustss  688: #endif
1.1       augustss  689:                        continue;
1.35      augustss  690:                }
1.110     kiyohara  691:                if (!(status & UPS_PORT_ENABLED)) {
                    692:                        /* Not allowed send/receive packet. */
                    693: #ifdef DIAGNOSTIC
1.115     sborrill  694:                        printf("%s: port %d, device not enabled\n",
1.112     dyoung    695:                               device_xname(sc->sc_dev), port);
1.110     kiyohara  696: #endif
                    697:                        continue;
                    698:                }
1.126.2.12  skrll     699:                /* port reset may cause Warm Reset Change, drop it. */
                    700:                if (change & UPS_C_BH_PORT_RESET)
                    701:                        usbd_clear_port_feature(dev, port,
                    702:                            UHF_C_BH_PORT_RESET);
1.1       augustss  703:
1.126.2.16  skrll     704:                /*
                    705:                 * Figure out device speed from power bit of port status.
                    706:                 *  USB 2.0 ch 11.24.2.7.1
                    707:                 *  USB 3.1 ch 10.16.2.6.1
                    708:                 */
                    709:                int sts = status;
                    710:                if ((sts & UPS_PORT_POWER) == 0)
                    711:                        sts &= ~UPS_PORT_POWER_SS;
                    712:
                    713:                if (sts & UPS_HIGH_SPEED)
1.56      augustss  714:                        speed = USB_SPEED_HIGH;
1.126.2.16  skrll     715:                else if (sts & UPS_LOW_SPEED)
1.56      augustss  716:                        speed = USB_SPEED_LOW;
1.126.2.16  skrll     717:                else {
                    718:                        /*
                    719:                         * If there is no power bit set, it is certainly
                    720:                         * a Super Speed device, so use the speed of its
                    721:                         * parent hub.
                    722:                         */
                    723:                        if (sts & UPS_PORT_POWER)
                    724:                                speed = USB_SPEED_FULL;
                    725:                        else
                    726:                                speed = dev->ud_speed;
                    727:                }
                    728:
                    729:                /*
                    730:                 * Reduce the speed, otherwise we won't setup the proper
                    731:                 * transfer methods.
                    732:                 */
                    733:                if (speed > dev->ud_speed)
                    734:                        speed = dev->ud_speed;
1.126.2.9  skrll     735:
1.126.2.17  skrll     736:                DPRINTF("uhub%d speed %u", device_unit(sc->sc_dev), speed, 0,
1.126.2.9  skrll     737:                    0);
                    738:
1.126.2.16  skrll     739:                /*
                    740:                 * To check whether port has power,
                    741:                 *  check UPS_PORT_POWER_SS bit if port speed is SS, and
                    742:                 *  check UPS_PORT_POWER bit if port speed is HS/FS/LS.
                    743:                 */
                    744:                if (USB_IS_SS(speed)) {
                    745:                        /* SS hub port */
                    746:                        if (!(status & UPS_PORT_POWER_SS))
                    747:                                aprint_normal_dev(sc->sc_dev,
                    748:                                    "strange, connected port %d has no power\n",
                    749:                                    port);
                    750:                } else {
                    751:                        /* HS/FS/LS hub port */
                    752:                        if (!(status & UPS_PORT_POWER))
                    753:                                aprint_normal_dev(sc->sc_dev,
                    754:                                    "strange, connected port %d has no power\n",
                    755:                                    port);
                    756:                }
                    757:
1.1       augustss  758:                /* Get device info and set its address. */
1.126.2.2  skrll     759:                err = usbd_new_device(sc->sc_dev, dev->ud_bus,
                    760:                          dev->ud_depth + 1, speed, port, up);
1.1       augustss  761:                /* XXX retry a few times? */
1.33      augustss  762:                if (err) {
1.126.2.9  skrll     763:                        DPRINTF("usbd_new_device failed, error %d", err, 0, 0,
                    764:                            0);
1.1       augustss  765:                        /* Avoid addressing problems by disabling. */
                    766:                        /* usbd_reset_port(dev, port, &up->status); */
1.30      augustss  767:
1.58      augustss  768:                        /*
1.30      augustss  769:                         * The unit refused to accept a new address, or had
                    770:                         * some other serious problem.  Since we cannot leave
                    771:                         * at 0 we have to disable the port instead.
                    772:                         */
1.98      cube      773:                        aprint_error_dev(sc->sc_dev,
                    774:                            "device problem, disabling port %d\n", port);
1.30      augustss  775:                        usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
1.1       augustss  776:                } else {
1.47      augustss  777:                        /* The port set up succeeded, reset error count. */
1.126.2.2  skrll     778:                        up->up_restartcnt = 0;
1.47      augustss  779:
1.126.2.2  skrll     780:                        if (up->up_dev->ud_hub)
                    781:                                up->up_dev->ud_hub->uh_explore(up->up_dev);
1.1       augustss  782:                }
                    783:        }
1.126.2.18  skrll     784:        mutex_enter(&sc->sc_lock);
1.87      drochner  785:        sc->sc_explorepending = 0;
1.126.2.12  skrll     786:        for (int i = 0; i < sc->sc_statuslen; i++) {
                    787:                if (sc->sc_statuspend[i] != 0) {
                    788:                        memcpy(sc->sc_status, sc->sc_statuspend,
                    789:                            sc->sc_statuslen);
                    790:                        memset(sc->sc_statuspend, 0, sc->sc_statuslen);
                    791:                        usb_needs_explore(sc->sc_hub);
                    792:                        break;
                    793:                }
                    794:        }
1.126.2.18  skrll     795:        mutex_exit(&sc->sc_lock);
                    796:
1.126.2.4  skrll     797:        return USBD_NORMAL_COMPLETION;
1.1       augustss  798: }
                    799:
1.18      augustss  800: /*
                    801:  * Called from process context when the hub is gone.
                    802:  * Detach all devices on active ports.
                    803:  */
1.105     dyoung    804: int
                    805: uhub_detach(device_t self, int flags)
1.18      augustss  806: {
1.107     dyoung    807:        struct uhub_softc *sc = device_private(self);
1.126.2.2  skrll     808:        struct usbd_hub *hub = sc->sc_hub->ud_hub;
1.18      augustss  809:        struct usbd_port *rup;
1.108     dyoung    810:        int nports, port, rc;
1.18      augustss  811:
1.126.2.9  skrll     812:        UHUBHIST_FUNC(); UHUBHIST_CALLED();
                    813:
1.126.2.17  skrll     814:        DPRINTF("uhub%d flags=%d", device_unit(self), flags, 0, 0);
1.18      augustss  815:
1.39      augustss  816:        if (hub == NULL)                /* Must be partially working */
1.126.2.4  skrll     817:                return 0;
1.18      augustss  818:
1.117     mrg       819:        /* XXXSMP usb */
                    820:        KERNEL_LOCK(1, curlwp);
                    821:
1.126.2.2  skrll     822:        nports = hub->uh_hubdesc.bNbrPorts;
1.32      augustss  823:        for(port = 0; port < nports; port++) {
1.126.2.2  skrll     824:                rup = &hub->uh_ports[port];
                    825:                if (rup->up_dev == NULL)
1.108     dyoung    826:                        continue;
1.117     mrg       827:                if ((rc = usb_disconnect_port(rup, self, flags)) != 0) {
                    828:                        /* XXXSMP usb */
                    829:                        KERNEL_UNLOCK_ONE(curlwp);
                    830:
1.108     dyoung    831:                        return rc;
1.117     mrg       832:                }
1.18      augustss  833:        }
1.58      augustss  834:
1.108     dyoung    835:        pmf_device_deregister(self);
                    836:        usbd_abort_pipe(sc->sc_ipipe);
                    837:        usbd_close_pipe(sc->sc_ipipe);
                    838:
1.105     dyoung    839:        usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub, sc->sc_dev);
1.37      augustss  840:
1.83      drochner  841: #if 0
1.70      augustss  842:        if (hub->ports[0].tt)
1.126.2.3  skrll     843:                kmem_free(hub->ports[0].tt,
                    844:                    (UHUB_IS_SINGLE_TT(sc) ? 1 : nports) *
1.126.2.15  skrll     845:                    sizeof(struct usbd_tt));
1.83      drochner  846: #endif
1.126.2.3  skrll     847:        kmem_free(hub,
                    848:            sizeof(*hub) + (nports-1) * sizeof(struct usbd_port));
1.126.2.2  skrll     849:        sc->sc_hub->ud_hub = NULL;
1.84      drochner  850:        if (sc->sc_status)
1.126.2.6  skrll     851:                kmem_free(sc->sc_status, sc->sc_statuslen);
1.126.2.12  skrll     852:        if (sc->sc_statuspend)
                    853:                kmem_free(sc->sc_statuspend, sc->sc_statuslen);
1.101     drochner  854:        if (sc->sc_statusbuf)
1.126.2.3  skrll     855:                kmem_free(sc->sc_statusbuf, sc->sc_statuslen);
1.18      augustss  856:
1.117     mrg       857:        /* XXXSMP usb */
                    858:        KERNEL_UNLOCK_ONE(curlwp);
                    859:
1.126.2.4  skrll     860:        return 0;
1.18      augustss  861: }
1.34      augustss  862:
1.103     kent      863: int
                    864: uhub_rescan(device_t self, const char *ifattr, const int *locators)
                    865: {
                    866:        struct uhub_softc *sc = device_private(self);
1.126.2.2  skrll     867:        struct usbd_hub *hub = sc->sc_hub->ud_hub;
1.126.2.7  skrll     868:        struct usbd_device *dev;
1.124     martin    869:        int port;
1.103     kent      870:
1.126.2.2  skrll     871:        for (port = 0; port < hub->uh_hubdesc.bNbrPorts; port++) {
                    872:                dev = hub->uh_ports[port].up_dev;
1.103     kent      873:                if (dev == NULL)
                    874:                        continue;
1.124     martin    875:                usbd_reattach_device(sc->sc_dev, dev, port, locators);
1.103     kent      876:        }
                    877:        return 0;
                    878: }
                    879:
1.34      augustss  880: /* Called when a device has been detached from it */
1.95      dyoung    881: void
                    882: uhub_childdet(device_t self, device_t child)
1.34      augustss  883: {
1.95      dyoung    884:        struct uhub_softc *sc = device_private(self);
1.126.2.7  skrll     885:        struct usbd_device *devhub = sc->sc_hub;
                    886:        struct usbd_device *dev;
1.95      dyoung    887:        int nports;
                    888:        int port;
                    889:        int i;
                    890:
1.126.2.2  skrll     891:        if (!devhub->ud_hub)
1.95      dyoung    892:                /* should never happen; children are only created after init */
                    893:                panic("hub not fully initialised, but child deleted?");
                    894:
1.126.2.2  skrll     895:        nports = devhub->ud_hub->uh_hubdesc.bNbrPorts;
1.95      dyoung    896:        for (port = 0; port < nports; port++) {
1.126.2.2  skrll     897:                dev = devhub->ud_hub->uh_ports[port].up_dev;
                    898:                if (!dev || dev->ud_subdevlen == 0)
1.95      dyoung    899:                        continue;
1.126.2.2  skrll     900:                for (i = 0; i < dev->ud_subdevlen; i++) {
                    901:                        if (dev->ud_subdevs[i] == child) {
                    902:                                dev->ud_subdevs[i] = NULL;
                    903:                                dev->ud_nifaces_claimed--;
1.95      dyoung    904:                        }
                    905:                }
1.126.2.2  skrll     906:                if (dev->ud_nifaces_claimed == 0) {
1.126.2.3  skrll     907:                        kmem_free(dev->ud_subdevs,
                    908:                            dev->ud_subdevlen * sizeof(device_t));
1.126.2.2  skrll     909:                        dev->ud_subdevs = NULL;
                    910:                        dev->ud_subdevlen = 0;
1.113     jmcneill  911:                }
1.95      dyoung    912:        }
1.34      augustss  913: }
                    914:
1.18      augustss  915:
                    916: /*
                    917:  * Hub interrupt.
                    918:  * This an indication that some port has changed status.
                    919:  * Notify the bus event handler thread that we need
                    920:  * to be explored again.
                    921:  */
1.1       augustss  922: void
1.126.2.7  skrll     923: uhub_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
1.1       augustss  924: {
                    925:        struct uhub_softc *sc = addr;
                    926:
1.126.2.9  skrll     927:        UHUBHIST_FUNC(); UHUBHIST_CALLED();
                    928:
1.126.2.17  skrll     929:        DPRINTFN(5, "uhub%d", device_unit(sc->sc_dev), 0, 0, 0);
1.87      drochner  930:
1.50      augustss  931:        if (status == USBD_STALLED)
1.9       augustss  932:                usbd_clear_endpoint_stall_async(sc->sc_ipipe);
1.126.2.12  skrll     933:        else if (status == USBD_NORMAL_COMPLETION) {
1.126.2.18  skrll     934:
                    935:                mutex_enter(&sc->sc_lock);
                    936:
                    937:                DPRINTFN(5, "uhub%d: explore pending %d",
                    938:                    device_unit(sc->sc_dev), sc->sc_explorepending, 0, 0);
1.126.2.12  skrll     939:
                    940:                /* merge port bitmap into pending interrupts list */
1.126.2.19! skrll     941:                for (size_t i = 0; i < sc->sc_statuslen; i++) {
1.126.2.12  skrll     942:                        sc->sc_statuspend[i] |= sc->sc_statusbuf[i];
                    943:
1.126.2.18  skrll     944:                        DPRINTFN(5, "uhub%d: pending/new ports "
                    945:                            "[%d] %#x/%#x", device_unit(sc->sc_dev),
                    946:                            i, sc->sc_statuspend[i], sc->sc_statusbuf[i]);
                    947:                }
                    948:
1.126.2.12  skrll     949:                if (!sc->sc_explorepending) {
                    950:                        sc->sc_explorepending = 1;
1.126.2.18  skrll     951:
1.126.2.12  skrll     952:                        memcpy(sc->sc_status, sc->sc_statuspend,
                    953:                            sc->sc_statuslen);
                    954:                        memset(sc->sc_statuspend, 0, sc->sc_statuslen);
1.126.2.18  skrll     955:
                    956:                        for (size_t i = 0; i < sc->sc_statuslen; i++) {
                    957:                                DPRINTFN(5, "uhub%d: exploring ports "
                    958:                                    "[%d] %#x", device_unit(sc->sc_dev),
                    959:                                    i, sc->sc_status[i], 0);
                    960:                        }
                    961:
1.126.2.12  skrll     962:                        usb_needs_explore(sc->sc_hub);
                    963:                }
1.126.2.18  skrll     964:                mutex_exit(&sc->sc_lock);
1.87      drochner  965:        }
1.1       augustss  966: }

CVSweb <webmaster@jp.NetBSD.org>