xref: /netbsd-src/sys/dev/usb/usbdi_util.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: usbdi_util.c,v 1.70 2017/10/28 00:37:13 pgoyette 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.70 2017/10/28 00:37:13 pgoyette 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	DPRINTF(FMT,A,B,C,D)	USBHIST_LOGN(usbdebug,1,FMT,A,B,C,D)
56 #define	DPRINTFN(N,FMT,A,B,C,D)	USBHIST_LOGN(usbdebug,N,FMT,A,B,C,D)
57 
58 usbd_status
59 usbd_get_desc(struct usbd_device *dev, int type, int index, int len, void *desc)
60 {
61 	usb_device_request_t req;
62 
63 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
64 
65 	DPRINTFN(3,"type=%jd, index=%jd, len=%jd", type, index, len, 0);
66 
67 	req.bmRequestType = UT_READ_DEVICE;
68 	req.bRequest = UR_GET_DESCRIPTOR;
69 	USETW2(req.wValue, type, index);
70 	USETW(req.wIndex, 0);
71 	USETW(req.wLength, len);
72 	return usbd_do_request(dev, &req, desc);
73 }
74 
75 usbd_status
76 usbd_get_config_desc(struct usbd_device *dev, int confidx,
77 		     usb_config_descriptor_t *d)
78 {
79 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
80 	usbd_status err;
81 
82 	DPRINTFN(3, "confidx=%jd", confidx, 0, 0, 0);
83 	err = usbd_get_desc(dev, UDESC_CONFIG, confidx,
84 			    USB_CONFIG_DESCRIPTOR_SIZE, d);
85 	if (err)
86 		return err;
87 	if (d->bDescriptorType != UDESC_CONFIG) {
88 		DPRINTFN(1, "confidx=%jd, bad desc len=%d type=%d",
89 		    confidx, d->bLength, d->bDescriptorType, 0);
90 		return USBD_INVAL;
91 	}
92 	return USBD_NORMAL_COMPLETION;
93 }
94 
95 usbd_status
96 usbd_get_config_desc_full(struct usbd_device *dev, int conf, void *d, int size)
97 {
98 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
99 
100 	DPRINTFN(3, "conf=%jd", conf, 0, 0, 0);
101 	return usbd_get_desc(dev, UDESC_CONFIG, conf, size, d);
102 }
103 
104 usbd_status
105 usbd_get_bos_desc(struct usbd_device *dev, int confidx,
106 		     usb_bos_descriptor_t *d)
107 {
108 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
109 	usbd_status err;
110 
111 	DPRINTFN(3, "confidx=%jd", confidx, 0, 0, 0);
112 	err = usbd_get_desc(dev, UDESC_BOS, confidx,
113 			    USB_BOS_DESCRIPTOR_SIZE, d);
114 	if (err)
115 		return err;
116 	if (d->bDescriptorType != UDESC_BOS) {
117 		DPRINTFN(1, "confidx=%jd, bad desc len=%d type=%d",
118 		    confidx, d->bLength, d->bDescriptorType, 0);
119 		return USBD_INVAL;
120 	}
121 	return USBD_NORMAL_COMPLETION;
122 }
123 
124 usbd_status
125 usbd_get_bos_desc_full(struct usbd_device *dev, int conf, void *d, int size)
126 {
127 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
128 
129 	DPRINTFN(3, "conf=%jd", conf, 0, 0, 0);
130 	return usbd_get_desc(dev, UDESC_BOS, conf, size, d);
131 }
132 
133 usbd_status
134 usbd_get_device_desc(struct usbd_device *dev, usb_device_descriptor_t *d)
135 {
136 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
137 
138 	return usbd_get_desc(dev, UDESC_DEVICE,
139 			     0, USB_DEVICE_DESCRIPTOR_SIZE, d);
140 }
141 
142 usbd_status
143 usbd_get_device_status(struct usbd_device *dev, usb_status_t *st)
144 {
145 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
146 	usb_device_request_t req;
147 
148 	req.bmRequestType = UT_READ_DEVICE;
149 	req.bRequest = UR_GET_STATUS;
150 	USETW(req.wValue, 0);
151 	USETW(req.wIndex, 0);
152 	USETW(req.wLength, sizeof(usb_status_t));
153 	return usbd_do_request(dev, &req, st);
154 }
155 
156 usbd_status
157 usbd_get_hub_status(struct usbd_device *dev, usb_hub_status_t *st)
158 {
159 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
160 	usb_device_request_t req;
161 
162 	DPRINTF("dev %#jx", (uintptr_t)dev, 0, 0, 0);
163 	req.bmRequestType = UT_READ_CLASS_DEVICE;
164 	req.bRequest = UR_GET_STATUS;
165 	USETW(req.wValue, 0);
166 	USETW(req.wIndex, 0);
167 	USETW(req.wLength, sizeof(usb_hub_status_t));
168 	return usbd_do_request(dev, &req, st);
169 }
170 
171 usbd_status
172 usbd_set_address(struct usbd_device *dev, int addr)
173 {
174 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
175 	usb_device_request_t req;
176 
177 	DPRINTF("dev %#jx addr %jd", (uintptr_t)dev, addr, 0, 0);
178 	req.bmRequestType = UT_WRITE_DEVICE;
179 	req.bRequest = UR_SET_ADDRESS;
180 	USETW(req.wValue, addr);
181 	USETW(req.wIndex, 0);
182 	USETW(req.wLength, 0);
183 	return usbd_do_request(dev, &req, 0);
184 }
185 
186 usbd_status
187 usbd_get_port_status(struct usbd_device *dev, int port, usb_port_status_t *ps)
188 {
189 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
190 	usb_device_request_t req;
191 
192 	DPRINTF("dev %#jx port %jd", (uintptr_t)dev, port, 0, 0);
193 	req.bmRequestType = UT_READ_CLASS_OTHER;
194 	req.bRequest = UR_GET_STATUS;
195 	USETW(req.wValue, 0);
196 	USETW(req.wIndex, port);
197 	USETW(req.wLength, sizeof(*ps));
198 	return usbd_do_request(dev, &req, ps);
199 }
200 
201 /* USB 3.1 10.16.2.6, 10.16.2.6.3 */
202 usbd_status
203 usbd_get_port_status_ext(struct usbd_device *dev, int port,
204     usb_port_status_ext_t *pse)
205 {
206 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
207 	usb_device_request_t req;
208 
209 	DPRINTF("dev %#jx port %jd", (uintptr_t)dev, port, 0, 0);
210 	req.bmRequestType = UT_READ_CLASS_OTHER;
211 	req.bRequest = UR_GET_STATUS;
212 	USETW2(req.wValue, 0, UR_PST_EXT_PORT_STATUS);
213 	USETW(req.wIndex, port);
214 	USETW(req.wLength, sizeof(*pse));
215 	return usbd_do_request(dev, &req, pse);
216 }
217 
218 usbd_status
219 usbd_clear_hub_feature(struct usbd_device *dev, int sel)
220 {
221 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
222 	usb_device_request_t req;
223 
224 	DPRINTF("dev %#jx sel %jd", (uintptr_t)dev, sel, 0, 0);
225 	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
226 	req.bRequest = UR_CLEAR_FEATURE;
227 	USETW(req.wValue, sel);
228 	USETW(req.wIndex, 0);
229 	USETW(req.wLength, 0);
230 	return usbd_do_request(dev, &req, 0);
231 }
232 
233 usbd_status
234 usbd_set_hub_feature(struct usbd_device *dev, int sel)
235 {
236 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
237 	usb_device_request_t req;
238 
239 	DPRINTF("dev %#jx sel %jd", (uintptr_t)dev, sel, 0, 0);
240 	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
241 	req.bRequest = UR_SET_FEATURE;
242 	USETW(req.wValue, sel);
243 	USETW(req.wIndex, 0);
244 	USETW(req.wLength, 0);
245 	return usbd_do_request(dev, &req, 0);
246 }
247 
248 usbd_status
249 usbd_clear_port_feature(struct usbd_device *dev, int port, int sel)
250 {
251 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
252 	usb_device_request_t req;
253 
254 	DPRINTF("dev %#jx port %jd sel %jd", (uintptr_t)dev, port, sel, 0);
255 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
256 	req.bRequest = UR_CLEAR_FEATURE;
257 	USETW(req.wValue, sel);
258 	USETW(req.wIndex, port);
259 	USETW(req.wLength, 0);
260 	return usbd_do_request(dev, &req, 0);
261 }
262 
263 usbd_status
264 usbd_set_port_feature(struct usbd_device *dev, int port, int sel)
265 {
266 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
267 	usb_device_request_t req;
268 
269 	DPRINTF("dev %#jx port %jd sel %.d", (uintptr_t)dev, sel, 0, 0);
270 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
271 	req.bRequest = UR_SET_FEATURE;
272 	USETW(req.wValue, sel);
273 	USETW(req.wIndex, port);
274 	USETW(req.wLength, 0);
275 	return usbd_do_request(dev, &req, 0);
276 }
277 
278 usbd_status
279 usbd_set_port_u1_timeout(struct usbd_device *dev, int port, int timeout)
280 {
281 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
282 	usb_device_request_t req;
283 
284 	DPRINTF("dev %#jx port %jd timeout %.d", (uintptr_t)dev, port,
285 	    timeout, 0);
286 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
287 	req.bRequest = UR_SET_FEATURE;
288 	USETW(req.wValue, UHF_PORT_U1_TIMEOUT);
289 	USETW2(req.wIndex, timeout, port);
290 	USETW(req.wLength, 0);
291 	return usbd_do_request(dev, &req, 0);
292 }
293 
294 usbd_status
295 usbd_set_port_u2_timeout(struct usbd_device *dev, int port, int timeout)
296 {
297 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
298 	usb_device_request_t req;
299 
300 	DPRINTF("dev %#jx port %jd timeout %jd", (uintptr_t)dev, port,
301 	    timeout, 0);
302 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
303 	req.bRequest = UR_SET_FEATURE;
304 	USETW(req.wValue, UHF_PORT_U2_TIMEOUT);
305 	USETW2(req.wIndex, timeout, port);
306 	USETW(req.wLength, 0);
307 	return usbd_do_request(dev, &req, 0);
308 }
309 
310 usbd_status
311 usbd_get_protocol(struct usbd_interface *iface, uint8_t *report)
312 {
313 	usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
314 	struct usbd_device *dev;
315 	usb_device_request_t req;
316 
317 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
318 
319 	if (id == NULL)
320 		return USBD_IOERROR;
321 	DPRINTFN(4, "iface=%#jx, endpt=%jd", (uintptr_t)iface,
322 	    id->bInterfaceNumber, 0, 0);
323 
324 	usbd_interface2device_handle(iface, &dev);
325 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
326 	req.bRequest = UR_GET_PROTOCOL;
327 	USETW(req.wValue, 0);
328 	USETW(req.wIndex, id->bInterfaceNumber);
329 	USETW(req.wLength, 1);
330 	return usbd_do_request(dev, &req, report);
331 }
332 
333 usbd_status
334 usbd_set_protocol(struct usbd_interface *iface, int report)
335 {
336 	usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
337 	struct usbd_device *dev;
338 	usb_device_request_t req;
339 
340 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
341 
342 	if (id == NULL)
343 		return USBD_IOERROR;
344 	DPRINTFN(4, "iface=%#jx, report=%jd, endpt=%jd", (uintptr_t)iface,
345 	    report, id->bInterfaceNumber, 0);
346 
347 	usbd_interface2device_handle(iface, &dev);
348 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
349 	req.bRequest = UR_SET_PROTOCOL;
350 	USETW(req.wValue, report);
351 	USETW(req.wIndex, id->bInterfaceNumber);
352 	USETW(req.wLength, 0);
353 	return usbd_do_request(dev, &req, 0);
354 }
355 
356 usbd_status
357 usbd_set_report(struct usbd_interface *iface, int type, int id, void *data,
358 		int len)
359 {
360 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
361 	struct usbd_device *dev;
362 	usb_device_request_t req;
363 
364 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
365 
366 	DPRINTFN(4, "len=%jd", len, 0, 0, 0);
367 	if (ifd == NULL)
368 		return USBD_IOERROR;
369 	usbd_interface2device_handle(iface, &dev);
370 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
371 	req.bRequest = UR_SET_REPORT;
372 	USETW2(req.wValue, type, id);
373 	USETW(req.wIndex, ifd->bInterfaceNumber);
374 	USETW(req.wLength, len);
375 	return usbd_do_request(dev, &req, data);
376 }
377 
378 usbd_status
379 usbd_get_report(struct usbd_interface *iface, int type, int id, void *data,
380 		int len)
381 {
382 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
383 	struct usbd_device *dev;
384 	usb_device_request_t req;
385 
386 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
387 
388 	DPRINTFN(4, "len=%jd", len, 0, 0, 0);
389 	if (ifd == NULL)
390 		return USBD_IOERROR;
391 	usbd_interface2device_handle(iface, &dev);
392 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
393 	req.bRequest = UR_GET_REPORT;
394 	USETW2(req.wValue, type, id);
395 	USETW(req.wIndex, ifd->bInterfaceNumber);
396 	USETW(req.wLength, len);
397 	return usbd_do_request(dev, &req, data);
398 }
399 
400 usbd_status
401 usbd_set_idle(struct usbd_interface *iface, int duration, int id)
402 {
403 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
404 	struct usbd_device *dev;
405 	usb_device_request_t req;
406 
407 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
408 
409 	DPRINTFN(4, "duration %jd id %jd", duration, id, 0, 0);
410 	if (ifd == NULL)
411 		return USBD_IOERROR;
412 	usbd_interface2device_handle(iface, &dev);
413 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
414 	req.bRequest = UR_SET_IDLE;
415 	USETW2(req.wValue, duration, id);
416 	USETW(req.wIndex, ifd->bInterfaceNumber);
417 	USETW(req.wLength, 0);
418 	return usbd_do_request(dev, &req, 0);
419 }
420 
421 usbd_status
422 usbd_get_report_descriptor(struct usbd_device *dev, int ifcno,
423 			   int size, void *d)
424 {
425 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
426 	usb_device_request_t req;
427 
428 	DPRINTF("dev %#jx ifcno %jd size %jd", (uintptr_t)dev, ifcno, size, 0);
429 	req.bmRequestType = UT_READ_INTERFACE;
430 	req.bRequest = UR_GET_DESCRIPTOR;
431 	USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */
432 	USETW(req.wIndex, ifcno);
433 	USETW(req.wLength, size);
434 	return usbd_do_request(dev, &req, d);
435 }
436 
437 usb_hid_descriptor_t *
438 usbd_get_hid_descriptor(struct usbd_interface *ifc)
439 {
440 	usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
441 	struct usbd_device *dev;
442 	usb_config_descriptor_t *cdesc;
443 	usb_hid_descriptor_t *hd;
444 	char *p, *end;
445 
446 	if (idesc == NULL)
447 		return NULL;
448 	usbd_interface2device_handle(ifc, &dev);
449 	cdesc = usbd_get_config_descriptor(dev);
450 
451 	p = (char *)idesc + idesc->bLength;
452 	end = (char *)cdesc + UGETW(cdesc->wTotalLength);
453 
454 	for (; p < end; p += hd->bLength) {
455 		hd = (usb_hid_descriptor_t *)p;
456 		if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
457 			return hd;
458 		if (hd->bDescriptorType == UDESC_INTERFACE)
459 			break;
460 	}
461 	return NULL;
462 }
463 
464 usbd_status
465 usbd_read_report_desc(struct usbd_interface *ifc, void **descp, int *sizep)
466 {
467 	usb_interface_descriptor_t *id;
468 	usb_hid_descriptor_t *hid;
469 	struct usbd_device *dev;
470 	usbd_status err;
471 
472 	usbd_interface2device_handle(ifc, &dev);
473 	id = usbd_get_interface_descriptor(ifc);
474 	if (id == NULL)
475 		return USBD_INVAL;
476 	hid = usbd_get_hid_descriptor(ifc);
477 	if (hid == NULL)
478 		return USBD_IOERROR;
479 	*sizep = UGETW(hid->descrs[0].wDescriptorLength);
480 	*descp = kmem_alloc(*sizep, KM_SLEEP);
481 	err = usbd_get_report_descriptor(dev, id->bInterfaceNumber,
482 					 *sizep, *descp);
483 	if (err) {
484 		kmem_free(*descp, *sizep);
485 		*descp = NULL;
486 		return err;
487 	}
488 	return USBD_NORMAL_COMPLETION;
489 }
490 
491 usbd_status
492 usbd_get_config(struct usbd_device *dev, uint8_t *conf)
493 {
494 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
495 	usb_device_request_t req;
496 
497 	DPRINTF("dev %#jx", (uintptr_t)dev, 0, 0, 0);
498 	req.bmRequestType = UT_READ_DEVICE;
499 	req.bRequest = UR_GET_CONFIG;
500 	USETW(req.wValue, 0);
501 	USETW(req.wIndex, 0);
502 	USETW(req.wLength, 1);
503 	return usbd_do_request(dev, &req, conf);
504 }
505 
506 usbd_status
507 usbd_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
508     uint16_t flags, uint32_t timeout, void *buf, uint32_t *size)
509 {
510 	usbd_status err;
511 
512 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
513 
514 	usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL);
515 	DPRINTFN(1, "start transfer %jd bytes", *size, 0, 0, 0);
516 	err = usbd_sync_transfer_sig(xfer);
517 
518 	usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
519 	DPRINTFN(1, "transferred %jd", *size, 0, 0, 0);
520 	if (err) {
521 		usbd_clear_endpoint_stall(pipe);
522 	}
523 	USBHIST_LOG(usbdebug, "<- done xfer %#jx err %d", (uintptr_t)xfer,
524 	    err, 0, 0);
525 
526 	return err;
527 }
528 
529 usbd_status
530 usbd_intr_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
531     uint16_t flags, uint32_t timeout, void *buf, uint32_t *size)
532 {
533 	usbd_status err;
534 
535 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
536 
537 	usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL);
538 
539 	DPRINTFN(1, "start transfer %jd bytes", *size, 0, 0, 0);
540 	err = usbd_sync_transfer_sig(xfer);
541 
542 	usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
543 
544 	DPRINTFN(1, "transferred %jd", *size, 0, 0, 0);
545 	if (err) {
546 		usbd_clear_endpoint_stall(pipe);
547 	}
548 	USBHIST_LOG(usbdebug, "<- done xfer %#jx err %jd", (uintptr_t)xfer,
549 	    err, 0, 0);
550 
551 	return err;
552 }
553 
554 void
555 usb_detach_wait(device_t dv, kcondvar_t *cv, kmutex_t *lock)
556 {
557 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
558 
559 	DPRINTFN(1, "waiting for dv %#jx", (uintptr_t)dv, 0, 0, 0);
560 	if (cv_timedwait(cv, lock, hz * 60))	// dv, PZERO, "usbdet", hz * 60
561 		printf("usb_detach_wait: %s didn't detach\n",
562 			device_xname(dv));
563 	DPRINTFN(1, "done", 0, 0, 0, 0);
564 }
565 
566 void
567 usb_detach_broadcast(device_t dv, kcondvar_t *cv)
568 {
569 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
570 
571 	DPRINTFN(1, "for dv %#jx", (uintptr_t)dv, 0, 0, 0);
572 	cv_broadcast(cv);
573 }
574 
575 void
576 usb_detach_waitold(device_t dv)
577 {
578 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
579 
580 	DPRINTFN(1, "waiting for dv %#jx", (uintptr_t)dv, 0, 0, 0);
581 	if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */
582 		printf("usb_detach_waitold: %s didn't detach\n",
583 			device_xname(dv));
584 	DPRINTFN(1, "done", 0, 0, 0, 0);
585 }
586 
587 void
588 usb_detach_wakeupold(device_t dv)
589 {
590 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
591 
592 	DPRINTFN(1, "for dv %#jx", (uintptr_t)dv, 0, 0, 0);
593 	wakeup(dv); /* XXXSMP ok */
594 }
595 
596 const usb_cdc_descriptor_t *
597 usb_find_desc(struct usbd_device *dev, int type, int subtype)
598 {
599 	usbd_desc_iter_t iter;
600 	const usb_cdc_descriptor_t *desc;
601 
602 	usb_desc_iter_init(dev, &iter);
603 	for (;;) {
604 		desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
605 		if (!desc || (desc->bDescriptorType == type &&
606 			      (subtype == USBD_CDCSUBTYPE_ANY ||
607 			       subtype == desc->bDescriptorSubtype)))
608 			break;
609 	}
610 	return desc;
611 }
612 
613 /* same as usb_find_desc(), but searches only in the specified interface. */
614 const usb_cdc_descriptor_t *
615 usb_find_desc_if(struct usbd_device *dev, int type, int subtype,
616 		 usb_interface_descriptor_t *id)
617 {
618 	usbd_desc_iter_t iter;
619 	const usb_cdc_descriptor_t *desc;
620 
621 	if (id == NULL)
622 		return usb_find_desc(dev, type, subtype);
623 
624 	usb_desc_iter_init(dev, &iter);
625 
626 	iter.cur = (void *)id;		/* start from the interface desc */
627 	usb_desc_iter_next(&iter);	/* and skip it */
628 
629 	while ((desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter))
630 	       != NULL) {
631 		if (desc->bDescriptorType == UDESC_INTERFACE) {
632 			/* we ran into the next interface --- not found */
633 			return NULL;
634 		}
635 		if (desc->bDescriptorType == type &&
636 		    (subtype == USBD_CDCSUBTYPE_ANY ||
637 		     subtype == desc->bDescriptorSubtype))
638 			break;
639 	}
640 	return desc;
641 }
642