usbdi_util.c revision 1.63.2.7 1 /* $NetBSD: usbdi_util.c,v 1.63.2.7 2015/03/19 17:26:43 skrll Exp $ */
2
3 /*
4 * Copyright (c) 1998, 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart (at) augustsson.net) at
9 * Carlstedt Research & Technology and Matthew R. Green (mrg (at) eterna.com.au).
10 *
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.
19 *
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.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: usbdi_util.c,v 1.63.2.7 2015/03/19 17:26:43 skrll Exp $");
35
36 #ifdef _KERNEL_OPT
37 #include "opt_usb.h"
38 #endif
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/kmem.h>
44 #include <sys/proc.h>
45 #include <sys/device.h>
46 #include <sys/bus.h>
47
48 #include <dev/usb/usb.h>
49 #include <dev/usb/usbhid.h>
50 #include <dev/usb/usbdi.h>
51 #include <dev/usb/usbdivar.h>
52 #include <dev/usb/usbdi_util.h>
53 #include <dev/usb/usbhist.h>
54
55 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(usbdebug,N,FMT,A,B,C,D)
56
57 usbd_status
58 usbd_get_desc(struct usbd_device *dev, int type, int index, int len, void *desc)
59 {
60 usb_device_request_t req;
61
62 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
63
64 DPRINTFN(3,"type=%d, index=%d, len=%d", type, index, len, 0);
65
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);
72 }
73
74 usbd_status
75 usbd_get_config_desc(struct usbd_device *dev, int confidx,
76 usb_config_descriptor_t *d)
77 {
78 usbd_status err;
79 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
80
81 DPRINTFN(3, "confidx=%d", confidx, 0, 0, 0);
82 err = usbd_get_desc(dev, UDESC_CONFIG, confidx,
83 USB_CONFIG_DESCRIPTOR_SIZE, d);
84 if (err)
85 return err;
86 if (d->bDescriptorType != UDESC_CONFIG) {
87 DPRINTFN(1, "confidx=%d, bad desc len=%d type=%d",
88 confidx, d->bLength, d->bDescriptorType, 0);
89 return USBD_INVAL;
90 }
91 return USBD_NORMAL_COMPLETION;
92 }
93
94 usbd_status
95 usbd_get_config_desc_full(struct usbd_device *dev, int conf, void *d, int size)
96 {
97 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
98
99 DPRINTFN(3, "conf=%d", conf, 0, 0, 0);
100 return usbd_get_desc(dev, UDESC_CONFIG, conf, size, d);
101 }
102
103 usbd_status
104 usbd_get_device_desc(struct usbd_device *dev, usb_device_descriptor_t *d)
105 {
106 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
107
108 return (usbd_get_desc(dev, UDESC_DEVICE,
109 0, USB_DEVICE_DESCRIPTOR_SIZE, d));
110 }
111
112 usbd_status
113 usbd_get_device_status(struct usbd_device *dev, usb_status_t *st)
114 {
115 usb_device_request_t req;
116
117 req.bmRequestType = UT_READ_DEVICE;
118 req.bRequest = UR_GET_STATUS;
119 USETW(req.wValue, 0);
120 USETW(req.wIndex, 0);
121 USETW(req.wLength, sizeof(usb_status_t));
122 return usbd_do_request(dev, &req, st);
123 }
124
125 usbd_status
126 usbd_get_hub_status(struct usbd_device *dev, usb_hub_status_t *st)
127 {
128 usb_device_request_t req;
129
130 req.bmRequestType = UT_READ_CLASS_DEVICE;
131 req.bRequest = UR_GET_STATUS;
132 USETW(req.wValue, 0);
133 USETW(req.wIndex, 0);
134 USETW(req.wLength, sizeof(usb_hub_status_t));
135 return usbd_do_request(dev, &req, st);
136 }
137
138 usbd_status
139 usbd_set_address(struct usbd_device *dev, int addr)
140 {
141 usb_device_request_t req;
142
143 req.bmRequestType = UT_WRITE_DEVICE;
144 req.bRequest = UR_SET_ADDRESS;
145 USETW(req.wValue, addr);
146 USETW(req.wIndex, 0);
147 USETW(req.wLength, 0);
148 return usbd_do_request(dev, &req, 0);
149 }
150
151 usbd_status
152 usbd_get_port_status(struct usbd_device *dev, int port, usb_port_status_t *ps)
153 {
154 usb_device_request_t req;
155
156 req.bmRequestType = UT_READ_CLASS_OTHER;
157 req.bRequest = UR_GET_STATUS;
158 USETW(req.wValue, 0);
159 USETW(req.wIndex, port);
160 USETW(req.wLength, sizeof *ps);
161 return usbd_do_request(dev, &req, ps);
162 }
163
164 usbd_status
165 usbd_clear_hub_feature(struct usbd_device *dev, int sel)
166 {
167 usb_device_request_t req;
168
169 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
170 req.bRequest = UR_CLEAR_FEATURE;
171 USETW(req.wValue, sel);
172 USETW(req.wIndex, 0);
173 USETW(req.wLength, 0);
174 return usbd_do_request(dev, &req, 0);
175 }
176
177 usbd_status
178 usbd_set_hub_feature(struct usbd_device *dev, int sel)
179 {
180 usb_device_request_t req;
181
182 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
183 req.bRequest = UR_SET_FEATURE;
184 USETW(req.wValue, sel);
185 USETW(req.wIndex, 0);
186 USETW(req.wLength, 0);
187 return usbd_do_request(dev, &req, 0);
188 }
189
190 usbd_status
191 usbd_clear_port_feature(struct usbd_device *dev, int port, int sel)
192 {
193 usb_device_request_t req;
194
195 req.bmRequestType = UT_WRITE_CLASS_OTHER;
196 req.bRequest = UR_CLEAR_FEATURE;
197 USETW(req.wValue, sel);
198 USETW(req.wIndex, port);
199 USETW(req.wLength, 0);
200 return usbd_do_request(dev, &req, 0);
201 }
202
203 usbd_status
204 usbd_set_port_feature(struct usbd_device *dev, int port, int sel)
205 {
206 usb_device_request_t req;
207
208 req.bmRequestType = UT_WRITE_CLASS_OTHER;
209 req.bRequest = UR_SET_FEATURE;
210 USETW(req.wValue, sel);
211 USETW(req.wIndex, port);
212 USETW(req.wLength, 0);
213 return usbd_do_request(dev, &req, 0);
214 }
215
216 usbd_status
217 usbd_get_protocol(struct usbd_interface *iface, uint8_t *report)
218 {
219 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
220 struct usbd_device *dev;
221 usb_device_request_t req;
222
223 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
224
225 DPRINTFN(4, "iface=%p, endpt=%d", iface, id->bInterfaceNumber, 0, 0);
226 if (id == NULL)
227 return USBD_IOERROR;
228 usbd_interface2device_handle(iface, &dev);
229 req.bmRequestType = UT_READ_CLASS_INTERFACE;
230 req.bRequest = UR_GET_PROTOCOL;
231 USETW(req.wValue, 0);
232 USETW(req.wIndex, id->bInterfaceNumber);
233 USETW(req.wLength, 1);
234 return usbd_do_request(dev, &req, report);
235 }
236
237 usbd_status
238 usbd_set_protocol(struct usbd_interface *iface, int report)
239 {
240 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
241 struct usbd_device *dev;
242 usb_device_request_t req;
243
244 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
245
246 DPRINTFN(4, "iface=%p, report=%d, endpt=%d", iface, report,
247 id->bInterfaceNumber, 0);
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(struct usbd_interface *iface, int type, int id, void *data,
261 int len)
262 {
263 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
264 struct usbd_device *dev;
265 usb_device_request_t req;
266
267 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
268
269 DPRINTFN(4, "len=%d", len, 0, 0, 0);
270 if (ifd == NULL)
271 return USBD_IOERROR;
272 usbd_interface2device_handle(iface, &dev);
273 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
274 req.bRequest = UR_SET_REPORT;
275 USETW2(req.wValue, type, id);
276 USETW(req.wIndex, ifd->bInterfaceNumber);
277 USETW(req.wLength, len);
278 return usbd_do_request(dev, &req, data);
279 }
280
281 usbd_status
282 usbd_get_report(struct usbd_interface *iface, int type, int id, void *data,
283 int len)
284 {
285 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
286 struct usbd_device *dev;
287 usb_device_request_t req;
288
289 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
290
291 DPRINTFN(4, "len=%d", len, 0, 0, 0);
292 if (ifd == NULL)
293 return USBD_IOERROR;
294 usbd_interface2device_handle(iface, &dev);
295 req.bmRequestType = UT_READ_CLASS_INTERFACE;
296 req.bRequest = UR_GET_REPORT;
297 USETW2(req.wValue, type, id);
298 USETW(req.wIndex, ifd->bInterfaceNumber);
299 USETW(req.wLength, len);
300 return usbd_do_request(dev, &req, data);
301 }
302
303 usbd_status
304 usbd_set_idle(struct usbd_interface *iface, int duration, int id)
305 {
306 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
307 struct usbd_device *dev;
308 usb_device_request_t req;
309
310 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
311
312 DPRINTFN(4, "duration %d id %d", duration, id, 0, 0);
313 if (ifd == NULL)
314 return USBD_IOERROR;
315 usbd_interface2device_handle(iface, &dev);
316 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
317 req.bRequest = UR_SET_IDLE;
318 USETW2(req.wValue, duration, id);
319 USETW(req.wIndex, ifd->bInterfaceNumber);
320 USETW(req.wLength, 0);
321 return usbd_do_request(dev, &req, 0);
322 }
323
324 usbd_status
325 usbd_get_report_descriptor(struct usbd_device *dev, int ifcno,
326 int size, void *d)
327 {
328 usb_device_request_t req;
329
330 req.bmRequestType = UT_READ_INTERFACE;
331 req.bRequest = UR_GET_DESCRIPTOR;
332 USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */
333 USETW(req.wIndex, ifcno);
334 USETW(req.wLength, size);
335 return usbd_do_request(dev, &req, d);
336 }
337
338 usb_hid_descriptor_t *
339 usbd_get_hid_descriptor(struct usbd_interface *ifc)
340 {
341 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
342 struct usbd_device *dev;
343 usb_config_descriptor_t *cdesc;
344 usb_hid_descriptor_t *hd;
345 char *p, *end;
346
347 if (idesc == NULL)
348 return NULL;
349 usbd_interface2device_handle(ifc, &dev);
350 cdesc = usbd_get_config_descriptor(dev);
351
352 p = (char *)idesc + idesc->bLength;
353 end = (char *)cdesc + UGETW(cdesc->wTotalLength);
354
355 for (; p < end; p += hd->bLength) {
356 hd = (usb_hid_descriptor_t *)p;
357 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
358 return hd;
359 if (hd->bDescriptorType == UDESC_INTERFACE)
360 break;
361 }
362 return NULL;
363 }
364
365 usbd_status
366 usbd_read_report_desc(struct usbd_interface *ifc, void **descp, int *sizep)
367 {
368 usb_interface_descriptor_t *id;
369 usb_hid_descriptor_t *hid;
370 struct usbd_device *dev;
371 usbd_status err;
372
373 usbd_interface2device_handle(ifc, &dev);
374 id = usbd_get_interface_descriptor(ifc);
375 if (id == NULL)
376 return USBD_INVAL;
377 hid = usbd_get_hid_descriptor(ifc);
378 if (hid == NULL)
379 return USBD_IOERROR;
380 *sizep = UGETW(hid->descrs[0].wDescriptorLength);
381 *descp = kmem_alloc(*sizep, KM_SLEEP);
382 if (*descp == NULL)
383 return USBD_NOMEM;
384 err = usbd_get_report_descriptor(dev, id->bInterfaceNumber,
385 *sizep, *descp);
386 if (err) {
387 kmem_free(*descp, *sizep);
388 *descp = NULL;
389 return err;
390 }
391 return USBD_NORMAL_COMPLETION;
392 }
393
394 usbd_status
395 usbd_get_config(struct usbd_device *dev, uint8_t *conf)
396 {
397 usb_device_request_t req;
398
399 req.bmRequestType = UT_READ_DEVICE;
400 req.bRequest = UR_GET_CONFIG;
401 USETW(req.wValue, 0);
402 USETW(req.wIndex, 0);
403 USETW(req.wLength, 1);
404 return usbd_do_request(dev, &req, conf);
405 }
406
407 usbd_status
408 usbd_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
409 uint16_t flags, uint32_t timeout, void *buf,
410 uint32_t *size)
411 {
412 usbd_status err;
413
414 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
415
416 usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, NULL);
417 DPRINTFN(1, "start transfer %d bytes", *size, 0, 0, 0);
418 err = usbd_sync_transfer_sig(xfer);
419
420 usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
421 DPRINTFN(1, "transferred %d", *size, 0, 0, 0);
422 if (err) {
423 usbd_clear_endpoint_stall(pipe);
424 }
425 USBHIST_LOG(usbdebug, "<- done xfer %p err %d", xfer, err, 0, 0);
426
427 return err;
428 }
429
430 usbd_status
431 usbd_intr_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
432 uint16_t flags, uint32_t timeout, void *buf,
433 uint32_t *size)
434 {
435 usbd_status err;
436
437 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
438
439 usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, NULL);
440
441 DPRINTFN(1, "start transfer %d bytes", *size, 0, 0, 0);
442 err = usbd_sync_transfer_sig(xfer);
443
444 usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
445
446 DPRINTFN(1, "transferred %d", *size, 0, 0, 0);
447 if (err) {
448 usbd_clear_endpoint_stall(pipe);
449 }
450 USBHIST_LOG(usbdebug, "<- done xfer %p err %d", xfer, err, 0, 0);
451
452 return err;
453 }
454
455 void
456 usb_detach_wait(device_t dv, kcondvar_t *cv, kmutex_t *lock)
457 {
458 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
459
460 DPRINTFN(1, "waiting for dv %p", dv, 0, 0, 0);
461 if (cv_timedwait(cv, lock, hz * 60)) // dv, PZERO, "usbdet", hz * 60
462 printf("usb_detach_wait: %s didn't detach\n",
463 device_xname(dv));
464 DPRINTFN(1, "done", 0, 0, 0, 0);
465 }
466
467 void
468 usb_detach_broadcast(device_t dv, kcondvar_t *cv)
469 {
470 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
471
472 DPRINTFN(1, "for dv %p", dv, 0, 0, 0);
473 cv_broadcast(cv);
474 }
475
476 void
477 usb_detach_waitold(device_t dv)
478 {
479 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
480
481 DPRINTFN(1, "waiting for dv %p", dv, 0, 0, 0);
482 if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */
483 printf("usb_detach_waitold: %s didn't detach\n",
484 device_xname(dv));
485 DPRINTFN(1, "done", 0, 0, 0, 0);
486 }
487
488 void
489 usb_detach_wakeupold(device_t dv)
490 {
491 USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
492
493 DPRINTFN(1, "for dv %p", dv, 0, 0, 0);
494 wakeup(dv); /* XXXSMP ok */
495 }
496
497 const usb_cdc_descriptor_t *
498 usb_find_desc(struct usbd_device *dev, int type, int subtype)
499 {
500 usbd_desc_iter_t iter;
501 const usb_cdc_descriptor_t *desc;
502
503 usb_desc_iter_init(dev, &iter);
504 for (;;) {
505 desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
506 if (!desc || (desc->bDescriptorType == type &&
507 (subtype == USBD_CDCSUBTYPE_ANY ||
508 subtype == desc->bDescriptorSubtype)))
509 break;
510 }
511 return desc;
512 }
513
514 /* same as usb_find_desc(), but searches only in the specified interface. */
515 const usb_cdc_descriptor_t *
516 usb_find_desc_if(struct usbd_device *dev, int type, int subtype,
517 usb_interface_descriptor_t *id)
518 {
519 usbd_desc_iter_t iter;
520 const usb_cdc_descriptor_t *desc;
521
522 if (id == NULL)
523 return usb_find_desc(dev, type, subtype);
524
525 usb_desc_iter_init(dev, &iter);
526
527 iter.cur = (void *)id; /* start from the interface desc */
528 usb_desc_iter_next(&iter); /* and skip it */
529
530 while ((desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter))
531 != NULL) {
532 if (desc->bDescriptorType == UDESC_INTERFACE) {
533 /* we ran into the next interface --- not found */
534 return NULL;
535 }
536 if (desc->bDescriptorType == type &&
537 (subtype == USBD_CDCSUBTYPE_ANY ||
538 subtype == desc->bDescriptorSubtype))
539 break;
540 }
541 return desc;
542 }
543