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