Annotation of sys/dev/usb/usbdi_util.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: usbdi_util.c,v 1.24 2007/06/18 11:53:11 mbalmer Exp $ */
2: /* $NetBSD: usbdi_util.c,v 1.40 2002/07/11 21:14:36 augustss Exp $ */
3: /* $FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.14 1999/11/17 22:33:50 n_hibma Exp $ */
4:
5: /*
6: * Copyright (c) 1998 The NetBSD Foundation, Inc.
7: * All rights reserved.
8: *
9: * This code is derived from software contributed to The NetBSD Foundation
10: * by Lennart Augustsson (lennart@augustsson.net) at
11: * Carlstedt Research & Technology.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. All advertising materials mentioning features or use of this software
22: * must display the following acknowledgement:
23: * This product includes software developed by the NetBSD
24: * Foundation, Inc. and its contributors.
25: * 4. Neither the name of The NetBSD Foundation nor the names of its
26: * contributors may be used to endorse or promote products derived
27: * from this software without specific prior written permission.
28: *
29: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39: * POSSIBILITY OF SUCH DAMAGE.
40: */
41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/kernel.h>
45: #include <sys/malloc.h>
46: #include <sys/proc.h>
47: #include <sys/device.h>
48:
49: #include <dev/usb/usb.h>
50: #include <dev/usb/usbhid.h>
51:
52: #include <dev/usb/usbdi.h>
53: #include <dev/usb/usbdi_util.h>
54:
55: #ifdef USB_DEBUG
56: #define DPRINTF(x) do { if (usbdebug) printf x; } while (0)
57: #define DPRINTFN(n,x) do { if (usbdebug>(n)) printf x; } while (0)
58: extern int usbdebug;
59: #else
60: #define DPRINTF(x)
61: #define DPRINTFN(n,x)
62: #endif
63:
64: usbd_status
65: usbd_get_desc(usbd_device_handle dev, int type, int index, int len, void *desc)
66: {
67: usb_device_request_t req;
68:
69: DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n", type, index,
70: len));
71:
72: req.bmRequestType = UT_READ_DEVICE;
73: req.bRequest = UR_GET_DESCRIPTOR;
74: USETW2(req.wValue, type, index);
75: USETW(req.wIndex, 0);
76: USETW(req.wLength, len);
77: return (usbd_do_request(dev, &req, desc));
78: }
79:
80: usbd_status
81: usbd_get_config_desc(usbd_device_handle dev, int confidx,
82: usb_config_descriptor_t *d)
83: {
84: usbd_status err;
85:
86: DPRINTFN(3,("usbd_get_config_desc: confidx=%d\n", confidx));
87: err = usbd_get_desc(dev, UDESC_CONFIG, confidx,
88: USB_CONFIG_DESCRIPTOR_SIZE, d);
89: if (err)
90: return (err);
91: if (d->bDescriptorType != UDESC_CONFIG) {
92: DPRINTFN(-1,("usbd_get_config_desc: confidx=%d, bad desc "
93: "len=%d type=%d\n", confidx, d->bLength,
94: d->bDescriptorType));
95: return (USBD_INVAL);
96: }
97: return (USBD_NORMAL_COMPLETION);
98: }
99:
100: usbd_status
101: usbd_get_config_desc_full(usbd_device_handle dev, int conf, void *d, int size)
102: {
103: DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf));
104: return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d));
105: }
106:
107: usbd_status
108: usbd_get_device_desc(usbd_device_handle dev, usb_device_descriptor_t *d)
109: {
110: DPRINTFN(3,("usbd_get_device_desc:\n"));
111: return (usbd_get_desc(dev, UDESC_DEVICE, 0, USB_DEVICE_DESCRIPTOR_SIZE,
112: d));
113: }
114:
115: usbd_status
116: usbd_get_device_status(usbd_device_handle dev, usb_status_t *st)
117: {
118: usb_device_request_t req;
119:
120: req.bmRequestType = UT_READ_DEVICE;
121: req.bRequest = UR_GET_STATUS;
122: USETW(req.wValue, 0);
123: USETW(req.wIndex, 0);
124: USETW(req.wLength, sizeof(usb_status_t));
125: return (usbd_do_request(dev, &req, st));
126: }
127:
128: usbd_status
129: usbd_get_hub_status(usbd_device_handle dev, usb_hub_status_t *st)
130: {
131: usb_device_request_t req;
132:
133: req.bmRequestType = UT_READ_CLASS_DEVICE;
134: req.bRequest = UR_GET_STATUS;
135: USETW(req.wValue, 0);
136: USETW(req.wIndex, 0);
137: USETW(req.wLength, sizeof(usb_hub_status_t));
138: return (usbd_do_request(dev, &req, st));
139: }
140:
141: usbd_status
142: usbd_set_address(usbd_device_handle dev, int addr)
143: {
144: usb_device_request_t req;
145:
146: req.bmRequestType = UT_WRITE_DEVICE;
147: req.bRequest = UR_SET_ADDRESS;
148: USETW(req.wValue, addr);
149: USETW(req.wIndex, 0);
150: USETW(req.wLength, 0);
151: return usbd_do_request(dev, &req, 0);
152: }
153:
154: usbd_status
155: usbd_get_port_status(usbd_device_handle dev, int port, usb_port_status_t *ps)
156: {
157: usb_device_request_t req;
158:
159: req.bmRequestType = UT_READ_CLASS_OTHER;
160: req.bRequest = UR_GET_STATUS;
161: USETW(req.wValue, 0);
162: USETW(req.wIndex, port);
163: USETW(req.wLength, sizeof *ps);
164: return (usbd_do_request(dev, &req, ps));
165: }
166:
167: usbd_status
168: usbd_clear_hub_feature(usbd_device_handle dev, int sel)
169: {
170: usb_device_request_t req;
171:
172: req.bmRequestType = UT_WRITE_CLASS_DEVICE;
173: req.bRequest = UR_CLEAR_FEATURE;
174: USETW(req.wValue, sel);
175: USETW(req.wIndex, 0);
176: USETW(req.wLength, 0);
177: return (usbd_do_request(dev, &req, 0));
178: }
179:
180: usbd_status
181: usbd_set_hub_feature(usbd_device_handle dev, int sel)
182: {
183: usb_device_request_t req;
184:
185: req.bmRequestType = UT_WRITE_CLASS_DEVICE;
186: req.bRequest = UR_SET_FEATURE;
187: USETW(req.wValue, sel);
188: USETW(req.wIndex, 0);
189: USETW(req.wLength, 0);
190: return (usbd_do_request(dev, &req, 0));
191: }
192:
193: usbd_status
194: usbd_clear_port_feature(usbd_device_handle dev, int port, int sel)
195: {
196: usb_device_request_t req;
197:
198: req.bmRequestType = UT_WRITE_CLASS_OTHER;
199: req.bRequest = UR_CLEAR_FEATURE;
200: USETW(req.wValue, sel);
201: USETW(req.wIndex, port);
202: USETW(req.wLength, 0);
203: return (usbd_do_request(dev, &req, 0));
204: }
205:
206: usbd_status
207: usbd_set_port_feature(usbd_device_handle dev, int port, int sel)
208: {
209: usb_device_request_t req;
210:
211: req.bmRequestType = UT_WRITE_CLASS_OTHER;
212: req.bRequest = UR_SET_FEATURE;
213: USETW(req.wValue, sel);
214: USETW(req.wIndex, port);
215: USETW(req.wLength, 0);
216: return (usbd_do_request(dev, &req, 0));
217: }
218:
219: usbd_status
220: usbd_get_protocol(usbd_interface_handle iface, u_int8_t *report)
221: {
222: usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
223: usbd_device_handle dev;
224: usb_device_request_t req;
225:
226: DPRINTFN(4, ("usbd_get_protocol: iface=%p, endpt=%d\n", iface,
227: id->bInterfaceNumber));
228: if (id == NULL)
229: return (USBD_IOERROR);
230: usbd_interface2device_handle(iface, &dev);
231: req.bmRequestType = UT_READ_CLASS_INTERFACE;
232: req.bRequest = UR_GET_PROTOCOL;
233: USETW(req.wValue, 0);
234: USETW(req.wIndex, id->bInterfaceNumber);
235: USETW(req.wLength, 1);
236: return (usbd_do_request(dev, &req, report));
237: }
238:
239: usbd_status
240: usbd_set_protocol(usbd_interface_handle iface, int report)
241: {
242: usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
243: usbd_device_handle dev;
244: usb_device_request_t req;
245:
246: DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
247: iface, report, id->bInterfaceNumber));
248: if (id == NULL)
249: return (USBD_IOERROR);
250: usbd_interface2device_handle(iface, &dev);
251: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
252: req.bRequest = UR_SET_PROTOCOL;
253: USETW(req.wValue, report);
254: USETW(req.wIndex, id->bInterfaceNumber);
255: USETW(req.wLength, 0);
256: return (usbd_do_request(dev, &req, 0));
257: }
258:
259: usbd_status
260: usbd_set_report(usbd_interface_handle iface, int type, int id, void *data,
261: int len)
262: {
263: usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
264: usbd_device_handle dev;
265: usb_device_request_t req;
266:
267: DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
268: if (ifd == NULL)
269: return (USBD_IOERROR);
270: usbd_interface2device_handle(iface, &dev);
271: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
272: req.bRequest = UR_SET_REPORT;
273: USETW2(req.wValue, type, id);
274: USETW(req.wIndex, ifd->bInterfaceNumber);
275: USETW(req.wLength, len);
276: return (usbd_do_request(dev, &req, data));
277: }
278:
279: usbd_status
280: usbd_set_report_async(usbd_interface_handle iface, int type, int id,
281: void *data, int len)
282: {
283: usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
284: usbd_device_handle dev;
285: usb_device_request_t req;
286:
287: DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
288: if (ifd == NULL)
289: return (USBD_IOERROR);
290: usbd_interface2device_handle(iface, &dev);
291: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
292: req.bRequest = UR_SET_REPORT;
293: USETW2(req.wValue, type, id);
294: USETW(req.wIndex, ifd->bInterfaceNumber);
295: USETW(req.wLength, len);
296: return (usbd_do_request_async(dev, &req, data));
297: }
298:
299: usbd_status
300: usbd_get_report(usbd_interface_handle iface, int type, int id, void *data,
301: int len)
302: {
303: usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
304: usbd_device_handle dev;
305: usb_device_request_t req;
306:
307: DPRINTFN(4, ("usbd_get_report: len=%d\n", len));
308: if (ifd == NULL)
309: return (USBD_IOERROR);
310: usbd_interface2device_handle(iface, &dev);
311: req.bmRequestType = UT_READ_CLASS_INTERFACE;
312: req.bRequest = UR_GET_REPORT;
313: USETW2(req.wValue, type, id);
314: USETW(req.wIndex, ifd->bInterfaceNumber);
315: USETW(req.wLength, len);
316: return (usbd_do_request(dev, &req, data));
317: }
318:
319: usbd_status
320: usbd_set_idle(usbd_interface_handle iface, int duration, int id)
321: {
322: usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
323: usbd_device_handle dev;
324: usb_device_request_t req;
325:
326: DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
327: if (ifd == NULL)
328: return (USBD_IOERROR);
329: usbd_interface2device_handle(iface, &dev);
330: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
331: req.bRequest = UR_SET_IDLE;
332: USETW2(req.wValue, duration, id);
333: USETW(req.wIndex, ifd->bInterfaceNumber);
334: USETW(req.wLength, 0);
335: return (usbd_do_request(dev, &req, 0));
336: }
337:
338: usbd_status
339: usbd_get_report_descriptor(usbd_device_handle dev, int ifcno, int size,
340: void *d)
341: {
342: usb_device_request_t req;
343:
344: req.bmRequestType = UT_READ_INTERFACE;
345: req.bRequest = UR_GET_DESCRIPTOR;
346: USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */
347: USETW(req.wIndex, ifcno);
348: USETW(req.wLength, size);
349: return (usbd_do_request(dev, &req, d));
350: }
351:
352: usb_hid_descriptor_t *
353: usbd_get_hid_descriptor(usbd_interface_handle ifc)
354: {
355: usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
356: usbd_device_handle dev;
357: usb_config_descriptor_t *cdesc;
358: usb_hid_descriptor_t *hd;
359: char *p, *end;
360:
361: if (idesc == NULL)
362: return (0);
363: usbd_interface2device_handle(ifc, &dev);
364: cdesc = usbd_get_config_descriptor(dev);
365:
366: p = (char *)idesc + idesc->bLength;
367: end = (char *)cdesc + UGETW(cdesc->wTotalLength);
368:
369: for (; p < end; p += hd->bLength) {
370: hd = (usb_hid_descriptor_t *)p;
371: if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
372: return (hd);
373: if (hd->bDescriptorType == UDESC_INTERFACE)
374: break;
375: }
376: return (0);
377: }
378:
379: usbd_status
380: usbd_read_report_desc(usbd_interface_handle ifc, void **descp, int *sizep,
381: int mem)
382: {
383: usb_interface_descriptor_t *id;
384: usb_hid_descriptor_t *hid;
385: usbd_device_handle dev;
386: usbd_status err;
387:
388: usbd_interface2device_handle(ifc, &dev);
389: id = usbd_get_interface_descriptor(ifc);
390: if (id == NULL)
391: return (USBD_INVAL);
392: hid = usbd_get_hid_descriptor(ifc);
393: if (hid == NULL)
394: return (USBD_IOERROR);
395: *sizep = UGETW(hid->descrs[0].wDescriptorLength);
396: *descp = malloc(*sizep, mem, M_NOWAIT);
397: if (*descp == NULL)
398: return (USBD_NOMEM);
399: err = usbd_get_report_descriptor(dev, id->bInterfaceNumber, *sizep,
400: *descp);
401: if (err) {
402: free(*descp, mem);
403: *descp = NULL;
404: return (err);
405: }
406: return (USBD_NORMAL_COMPLETION);
407: }
408:
409: usbd_status
410: usbd_get_config(usbd_device_handle dev, u_int8_t *conf)
411: {
412: usb_device_request_t req;
413:
414: req.bmRequestType = UT_READ_DEVICE;
415: req.bRequest = UR_GET_CONFIG;
416: USETW(req.wValue, 0);
417: USETW(req.wIndex, 0);
418: USETW(req.wLength, 1);
419: return (usbd_do_request(dev, &req, conf));
420: }
421:
422: void usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
423: usbd_status status);
424: void
425: usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
426: usbd_status status)
427: {
428: wakeup(xfer);
429: }
430:
431: usbd_status
432: usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
433: u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size, char *lbl)
434: {
435: usbd_status err;
436: int s, error;
437:
438: usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout,
439: usbd_bulk_transfer_cb);
440: DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size));
441: s = splusb(); /* don't want callback until tsleep() */
442: err = usbd_transfer(xfer);
443: if (err != USBD_IN_PROGRESS) {
444: splx(s);
445: return (err);
446: }
447: error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0);
448: splx(s);
449: if (error) {
450: DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error));
451: usbd_abort_pipe(pipe);
452: return (USBD_INTERRUPTED);
453: }
454: usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
455: DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size));
456: if (err) {
457: DPRINTF(("usbd_bulk_transfer: error=%d\n", err));
458: usbd_clear_endpoint_stall(pipe);
459: }
460: return (err);
461: }
462:
463: void usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
464: usbd_status status);
465: void
466: usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
467: usbd_status status)
468: {
469: wakeup(xfer);
470: }
471:
472: usbd_status
473: usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
474: u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size, char *lbl)
475: {
476: usbd_status err;
477: int s, error;
478:
479: usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout,
480: usbd_intr_transfer_cb);
481: DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size));
482: s = splusb(); /* don't want callback until tsleep() */
483: err = usbd_transfer(xfer);
484: if (err != USBD_IN_PROGRESS) {
485: splx(s);
486: return (err);
487: }
488: error = tsleep(xfer, PZERO | PCATCH, lbl, 0);
489: splx(s);
490: if (error) {
491: DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error));
492: usbd_abort_pipe(pipe);
493: return (USBD_INTERRUPTED);
494: }
495: usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
496: DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size));
497: if (err) {
498: DPRINTF(("usbd_intr_transfer: error=%d\n", err));
499: usbd_clear_endpoint_stall(pipe);
500: }
501: return (err);
502: }
503:
504: void
505: usb_detach_wait(struct device *dv)
506: {
507: DPRINTF(("usb_detach_wait: waiting for %s\n", dv->dv_xname));
508: if (tsleep(dv, PZERO, "usbdet", hz * 60))
509: printf("usb_detach_wait: %s didn't detach\n", dv->dv_xname);
510: DPRINTF(("usb_detach_wait: %s done\n", dv->dv_xname));
511: }
512:
513: void
514: usb_detach_wakeup(struct device *dv)
515: {
516: DPRINTF(("usb_detach_wakeup: for %s\n", dv->dv_xname));
517: wakeup(dv);
518: }
519:
520: usb_descriptor_t *
521: usb_find_desc(usbd_device_handle dev, int type)
522: {
523: usb_descriptor_t *desc;
524: usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
525: uByte *p = (uByte *)cd;
526: uByte *end = p + UGETW(cd->wTotalLength);
527:
528: while (p < end) {
529: desc = (usb_descriptor_t *)p;
530: if (desc->bDescriptorType == type)
531: return (desc);
532: p += desc->bLength;
533: }
534:
535: return (NULL);
536: }
CVSweb