1 /* $OpenBSD: usbdi_util.c,v 1.17 2004/07/21 00:01:08 dlg 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 #if defined(__NetBSD__) || defined(__OpenBSD__)
47 #include <sys/proc.h>
48 #include <sys/device.h>
49 #elif defined(__FreeBSD__)
50 #include <sys/bus.h>
51 #endif
52
53 #include <dev/usb/usb.h>
54 #include <dev/usb/usbhid.h>
55
56 #include <dev/usb/usbdi.h>
57 #include <dev/usb/usbdi_util.h>
58
59 #ifdef USB_DEBUG
60 #define DPRINTF(x) do { if (usbdebug) logprintf x; } while (0)
61 #define DPRINTFN(n,x) do { if (usbdebug>(n)) logprintf x; } while (0)
62 extern int usbdebug;
63 #else
64 #define DPRINTF(x)
65 #define DPRINTFN(n,x)
66 #endif
67
68 usbd_status
usbd_get_desc(usbd_device_handle dev,int type,int index,int len,void * desc)69 usbd_get_desc(usbd_device_handle dev, int type, int index, int len, void *desc)
70 {
71 usb_device_request_t req;
72
73 DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n",
74 type, index, len));
75
76 req.bmRequestType = UT_READ_DEVICE;
77 req.bRequest = UR_GET_DESCRIPTOR;
78 USETW2(req.wValue, type, index);
79 USETW(req.wIndex, 0);
80 USETW(req.wLength, len);
81 return (usbd_do_request(dev, &req, desc));
82 }
83
84 usbd_status
usbd_get_config_desc(usbd_device_handle dev,int confidx,usb_config_descriptor_t * d)85 usbd_get_config_desc(usbd_device_handle dev, int confidx,
86 usb_config_descriptor_t *d)
87 {
88 usbd_status err;
89
90 DPRINTFN(3,("usbd_get_config_desc: confidx=%d\n", confidx));
91 err = usbd_get_desc(dev, UDESC_CONFIG, confidx,
92 USB_CONFIG_DESCRIPTOR_SIZE, d);
93 if (err)
94 return (err);
95 if (d->bDescriptorType != UDESC_CONFIG) {
96 DPRINTFN(-1,("usbd_get_config_desc: confidx=%d, bad desc "
97 "len=%d type=%d\n",
98 confidx, d->bLength, d->bDescriptorType));
99 return (USBD_INVAL);
100 }
101 return (USBD_NORMAL_COMPLETION);
102 }
103
104 usbd_status
usbd_get_config_desc_full(usbd_device_handle dev,int conf,void * d,int size)105 usbd_get_config_desc_full(usbd_device_handle dev, int conf, void *d, int size)
106 {
107 DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf));
108 return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d));
109 }
110
111 usbd_status
usbd_get_device_desc(usbd_device_handle dev,usb_device_descriptor_t * d)112 usbd_get_device_desc(usbd_device_handle dev, usb_device_descriptor_t *d)
113 {
114 DPRINTFN(3,("usbd_get_device_desc:\n"));
115 return (usbd_get_desc(dev, UDESC_DEVICE,
116 0, USB_DEVICE_DESCRIPTOR_SIZE, d));
117 }
118
119 usbd_status
usbd_get_device_status(usbd_device_handle dev,usb_status_t * st)120 usbd_get_device_status(usbd_device_handle dev, usb_status_t *st)
121 {
122 usb_device_request_t req;
123
124 req.bmRequestType = UT_READ_DEVICE;
125 req.bRequest = UR_GET_STATUS;
126 USETW(req.wValue, 0);
127 USETW(req.wIndex, 0);
128 USETW(req.wLength, sizeof(usb_status_t));
129 return (usbd_do_request(dev, &req, st));
130 }
131
132 usbd_status
usbd_get_hub_status(usbd_device_handle dev,usb_hub_status_t * st)133 usbd_get_hub_status(usbd_device_handle dev, usb_hub_status_t *st)
134 {
135 usb_device_request_t req;
136
137 req.bmRequestType = UT_READ_CLASS_DEVICE;
138 req.bRequest = UR_GET_STATUS;
139 USETW(req.wValue, 0);
140 USETW(req.wIndex, 0);
141 USETW(req.wLength, sizeof(usb_hub_status_t));
142 return (usbd_do_request(dev, &req, st));
143 }
144
145 usbd_status
usbd_set_address(usbd_device_handle dev,int addr)146 usbd_set_address(usbd_device_handle dev, int addr)
147 {
148 usb_device_request_t req;
149
150 req.bmRequestType = UT_WRITE_DEVICE;
151 req.bRequest = UR_SET_ADDRESS;
152 USETW(req.wValue, addr);
153 USETW(req.wIndex, 0);
154 USETW(req.wLength, 0);
155 return usbd_do_request(dev, &req, 0);
156 }
157
158 usbd_status
usbd_get_port_status(usbd_device_handle dev,int port,usb_port_status_t * ps)159 usbd_get_port_status(usbd_device_handle dev, int port, usb_port_status_t *ps)
160 {
161 usb_device_request_t req;
162
163 req.bmRequestType = UT_READ_CLASS_OTHER;
164 req.bRequest = UR_GET_STATUS;
165 USETW(req.wValue, 0);
166 USETW(req.wIndex, port);
167 USETW(req.wLength, sizeof *ps);
168 return (usbd_do_request(dev, &req, ps));
169 }
170
171 usbd_status
usbd_clear_hub_feature(usbd_device_handle dev,int sel)172 usbd_clear_hub_feature(usbd_device_handle dev, int sel)
173 {
174 usb_device_request_t req;
175
176 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
177 req.bRequest = UR_CLEAR_FEATURE;
178 USETW(req.wValue, sel);
179 USETW(req.wIndex, 0);
180 USETW(req.wLength, 0);
181 return (usbd_do_request(dev, &req, 0));
182 }
183
184 usbd_status
usbd_set_hub_feature(usbd_device_handle dev,int sel)185 usbd_set_hub_feature(usbd_device_handle dev, int sel)
186 {
187 usb_device_request_t req;
188
189 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
190 req.bRequest = UR_SET_FEATURE;
191 USETW(req.wValue, sel);
192 USETW(req.wIndex, 0);
193 USETW(req.wLength, 0);
194 return (usbd_do_request(dev, &req, 0));
195 }
196
197 usbd_status
usbd_clear_port_feature(usbd_device_handle dev,int port,int sel)198 usbd_clear_port_feature(usbd_device_handle dev, int port, int sel)
199 {
200 usb_device_request_t req;
201
202 req.bmRequestType = UT_WRITE_CLASS_OTHER;
203 req.bRequest = UR_CLEAR_FEATURE;
204 USETW(req.wValue, sel);
205 USETW(req.wIndex, port);
206 USETW(req.wLength, 0);
207 return (usbd_do_request(dev, &req, 0));
208 }
209
210 usbd_status
usbd_set_port_feature(usbd_device_handle dev,int port,int sel)211 usbd_set_port_feature(usbd_device_handle dev, int port, int sel)
212 {
213 usb_device_request_t req;
214
215 req.bmRequestType = UT_WRITE_CLASS_OTHER;
216 req.bRequest = UR_SET_FEATURE;
217 USETW(req.wValue, sel);
218 USETW(req.wIndex, port);
219 USETW(req.wLength, 0);
220 return (usbd_do_request(dev, &req, 0));
221 }
222
223 usbd_status
usbd_get_protocol(usbd_interface_handle iface,u_int8_t * report)224 usbd_get_protocol(usbd_interface_handle iface, u_int8_t *report)
225 {
226 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
227 usbd_device_handle dev;
228 usb_device_request_t req;
229
230 DPRINTFN(4, ("usbd_get_protocol: iface=%p, endpt=%d\n",
231 iface, id->bInterfaceNumber));
232 if (id == NULL)
233 return (USBD_IOERROR);
234 usbd_interface2device_handle(iface, &dev);
235 req.bmRequestType = UT_READ_CLASS_INTERFACE;
236 req.bRequest = UR_GET_PROTOCOL;
237 USETW(req.wValue, 0);
238 USETW(req.wIndex, id->bInterfaceNumber);
239 USETW(req.wLength, 1);
240 return (usbd_do_request(dev, &req, report));
241 }
242
243 usbd_status
usbd_set_protocol(usbd_interface_handle iface,int report)244 usbd_set_protocol(usbd_interface_handle iface, int report)
245 {
246 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
247 usbd_device_handle dev;
248 usb_device_request_t req;
249
250 DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
251 iface, report, id->bInterfaceNumber));
252 if (id == NULL)
253 return (USBD_IOERROR);
254 usbd_interface2device_handle(iface, &dev);
255 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
256 req.bRequest = UR_SET_PROTOCOL;
257 USETW(req.wValue, report);
258 USETW(req.wIndex, id->bInterfaceNumber);
259 USETW(req.wLength, 0);
260 return (usbd_do_request(dev, &req, 0));
261 }
262
263 usbd_status
usbd_set_report(usbd_interface_handle iface,int type,int id,void * data,int len)264 usbd_set_report(usbd_interface_handle iface, int type, int id, void *data,
265 int len)
266 {
267 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
268 usbd_device_handle dev;
269 usb_device_request_t req;
270
271 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
272 if (ifd == NULL)
273 return (USBD_IOERROR);
274 usbd_interface2device_handle(iface, &dev);
275 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
276 req.bRequest = UR_SET_REPORT;
277 USETW2(req.wValue, type, id);
278 USETW(req.wIndex, ifd->bInterfaceNumber);
279 USETW(req.wLength, len);
280 return (usbd_do_request(dev, &req, data));
281 }
282
283 usbd_status
usbd_set_report_async(usbd_interface_handle iface,int type,int id,void * data,int len)284 usbd_set_report_async(usbd_interface_handle iface, int type, int id,
285 void *data, int len)
286 {
287 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
288 usbd_device_handle dev;
289 usb_device_request_t req;
290
291 DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
292 if (ifd == NULL)
293 return (USBD_IOERROR);
294 usbd_interface2device_handle(iface, &dev);
295 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
296 req.bRequest = UR_SET_REPORT;
297 USETW2(req.wValue, type, id);
298 USETW(req.wIndex, ifd->bInterfaceNumber);
299 USETW(req.wLength, len);
300 return (usbd_do_request_async(dev, &req, data));
301 }
302
303 usbd_status
usbd_get_report(usbd_interface_handle iface,int type,int id,void * data,int len)304 usbd_get_report(usbd_interface_handle iface, int type, int id, void *data,
305 int len)
306 {
307 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
308 usbd_device_handle dev;
309 usb_device_request_t req;
310
311 DPRINTFN(4, ("usbd_get_report: len=%d\n", len));
312 if (ifd == NULL)
313 return (USBD_IOERROR);
314 usbd_interface2device_handle(iface, &dev);
315 req.bmRequestType = UT_READ_CLASS_INTERFACE;
316 req.bRequest = UR_GET_REPORT;
317 USETW2(req.wValue, type, id);
318 USETW(req.wIndex, ifd->bInterfaceNumber);
319 USETW(req.wLength, len);
320 return (usbd_do_request(dev, &req, data));
321 }
322
323 usbd_status
usbd_set_idle(usbd_interface_handle iface,int duration,int id)324 usbd_set_idle(usbd_interface_handle iface, int duration, int id)
325 {
326 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
327 usbd_device_handle dev;
328 usb_device_request_t req;
329
330 DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
331 if (ifd == NULL)
332 return (USBD_IOERROR);
333 usbd_interface2device_handle(iface, &dev);
334 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
335 req.bRequest = UR_SET_IDLE;
336 USETW2(req.wValue, duration, id);
337 USETW(req.wIndex, ifd->bInterfaceNumber);
338 USETW(req.wLength, 0);
339 return (usbd_do_request(dev, &req, 0));
340 }
341
342 usbd_status
usbd_get_report_descriptor(usbd_device_handle dev,int ifcno,int size,void * d)343 usbd_get_report_descriptor(usbd_device_handle dev, int ifcno,
344 int size, void *d)
345 {
346 usb_device_request_t req;
347
348 req.bmRequestType = UT_READ_INTERFACE;
349 req.bRequest = UR_GET_DESCRIPTOR;
350 USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */
351 USETW(req.wIndex, ifcno);
352 USETW(req.wLength, size);
353 return (usbd_do_request(dev, &req, d));
354 }
355
356 usb_hid_descriptor_t *
usbd_get_hid_descriptor(usbd_interface_handle ifc)357 usbd_get_hid_descriptor(usbd_interface_handle ifc)
358 {
359 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
360 usbd_device_handle dev;
361 usb_config_descriptor_t *cdesc;
362 usb_hid_descriptor_t *hd;
363 char *p, *end;
364
365 if (idesc == NULL)
366 return (0);
367 usbd_interface2device_handle(ifc, &dev);
368 cdesc = usbd_get_config_descriptor(dev);
369
370 p = (char *)idesc + idesc->bLength;
371 end = (char *)cdesc + UGETW(cdesc->wTotalLength);
372
373 for (; p < end; p += hd->bLength) {
374 hd = (usb_hid_descriptor_t *)p;
375 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
376 return (hd);
377 if (hd->bDescriptorType == UDESC_INTERFACE)
378 break;
379 }
380 return (0);
381 }
382
383 usbd_status
usbd_read_report_desc(usbd_interface_handle ifc,void ** descp,int * sizep,usb_malloc_type mem)384 usbd_read_report_desc(usbd_interface_handle ifc, void **descp, int *sizep,
385 usb_malloc_type mem)
386 {
387 usb_interface_descriptor_t *id;
388 usb_hid_descriptor_t *hid;
389 usbd_device_handle dev;
390 usbd_status err;
391
392 usbd_interface2device_handle(ifc, &dev);
393 id = usbd_get_interface_descriptor(ifc);
394 if (id == NULL)
395 return (USBD_INVAL);
396 hid = usbd_get_hid_descriptor(ifc);
397 if (hid == NULL)
398 return (USBD_IOERROR);
399 *sizep = UGETW(hid->descrs[0].wDescriptorLength);
400 *descp = malloc(*sizep, mem, M_NOWAIT);
401 if (*descp == NULL)
402 return (USBD_NOMEM);
403 err = usbd_get_report_descriptor(dev, id->bInterfaceNumber,
404 *sizep, *descp);
405 if (err) {
406 free(*descp, mem);
407 *descp = NULL;
408 return (err);
409 }
410 return (USBD_NORMAL_COMPLETION);
411 }
412
413 usbd_status
usbd_get_config(usbd_device_handle dev,u_int8_t * conf)414 usbd_get_config(usbd_device_handle dev, u_int8_t *conf)
415 {
416 usb_device_request_t req;
417
418 req.bmRequestType = UT_READ_DEVICE;
419 req.bRequest = UR_GET_CONFIG;
420 USETW(req.wValue, 0);
421 USETW(req.wIndex, 0);
422 USETW(req.wLength, 1);
423 return (usbd_do_request(dev, &req, conf));
424 }
425
426 Static void usbd_bulk_transfer_cb(usbd_xfer_handle xfer,
427 usbd_private_handle priv, usbd_status status);
428 Static void
usbd_bulk_transfer_cb(usbd_xfer_handle xfer,usbd_private_handle priv,usbd_status status)429 usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
430 usbd_status status)
431 {
432 wakeup(xfer);
433 }
434
435 usbd_status
usbd_bulk_transfer(usbd_xfer_handle xfer,usbd_pipe_handle pipe,u_int16_t flags,u_int32_t timeout,void * buf,u_int32_t * size,char * lbl)436 usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
437 u_int16_t flags, u_int32_t timeout, void *buf,
438 u_int32_t *size, char *lbl)
439 {
440 usbd_status err;
441 int s, error;
442
443 usbd_setup_xfer(xfer, pipe, 0, buf, *size,
444 flags, timeout, usbd_bulk_transfer_cb);
445 DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size));
446 s = splusb(); /* don't want callback until tsleep() */
447 err = usbd_transfer(xfer);
448 if (err != USBD_IN_PROGRESS) {
449 splx(s);
450 return (err);
451 }
452 error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0);
453 splx(s);
454 if (error) {
455 DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error));
456 usbd_abort_pipe(pipe);
457 return (USBD_INTERRUPTED);
458 }
459 usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
460 DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size));
461 if (err) {
462 DPRINTF(("usbd_bulk_transfer: error=%d\n", err));
463 usbd_clear_endpoint_stall(pipe);
464 }
465 return (err);
466 }
467
468 Static void usbd_intr_transfer_cb(usbd_xfer_handle xfer,
469 usbd_private_handle priv, usbd_status status);
470 Static void
usbd_intr_transfer_cb(usbd_xfer_handle xfer,usbd_private_handle priv,usbd_status status)471 usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
472 usbd_status status)
473 {
474 wakeup(xfer);
475 }
476
477 usbd_status
usbd_intr_transfer(usbd_xfer_handle xfer,usbd_pipe_handle pipe,u_int16_t flags,u_int32_t timeout,void * buf,u_int32_t * size,char * lbl)478 usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
479 u_int16_t flags, u_int32_t timeout, void *buf,
480 u_int32_t *size, char *lbl)
481 {
482 usbd_status err;
483 int s, error;
484
485 usbd_setup_xfer(xfer, pipe, 0, buf, *size,
486 flags, timeout, usbd_intr_transfer_cb);
487 DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size));
488 s = splusb(); /* don't want callback until tsleep() */
489 err = usbd_transfer(xfer);
490 if (err != USBD_IN_PROGRESS) {
491 splx(s);
492 return (err);
493 }
494 error = tsleep(xfer, PZERO | PCATCH, lbl, 0);
495 splx(s);
496 if (error) {
497 DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error));
498 usbd_abort_pipe(pipe);
499 return (USBD_INTERRUPTED);
500 }
501 usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
502 DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size));
503 if (err) {
504 DPRINTF(("usbd_intr_transfer: error=%d\n", err));
505 usbd_clear_endpoint_stall(pipe);
506 }
507 return (err);
508 }
509
510 void
usb_detach_wait(device_ptr_t dv)511 usb_detach_wait(device_ptr_t dv)
512 {
513 DPRINTF(("usb_detach_wait: waiting for %s\n", USBDEVPTRNAME(dv)));
514 if (tsleep(dv, PZERO, "usbdet", hz * 60))
515 printf("usb_detach_wait: %s didn't detach\n",
516 USBDEVPTRNAME(dv));
517 DPRINTF(("usb_detach_wait: %s done\n", USBDEVPTRNAME(dv)));
518 }
519
520 void
usb_detach_wakeup(device_ptr_t dv)521 usb_detach_wakeup(device_ptr_t dv)
522 {
523 DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVPTRNAME(dv)));
524 wakeup(dv);
525 }
526
527 usb_descriptor_t *
usb_find_desc(usbd_device_handle dev,int type)528 usb_find_desc(usbd_device_handle dev, int type)
529 {
530 usb_descriptor_t *desc;
531 usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
532 uByte *p = (uByte *)cd;
533 uByte *end = p + UGETW(cd->wTotalLength);
534
535 while (p < end) {
536 desc = (usb_descriptor_t *)p;
537 if (desc->bDescriptorType == type)
538 return (desc);
539 p += desc->bLength;
540 }
541
542 return (NULL);
543 }
544