Sync usage with man page.
[netbsd-mini2440.git] / sys / dev / usb / usbdi_util.c
blob5b1118db896f41765b3e233a0d85e48d96b6ebc1
1 /* $NetBSD$ */
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at
9 * Carlstedt Research & Technology.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/proc.h>
41 #include <sys/device.h>
43 #include <dev/usb/usb.h>
44 #include <dev/usb/usbhid.h>
46 #include <dev/usb/usbdi.h>
47 #include <dev/usb/usbdi_util.h>
49 #ifdef USB_DEBUG
50 #define DPRINTF(x) if (usbdebug) logprintf x
51 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
52 extern int usbdebug;
53 #else
54 #define DPRINTF(x)
55 #define DPRINTFN(n,x)
56 #endif
58 usbd_status
59 usbd_get_desc(usbd_device_handle dev, int type, int index, int len, void *desc)
61 usb_device_request_t req;
63 DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n",
64 type, index, len));
66 req.bmRequestType = UT_READ_DEVICE;
67 req.bRequest = UR_GET_DESCRIPTOR;
68 USETW2(req.wValue, type, index);
69 USETW(req.wIndex, 0);
70 USETW(req.wLength, len);
71 return (usbd_do_request(dev, &req, desc));
74 usbd_status
75 usbd_get_config_desc(usbd_device_handle dev, int confidx,
76 usb_config_descriptor_t *d)
78 usbd_status err;
80 DPRINTFN(3,("usbd_get_config_desc: confidx=%d\n", confidx));
81 err = usbd_get_desc(dev, UDESC_CONFIG, confidx,
82 USB_CONFIG_DESCRIPTOR_SIZE, d);
83 if (err)
84 return (err);
85 if (d->bDescriptorType != UDESC_CONFIG) {
86 DPRINTFN(-1,("usbd_get_config_desc: confidx=%d, bad desc "
87 "len=%d type=%d\n",
88 confidx, d->bLength, d->bDescriptorType));
89 return (USBD_INVAL);
91 return (USBD_NORMAL_COMPLETION);
94 usbd_status
95 usbd_get_config_desc_full(usbd_device_handle dev, int conf, void *d, int size)
97 DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf));
98 return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d));
101 usbd_status
102 usbd_get_device_desc(usbd_device_handle dev, usb_device_descriptor_t *d)
104 DPRINTFN(3,("usbd_get_device_desc:\n"));
105 return (usbd_get_desc(dev, UDESC_DEVICE,
106 0, USB_DEVICE_DESCRIPTOR_SIZE, d));
109 usbd_status
110 usbd_get_device_status(usbd_device_handle dev, usb_status_t *st)
112 usb_device_request_t req;
114 req.bmRequestType = UT_READ_DEVICE;
115 req.bRequest = UR_GET_STATUS;
116 USETW(req.wValue, 0);
117 USETW(req.wIndex, 0);
118 USETW(req.wLength, sizeof(usb_status_t));
119 return (usbd_do_request(dev, &req, st));
122 usbd_status
123 usbd_get_hub_status(usbd_device_handle dev, usb_hub_status_t *st)
125 usb_device_request_t req;
127 req.bmRequestType = UT_READ_CLASS_DEVICE;
128 req.bRequest = UR_GET_STATUS;
129 USETW(req.wValue, 0);
130 USETW(req.wIndex, 0);
131 USETW(req.wLength, sizeof(usb_hub_status_t));
132 return (usbd_do_request(dev, &req, st));
135 usbd_status
136 usbd_set_address(usbd_device_handle dev, int addr)
138 usb_device_request_t req;
140 req.bmRequestType = UT_WRITE_DEVICE;
141 req.bRequest = UR_SET_ADDRESS;
142 USETW(req.wValue, addr);
143 USETW(req.wIndex, 0);
144 USETW(req.wLength, 0);
145 return usbd_do_request(dev, &req, 0);
148 usbd_status
149 usbd_get_port_status(usbd_device_handle dev, int port, usb_port_status_t *ps)
151 usb_device_request_t req;
153 req.bmRequestType = UT_READ_CLASS_OTHER;
154 req.bRequest = UR_GET_STATUS;
155 USETW(req.wValue, 0);
156 USETW(req.wIndex, port);
157 USETW(req.wLength, sizeof *ps);
158 return (usbd_do_request(dev, &req, ps));
161 usbd_status
162 usbd_clear_hub_feature(usbd_device_handle dev, int sel)
164 usb_device_request_t req;
166 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
167 req.bRequest = UR_CLEAR_FEATURE;
168 USETW(req.wValue, sel);
169 USETW(req.wIndex, 0);
170 USETW(req.wLength, 0);
171 return (usbd_do_request(dev, &req, 0));
174 usbd_status
175 usbd_set_hub_feature(usbd_device_handle dev, int sel)
177 usb_device_request_t req;
179 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
180 req.bRequest = UR_SET_FEATURE;
181 USETW(req.wValue, sel);
182 USETW(req.wIndex, 0);
183 USETW(req.wLength, 0);
184 return (usbd_do_request(dev, &req, 0));
187 usbd_status
188 usbd_clear_port_feature(usbd_device_handle dev, int port, int sel)
190 usb_device_request_t req;
192 req.bmRequestType = UT_WRITE_CLASS_OTHER;
193 req.bRequest = UR_CLEAR_FEATURE;
194 USETW(req.wValue, sel);
195 USETW(req.wIndex, port);
196 USETW(req.wLength, 0);
197 return (usbd_do_request(dev, &req, 0));
200 usbd_status
201 usbd_set_port_feature(usbd_device_handle dev, int port, int sel)
203 usb_device_request_t req;
205 req.bmRequestType = UT_WRITE_CLASS_OTHER;
206 req.bRequest = UR_SET_FEATURE;
207 USETW(req.wValue, sel);
208 USETW(req.wIndex, port);
209 USETW(req.wLength, 0);
210 return (usbd_do_request(dev, &req, 0));
213 usbd_status
214 usbd_get_protocol(usbd_interface_handle iface, u_int8_t *report)
216 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
217 usbd_device_handle dev;
218 usb_device_request_t req;
220 DPRINTFN(4, ("usbd_get_protocol: iface=%p, endpt=%d\n",
221 iface, id->bInterfaceNumber));
222 if (id == NULL)
223 return (USBD_IOERROR);
224 usbd_interface2device_handle(iface, &dev);
225 req.bmRequestType = UT_READ_CLASS_INTERFACE;
226 req.bRequest = UR_GET_PROTOCOL;
227 USETW(req.wValue, 0);
228 USETW(req.wIndex, id->bInterfaceNumber);
229 USETW(req.wLength, 1);
230 return (usbd_do_request(dev, &req, report));
233 usbd_status
234 usbd_set_protocol(usbd_interface_handle iface, int report)
236 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
237 usbd_device_handle dev;
238 usb_device_request_t req;
240 DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
241 iface, report, id->bInterfaceNumber));
242 if (id == NULL)
243 return (USBD_IOERROR);
244 usbd_interface2device_handle(iface, &dev);
245 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
246 req.bRequest = UR_SET_PROTOCOL;
247 USETW(req.wValue, report);
248 USETW(req.wIndex, id->bInterfaceNumber);
249 USETW(req.wLength, 0);
250 return (usbd_do_request(dev, &req, 0));
253 usbd_status
254 usbd_set_report(usbd_interface_handle iface, int type, int id, void *data,
255 int len)
257 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
258 usbd_device_handle dev;
259 usb_device_request_t req;
261 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
262 if (ifd == NULL)
263 return (USBD_IOERROR);
264 usbd_interface2device_handle(iface, &dev);
265 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
266 req.bRequest = UR_SET_REPORT;
267 USETW2(req.wValue, type, id);
268 USETW(req.wIndex, ifd->bInterfaceNumber);
269 USETW(req.wLength, len);
270 return (usbd_do_request(dev, &req, data));
273 usbd_status
274 usbd_set_report_async(usbd_interface_handle iface, int type, int id, void *data,
275 int len)
277 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
278 usbd_device_handle dev;
279 usb_device_request_t req;
281 DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
282 if (ifd == NULL)
283 return (USBD_IOERROR);
284 usbd_interface2device_handle(iface, &dev);
285 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
286 req.bRequest = UR_SET_REPORT;
287 USETW2(req.wValue, type, id);
288 USETW(req.wIndex, ifd->bInterfaceNumber);
289 USETW(req.wLength, len);
290 return (usbd_do_request_async(dev, &req, data));
293 usbd_status
294 usbd_get_report(usbd_interface_handle iface, int type, int id, void *data,
295 int len)
297 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
298 usbd_device_handle dev;
299 usb_device_request_t req;
301 DPRINTFN(4, ("usbd_get_report: len=%d\n", len));
302 if (ifd == NULL)
303 return (USBD_IOERROR);
304 usbd_interface2device_handle(iface, &dev);
305 req.bmRequestType = UT_READ_CLASS_INTERFACE;
306 req.bRequest = UR_GET_REPORT;
307 USETW2(req.wValue, type, id);
308 USETW(req.wIndex, ifd->bInterfaceNumber);
309 USETW(req.wLength, len);
310 return (usbd_do_request(dev, &req, data));
313 usbd_status
314 usbd_set_idle(usbd_interface_handle iface, int duration, int id)
316 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
317 usbd_device_handle dev;
318 usb_device_request_t req;
320 DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
321 if (ifd == NULL)
322 return (USBD_IOERROR);
323 usbd_interface2device_handle(iface, &dev);
324 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
325 req.bRequest = UR_SET_IDLE;
326 USETW2(req.wValue, duration, id);
327 USETW(req.wIndex, ifd->bInterfaceNumber);
328 USETW(req.wLength, 0);
329 return (usbd_do_request(dev, &req, 0));
332 usbd_status
333 usbd_get_report_descriptor(usbd_device_handle dev, int ifcno,
334 int size, void *d)
336 usb_device_request_t req;
338 req.bmRequestType = UT_READ_INTERFACE;
339 req.bRequest = UR_GET_DESCRIPTOR;
340 USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */
341 USETW(req.wIndex, ifcno);
342 USETW(req.wLength, size);
343 return (usbd_do_request(dev, &req, d));
346 usb_hid_descriptor_t *
347 usbd_get_hid_descriptor(usbd_interface_handle ifc)
349 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
350 usbd_device_handle dev;
351 usb_config_descriptor_t *cdesc;
352 usb_hid_descriptor_t *hd;
353 char *p, *end;
355 if (idesc == NULL)
356 return (NULL);
357 usbd_interface2device_handle(ifc, &dev);
358 cdesc = usbd_get_config_descriptor(dev);
360 p = (char *)idesc + idesc->bLength;
361 end = (char *)cdesc + UGETW(cdesc->wTotalLength);
363 for (; p < end; p += hd->bLength) {
364 hd = (usb_hid_descriptor_t *)p;
365 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
366 return (hd);
367 if (hd->bDescriptorType == UDESC_INTERFACE)
368 break;
370 return (NULL);
373 usbd_status
374 usbd_read_report_desc(usbd_interface_handle ifc, void **descp, int *sizep,
375 usb_malloc_type mem)
377 usb_interface_descriptor_t *id;
378 usb_hid_descriptor_t *hid;
379 usbd_device_handle dev;
380 usbd_status err;
382 usbd_interface2device_handle(ifc, &dev);
383 id = usbd_get_interface_descriptor(ifc);
384 if (id == NULL)
385 return (USBD_INVAL);
386 hid = usbd_get_hid_descriptor(ifc);
387 if (hid == NULL)
388 return (USBD_IOERROR);
389 *sizep = UGETW(hid->descrs[0].wDescriptorLength);
390 *descp = malloc(*sizep, mem, M_NOWAIT);
391 if (*descp == NULL)
392 return (USBD_NOMEM);
393 err = usbd_get_report_descriptor(dev, id->bInterfaceNumber,
394 *sizep, *descp);
395 if (err) {
396 free(*descp, mem);
397 *descp = NULL;
398 return (err);
400 return (USBD_NORMAL_COMPLETION);
403 usbd_status
404 usbd_get_config(usbd_device_handle dev, u_int8_t *conf)
406 usb_device_request_t req;
408 req.bmRequestType = UT_READ_DEVICE;
409 req.bRequest = UR_GET_CONFIG;
410 USETW(req.wValue, 0);
411 USETW(req.wIndex, 0);
412 USETW(req.wLength, 1);
413 return (usbd_do_request(dev, &req, conf));
416 Static void usbd_bulk_transfer_cb(usbd_xfer_handle xfer,
417 usbd_private_handle priv, usbd_status status);
418 Static void
419 usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
420 usbd_status status)
422 wakeup(xfer);
425 usbd_status
426 usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
427 u_int16_t flags, u_int32_t timeout, void *buf,
428 u_int32_t *size, const char *lbl)
430 usbd_status err;
431 int s, error;
433 usbd_setup_xfer(xfer, pipe, 0, buf, *size,
434 flags, timeout, usbd_bulk_transfer_cb);
435 DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size));
436 s = splusb(); /* don't want callback until tsleep() */
437 err = usbd_transfer(xfer);
438 if (err != USBD_IN_PROGRESS) {
439 splx(s);
440 return (err);
442 error = tsleep(xfer, PZERO | PCATCH, lbl, 0);
443 splx(s);
444 if (error) {
445 DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error));
446 usbd_abort_pipe(pipe);
447 return (USBD_INTERRUPTED);
449 usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
450 DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size));
451 if (err) {
452 DPRINTF(("usbd_bulk_transfer: error=%d\n", err));
453 usbd_clear_endpoint_stall(pipe);
455 return (err);
458 Static void usbd_intr_transfer_cb(usbd_xfer_handle xfer,
459 usbd_private_handle priv, usbd_status status);
460 Static void
461 usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
462 usbd_status status)
464 wakeup(xfer);
467 usbd_status
468 usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
469 u_int16_t flags, u_int32_t timeout, void *buf,
470 u_int32_t *size, const char *lbl)
472 usbd_status err;
473 int s, error;
475 usbd_setup_xfer(xfer, pipe, 0, buf, *size,
476 flags, timeout, usbd_intr_transfer_cb);
477 DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size));
478 s = splusb(); /* don't want callback until tsleep() */
479 err = usbd_transfer(xfer);
480 if (err != USBD_IN_PROGRESS) {
481 splx(s);
482 return (err);
484 error = tsleep(xfer, PZERO | PCATCH, lbl, 0);
485 splx(s);
486 if (error) {
487 DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error));
488 usbd_abort_pipe(pipe);
489 return (USBD_INTERRUPTED);
491 usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
492 DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size));
493 if (err) {
494 DPRINTF(("usbd_intr_transfer: error=%d\n", err));
495 usbd_clear_endpoint_stall(pipe);
497 return (err);
500 void
501 usb_detach_wait(device_ptr_t dv)
503 DPRINTF(("usb_detach_wait: waiting for %s\n", USBDEVPTRNAME(dv)));
504 if (tsleep(dv, PZERO, "usbdet", hz * 60))
505 printf("usb_detach_wait: %s didn't detach\n",
506 USBDEVPTRNAME(dv));
507 DPRINTF(("usb_detach_wait: %s done\n", USBDEVPTRNAME(dv)));
510 void
511 usb_detach_wakeup(device_ptr_t dv)
513 DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVPTRNAME(dv)));
514 wakeup(dv);
517 const usb_cdc_descriptor_t *
518 usb_find_desc(usbd_device_handle dev, int type, int subtype)
520 usbd_desc_iter_t iter;
521 const usb_cdc_descriptor_t *desc;
523 usb_desc_iter_init(dev, &iter);
524 for (;;) {
525 desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
526 if (!desc || (desc->bDescriptorType == type &&
527 (subtype == USBD_CDCSUBTYPE_ANY ||
528 subtype == desc->bDescriptorSubtype)))
529 break;
531 return desc;
534 /* same as usb_find_desc(), but searches only in the specified interface. */
535 const usb_cdc_descriptor_t *
536 usb_find_desc_if(usbd_device_handle dev, int type, int subtype,
537 usb_interface_descriptor_t *id)
539 usbd_desc_iter_t iter;
540 const usb_cdc_descriptor_t *desc;
542 usb_desc_iter_init(dev, &iter);
544 iter.cur = (void *)id; /* start from the interface desc */
545 usb_desc_iter_next(&iter); /* and skip it */
547 while ((desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter))
548 != NULL) {
549 if (desc->bDescriptorType == UDESC_INTERFACE) {
550 /* we ran into the next interface --- not found */
551 return NULL;
553 if (desc->bDescriptorType == type &&
554 (subtype == USBD_CDCSUBTYPE_ANY ||
555 subtype == desc->bDescriptorSubtype))
556 break;
558 return desc;