[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

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