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

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

1.1     ! nbrk        1: /*     $OpenBSD: usbf.c,v 1.9 2007/06/19 11:52:07 mbalmer Exp $        */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: /*
        !            20:  * USB 2.0 logical device driver
        !            21:  *
        !            22:  * Specification non-comformities:
        !            23:  *
        !            24:  * - not all Standard Device Requests are supported (see 9.4)
        !            25:  * - USB 2.0 devices (device_descriptor.bcdUSB >= 0x0200) must support
        !            26:  *   the other_speed requests but we do not
        !            27:  *
        !            28:  * Missing functionality:
        !            29:  *
        !            30:  * - isochronous pipes/transfers
        !            31:  * - clever, automatic endpoint address assignment to make optimal use
        !            32:  *   of available hardware endpoints
        !            33:  * - alternate settings for interfaces are unsupported
        !            34:  */
        !            35:
        !            36: /*
        !            37:  * The source code below is marked an can be split into a number of pieces
        !            38:  * (in that order):
        !            39:  *
        !            40:  * - USB logical device match/attach/detach
        !            41:  * - USB device tasks
        !            42:  * - Bus event handling
        !            43:  * - Device request handling
        !            44:  *
        !            45:  * Stylistic issues:
        !            46:  *
        !            47:  * - "endpoint number" and "endpoint address" are sometimes confused in
        !            48:  *   this source code, OTOH the endpoint number is just the address, aside
        !            49:  *   from the direction bit that is added to the number to form a unique
        !            50:  *   endpoint address
        !            51:  */
        !            52:
        !            53: #include <sys/param.h>
        !            54: #include <sys/device.h>
        !            55: #include <sys/kthread.h>
        !            56: #include <sys/malloc.h>
        !            57: #include <sys/systm.h>
        !            58:
        !            59: #include <machine/bus.h>
        !            60:
        !            61: #include <dev/usb/usb.h>
        !            62: #include <dev/usb/usbdi.h>
        !            63: #include <dev/usb/usbdivar.h>
        !            64: #include <dev/usb/usbf.h>
        !            65: #include <dev/usb/usbfvar.h>
        !            66:
        !            67: #ifndef USBF_DEBUG
        !            68: #define DPRINTF(l, x)  do {} while (0)
        !            69: #else
        !            70: int usbfdebug = 0;
        !            71: #define DPRINTF(l, x)  if ((l) <= usbfdebug) printf x; else {}
        !            72: #endif
        !            73:
        !            74: struct usbf_softc {
        !            75:        struct device            sc_dev;        /* base device */
        !            76:        usbf_bus_handle          sc_bus;        /* USB device controller */
        !            77:        struct usbf_port         sc_port;       /* dummy port for function */
        !            78:        struct proc             *sc_proc;       /* task thread */
        !            79:        TAILQ_HEAD(,usbf_task)   sc_tskq;       /* task queue head */
        !            80:        int                      sc_dying;
        !            81: };
        !            82:
        !            83: #define DEVNAME(sc)    ((sc)->sc_dev.dv_xname)
        !            84:
        !            85: int            usbf_match(struct device *, void *, void *);
        !            86: void           usbf_attach(struct device *, struct device *, void *);
        !            87: void           usbf_create_thread(void *);
        !            88: void           usbf_task_thread(void *);
        !            89:
        !            90: usbf_status    usbf_get_descriptor(usbf_device_handle, usb_device_request_t *,
        !            91:                    void **);
        !            92: void           usbf_set_address(usbf_device_handle, u_int8_t);
        !            93: usbf_status    usbf_set_config(usbf_device_handle, u_int8_t);
        !            94:
        !            95: #ifdef USBF_DEBUG
        !            96: void           usbf_dump_request(usbf_device_handle, usb_device_request_t *);
        !            97: #endif
        !            98:
        !            99: struct cfattach usbf_ca = {
        !           100:        sizeof(struct usbf_softc), usbf_match, usbf_attach
        !           101: };
        !           102:
        !           103: struct cfdriver usbf_cd = {
        !           104:        NULL, "usbf", DV_DULL
        !           105: };
        !           106:
        !           107: static const char * const usbrev_str[] = USBREV_STR;
        !           108:
        !           109: int
        !           110: usbf_match(struct device *parent, void *match, void *aux)
        !           111: {
        !           112:        return UMATCH_GENERIC;
        !           113: }
        !           114:
        !           115: void
        !           116: usbf_attach(struct device *parent, struct device *self, void *aux)
        !           117: {
        !           118:        struct usbf_softc *sc = (struct usbf_softc *)self;
        !           119:        int usbrev;
        !           120:        int speed;
        !           121:        usbf_status err;
        !           122:
        !           123:        /* Continue to set up the bus struct. */
        !           124:        sc->sc_bus = aux;
        !           125:        sc->sc_bus->usbfctl = sc;
        !           126:
        !           127:        usbrev = sc->sc_bus->usbrev;
        !           128:        printf(": USB revision %s", usbrev_str[usbrev]);
        !           129:        switch (usbrev) {
        !           130:        case USBREV_2_0:
        !           131:                speed = USB_SPEED_HIGH;
        !           132:                break;
        !           133:        case USBREV_1_1:
        !           134:        case USBREV_1_0:
        !           135:                speed = USB_SPEED_FULL;
        !           136:                break;
        !           137:        default:
        !           138:                printf(", not supported\n");
        !           139:                sc->sc_dying = 1;
        !           140:                return;
        !           141:        }
        !           142:        printf("\n");
        !           143:
        !           144:        /* Initialize the usbf struct. */
        !           145:        TAILQ_INIT(&sc->sc_tskq);
        !           146:
        !           147:        /* Establish the software interrupt. */
        !           148:        if (usbf_softintr_establish(sc->sc_bus)) {
        !           149:                printf("%s: can't establish softintr\n", DEVNAME(sc));
        !           150:                sc->sc_dying = 1;
        !           151:                return;
        !           152:        }
        !           153:
        !           154:        /* Attach the function driver. */
        !           155:        err = usbf_new_device(self, sc->sc_bus, 0, speed, 0, &sc->sc_port);
        !           156:        if (err) {
        !           157:                printf("%s: usbf_new_device failed, %s\n", DEVNAME(sc),
        !           158:                    usbf_errstr(err));
        !           159:                sc->sc_dying = 1;
        !           160:                return;
        !           161:        }
        !           162:
        !           163:        /* Create a process context for asynchronous tasks. */
        !           164:        config_pending_incr();
        !           165:        kthread_create_deferred(usbf_create_thread, sc);
        !           166: }
        !           167:
        !           168: /*
        !           169:  * USB device tasks
        !           170:  */
        !           171:
        !           172: /*
        !           173:  * Add a task to be performed by the task thread.  This function can be
        !           174:  * called from any context and the task function will be executed in a
        !           175:  * process context ASAP.
        !           176:  */
        !           177: void
        !           178: usbf_add_task(usbf_device_handle dev, struct usbf_task *task)
        !           179: {
        !           180:        struct usbf_softc *sc = dev->bus->usbfctl;
        !           181:        int s;
        !           182:
        !           183:        s = splusb();
        !           184:        if (!task->onqueue) {
        !           185:                DPRINTF(1,("usbf_add_task: task=%p, proc=%s\n",
        !           186:                    task, sc->sc_bus->intr_context ? "(null)" :
        !           187:                    curproc->p_comm));
        !           188:                TAILQ_INSERT_TAIL(&sc->sc_tskq, task, next);
        !           189:                task->onqueue = 1;
        !           190:        } else {
        !           191:                DPRINTF(0,("usbf_add_task: task=%p on q, proc=%s\n",
        !           192:                    task, sc->sc_bus->intr_context ? "(null)" :
        !           193:                    curproc->p_comm));
        !           194:        }
        !           195:        wakeup(&sc->sc_tskq);
        !           196:        splx(s);
        !           197: }
        !           198:
        !           199: void
        !           200: usbf_rem_task(usbf_device_handle dev, struct usbf_task *task)
        !           201: {
        !           202:        struct usbf_softc *sc = dev->bus->usbfctl;
        !           203:        int s;
        !           204:
        !           205:        s = splusb();
        !           206:        if (task->onqueue) {
        !           207:                DPRINTF(1,("usbf_rem_task: task=%p\n", task));
        !           208:                TAILQ_REMOVE(&sc->sc_tskq, task, next);
        !           209:                task->onqueue = 0;
        !           210:
        !           211:        } else {
        !           212:                DPRINTF(0,("usbf_rem_task: task=%p not on q", task));
        !           213:        }
        !           214:        splx(s);
        !           215: }
        !           216:
        !           217: /*
        !           218:  * Called from the kernel proper when it can create threads.
        !           219:  */
        !           220: void
        !           221: usbf_create_thread(void *arg)
        !           222: {
        !           223:        struct usbf_softc *sc = arg;
        !           224:
        !           225:        if (kthread_create(usbf_task_thread, sc, &sc->sc_proc, "%s",
        !           226:            DEVNAME(sc)) != 0) {
        !           227:                printf("%s: can't create task thread\n", DEVNAME(sc));
        !           228:                return;
        !           229:        }
        !           230:        config_pending_decr();
        !           231: }
        !           232:
        !           233: /*
        !           234:  * Process context for USB function tasks.
        !           235:  */
        !           236: void
        !           237: usbf_task_thread(void *arg)
        !           238: {
        !           239:        struct usbf_softc *sc = arg;
        !           240:        struct usbf_task *task;
        !           241:        int s;
        !           242:
        !           243:        DPRINTF(0,("usbf_task_thread: start (pid %d)\n", curproc->p_pid));
        !           244:
        !           245:        s = splusb();
        !           246:        while (!sc->sc_dying) {
        !           247:                task = TAILQ_FIRST(&sc->sc_tskq);
        !           248:                if (task == NULL) {
        !           249:                        tsleep(&sc->sc_tskq, PWAIT, "usbtsk", 0);
        !           250:                        task = TAILQ_FIRST(&sc->sc_tskq);
        !           251:                }
        !           252:                DPRINTF(1,("usbf_task_thread: woke up task=%p\n", task));
        !           253:                if (task != NULL) {
        !           254:                        TAILQ_REMOVE(&sc->sc_tskq, task, next);
        !           255:                        task->onqueue = 0;
        !           256:                        splx(s);
        !           257:                        task->fun(task->arg);
        !           258:                        s = splusb();
        !           259:                        DPRINTF(1,("usbf_task_thread: done task=%p\n", task));
        !           260:                }
        !           261:        }
        !           262:        splx(s);
        !           263:
        !           264:        DPRINTF(0,("usbf_task_thread: exit\n"));
        !           265:        kthread_exit(0);
        !           266: }
        !           267:
        !           268: /*
        !           269:  * Bus event handling
        !           270:  */
        !           271:
        !           272: void
        !           273: usbf_host_reset(usbf_bus_handle bus)
        !           274: {
        !           275:        usbf_device_handle dev = bus->usbfctl->sc_port.device;
        !           276:
        !           277:        DPRINTF(0,("usbf_host_reset\n"));
        !           278:
        !           279:        /* Change device state from any state backe to Default. */
        !           280:        (void)usbf_set_config(dev, USB_UNCONFIG_NO);
        !           281:        dev->address = 0;
        !           282: }
        !           283:
        !           284: /*
        !           285:  * Device request handling
        !           286:  */
        !           287:
        !           288: /* XXX */
        !           289: static u_int8_t hs_config[65536];
        !           290:
        !           291: usbf_status
        !           292: usbf_get_descriptor(usbf_device_handle dev, usb_device_request_t *req,
        !           293:     void **data)
        !           294: {
        !           295:        u_int8_t type = UGETW(req->wValue) >> 8;
        !           296:        u_int8_t index = UGETW(req->wValue) & 0xff;
        !           297:        usb_device_descriptor_t *dd;
        !           298:        usb_config_descriptor_t *cd;
        !           299:        usb_string_descriptor_t *sd;
        !           300:
        !           301:        switch (type) {
        !           302:        case UDESC_DEVICE:
        !           303:                dd = usbf_device_descriptor(dev);
        !           304:                *data = dd;
        !           305:                USETW(req->wLength, MIN(UGETW(req->wLength), dd->bLength));;
        !           306:                return USBF_NORMAL_COMPLETION;
        !           307:
        !           308:        case UDESC_DEVICE_QUALIFIER: {
        !           309:                static usb_device_qualifier_t dq;
        !           310:
        !           311:                dd = usbf_device_descriptor(dev);
        !           312:                bzero(&dq, sizeof dq);
        !           313:                dq.bLength = USB_DEVICE_QUALIFIER_SIZE;
        !           314:                dq.bDescriptorType = UDESC_DEVICE_QUALIFIER;
        !           315:                USETW(dq.bcdUSB, 0x0200);
        !           316:                dq.bDeviceClass = dd->bDeviceClass;
        !           317:                dq.bDeviceSubClass = dd->bDeviceSubClass;
        !           318:                dq.bDeviceProtocol = dd->bDeviceProtocol;
        !           319:                dq.bMaxPacketSize0 = dd->bMaxPacketSize;
        !           320:                dq.bNumConfigurations = dd->bNumConfigurations;
        !           321:                *data = &dq;
        !           322:                USETW(req->wLength, MIN(UGETW(req->wLength), dq.bLength));;
        !           323:                return USBF_NORMAL_COMPLETION;
        !           324:        }
        !           325:
        !           326:        case UDESC_CONFIG:
        !           327:                cd = usbf_config_descriptor(dev, index);
        !           328:                if (cd == NULL)
        !           329:                        return USBF_INVAL;
        !           330:                *data = cd;
        !           331:                USETW(req->wLength, MIN(UGETW(req->wLength),
        !           332:                    UGETW(cd->wTotalLength)));
        !           333:                return USBF_NORMAL_COMPLETION;
        !           334:
        !           335:        /* XXX */
        !           336:        case UDESC_OTHER_SPEED_CONFIGURATION:
        !           337:                cd = usbf_config_descriptor(dev, index);
        !           338:                if (cd == NULL)
        !           339:                        return USBF_INVAL;
        !           340:                bcopy(cd, &hs_config, UGETW(cd->wTotalLength));
        !           341:                *data = &hs_config;
        !           342:                ((usb_config_descriptor_t *)&hs_config)->bDescriptorType =
        !           343:                    UDESC_OTHER_SPEED_CONFIGURATION;
        !           344:                USETW(req->wLength, MIN(UGETW(req->wLength),
        !           345:                    UGETW(cd->wTotalLength)));
        !           346:                return USBF_NORMAL_COMPLETION;
        !           347:
        !           348:        case UDESC_STRING:
        !           349:                sd = usbf_string_descriptor(dev, index);
        !           350:                if (sd == NULL)
        !           351:                        return USBF_INVAL;
        !           352:                *data = sd;
        !           353:                USETW(req->wLength, MIN(UGETW(req->wLength), sd->bLength));
        !           354:                return USBF_NORMAL_COMPLETION;
        !           355:
        !           356:        default:
        !           357:                DPRINTF(0,("usbf_get_descriptor: unknown descriptor type=%u\n",
        !           358:                    type));
        !           359:                return USBF_INVAL;
        !           360:        }
        !           361: }
        !           362:
        !           363: /*
        !           364:  * Change device state from Default to Address, or change the device address
        !           365:  * if the device is not currently in the Default state.
        !           366:  */
        !           367: void
        !           368: usbf_set_address(usbf_device_handle dev, u_int8_t address)
        !           369: {
        !           370:        DPRINTF(0,("usbf_set_address: dev=%p, %u -> %u\n", dev,
        !           371:            dev->address, address));
        !           372:        dev->address = address;
        !           373: }
        !           374:
        !           375: /*
        !           376:  * If the device was in the Addressed state (dev->config == NULL) before, it
        !           377:  * will be in the Configured state upon successful return from this routine.
        !           378:  */
        !           379: usbf_status
        !           380: usbf_set_config(usbf_device_handle dev, u_int8_t new)
        !           381: {
        !           382:        usbf_config_handle cfg = dev->config;
        !           383:        usbf_function_handle fun = dev->function;
        !           384:        usbf_status err = USBF_NORMAL_COMPLETION;
        !           385:        u_int8_t old = cfg ? cfg->uc_cdesc->bConfigurationValue :
        !           386:            USB_UNCONFIG_NO;
        !           387:
        !           388:        if (old == new)
        !           389:                return USBF_NORMAL_COMPLETION;
        !           390:
        !           391:        DPRINTF(0,("usbf_set_config: dev=%p, %u -> %u\n", dev, old, new));
        !           392:
        !           393:        /*
        !           394:         * Resetting the device state to Unconfigured must always succeed.
        !           395:         * This happens typically when the host resets the bus.
        !           396:         */
        !           397:        if (new == USB_UNCONFIG_NO) {
        !           398:                if (dev->function->methods->set_config)
        !           399:                        err = fun->methods->set_config(fun, NULL);
        !           400:                if (err) {
        !           401:                        DPRINTF(0,("usbf_set_config: %s\n", usbf_errstr(err)));
        !           402:                }
        !           403:                dev->config = NULL;
        !           404:                return USBF_NORMAL_COMPLETION;
        !           405:        }
        !           406:
        !           407:        /*
        !           408:         * Changing the device configuration may fail.  The function
        !           409:         * may decline to set the new configuration.
        !           410:         */
        !           411:        SIMPLEQ_FOREACH(cfg, &dev->configs, next) {
        !           412:                if (cfg->uc_cdesc->bConfigurationValue == new) {
        !           413:                        if (dev->function->methods->set_config)
        !           414:                                err = fun->methods->set_config(fun, cfg);
        !           415:                        if (!err)
        !           416:                                dev->config = cfg;
        !           417:                        return err;
        !           418:                }
        !           419:        }
        !           420:        return USBF_INVAL;
        !           421: }
        !           422:
        !           423: /*
        !           424:  * Handle device requests coming in via endpoint 0 pipe.
        !           425:  */
        !           426: void
        !           427: usbf_do_request(usbf_xfer_handle xfer, usbf_private_handle priv,
        !           428:     usbf_status err)
        !           429: {
        !           430:        usbf_device_handle dev = xfer->pipe->device;
        !           431:        usb_device_request_t *req = xfer->buffer;
        !           432:        usbf_config_handle cfg;
        !           433:        void *data = NULL;
        !           434:        u_int16_t value;
        !           435:        u_int16_t index;
        !           436:
        !           437:        if (err) {
        !           438:                DPRINTF(0,("usbf_do_request: receive failed, %s\n",
        !           439:                    usbf_errstr(err)));
        !           440:                return;
        !           441:        }
        !           442:
        !           443: #ifdef USBF_DEBUG
        !           444:        if (usbfdebug >= 0)
        !           445:                usbf_dump_request(dev, req);
        !           446: #endif
        !           447:
        !           448: #define C(x,y) ((x) | ((y) << 8))
        !           449:        switch (C(req->bRequest, req->bmRequestType)) {
        !           450:
        !           451:        case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
        !           452:                /* Change device state from Default to Address. */
        !           453:                usbf_set_address(dev, UGETW(req->wValue));
        !           454:                break;
        !           455:
        !           456:        case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
        !           457:                /* Change device state from Address to Configured. */
        !           458:                printf("set config activated\n");
        !           459:                err = usbf_set_config(dev, UGETW(req->wValue) & 0xff);
        !           460:                break;
        !           461:
        !           462:        case C(UR_GET_CONFIG, UT_READ_DEVICE):
        !           463:        {                       /* XXX */
        !           464:                if ((cfg = dev->config) == NULL) {
        !           465:                        static u_int8_t zero = 0;
        !           466:                        data = &zero;
        !           467:                } else
        !           468:                        data = &cfg->uc_cdesc->bConfigurationValue;
        !           469:                USETW(req->wLength, MIN(UGETW(req->wLength), 1));;
        !           470:        }
        !           471:                break;
        !           472:
        !           473:        case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
        !           474:                err = usbf_get_descriptor(dev, req, &data);
        !           475:                break;
        !           476:
        !           477:        case C(UR_GET_STATUS, UT_READ_DEVICE):
        !           478:                DPRINTF(1,("usbf_do_request: UR_GET_STATUS %d\n",
        !           479:                            UGETW(req->wLength)));
        !           480:                data = &dev->status;
        !           481:                USETW(req->wLength, MIN(UGETW(req->wLength),
        !           482:                    sizeof dev->status));
        !           483:                break;
        !           484:
        !           485:        case C(UR_GET_STATUS, UT_READ_ENDPOINT): {
        !           486:                //u_int8_t addr = UGETW(req->wIndex) & 0xff;
        !           487:                static u_int16_t status = 0;
        !           488:
        !           489:                data = &status;
        !           490:                USETW(req->wLength, MIN(UGETW(req->wLength), sizeof status));
        !           491:                break;
        !           492:        }
        !           493:
        !           494:        case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
        !           495:                value = UGETW(req->wValue);
        !           496:                index = UGETW(req->wIndex);
        !           497:                if ((cfg = dev->config) == NULL)
        !           498:                        err = USBF_STALLED;
        !           499:                else
        !           500:                        err = usbf_set_endpoint_feature(cfg, index, value);
        !           501:                break;
        !           502:
        !           503:        case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
        !           504:                value = UGETW(req->wValue);
        !           505:                index = UGETW(req->wIndex);
        !           506:                if ((cfg = dev->config) == NULL)
        !           507:                        err = USBF_STALLED;
        !           508:                else
        !           509:                        err = usbf_clear_endpoint_feature(cfg, index, value);
        !           510:                break;
        !           511:
        !           512:        /* Alternate settings for interfaces are unsupported. */
        !           513:        case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
        !           514:                if (UGETW(req->wValue) != 0)
        !           515:                        err = USBF_STALLED;
        !           516:                break;
        !           517:        case C(UR_GET_INTERFACE, UT_READ_INTERFACE): {
        !           518:                static u_int8_t zero = 0;
        !           519:                data = &zero;
        !           520:                USETW(req->wLength, MIN(UGETW(req->wLength), 1));
        !           521:                break;
        !           522:        }
        !           523:
        !           524:        default: {
        !           525:                usbf_function_handle fun = dev->function;
        !           526:
        !           527:                if (fun == NULL)
        !           528:                        err = USBF_STALLED;
        !           529:                else
        !           530:                        /* XXX change prototype for this method to remove
        !           531:                         * XXX the data argument. */
        !           532:                        err = fun->methods->do_request(fun, req, &data);
        !           533:        }
        !           534:        }
        !           535:
        !           536:        if (err) {
        !           537:                DPRINTF(0,("usbf_do_request: request=%#x, type=%#x "
        !           538:                    "failed, %s\n", req->bRequest, req->bmRequestType,
        !           539:                    usbf_errstr(err)));
        !           540:                usbf_stall_pipe(dev->default_pipe);
        !           541:        } else if (UGETW(req->wLength) > 0) {
        !           542:                if (data == NULL) {
        !           543:                        DPRINTF(0,("usbf_do_request: no data, "
        !           544:                            "sending ZLP\n"));
        !           545:                        USETW(req->wLength, 0);
        !           546:                }
        !           547:                /* Transfer IN data in response to the request. */
        !           548:                usbf_setup_xfer(dev->data_xfer, dev->default_pipe,
        !           549:                    NULL, data, UGETW(req->wLength), 0, 0, NULL);
        !           550:                err = usbf_transfer(dev->data_xfer);
        !           551:                if (err && err != USBF_IN_PROGRESS) {
        !           552:                        DPRINTF(0,("usbf_do_request: data xfer=%p, %s\n",
        !           553:                            xfer, usbf_errstr(err)));
        !           554:                }
        !           555:        }
        !           556:
        !           557:        /* Schedule another request transfer. */
        !           558:        usbf_setup_default_xfer(dev->default_xfer, dev->default_pipe,
        !           559:            NULL, &dev->def_req, 0, 0, usbf_do_request);
        !           560:        err = usbf_transfer(dev->default_xfer);
        !           561:        if (err && err != USBF_IN_PROGRESS) {
        !           562:                DPRINTF(0,("usbf_do_request: ctrl xfer=%p, %s\n", xfer,
        !           563:                    usbf_errstr(err)));
        !           564:        }
        !           565: }
        !           566:
        !           567: #ifdef USBF_DEBUG
        !           568: struct usb_enum_str {
        !           569:        int code;
        !           570:        const char * const str;
        !           571: };
        !           572:
        !           573: static const struct usb_enum_str usb_request_str[] = {
        !           574:        { UR_GET_STATUS,                "GET STATUS"             },
        !           575:        { UR_CLEAR_FEATURE,             "CLEAR FEATURE"          },
        !           576:        { UR_SET_FEATURE,               "SET FEATURE"            },
        !           577:        { UR_SET_ADDRESS,               "SET ADDRESS"            },
        !           578:        { UR_GET_DESCRIPTOR,            "GET DESCRIPTOR"         },
        !           579:        { UR_SET_DESCRIPTOR,            "SET DESCRIPTOR"         },
        !           580:        { UR_GET_CONFIG,                "GET CONFIG"             },
        !           581:        { UR_SET_CONFIG,                "SET CONFIG"             },
        !           582:        { UR_GET_INTERFACE,             "GET INTERFACE"          },
        !           583:        { UR_SET_INTERFACE,             "SET INTERFACE"          },
        !           584:        { UR_SYNCH_FRAME,               "SYNCH FRAME"            },
        !           585:        { 0, NULL }
        !           586: };
        !           587:
        !           588: static const struct usb_enum_str usb_request_type_str[] = {
        !           589:        { UT_READ_DEVICE,               "Read Device"            },
        !           590:        { UT_READ_INTERFACE,            "Read Interface"         },
        !           591:        { UT_READ_ENDPOINT,             "Read Endpoint"          },
        !           592:        { UT_WRITE_DEVICE,              "Write Device"           },
        !           593:        { UT_WRITE_INTERFACE,           "Write Interface"        },
        !           594:        { UT_WRITE_ENDPOINT,            "Write Endpoint"         },
        !           595:        { UT_READ_CLASS_DEVICE,         "Read Class Device"      },
        !           596:        { UT_READ_CLASS_INTERFACE,      "Read Class Interface"   },
        !           597:        { UT_READ_CLASS_OTHER,          "Read Class Other"       },
        !           598:        { UT_READ_CLASS_ENDPOINT,       "Read Class Endpoint"    },
        !           599:        { UT_WRITE_CLASS_DEVICE,        "Write Class Device"     },
        !           600:        { UT_WRITE_CLASS_INTERFACE,     "Write Class Interface"  },
        !           601:        { UT_WRITE_CLASS_OTHER,         "Write Class Other"      },
        !           602:        { UT_WRITE_CLASS_ENDPOINT,      "Write Class Endpoint"   },
        !           603:        { UT_READ_VENDOR_DEVICE,        "Read Vendor Device"     },
        !           604:        { UT_READ_VENDOR_INTERFACE,     "Read Vendor Interface"  },
        !           605:        { UT_READ_VENDOR_OTHER,         "Read Vendor Other"      },
        !           606:        { UT_READ_VENDOR_ENDPOINT,      "Read Vendor Endpoint"   },
        !           607:        { UT_WRITE_VENDOR_DEVICE,       "Write Vendor Device"    },
        !           608:        { UT_WRITE_VENDOR_INTERFACE,    "Write Vendor Interface" },
        !           609:        { UT_WRITE_VENDOR_OTHER,        "Write Vendor Other"     },
        !           610:        { UT_WRITE_VENDOR_ENDPOINT,     "Write Vendor Endpoint"  },
        !           611:        { 0, NULL }
        !           612: };
        !           613:
        !           614: static const struct usb_enum_str usb_request_desc_str[] = {
        !           615:        { UDESC_DEVICE,                 "Device"                       },
        !           616:        { UDESC_CONFIG,                 "Configuration"                },
        !           617:        { UDESC_STRING,                 "String"                       },
        !           618:        { UDESC_INTERFACE,              "Interface"                    },
        !           619:        { UDESC_ENDPOINT,               "Endpoint"                     },
        !           620:        { UDESC_DEVICE_QUALIFIER,       "Device Qualifier"             },
        !           621:        { UDESC_OTHER_SPEED_CONFIGURATION, "Other Speed Configuration" },
        !           622:        { UDESC_INTERFACE_POWER,        "Interface Power"              },
        !           623:        { UDESC_OTG,                    "OTG"                          },
        !           624:        { UDESC_CS_DEVICE,              "Class-specific Device"        },
        !           625:        { UDESC_CS_CONFIG,              "Class-specific Configuration" },
        !           626:        { UDESC_CS_STRING,              "Class-specific String"        },
        !           627:        { UDESC_CS_INTERFACE,           "Class-specific Interface"     },
        !           628:        { UDESC_CS_ENDPOINT,            "Class-specific Endpoint"      },
        !           629:        { UDESC_HUB,                    "Hub"                          },
        !           630:        { 0, NULL }
        !           631: };
        !           632:
        !           633: static const char *
        !           634: usb_enum_string(const struct usb_enum_str *tab, int code)
        !           635: {
        !           636:        static char buf[16];
        !           637:
        !           638:        while (tab->str != NULL) {
        !           639:                if (tab->code == code)
        !           640:                        return tab->str;
        !           641:                tab++;
        !           642:        }
        !           643:
        !           644:        (void)snprintf(buf, sizeof buf, "0x%02x", code);
        !           645:        return buf;
        !           646: }
        !           647:
        !           648: static const char *
        !           649: usbf_request_code_string(usb_device_request_t *req)
        !           650: {
        !           651:        static char buf[32];
        !           652:
        !           653:        (void)snprintf(buf, sizeof buf, "%s",
        !           654:            usb_enum_string(usb_request_str, req->bRequest));
        !           655:        return buf;
        !           656: }
        !           657:
        !           658: static const char *
        !           659: usbf_request_type_string(usb_device_request_t *req)
        !           660: {
        !           661:        static char buf[32];
        !           662:
        !           663:        (void)snprintf(buf, sizeof buf, "%s",
        !           664:            usb_enum_string(usb_request_type_str, req->bmRequestType));
        !           665:        return buf;
        !           666: }
        !           667:
        !           668: static const char *
        !           669: usbf_request_desc_string(usb_device_request_t *req)
        !           670: {
        !           671:        static char buf[32];
        !           672:        u_int8_t type = UGETW(req->wValue) >> 8;
        !           673:        u_int8_t index = UGETW(req->wValue) & 0xff;
        !           674:
        !           675:        (void)snprintf(buf, sizeof buf, "%s/%u",
        !           676:            usb_enum_string(usb_request_desc_str, type), index);
        !           677:        return buf;
        !           678: }
        !           679:
        !           680: void
        !           681: usbf_dump_request(usbf_device_handle dev, usb_device_request_t *req)
        !           682: {
        !           683:        struct usbf_softc *sc = dev->bus->usbfctl;
        !           684:
        !           685:        printf("%s: %s request %s\n",
        !           686:            DEVNAME(sc), usbf_request_type_string(req),
        !           687:            usbf_request_code_string(req));
        !           688:
        !           689:        if (req->bRequest == UR_GET_DESCRIPTOR)
        !           690:                printf("%s:    VALUE:  0x%04x (%s)\n", DEVNAME(sc),
        !           691:                    UGETW(req->wValue), usbf_request_desc_string(req));
        !           692:        else
        !           693:                printf("%s:    VALUE:  0x%04x\n", DEVNAME(sc),
        !           694:                    UGETW(req->wValue));
        !           695:
        !           696:        printf("%s:    INDEX:  0x%04x\n", DEVNAME(sc), UGETW(req->wIndex));
        !           697:        printf("%s:    LENGTH: 0x%04x\n", DEVNAME(sc), UGETW(req->wLength));
        !           698: }
        !           699: #endif

CVSweb