xref: /netbsd-src/sys/dev/usb/usbdi_util.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
1 /*	$NetBSD: usbdi_util.c,v 1.84 2020/06/16 17:25:56 maxv 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@augustsson.net) at
9  * Carlstedt Research & Technology and Matthew R. Green (mrg@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.84 2020/06/16 17:25:56 maxv 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/usb_quirks.h>
54 #include <dev/usb/usbhist.h>
55 
56 #define	DPRINTF(FMT,A,B,C,D)	USBHIST_LOGN(usbdebug,1,FMT,A,B,C,D)
57 #define	DPRINTFN(N,FMT,A,B,C,D)	USBHIST_LOGN(usbdebug,N,FMT,A,B,C,D)
58 
59 usbd_status
60 usbd_get_desc(struct usbd_device *dev, int type, int index, int len, void *desc)
61 {
62 	usb_device_request_t req;
63 	usbd_status err;
64 
65 	USBHIST_FUNC();
66 	USBHIST_CALLARGS(usbdebug, "type=%jd, index=%jd, len=%jd",
67 	    type, index, len, 0);
68 
69 	/*
70 	 * Provide hard-coded configuration descriptors
71 	 * for devices that may corrupt it. This cannot
72 	 * be done for device descriptors which are used
73 	 * to identify the device.
74 	 */
75 	if (type != UDESC_DEVICE &&
76 	    dev->ud_quirks->uq_flags & UQ_DESC_CORRUPT) {
77 		err = usbd_get_desc_fake(dev, type, index, len, desc);
78 		goto out;
79 	}
80 
81 	req.bmRequestType = UT_READ_DEVICE;
82 	req.bRequest = UR_GET_DESCRIPTOR;
83 	USETW2(req.wValue, type, index);
84 	USETW(req.wIndex, 0);
85 	USETW(req.wLength, len);
86 	err = usbd_do_request(dev, &req, desc);
87 
88 out:
89 	return err;
90 }
91 
92 usbd_status
93 usbd_get_config_desc(struct usbd_device *dev, int confidx,
94 		     usb_config_descriptor_t *d)
95 {
96 	USBHIST_FUNC();
97 	USBHIST_CALLARGS(usbdebug, "confidx=%jd", confidx, 0, 0, 0);
98 	usbd_status err;
99 
100 	err = usbd_get_desc(dev, UDESC_CONFIG, confidx,
101 			    USB_CONFIG_DESCRIPTOR_SIZE, d);
102 	if (err)
103 		return err;
104 	if (d->bDescriptorType != UDESC_CONFIG) {
105 		DPRINTFN(1, "confidx=%jd, bad desc len=%jd type=%jd",
106 		    confidx, d->bLength, d->bDescriptorType, 0);
107 		return USBD_INVAL;
108 	}
109 	return USBD_NORMAL_COMPLETION;
110 }
111 
112 usbd_status
113 usbd_get_config_desc_full(struct usbd_device *dev, int conf, void *d, int size)
114 {
115 	USBHIST_FUNC(); USBHIST_CALLARGS(usbdebug, "conf=%jd", conf, 0, 0, 0);
116 
117 	return usbd_get_desc(dev, UDESC_CONFIG, conf, size, d);
118 }
119 
120 usbd_status
121 usbd_get_bos_desc(struct usbd_device *dev, int confidx,
122 		     usb_bos_descriptor_t *d)
123 {
124 	USBHIST_FUNC();
125 	USBHIST_CALLARGS(usbdebug, "confidx=%jd", confidx, 0, 0, 0);
126 	usbd_status err;
127 
128 	err = usbd_get_desc(dev, UDESC_BOS, confidx,
129 			    USB_BOS_DESCRIPTOR_SIZE, d);
130 	if (err)
131 		return err;
132 	if (d->bDescriptorType != UDESC_BOS) {
133 		DPRINTFN(1, "confidx=%jd, bad desc len=%jd type=%jd",
134 		    confidx, d->bLength, d->bDescriptorType, 0);
135 		return USBD_INVAL;
136 	}
137 	return USBD_NORMAL_COMPLETION;
138 }
139 
140 usbd_status
141 usbd_get_device_desc(struct usbd_device *dev, usb_device_descriptor_t *d)
142 {
143 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
144 
145 	return usbd_get_desc(dev, UDESC_DEVICE,
146 			     0, USB_DEVICE_DESCRIPTOR_SIZE, d);
147 }
148 
149 /*
150  * Get the first 8 bytes of the device descriptor.
151  * Do as Windows does: try to read 64 bytes -- there are devices which
152  * recognize the initial descriptor fetch (before the control endpoint's
153  * MaxPacketSize is known by the host) by exactly this length.
154  */
155 usbd_status
156 usbd_get_initial_ddesc(struct usbd_device *dev, usb_device_descriptor_t *desc)
157 {
158 	USBHIST_FUNC();
159 	USBHIST_CALLARGS(usbdebug, "dev %#jx", (uintptr_t)dev, 0, 0, 0);
160 	usb_device_request_t req;
161 	char buf[64];
162 	int res, actlen;
163 
164 	req.bmRequestType = UT_READ_DEVICE;
165 	req.bRequest = UR_GET_DESCRIPTOR;
166 	USETW2(req.wValue, UDESC_DEVICE, 0);
167 	USETW(req.wIndex, 0);
168 	USETW(req.wLength, 8);
169 	res = usbd_do_request_flags(dev, &req, buf, USBD_SHORT_XFER_OK,
170 		&actlen, USBD_DEFAULT_TIMEOUT);
171 	if (res)
172 		return res;
173 	if (actlen < 8)
174 		return USBD_SHORT_XFER;
175 	memcpy(desc, buf, 8);
176 	return USBD_NORMAL_COMPLETION;
177 }
178 
179 usbd_status
180 usbd_get_string_desc(struct usbd_device *dev, int sindex, int langid,
181     usb_string_descriptor_t *sdesc, int *sizep)
182 {
183 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
184 	usb_device_request_t req;
185 	usbd_status err;
186 	int actlen;
187 
188 	/*
189 	 * Pass a full-sized buffer to usbd_do_request_len().  At least
190 	 * one device has been seen returning additional data beyond the
191 	 * provided buffers (2-bytes written shortly after the request
192 	 * claims to have completed and returned the 2 byte header,
193 	 * corrupting other memory.)
194 	 */
195 	req.bmRequestType = UT_READ_DEVICE;
196 	req.bRequest = UR_GET_DESCRIPTOR;
197 	USETW2(req.wValue, UDESC_STRING, sindex);
198 	USETW(req.wIndex, langid);
199 	USETW(req.wLength, 2);	/* only size byte first */
200 	err = usbd_do_request_len(dev, &req, sizeof(*sdesc), sdesc,
201 	    USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT);
202 	if (err)
203 		return err;
204 
205 	if (actlen < 2)
206 		return USBD_SHORT_XFER;
207 
208 	if (sdesc->bLength > sizeof(*sdesc))
209 		return USBD_INVAL;
210 	USETW(req.wLength, sdesc->bLength);	/* the whole string */
211 	err = usbd_do_request_len(dev, &req, sizeof(*sdesc), sdesc,
212 	    USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT);
213 	if (err)
214 		return err;
215 
216 	if (actlen != sdesc->bLength) {
217 		DPRINTF("expected %jd, got %jd", sdesc->bLength, actlen, 0, 0);
218 	}
219 
220 	*sizep = actlen;
221 	return USBD_NORMAL_COMPLETION;
222 }
223 
224 /* -------------------------------------------------------------------------- */
225 
226 usbd_status
227 usbd_get_device_status(struct usbd_device *dev, usb_status_t *st)
228 {
229 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
230 	usb_device_request_t req;
231 
232 	req.bmRequestType = UT_READ_DEVICE;
233 	req.bRequest = UR_GET_STATUS;
234 	USETW(req.wValue, 0);
235 	USETW(req.wIndex, 0);
236 	USETW(req.wLength, sizeof(usb_status_t));
237 	return usbd_do_request(dev, &req, st);
238 }
239 
240 usbd_status
241 usbd_get_hub_status(struct usbd_device *dev, usb_hub_status_t *st)
242 {
243 	USBHIST_FUNC();
244 	USBHIST_CALLARGS(usbdebug, "dev %#jx", (uintptr_t)dev, 0, 0, 0);
245 	usb_device_request_t req;
246 
247 	req.bmRequestType = UT_READ_CLASS_DEVICE;
248 	req.bRequest = UR_GET_STATUS;
249 	USETW(req.wValue, 0);
250 	USETW(req.wIndex, 0);
251 	USETW(req.wLength, sizeof(usb_hub_status_t));
252 	return usbd_do_request(dev, &req, st);
253 }
254 
255 usbd_status
256 usbd_get_port_status(struct usbd_device *dev, int port, usb_port_status_t *ps)
257 {
258 	USBHIST_FUNC();
259 	USBHIST_CALLARGS(usbdebug, "dev %#jx port %jd",
260 	    (uintptr_t)dev, port, 0, 0);
261 	usb_device_request_t req;
262 
263 	req.bmRequestType = UT_READ_CLASS_OTHER;
264 	req.bRequest = UR_GET_STATUS;
265 	USETW(req.wValue, 0);
266 	USETW(req.wIndex, port);
267 	USETW(req.wLength, sizeof(*ps));
268 	return usbd_do_request(dev, &req, ps);
269 }
270 
271 /* USB 3.1 10.16.2.6, 10.16.2.6.3 */
272 usbd_status
273 usbd_get_port_status_ext(struct usbd_device *dev, int port,
274     usb_port_status_ext_t *pse)
275 {
276 	USBHIST_FUNC();
277 	USBHIST_CALLARGS(usbdebug, "dev %#jx port %jd",
278 	    (uintptr_t)dev, port, 0, 0);
279 	usb_device_request_t req;
280 
281 	req.bmRequestType = UT_READ_CLASS_OTHER;
282 	req.bRequest = UR_GET_STATUS;
283 	USETW2(req.wValue, 0, UR_PST_EXT_PORT_STATUS);
284 	USETW(req.wIndex, port);
285 	USETW(req.wLength, sizeof(*pse));
286 	return usbd_do_request(dev, &req, pse);
287 }
288 
289 /* -------------------------------------------------------------------------- */
290 
291 usbd_status
292 usbd_clear_hub_feature(struct usbd_device *dev, int sel)
293 {
294 	USBHIST_FUNC();
295 	USBHIST_CALLARGS(usbdebug, "dev %#jx sel %jd",
296 	    (uintptr_t)dev, sel, 0, 0);
297 	usb_device_request_t req;
298 
299 	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
300 	req.bRequest = UR_CLEAR_FEATURE;
301 	USETW(req.wValue, sel);
302 	USETW(req.wIndex, 0);
303 	USETW(req.wLength, 0);
304 	return usbd_do_request(dev, &req, 0);
305 }
306 
307 usbd_status
308 usbd_set_hub_feature(struct usbd_device *dev, int sel)
309 {
310 	USBHIST_FUNC();
311 	USBHIST_CALLARGS(usbdebug,
312 	    "dev %#jx sel %jd", (uintptr_t)dev, sel, 0, 0);
313 	usb_device_request_t req;
314 
315 	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
316 	req.bRequest = UR_SET_FEATURE;
317 	USETW(req.wValue, sel);
318 	USETW(req.wIndex, 0);
319 	USETW(req.wLength, 0);
320 	return usbd_do_request(dev, &req, 0);
321 }
322 
323 usbd_status
324 usbd_clear_port_feature(struct usbd_device *dev, int port, int sel)
325 {
326 	USBHIST_FUNC();
327 	USBHIST_CALLARGS(usbdebug, "dev %#jx port %jd sel %jd",
328 	    (uintptr_t)dev, port, sel, 0);
329 	usb_device_request_t req;
330 
331 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
332 	req.bRequest = UR_CLEAR_FEATURE;
333 	USETW(req.wValue, sel);
334 	USETW(req.wIndex, port);
335 	USETW(req.wLength, 0);
336 	return usbd_do_request(dev, &req, 0);
337 }
338 
339 usbd_status
340 usbd_set_port_feature(struct usbd_device *dev, int port, int sel)
341 {
342 	USBHIST_FUNC();
343 	USBHIST_CALLARGS(usbdebug, "dev %#jx port %jd sel %.d",
344 	    (uintptr_t)dev, sel, 0, 0);
345 	usb_device_request_t req;
346 
347 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
348 	req.bRequest = UR_SET_FEATURE;
349 	USETW(req.wValue, sel);
350 	USETW(req.wIndex, port);
351 	USETW(req.wLength, 0);
352 	return usbd_do_request(dev, &req, 0);
353 }
354 
355 usbd_status
356 usbd_set_port_u1_timeout(struct usbd_device *dev, int port, int timeout)
357 {
358 	USBHIST_FUNC();
359 	USBHIST_CALLARGS(usbdebug, "dev %#jx port %jd timeout %.d",
360 	    (uintptr_t)dev, port, timeout, 0);
361 	usb_device_request_t req;
362 
363 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
364 	req.bRequest = UR_SET_FEATURE;
365 	USETW(req.wValue, UHF_PORT_U1_TIMEOUT);
366 	USETW2(req.wIndex, timeout, port);
367 	USETW(req.wLength, 0);
368 	return usbd_do_request(dev, &req, 0);
369 }
370 
371 usbd_status
372 usbd_set_port_u2_timeout(struct usbd_device *dev, int port, int timeout)
373 {
374 	USBHIST_FUNC();
375 	USBHIST_CALLARGS(usbdebug, "dev %#jx port %jd timeout %jd",
376 	    (uintptr_t)dev, port, timeout, 0);
377 	usb_device_request_t req;
378 
379 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
380 	req.bRequest = UR_SET_FEATURE;
381 	USETW(req.wValue, UHF_PORT_U2_TIMEOUT);
382 	USETW2(req.wIndex, timeout, port);
383 	USETW(req.wLength, 0);
384 	return usbd_do_request(dev, &req, 0);
385 }
386 
387 usbd_status
388 usbd_clear_endpoint_feature(struct usbd_device *dev, int epaddr, int sel)
389 {
390 	USBHIST_FUNC();
391 	USBHIST_CALLARGS(usbdebug, "dev %#jx epaddr %jd sel %jd",
392 	    (uintptr_t)dev, epaddr, sel, 0);
393 	usb_device_request_t req;
394 
395 	req.bmRequestType = UT_WRITE_ENDPOINT;
396 	req.bRequest = UR_CLEAR_FEATURE;
397 	USETW(req.wValue, sel);
398 	USETW(req.wIndex, epaddr);
399 	USETW(req.wLength, 0);
400 	return usbd_do_request(dev, &req, 0);
401 }
402 
403 /* -------------------------------------------------------------------------- */
404 
405 usbd_status
406 usbd_get_config(struct usbd_device *dev, uint8_t *conf)
407 {
408 	USBHIST_FUNC();
409 	USBHIST_CALLARGS(usbdebug, "dev %#jx", (uintptr_t)dev, 0, 0, 0);
410 	usb_device_request_t req;
411 
412 	req.bmRequestType = UT_READ_DEVICE;
413 	req.bRequest = UR_GET_CONFIG;
414 	USETW(req.wValue, 0);
415 	USETW(req.wIndex, 0);
416 	USETW(req.wLength, 1);
417 	return usbd_do_request(dev, &req, conf);
418 }
419 
420 usbd_status
421 usbd_set_config(struct usbd_device *dev, int conf)
422 {
423 	USBHIST_FUNC();
424 	USBHIST_CALLARGS(usbdebug, "dev %#jx conf %jd",
425 	    (uintptr_t)dev, conf, 0, 0);
426 	usb_device_request_t req;
427 
428 	req.bmRequestType = UT_WRITE_DEVICE;
429 	req.bRequest = UR_SET_CONFIG;
430 	USETW(req.wValue, conf);
431 	USETW(req.wIndex, 0);
432 	USETW(req.wLength, 0);
433 	return usbd_do_request(dev, &req, 0);
434 }
435 
436 usbd_status
437 usbd_set_address(struct usbd_device *dev, int addr)
438 {
439 	USBHIST_FUNC();
440 	USBHIST_CALLARGS(usbdebug, "dev %#jx addr %jd",
441 	    (uintptr_t)dev, addr, 0, 0);
442 	usb_device_request_t req;
443 
444 	req.bmRequestType = UT_WRITE_DEVICE;
445 	req.bRequest = UR_SET_ADDRESS;
446 	USETW(req.wValue, addr);
447 	USETW(req.wIndex, 0);
448 	USETW(req.wLength, 0);
449 	return usbd_do_request(dev, &req, 0);
450 }
451 
452 usbd_status
453 usbd_set_idle(struct usbd_interface *iface, int duration, int id)
454 {
455 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
456 	struct usbd_device *dev;
457 	usb_device_request_t req;
458 
459 	USBHIST_FUNC();
460 	USBHIST_CALLARGS(usbdebug, "duration %jd id %jd", duration, id, 0, 0);
461 
462 	if (ifd == NULL)
463 		return USBD_IOERROR;
464 	usbd_interface2device_handle(iface, &dev);
465 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
466 	req.bRequest = UR_SET_IDLE;
467 	USETW2(req.wValue, duration, id);
468 	USETW(req.wIndex, ifd->bInterfaceNumber);
469 	USETW(req.wLength, 0);
470 	return usbd_do_request(dev, &req, 0);
471 }
472 
473 /* -------------------------------------------------------------------------- */
474 
475 usbd_status
476 usbd_get_protocol(struct usbd_interface *iface, uint8_t *report)
477 {
478 	usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
479 	struct usbd_device *dev;
480 	usb_device_request_t req;
481 
482 	USBHIST_FUNC();
483 	USBHIST_CALLARGS(usbdebug, "iface=%#jx, endpt=%jd",
484 	    (uintptr_t)iface, id->bInterfaceNumber, 0, 0);
485 
486 	if (id == NULL)
487 		return USBD_IOERROR;
488 
489 	usbd_interface2device_handle(iface, &dev);
490 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
491 	req.bRequest = UR_GET_PROTOCOL;
492 	USETW(req.wValue, 0);
493 	USETW(req.wIndex, id->bInterfaceNumber);
494 	USETW(req.wLength, 1);
495 	return usbd_do_request(dev, &req, report);
496 }
497 
498 usbd_status
499 usbd_set_protocol(struct usbd_interface *iface, int report)
500 {
501 	usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
502 	struct usbd_device *dev;
503 	usb_device_request_t req;
504 
505 	USBHIST_FUNC();
506 	USBHIST_CALLARGS(usbdebug, "iface=%#jx, report=%jd, endpt=%jd",
507 	    (uintptr_t)iface, report, id->bInterfaceNumber, 0);
508 
509 	if (id == NULL)
510 		return USBD_IOERROR;
511 
512 	usbd_interface2device_handle(iface, &dev);
513 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
514 	req.bRequest = UR_SET_PROTOCOL;
515 	USETW(req.wValue, report);
516 	USETW(req.wIndex, id->bInterfaceNumber);
517 	USETW(req.wLength, 0);
518 	return usbd_do_request(dev, &req, 0);
519 }
520 
521 /* -------------------------------------------------------------------------- */
522 
523 usbd_status
524 usbd_set_report(struct usbd_interface *iface, int type, int id, void *data,
525 		int len)
526 {
527 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
528 	struct usbd_device *dev;
529 	usb_device_request_t req;
530 
531 	USBHIST_FUNC();
532 	USBHIST_CALLARGS(usbdebug, "len=%jd", len, 0, 0, 0);
533 
534 	if (ifd == NULL)
535 		return USBD_IOERROR;
536 	usbd_interface2device_handle(iface, &dev);
537 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
538 	req.bRequest = UR_SET_REPORT;
539 	USETW2(req.wValue, type, id);
540 	USETW(req.wIndex, ifd->bInterfaceNumber);
541 	USETW(req.wLength, len);
542 	return usbd_do_request(dev, &req, data);
543 }
544 
545 usbd_status
546 usbd_get_report(struct usbd_interface *iface, int type, int id, void *data,
547 		int len)
548 {
549 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
550 	struct usbd_device *dev;
551 	usb_device_request_t req;
552 
553 	USBHIST_FUNC(); USBHIST_CALLARGS(usbdebug, "len=%jd", len, 0, 0, 0);
554 
555 	if (ifd == NULL)
556 		return USBD_IOERROR;
557 	usbd_interface2device_handle(iface, &dev);
558 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
559 	req.bRequest = UR_GET_REPORT;
560 	USETW2(req.wValue, type, id);
561 	USETW(req.wIndex, ifd->bInterfaceNumber);
562 	USETW(req.wLength, len);
563 	return usbd_do_request(dev, &req, data);
564 }
565 
566 usbd_status
567 usbd_get_report_descriptor(struct usbd_device *dev, int ifcno,
568 			   int size, void *d)
569 {
570 	USBHIST_FUNC();
571 	USBHIST_CALLARGS(usbdebug, "dev %#jx ifcno %jd size %jd",
572 	    (uintptr_t)dev, ifcno, size, 0);
573 	usb_device_request_t req;
574 
575 	req.bmRequestType = UT_READ_INTERFACE;
576 	req.bRequest = UR_GET_DESCRIPTOR;
577 	USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */
578 	USETW(req.wIndex, ifcno);
579 	USETW(req.wLength, size);
580 	return usbd_do_request(dev, &req, d);
581 }
582 
583 /* -------------------------------------------------------------------------- */
584 
585 usb_hid_descriptor_t *
586 usbd_get_hid_descriptor(struct usbd_interface *ifc)
587 {
588 	usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
589 	struct usbd_device *dev;
590 	usb_config_descriptor_t *cdesc;
591 	usb_hid_descriptor_t *hd;
592 	char *p, *end;
593 
594 	if (idesc == NULL)
595 		return NULL;
596 	usbd_interface2device_handle(ifc, &dev);
597 	cdesc = usbd_get_config_descriptor(dev);
598 
599 	p = (char *)idesc + idesc->bLength;
600 	end = (char *)cdesc + UGETW(cdesc->wTotalLength);
601 
602 	for (; p < end; p += hd->bLength) {
603 		hd = (usb_hid_descriptor_t *)p;
604 		if (p + hd->bLength <= end &&
605 		    hd->bLength >= USB_HID_DESCRIPTOR_SIZE(0) &&
606 		    hd->bDescriptorType == UDESC_HID)
607 			return hd;
608 		if (hd->bDescriptorType == UDESC_INTERFACE)
609 			break;
610 	}
611 	return NULL;
612 }
613 
614 usbd_status
615 usbd_read_report_desc(struct usbd_interface *ifc, void **descp, int *sizep)
616 {
617 	usb_interface_descriptor_t *id;
618 	usb_hid_descriptor_t *hid;
619 	struct usbd_device *dev;
620 	usbd_status err;
621 
622 	usbd_interface2device_handle(ifc, &dev);
623 	id = usbd_get_interface_descriptor(ifc);
624 	if (id == NULL)
625 		return USBD_INVAL;
626 	hid = usbd_get_hid_descriptor(ifc);
627 	if (hid == NULL)
628 		return USBD_IOERROR;
629 	*sizep = UGETW(hid->descrs[0].wDescriptorLength);
630 	if (*sizep == 0)
631 		return USBD_INVAL;
632 	*descp = kmem_alloc(*sizep, KM_SLEEP);
633 	err = usbd_get_report_descriptor(dev, id->bInterfaceNumber,
634 					 *sizep, *descp);
635 	if (err) {
636 		kmem_free(*descp, *sizep);
637 		*descp = NULL;
638 		return err;
639 	}
640 	return USBD_NORMAL_COMPLETION;
641 }
642 
643 usbd_status
644 usbd_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
645     uint16_t flags, uint32_t timeout, void *buf, uint32_t *size)
646 {
647 	usbd_status err;
648 
649 	USBHIST_FUNC();
650 	USBHIST_CALLARGS(usbdebug, "start transfer %jd bytes", *size, 0, 0, 0);
651 
652 	usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL);
653 	err = usbd_sync_transfer_sig(xfer);
654 
655 	usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
656 	DPRINTFN(1, "transferred %jd", *size, 0, 0, 0);
657 	if (err) {
658 		usbd_clear_endpoint_stall(pipe);
659 	}
660 	USBHIST_LOG(usbdebug, "<- done xfer %#jx err %jd", (uintptr_t)xfer,
661 	    err, 0, 0);
662 
663 	return err;
664 }
665 
666 usbd_status
667 usbd_intr_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
668     uint16_t flags, uint32_t timeout, void *buf, uint32_t *size)
669 {
670 	usbd_status err;
671 
672 	USBHIST_FUNC();
673 	USBHIST_CALLARGS(usbdebug, "start transfer %jd bytes", *size, 0, 0, 0);
674 
675 	usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL);
676 
677 	err = usbd_sync_transfer_sig(xfer);
678 
679 	usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
680 
681 	DPRINTFN(1, "transferred %jd", *size, 0, 0, 0);
682 	if (err) {
683 		usbd_clear_endpoint_stall(pipe);
684 	}
685 	USBHIST_LOG(usbdebug, "<- done xfer %#jx err %jd", (uintptr_t)xfer,
686 	    err, 0, 0);
687 
688 	return err;
689 }
690 
691 void
692 usb_detach_waitold(device_t dv)
693 {
694 	USBHIST_FUNC();
695 	USBHIST_CALLARGS(usbdebug, "waiting for dv %#jx",
696 	    (uintptr_t)dv, 0, 0, 0);
697 
698 	if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */
699 		aprint_error_dev(dv, "usb_detach_waitold: didn't detach\n");
700 	DPRINTFN(1, "done", 0, 0, 0, 0);
701 }
702 
703 void
704 usb_detach_wakeupold(device_t dv)
705 {
706 	USBHIST_FUNC();
707 	USBHIST_CALLARGS(usbdebug, "for dv %#jx", (uintptr_t)dv, 0, 0, 0);
708 
709 	wakeup(dv); /* XXXSMP ok */
710 }
711 
712 /* -------------------------------------------------------------------------- */
713 
714 void
715 usb_desc_iter_init(struct usbd_device *dev, usbd_desc_iter_t *iter)
716 {
717 	const usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
718 
719 	iter->cur = (const uByte *)cd;
720 	iter->end = (const uByte *)cd + UGETW(cd->wTotalLength);
721 }
722 
723 const usb_descriptor_t *
724 usb_desc_iter_peek(usbd_desc_iter_t *iter)
725 {
726 	const usb_descriptor_t *desc;
727 
728 	if (iter->cur + sizeof(usb_descriptor_t) > iter->end) {
729 		if (iter->cur != iter->end)
730 			printf("%s: bad descriptor\n", __func__);
731 		return NULL;
732 	}
733 	desc = (const usb_descriptor_t *)iter->cur;
734 	if (desc->bLength < USB_DESCRIPTOR_SIZE) {
735 		printf("%s: descriptor length too small\n", __func__);
736 		return NULL;
737 	}
738 	if (iter->cur + desc->bLength > iter->end) {
739 		printf("%s: descriptor length too large\n", __func__);
740 		return NULL;
741 	}
742 	return desc;
743 }
744 
745 const usb_descriptor_t *
746 usb_desc_iter_next(usbd_desc_iter_t *iter)
747 {
748 	const usb_descriptor_t *desc = usb_desc_iter_peek(iter);
749 	if (desc == NULL)
750 		return NULL;
751 	iter->cur += desc->bLength;
752 	return desc;
753 }
754 
755 /* Return the next interface descriptor, skipping over any other
756  * descriptors.  Returns NULL at the end or on error. */
757 const usb_interface_descriptor_t *
758 usb_desc_iter_next_interface(usbd_desc_iter_t *iter)
759 {
760 	const usb_descriptor_t *desc;
761 
762 	while ((desc = usb_desc_iter_peek(iter)) != NULL &&
763 	       desc->bDescriptorType != UDESC_INTERFACE)
764 	{
765 		usb_desc_iter_next(iter);
766 	}
767 
768 	return (const usb_interface_descriptor_t *)usb_desc_iter_next(iter);
769 }
770 
771 /* Returns the next non-interface descriptor, returning NULL when the
772  * next descriptor would be an interface descriptor. */
773 const usb_descriptor_t *
774 usb_desc_iter_next_non_interface(usbd_desc_iter_t *iter)
775 {
776 	const usb_descriptor_t *desc;
777 
778 	if ((desc = usb_desc_iter_peek(iter)) != NULL &&
779 	    desc->bDescriptorType != UDESC_INTERFACE)
780 	{
781 		return usb_desc_iter_next(iter);
782 	} else {
783 		return NULL;
784 	}
785 }
786 
787 const usb_cdc_descriptor_t *
788 usb_find_desc(struct usbd_device *dev, int type, int subtype)
789 {
790 	usbd_desc_iter_t iter;
791 	const usb_cdc_descriptor_t *desc;
792 
793 	usb_desc_iter_init(dev, &iter);
794 	for (;;) {
795 		desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
796 		if (!desc || (desc->bDescriptorType == type &&
797 			      (subtype == USBD_CDCSUBTYPE_ANY ||
798 			       subtype == desc->bDescriptorSubtype)))
799 			break;
800 	}
801 	return desc;
802 }
803 
804 /* same as usb_find_desc(), but searches only in the specified interface. */
805 const usb_cdc_descriptor_t *
806 usb_find_desc_if(struct usbd_device *dev, int type, int subtype,
807 		 usb_interface_descriptor_t *id)
808 {
809 	usbd_desc_iter_t iter;
810 	const usb_cdc_descriptor_t *desc;
811 
812 	if (id == NULL)
813 		return usb_find_desc(dev, type, subtype);
814 
815 	usb_desc_iter_init(dev, &iter);
816 
817 	iter.cur = (void *)id;		/* start from the interface desc */
818 	usb_desc_iter_next(&iter);	/* and skip it */
819 
820 	while ((desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter))
821 	       != NULL) {
822 		if (desc->bDescriptorType == UDESC_INTERFACE) {
823 			/* we ran into the next interface --- not found */
824 			return NULL;
825 		}
826 		if (desc->bDescriptorType == type &&
827 		    (subtype == USBD_CDCSUBTYPE_ANY ||
828 		     subtype == desc->bDescriptorSubtype))
829 			break;
830 	}
831 	return desc;
832 }
833