root/dev/usb/usbf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usbf_match
  2. usbf_attach
  3. usbf_add_task
  4. usbf_rem_task
  5. usbf_create_thread
  6. usbf_task_thread
  7. usbf_host_reset
  8. usbf_get_descriptor
  9. usbf_set_address
  10. usbf_set_config
  11. usbf_do_request
  12. usb_enum_string
  13. usbf_request_code_string
  14. usbf_request_type_string
  15. usbf_request_desc_string
  16. usbf_dump_request

    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

/* [<][>][^][v][top][bottom][index][help] */