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