[BACK]Return to usb.c CVS log [TXT][DIR] Up to [local] / sys / dev / usb

Annotation of sys/dev/usb/usb.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: usb.c,v 1.56 2007/06/15 11:41:48 mbalmer Exp $        */
        !             2: /*     $NetBSD: usb.c,v 1.77 2003/01/01 00:10:26 thorpej Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by Lennart Augustsson (lennart@augustsson.net) at
        !            10:  * Carlstedt Research & Technology.
        !            11:  *
        !            12:  * Redistribution and use in source and binary forms, with or without
        !            13:  * modification, are permitted provided that the following conditions
        !            14:  * are met:
        !            15:  * 1. Redistributions of source code must retain the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer.
        !            17:  * 2. Redistributions in binary form must reproduce the above copyright
        !            18:  *    notice, this list of conditions and the following disclaimer in the
        !            19:  *    documentation and/or other materials provided with the distribution.
        !            20:  * 3. All advertising materials mentioning features or use of this software
        !            21:  *    must display the following acknowledgement:
        !            22:  *        This product includes software developed by the NetBSD
        !            23:  *        Foundation, Inc. and its contributors.
        !            24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            25:  *    contributors may be used to endorse or promote products derived
        !            26:  *    from this software without specific prior written permission.
        !            27:  *
        !            28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            38:  * POSSIBILITY OF SUCH DAMAGE.
        !            39:  */
        !            40:
        !            41: /*
        !            42:  * USB specifications and other documentation can be found at
        !            43:  * http://www.usb.org/developers/docs/ and
        !            44:  * http://www.usb.org/developers/devclass_docs/
        !            45:  */
        !            46:
        !            47: #include "ohci.h"
        !            48: #include "uhci.h"
        !            49:
        !            50: #include <sys/param.h>
        !            51: #include <sys/systm.h>
        !            52: #include <sys/kernel.h>
        !            53: #include <sys/malloc.h>
        !            54: #include <sys/device.h>
        !            55: #include <sys/kthread.h>
        !            56: #include <sys/proc.h>
        !            57: #include <sys/conf.h>
        !            58: #include <sys/fcntl.h>
        !            59: #include <sys/poll.h>
        !            60: #include <sys/selinfo.h>
        !            61: #include <sys/vnode.h>
        !            62: #include <sys/signalvar.h>
        !            63:
        !            64: #include <dev/usb/usb.h>
        !            65: #include <dev/usb/usbdi.h>
        !            66: #include <dev/usb/usbdi_util.h>
        !            67:
        !            68: #define USB_DEV_MINOR 255
        !            69:
        !            70: #include <machine/bus.h>
        !            71:
        !            72: #include <dev/usb/usbdivar.h>
        !            73: #include <dev/usb/usb_quirks.h>
        !            74:
        !            75: #ifdef USB_DEBUG
        !            76: #define DPRINTF(x)     do { if (usbdebug) printf x; } while (0)
        !            77: #define DPRINTFN(n,x)  do { if (usbdebug>(n)) printf x; } while (0)
        !            78: int    usbdebug = 0;
        !            79: #if defined(UHCI_DEBUG) && NUHCI > 0
        !            80: extern int     uhcidebug;
        !            81: #endif
        !            82: #if defined(OHCI_DEBUG) && NOHCI > 0
        !            83: extern int     ohcidebug;
        !            84: #endif
        !            85: /*
        !            86:  * 0  - do usual exploration
        !            87:  * 1  - do not use timeout exploration
        !            88:  * >1 - do no exploration
        !            89:  */
        !            90: int    usb_noexplore = 0;
        !            91: #else
        !            92: #define DPRINTF(x)
        !            93: #define DPRINTFN(n,x)
        !            94: #endif
        !            95:
        !            96: struct usb_softc {
        !            97:        struct device    sc_dev;        /* base device */
        !            98:        usbd_bus_handle  sc_bus;        /* USB controller */
        !            99:        struct usbd_port sc_port;       /* dummy port for root hub */
        !           100:
        !           101:        struct proc     *sc_event_thread;
        !           102:
        !           103:        char             sc_dying;
        !           104: };
        !           105:
        !           106: TAILQ_HEAD(, usb_task) usb_all_tasks;
        !           107:
        !           108: volatile int threads_pending = 0;
        !           109:
        !           110: void   usb_discover(void *);
        !           111: void   usb_create_event_thread(void *);
        !           112: void   usb_event_thread(void *);
        !           113: void   usb_task_thread(void *);
        !           114: struct proc *usb_task_thread_proc = NULL;
        !           115:
        !           116: #define USB_MAX_EVENTS 100
        !           117: struct usb_event_q {
        !           118:        struct usb_event ue;
        !           119:        SIMPLEQ_ENTRY(usb_event_q) next;
        !           120: };
        !           121: SIMPLEQ_HEAD(, usb_event_q) usb_events =
        !           122:        SIMPLEQ_HEAD_INITIALIZER(usb_events);
        !           123: int usb_nevents = 0;
        !           124: struct selinfo usb_selevent;
        !           125: struct proc *usb_async_proc;  /* process that wants USB SIGIO */
        !           126: int usb_dev_open = 0;
        !           127: void usb_add_event(int, struct usb_event *);
        !           128:
        !           129: int usb_get_next_event(struct usb_event *);
        !           130:
        !           131: const char *usbrev_str[] = USBREV_STR;
        !           132:
        !           133: int usb_match(struct device *, void *, void *);
        !           134: void usb_attach(struct device *, struct device *, void *);
        !           135: int usb_detach(struct device *, int);
        !           136: int usb_activate(struct device *, enum devact);
        !           137:
        !           138: struct cfdriver usb_cd = {
        !           139:        NULL, "usb", DV_DULL
        !           140: };
        !           141:
        !           142: const struct cfattach usb_ca = {
        !           143:        sizeof(struct usb_softc),
        !           144:        usb_match,
        !           145:        usb_attach,
        !           146:        usb_detach,
        !           147:        usb_activate,
        !           148: };
        !           149:
        !           150: int
        !           151: usb_match(struct device *parent, void *match, void *aux)
        !           152: {
        !           153:        DPRINTF(("usbd_match\n"));
        !           154:        return (UMATCH_GENERIC);
        !           155: }
        !           156:
        !           157: void
        !           158: usb_attach(struct device *parent, struct device *self, void *aux)
        !           159: {
        !           160:        struct usb_softc *sc = (struct usb_softc *)self;
        !           161:        usbd_device_handle dev;
        !           162:        usbd_status err;
        !           163:        int usbrev;
        !           164:        int speed;
        !           165:        struct usb_event ue;
        !           166:
        !           167:        DPRINTF(("usbd_attach\n"));
        !           168:
        !           169:        usbd_init();
        !           170:        sc->sc_bus = aux;
        !           171:        sc->sc_bus->usbctl = sc;
        !           172:        sc->sc_port.power = USB_MAX_POWER;
        !           173:
        !           174:        usbrev = sc->sc_bus->usbrev;
        !           175:        printf(": USB revision %s", usbrev_str[usbrev]);
        !           176:        switch (usbrev) {
        !           177:        case USBREV_1_0:
        !           178:        case USBREV_1_1:
        !           179:                speed = USB_SPEED_FULL;
        !           180:                break;
        !           181:        case USBREV_2_0:
        !           182:                speed = USB_SPEED_HIGH;
        !           183:                break;
        !           184:        default:
        !           185:                printf(", not supported\n");
        !           186:                sc->sc_dying = 1;
        !           187:                return;
        !           188:        }
        !           189:        printf("\n");
        !           190:
        !           191:        /* Make sure not to use tsleep() if we are cold booting. */
        !           192:        if (cold)
        !           193:                sc->sc_bus->use_polling++;
        !           194:
        !           195:        ue.u.ue_ctrlr.ue_bus = sc->sc_dev.dv_unit;
        !           196:        usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue);
        !           197:
        !           198: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
        !           199:        /* XXX we should have our own level */
        !           200:        sc->sc_bus->soft = softintr_establish(IPL_SOFTNET,
        !           201:            sc->sc_bus->methods->soft_intr, sc->sc_bus);
        !           202:        if (sc->sc_bus->soft == NULL) {
        !           203:                printf("%s: can't register softintr\n", sc->sc_dev.dv_xname);
        !           204:                sc->sc_dying = 1;
        !           205:                return;
        !           206:        }
        !           207: #endif
        !           208:
        !           209:        err = usbd_new_device(&sc->sc_dev, sc->sc_bus, 0, speed, 0,
        !           210:                  &sc->sc_port);
        !           211:        if (!err) {
        !           212:                dev = sc->sc_port.device;
        !           213:                if (dev->hub == NULL) {
        !           214:                        sc->sc_dying = 1;
        !           215:                        printf("%s: root device is not a hub\n",
        !           216:                               sc->sc_dev.dv_xname);
        !           217:                        return;
        !           218:                }
        !           219:                sc->sc_bus->root_hub = dev;
        !           220: #if 1
        !           221:                /*
        !           222:                 * Turning this code off will delay attachment of USB devices
        !           223:                 * until the USB event thread is running, which means that
        !           224:                 * the keyboard will not work until after cold boot.
        !           225:                 */
        !           226:                if (cold && (sc->sc_dev.dv_cfdata->cf_flags & 1))
        !           227:                        dev->hub->explore(sc->sc_bus->root_hub);
        !           228: #endif
        !           229:        } else {
        !           230:                printf("%s: root hub problem, error=%d\n",
        !           231:                       sc->sc_dev.dv_xname, err);
        !           232:                sc->sc_dying = 1;
        !           233:        }
        !           234:        if (cold)
        !           235:                sc->sc_bus->use_polling--;
        !           236:
        !           237:        config_pending_incr();
        !           238:        kthread_create_deferred(usb_create_event_thread, sc);
        !           239: }
        !           240:
        !           241: void
        !           242: usb_create_event_thread(void *arg)
        !           243: {
        !           244:        struct usb_softc *sc = arg;
        !           245:        static int created = 0;
        !           246:
        !           247:        if (sc->sc_bus->usbrev == USBREV_2_0)
        !           248:                threads_pending++;
        !           249:
        !           250:        if (kthread_create(usb_event_thread, sc, &sc->sc_event_thread,
        !           251:            "%s", sc->sc_dev.dv_xname))
        !           252:                panic("unable to create event thread for %s",
        !           253:                    sc->sc_dev.dv_xname);
        !           254:
        !           255:        if (!created) {
        !           256:                created = 1;
        !           257:                TAILQ_INIT(&usb_all_tasks);
        !           258:                if (kthread_create(usb_task_thread, NULL,
        !           259:                    &usb_task_thread_proc, "usbtask"))
        !           260:                        panic("unable to create usb task thread");
        !           261:        }
        !           262: }
        !           263:
        !           264: /*
        !           265:  * Add a task to be performed by the task thread.  This function can be
        !           266:  * called from any context and the task will be executed in a process
        !           267:  * context ASAP.
        !           268:  */
        !           269: void
        !           270: usb_add_task(usbd_device_handle dev, struct usb_task *task)
        !           271: {
        !           272:        int s;
        !           273:
        !           274:        s = splusb();
        !           275:        if (!task->onqueue) {
        !           276:                DPRINTFN(2,("usb_add_task: task=%p\n", task));
        !           277:                TAILQ_INSERT_TAIL(&usb_all_tasks, task, next);
        !           278:                task->onqueue = 1;
        !           279:        } else {
        !           280:                DPRINTFN(3,("usb_add_task: task=%p on q\n", task));
        !           281:        }
        !           282:        wakeup(&usb_all_tasks);
        !           283:        splx(s);
        !           284: }
        !           285:
        !           286: void
        !           287: usb_rem_task(usbd_device_handle dev, struct usb_task *task)
        !           288: {
        !           289:        int s;
        !           290:
        !           291:        s = splusb();
        !           292:        if (task->onqueue) {
        !           293:                TAILQ_REMOVE(&usb_all_tasks, task, next);
        !           294:                task->onqueue = 0;
        !           295:        }
        !           296:        splx(s);
        !           297: }
        !           298:
        !           299: void
        !           300: usb_event_thread(void *arg)
        !           301: {
        !           302:        struct usb_softc *sc = arg;
        !           303:        int pwrdly;
        !           304:
        !           305:        DPRINTF(("usb_event_thread: start\n"));
        !           306:
        !           307:        /* Wait for power to come good. */
        !           308:        pwrdly = sc->sc_bus->root_hub->hub->hubdesc.bPwrOn2PwrGood *
        !           309:            UHD_PWRON_FACTOR + USB_EXTRA_POWER_UP_TIME;
        !           310:        usb_delay_ms(sc->sc_bus, pwrdly);
        !           311:
        !           312:        /* USB1 threads wait for USB2 threads to finish their first probe. */
        !           313:        while (sc->sc_bus->usbrev != USBREV_2_0 && threads_pending)
        !           314:                (void)tsleep((void *)&threads_pending, PWAIT, "config", 0);
        !           315:
        !           316:        /* Make sure first discover does something. */
        !           317:        sc->sc_bus->needs_explore = 1;
        !           318:        usb_discover(sc);
        !           319:        config_pending_decr();
        !           320:
        !           321:        /* Wake up any companions waiting for handover before their probes. */
        !           322:        if (sc->sc_bus->usbrev == USBREV_2_0) {
        !           323:                threads_pending--;
        !           324:                wakeup((void *)&threads_pending);
        !           325:        }
        !           326:
        !           327:        while (!sc->sc_dying) {
        !           328: #ifdef USB_DEBUG
        !           329:                if (usb_noexplore < 2)
        !           330: #endif
        !           331:                usb_discover(sc);
        !           332: #ifdef USB_DEBUG
        !           333:                (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
        !           334:                    usb_noexplore ? 0 : hz * 60);
        !           335: #else
        !           336:                (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
        !           337:                    hz * 60);
        !           338: #endif
        !           339:                DPRINTFN(2,("usb_event_thread: woke up\n"));
        !           340:        }
        !           341:        sc->sc_event_thread = NULL;
        !           342:
        !           343:        /* In case parent is waiting for us to exit. */
        !           344:        wakeup(sc);
        !           345:
        !           346:        DPRINTF(("usb_event_thread: exit\n"));
        !           347:        kthread_exit(0);
        !           348: }
        !           349:
        !           350: void
        !           351: usb_task_thread(void *arg)
        !           352: {
        !           353:        struct usb_task *task;
        !           354:        int s;
        !           355:
        !           356:        DPRINTF(("usb_task_thread: start\n"));
        !           357:
        !           358:        s = splusb();
        !           359:        for (;;) {
        !           360:                task = TAILQ_FIRST(&usb_all_tasks);
        !           361:                if (task == NULL) {
        !           362:                        tsleep(&usb_all_tasks, PWAIT, "usbtsk", 0);
        !           363:                        task = TAILQ_FIRST(&usb_all_tasks);
        !           364:                }
        !           365:                DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task));
        !           366:                if (task != NULL) {
        !           367:                        TAILQ_REMOVE(&usb_all_tasks, task, next);
        !           368:                        task->onqueue = 0;
        !           369:                        splx(s);
        !           370:                        task->fun(task->arg);
        !           371:                        s = splusb();
        !           372:                }
        !           373:        }
        !           374: }
        !           375:
        !           376: int
        !           377: usbctlprint(void *aux, const char *pnp)
        !           378: {
        !           379:        /* only "usb"es can attach to host controllers */
        !           380:        if (pnp)
        !           381:                printf("usb at %s", pnp);
        !           382:
        !           383:        return (UNCONF);
        !           384: }
        !           385:
        !           386: int
        !           387: usbopen(dev_t dev, int flag, int mode, struct proc *p)
        !           388: {
        !           389:        int unit = minor(dev);
        !           390:        struct usb_softc *sc;
        !           391:
        !           392:        if (unit == USB_DEV_MINOR) {
        !           393:                if (usb_dev_open)
        !           394:                        return (EBUSY);
        !           395:                usb_dev_open = 1;
        !           396:                usb_async_proc = 0;
        !           397:                return (0);
        !           398:        }
        !           399:
        !           400:        if (unit >= usb_cd.cd_ndevs)
        !           401:                return (ENXIO);
        !           402:        sc = usb_cd.cd_devs[unit];
        !           403:        if (sc == NULL)
        !           404:                return (ENXIO);
        !           405:
        !           406:        if (sc->sc_dying)
        !           407:                return (EIO);
        !           408:
        !           409:        return (0);
        !           410: }
        !           411:
        !           412: int
        !           413: usbread(dev_t dev, struct uio *uio, int flag)
        !           414: {
        !           415:        struct usb_event ue;
        !           416:        int s, error, n;
        !           417:
        !           418:        if (minor(dev) != USB_DEV_MINOR)
        !           419:                return (ENXIO);
        !           420:
        !           421:        if (uio->uio_resid != sizeof(struct usb_event))
        !           422:                return (EINVAL);
        !           423:
        !           424:        error = 0;
        !           425:        s = splusb();
        !           426:        for (;;) {
        !           427:                n = usb_get_next_event(&ue);
        !           428:                if (n != 0)
        !           429:                        break;
        !           430:                if (flag & IO_NDELAY) {
        !           431:                        error = EWOULDBLOCK;
        !           432:                        break;
        !           433:                }
        !           434:                error = tsleep(&usb_events, PZERO | PCATCH, "usbrea", 0);
        !           435:                if (error)
        !           436:                        break;
        !           437:        }
        !           438:        splx(s);
        !           439:        if (!error)
        !           440:                error = uiomove((void *)&ue, uio->uio_resid, uio);
        !           441:
        !           442:        return (error);
        !           443: }
        !           444:
        !           445: int
        !           446: usbclose(dev_t dev, int flag, int mode, struct proc *p)
        !           447: {
        !           448:        int unit = minor(dev);
        !           449:
        !           450:        if (unit == USB_DEV_MINOR) {
        !           451:                usb_async_proc = 0;
        !           452:                usb_dev_open = 0;
        !           453:        }
        !           454:
        !           455:        return (0);
        !           456: }
        !           457:
        !           458: int
        !           459: usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
        !           460: {
        !           461:        struct usb_softc *sc;
        !           462:        int unit = minor(devt);
        !           463:
        !           464:        if (unit == USB_DEV_MINOR) {
        !           465:                switch (cmd) {
        !           466:                case FIONBIO:
        !           467:                        /* All handled in the upper FS layer. */
        !           468:                        return (0);
        !           469:
        !           470:                case FIOASYNC:
        !           471:                        if (*(int *)data)
        !           472:                                usb_async_proc = p;
        !           473:                        else
        !           474:                                usb_async_proc = 0;
        !           475:                        return (0);
        !           476:
        !           477:                default:
        !           478:                        return (EINVAL);
        !           479:                }
        !           480:        }
        !           481:
        !           482:        sc = usb_cd.cd_devs[unit];
        !           483:
        !           484:        if (sc->sc_dying)
        !           485:                return (EIO);
        !           486:
        !           487:        switch (cmd) {
        !           488: #ifdef USB_DEBUG
        !           489:        case USB_SETDEBUG:
        !           490:                if (!(flag & FWRITE))
        !           491:                        return (EBADF);
        !           492:                usbdebug  = ((*(int *)data) & 0x000000ff);
        !           493: #if defined(UHCI_DEBUG) && NUHCI > 0
        !           494:                uhcidebug = ((*(int *)data) & 0x0000ff00) >> 8;
        !           495: #endif
        !           496: #if defined(OHCI_DEBUG) && NOHCI > 0
        !           497:                ohcidebug = ((*(int *)data) & 0x00ff0000) >> 16;
        !           498: #endif
        !           499:                break;
        !           500: #endif /* USB_DEBUG */
        !           501:        case USB_REQUEST:
        !           502:        {
        !           503:                struct usb_ctl_request *ur = (void *)data;
        !           504:                int len = UGETW(ur->ucr_request.wLength);
        !           505:                struct iovec iov;
        !           506:                struct uio uio;
        !           507:                void *ptr = 0;
        !           508:                int addr = ur->ucr_addr;
        !           509:                usbd_status err;
        !           510:                int error = 0;
        !           511:
        !           512:                if (!(flag & FWRITE))
        !           513:                        return (EBADF);
        !           514:
        !           515:                DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len));
        !           516:                if (len < 0 || len > 32768)
        !           517:                        return (EINVAL);
        !           518:                if (addr < 0 || addr >= USB_MAX_DEVICES ||
        !           519:                    sc->sc_bus->devices[addr] == 0)
        !           520:                        return (EINVAL);
        !           521:                if (len != 0) {
        !           522:                        iov.iov_base = (caddr_t)ur->ucr_data;
        !           523:                        iov.iov_len = len;
        !           524:                        uio.uio_iov = &iov;
        !           525:                        uio.uio_iovcnt = 1;
        !           526:                        uio.uio_resid = len;
        !           527:                        uio.uio_offset = 0;
        !           528:                        uio.uio_segflg = UIO_USERSPACE;
        !           529:                        uio.uio_rw =
        !           530:                                ur->ucr_request.bmRequestType & UT_READ ?
        !           531:                                UIO_READ : UIO_WRITE;
        !           532:                        uio.uio_procp = p;
        !           533:                        ptr = malloc(len, M_TEMP, M_WAITOK);
        !           534:                        if (uio.uio_rw == UIO_WRITE) {
        !           535:                                error = uiomove(ptr, len, &uio);
        !           536:                                if (error)
        !           537:                                        goto ret;
        !           538:                        }
        !           539:                }
        !           540:                err = usbd_do_request_flags(sc->sc_bus->devices[addr],
        !           541:                          &ur->ucr_request, ptr, ur->ucr_flags,
        !           542:                          &ur->ucr_actlen, USBD_DEFAULT_TIMEOUT);
        !           543:                if (err) {
        !           544:                        error = EIO;
        !           545:                        goto ret;
        !           546:                }
        !           547:                if (len != 0) {
        !           548:                        if (uio.uio_rw == UIO_READ) {
        !           549:                                error = uiomove(ptr, len, &uio);
        !           550:                                if (error)
        !           551:                                        goto ret;
        !           552:                        }
        !           553:                }
        !           554:        ret:
        !           555:                if (ptr)
        !           556:                        free(ptr, M_TEMP);
        !           557:                return (error);
        !           558:        }
        !           559:
        !           560:        case USB_DEVICEINFO:
        !           561:        {
        !           562:                struct usb_device_info *di = (void *)data;
        !           563:                int addr = di->udi_addr;
        !           564:                usbd_device_handle dev;
        !           565:
        !           566:                if (addr < 1 || addr >= USB_MAX_DEVICES)
        !           567:                        return (EINVAL);
        !           568:                dev = sc->sc_bus->devices[addr];
        !           569:                if (dev == NULL)
        !           570:                        return (ENXIO);
        !           571:                usbd_fill_deviceinfo(dev, di, 1);
        !           572:                break;
        !           573:        }
        !           574:
        !           575:        case USB_DEVICESTATS:
        !           576:                *(struct usb_device_stats *)data = sc->sc_bus->stats;
        !           577:                break;
        !           578:
        !           579:        default:
        !           580:                return (EINVAL);
        !           581:        }
        !           582:        return (0);
        !           583: }
        !           584:
        !           585: int
        !           586: usbpoll(dev_t dev, int events, struct proc *p)
        !           587: {
        !           588:        int revents, mask, s;
        !           589:
        !           590:        if (minor(dev) == USB_DEV_MINOR) {
        !           591:                revents = 0;
        !           592:                mask = POLLIN | POLLRDNORM;
        !           593:
        !           594:                s = splusb();
        !           595:                if (events & mask && usb_nevents > 0)
        !           596:                        revents |= events & mask;
        !           597:                if (revents == 0 && events & mask)
        !           598:                        selrecord(p, &usb_selevent);
        !           599:                splx(s);
        !           600:
        !           601:                return (revents);
        !           602:        } else {
        !           603:                return (POLLERR);
        !           604:        }
        !           605: }
        !           606:
        !           607: void filt_usbrdetach(struct knote *);
        !           608: int filt_usbread(struct knote *, long);
        !           609: int usbkqfilter(dev_t, struct knote *);
        !           610:
        !           611: void
        !           612: filt_usbrdetach(struct knote *kn)
        !           613: {
        !           614:        int s;
        !           615:
        !           616:        s = splusb();
        !           617:        SLIST_REMOVE(&usb_selevent.si_note, kn, knote, kn_selnext);
        !           618:        splx(s);
        !           619: }
        !           620:
        !           621: int
        !           622: filt_usbread(struct knote *kn, long hint)
        !           623: {
        !           624:
        !           625:        if (usb_nevents == 0)
        !           626:                return (0);
        !           627:
        !           628:        kn->kn_data = sizeof(struct usb_event);
        !           629:        return (1);
        !           630: }
        !           631:
        !           632: struct filterops usbread_filtops =
        !           633:        { 1, NULL, filt_usbrdetach, filt_usbread };
        !           634:
        !           635: int
        !           636: usbkqfilter(dev_t dev, struct knote *kn)
        !           637: {
        !           638:        struct klist *klist;
        !           639:        int s;
        !           640:
        !           641:        switch (kn->kn_filter) {
        !           642:        case EVFILT_READ:
        !           643:                if (minor(dev) != USB_DEV_MINOR)
        !           644:                        return (1);
        !           645:                klist = &usb_selevent.si_note;
        !           646:                kn->kn_fop = &usbread_filtops;
        !           647:                break;
        !           648:
        !           649:        default:
        !           650:                return (1);
        !           651:        }
        !           652:
        !           653:        kn->kn_hook = NULL;
        !           654:
        !           655:        s = splusb();
        !           656:        SLIST_INSERT_HEAD(klist, kn, kn_selnext);
        !           657:        splx(s);
        !           658:
        !           659:        return (0);
        !           660: }
        !           661:
        !           662: /* Explore device tree from the root. */
        !           663: void
        !           664: usb_discover(void *v)
        !           665: {
        !           666:        struct usb_softc *sc = v;
        !           667:
        !           668:        DPRINTFN(2,("usb_discover\n"));
        !           669: #ifdef USB_DEBUG
        !           670:        if (usb_noexplore > 1)
        !           671:                return;
        !           672: #endif
        !           673:        /*
        !           674:         * We need mutual exclusion while traversing the device tree,
        !           675:         * but this is guaranteed since this function is only called
        !           676:         * from the event thread for the controller.
        !           677:         */
        !           678:        while (sc->sc_bus->needs_explore && !sc->sc_dying) {
        !           679:                sc->sc_bus->needs_explore = 0;
        !           680:                sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
        !           681:        }
        !           682: }
        !           683:
        !           684: void
        !           685: usb_needs_explore(usbd_device_handle dev)
        !           686: {
        !           687:        DPRINTFN(2,("usb_needs_explore\n"));
        !           688:        dev->bus->needs_explore = 1;
        !           689:        wakeup(&dev->bus->needs_explore);
        !           690: }
        !           691:
        !           692: void
        !           693: usb_needs_reattach(usbd_device_handle dev)
        !           694: {
        !           695:        DPRINTFN(2,("usb_needs_reattach\n"));
        !           696:        dev->powersrc->reattach = 1;
        !           697:        dev->bus->needs_explore = 1;
        !           698:        wakeup(&dev->bus->needs_explore);
        !           699: }
        !           700:
        !           701: /* Called at splusb() */
        !           702: int
        !           703: usb_get_next_event(struct usb_event *ue)
        !           704: {
        !           705:        struct usb_event_q *ueq;
        !           706:
        !           707:        if (usb_nevents <= 0)
        !           708:                return (0);
        !           709:        ueq = SIMPLEQ_FIRST(&usb_events);
        !           710: #ifdef DIAGNOSTIC
        !           711:        if (ueq == NULL) {
        !           712:                printf("usb: usb_nevents got out of sync! %d\n", usb_nevents);
        !           713:                usb_nevents = 0;
        !           714:                return (0);
        !           715:        }
        !           716: #endif
        !           717:        *ue = ueq->ue;
        !           718:        SIMPLEQ_REMOVE_HEAD(&usb_events, next);
        !           719:        free(ueq, M_USBDEV);
        !           720:        usb_nevents--;
        !           721:        return (1);
        !           722: }
        !           723:
        !           724: void
        !           725: usbd_add_dev_event(int type, usbd_device_handle udev)
        !           726: {
        !           727:        struct usb_event ue;
        !           728:
        !           729:        usbd_fill_deviceinfo(udev, &ue.u.ue_device, USB_EVENT_IS_ATTACH(type));
        !           730:        usb_add_event(type, &ue);
        !           731: }
        !           732:
        !           733: void
        !           734: usbd_add_drv_event(int type, usbd_device_handle udev, struct device *dev)
        !           735: {
        !           736:        struct usb_event ue;
        !           737:
        !           738:        ue.u.ue_driver.ue_cookie = udev->cookie;
        !           739:        strncpy(ue.u.ue_driver.ue_devname, dev->dv_xname,
        !           740:            sizeof ue.u.ue_driver.ue_devname);
        !           741:        usb_add_event(type, &ue);
        !           742: }
        !           743:
        !           744: void
        !           745: usb_add_event(int type, struct usb_event *uep)
        !           746: {
        !           747:        struct usb_event_q *ueq;
        !           748:        struct usb_event ue;
        !           749:        struct timespec thetime;
        !           750:        int s;
        !           751:
        !           752:        nanotime(&thetime);
        !           753:        /* Don't want to wait here inside splusb() */
        !           754:        ueq = malloc(sizeof *ueq, M_USBDEV, M_WAITOK);
        !           755:        ueq->ue = *uep;
        !           756:        ueq->ue.ue_type = type;
        !           757:        ueq->ue.ue_time = thetime;
        !           758:
        !           759:        s = splusb();
        !           760:        if (++usb_nevents >= USB_MAX_EVENTS) {
        !           761:                /* Too many queued events, drop an old one. */
        !           762:                DPRINTFN(-1,("usb: event dropped\n"));
        !           763:                (void)usb_get_next_event(&ue);
        !           764:        }
        !           765:        SIMPLEQ_INSERT_TAIL(&usb_events, ueq, next);
        !           766:        wakeup(&usb_events);
        !           767:        selwakeup(&usb_selevent);
        !           768:        if (usb_async_proc != NULL)
        !           769:                psignal(usb_async_proc, SIGIO);
        !           770:        splx(s);
        !           771: }
        !           772:
        !           773: void
        !           774: usb_schedsoftintr(usbd_bus_handle bus)
        !           775: {
        !           776:        DPRINTFN(10,("usb_schedsoftintr: polling=%d\n", bus->use_polling));
        !           777: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
        !           778:        if (bus->use_polling) {
        !           779:                bus->methods->soft_intr(bus);
        !           780:        } else {
        !           781:                softintr_schedule(bus->soft);
        !           782:        }
        !           783: #else
        !           784:        bus->methods->soft_intr(bus);
        !           785: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
        !           786: }
        !           787:
        !           788: int
        !           789: usb_activate(struct device *self, enum devact act)
        !           790: {
        !           791:        struct usb_softc *sc = (struct usb_softc *)self;
        !           792:        usbd_device_handle dev = sc->sc_port.device;
        !           793:        int i, rv = 0;
        !           794:
        !           795:        switch (act) {
        !           796:        case DVACT_ACTIVATE:
        !           797:                break;
        !           798:
        !           799:        case DVACT_DEACTIVATE:
        !           800:                sc->sc_dying = 1;
        !           801:                if (dev != NULL && dev->cdesc != NULL &&
        !           802:                    dev->subdevs != NULL) {
        !           803:                        for (i = 0; dev->subdevs[i]; i++)
        !           804:                                rv |= config_deactivate(dev->subdevs[i]);
        !           805:                }
        !           806:                break;
        !           807:        }
        !           808:        return (rv);
        !           809: }
        !           810:
        !           811: int
        !           812: usb_detach(struct device *self, int flags)
        !           813: {
        !           814:        struct usb_softc *sc = (struct usb_softc *)self;
        !           815:        struct usb_event ue;
        !           816:
        !           817:        DPRINTF(("usb_detach: start\n"));
        !           818:
        !           819:        sc->sc_dying = 1;
        !           820:
        !           821:        /* Make all devices disconnect. */
        !           822:        if (sc->sc_port.device != NULL)
        !           823:                usb_disconnect_port(&sc->sc_port, self);
        !           824:
        !           825:        /* Kill off event thread. */
        !           826:        if (sc->sc_event_thread != NULL) {
        !           827:                wakeup(&sc->sc_bus->needs_explore);
        !           828:                if (tsleep(sc, PWAIT, "usbdet", hz * 60))
        !           829:                        printf("%s: event thread didn't die\n",
        !           830:                               sc->sc_dev.dv_xname);
        !           831:                DPRINTF(("usb_detach: event thread dead\n"));
        !           832:        }
        !           833:
        !           834:        usbd_finish();
        !           835:
        !           836: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
        !           837:        if (sc->sc_bus->soft != NULL) {
        !           838:                softintr_disestablish(sc->sc_bus->soft);
        !           839:                sc->sc_bus->soft = NULL;
        !           840:        }
        !           841: #endif
        !           842:
        !           843:        ue.u.ue_ctrlr.ue_bus = sc->sc_dev.dv_unit;
        !           844:        usb_add_event(USB_EVENT_CTRLR_DETACH, &ue);
        !           845:
        !           846:        return (0);
        !           847: }

CVSweb