1 /*	$NetBSD: usbdi_util.c,v 1.65 2016/04/23 10:15:32 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@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.65 2016/04/23 10:15:32 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	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
usbd_get_desc(struct usbd_device * dev,int type,int index,int len,void * desc)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=%d, index=%d, len=%d", 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
usbd_get_config_desc(struct usbd_device * dev,int confidx,usb_config_descriptor_t * d)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=%d", 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=%d, 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
usbd_get_config_desc_full(struct usbd_device * dev,int conf,void * d,int size)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=%d", conf, 0, 0, 0);
101 	return usbd_get_desc(dev, UDESC_CONFIG, conf, size, d);
102 }
103 
104 usbd_status
usbd_get_bos_desc(struct usbd_device * dev,int confidx,usb_bos_descriptor_t * d)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=%d", 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=%d, 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
usbd_get_bos_desc_full(struct usbd_device * dev,int conf,void * d,int size)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=%d", conf, 0, 0, 0);
130 	return usbd_get_desc(dev, UDESC_BOS, conf, size, d);
131 }
132 
133 usbd_status
usbd_get_device_desc(struct usbd_device * dev,usb_device_descriptor_t * d)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
usbd_get_device_status(struct usbd_device * dev,usb_status_t * st)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
usbd_get_hub_status(struct usbd_device * dev,usb_hub_status_t * st)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 %p", 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
usbd_set_address(struct usbd_device * dev,int addr)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 %p addr %d", 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
usbd_get_port_status(struct usbd_device * dev,int port,usb_port_status_t * ps)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 %p port %d", 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
usbd_get_port_status_ext(struct usbd_device * dev,int port,usb_port_status_ext_t * pse)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 %p port %d", 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
usbd_clear_hub_feature(struct usbd_device * dev,int sel)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 %p sel %d", 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
usbd_set_hub_feature(struct usbd_device * dev,int sel)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 %p sel %d", 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
usbd_clear_port_feature(struct usbd_device * dev,int port,int sel)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 %p port %d sel %d", 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
usbd_set_port_feature(struct usbd_device * dev,int port,int sel)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 %p port %d sel %d", 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
usbd_set_port_u1_timeout(struct usbd_device * dev,int port,int timeout)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 %p port %d timeout %d", dev, port, timeout, 0);
285 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
286 	req.bRequest = UR_SET_FEATURE;
287 	USETW(req.wValue, UHF_PORT_U1_TIMEOUT);
288 	USETW2(req.wIndex, timeout, port);
289 	USETW(req.wLength, 0);
290 	return usbd_do_request(dev, &req, 0);
291 }
292 
293 usbd_status
usbd_set_port_u2_timeout(struct usbd_device * dev,int port,int timeout)294 usbd_set_port_u2_timeout(struct usbd_device *dev, int port, int timeout)
295 {
296 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
297 	usb_device_request_t req;
298 
299 	DPRINTF("dev %p port %d timeout %d", dev, port, timeout, 0);
300 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
301 	req.bRequest = UR_SET_FEATURE;
302 	USETW(req.wValue, UHF_PORT_U2_TIMEOUT);
303 	USETW2(req.wIndex, timeout, port);
304 	USETW(req.wLength, 0);
305 	return usbd_do_request(dev, &req, 0);
306 }
307 
308 usbd_status
usbd_get_protocol(struct usbd_interface * iface,uint8_t * report)309 usbd_get_protocol(struct usbd_interface *iface, uint8_t *report)
310 {
311 	usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
312 	struct usbd_device *dev;
313 	usb_device_request_t req;
314 
315 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
316 
317 	DPRINTFN(4, "iface=%p, endpt=%d", iface, id->bInterfaceNumber, 0, 0);
318 	if (id == NULL)
319 		return USBD_IOERROR;
320 	usbd_interface2device_handle(iface, &dev);
321 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
322 	req.bRequest = UR_GET_PROTOCOL;
323 	USETW(req.wValue, 0);
324 	USETW(req.wIndex, id->bInterfaceNumber);
325 	USETW(req.wLength, 1);
326 	return usbd_do_request(dev, &req, report);
327 }
328 
329 usbd_status
usbd_set_protocol(struct usbd_interface * iface,int report)330 usbd_set_protocol(struct usbd_interface *iface, int report)
331 {
332 	usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
333 	struct usbd_device *dev;
334 	usb_device_request_t req;
335 
336 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
337 
338 	DPRINTFN(4, "iface=%p, report=%d, endpt=%d", iface, report,
339 	     id->bInterfaceNumber, 0);
340 	if (id == NULL)
341 		return USBD_IOERROR;
342 	usbd_interface2device_handle(iface, &dev);
343 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
344 	req.bRequest = UR_SET_PROTOCOL;
345 	USETW(req.wValue, report);
346 	USETW(req.wIndex, id->bInterfaceNumber);
347 	USETW(req.wLength, 0);
348 	return usbd_do_request(dev, &req, 0);
349 }
350 
351 usbd_status
usbd_set_report(struct usbd_interface * iface,int type,int id,void * data,int len)352 usbd_set_report(struct usbd_interface *iface, int type, int id, void *data,
353 		int len)
354 {
355 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
356 	struct usbd_device *dev;
357 	usb_device_request_t req;
358 
359 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
360 
361 	DPRINTFN(4, "len=%d", len, 0, 0, 0);
362 	if (ifd == NULL)
363 		return USBD_IOERROR;
364 	usbd_interface2device_handle(iface, &dev);
365 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
366 	req.bRequest = UR_SET_REPORT;
367 	USETW2(req.wValue, type, id);
368 	USETW(req.wIndex, ifd->bInterfaceNumber);
369 	USETW(req.wLength, len);
370 	return usbd_do_request(dev, &req, data);
371 }
372 
373 usbd_status
usbd_get_report(struct usbd_interface * iface,int type,int id,void * data,int len)374 usbd_get_report(struct usbd_interface *iface, int type, int id, void *data,
375 		int len)
376 {
377 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
378 	struct usbd_device *dev;
379 	usb_device_request_t req;
380 
381 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
382 
383 	DPRINTFN(4, "len=%d", len, 0, 0, 0);
384 	if (ifd == NULL)
385 		return USBD_IOERROR;
386 	usbd_interface2device_handle(iface, &dev);
387 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
388 	req.bRequest = UR_GET_REPORT;
389 	USETW2(req.wValue, type, id);
390 	USETW(req.wIndex, ifd->bInterfaceNumber);
391 	USETW(req.wLength, len);
392 	return usbd_do_request(dev, &req, data);
393 }
394 
395 usbd_status
usbd_set_idle(struct usbd_interface * iface,int duration,int id)396 usbd_set_idle(struct usbd_interface *iface, int duration, int id)
397 {
398 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
399 	struct usbd_device *dev;
400 	usb_device_request_t req;
401 
402 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
403 
404 	DPRINTFN(4, "duration %d id %d", duration, id, 0, 0);
405 	if (ifd == NULL)
406 		return USBD_IOERROR;
407 	usbd_interface2device_handle(iface, &dev);
408 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
409 	req.bRequest = UR_SET_IDLE;
410 	USETW2(req.wValue, duration, id);
411 	USETW(req.wIndex, ifd->bInterfaceNumber);
412 	USETW(req.wLength, 0);
413 	return usbd_do_request(dev, &req, 0);
414 }
415 
416 usbd_status
usbd_get_report_descriptor(struct usbd_device * dev,int ifcno,int size,void * d)417 usbd_get_report_descriptor(struct usbd_device *dev, int ifcno,
418 			   int size, void *d)
419 {
420 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
421 	usb_device_request_t req;
422 
423 	DPRINTF("dev %p ifcno %d size %d", dev, ifcno, size, 0);
424 	req.bmRequestType = UT_READ_INTERFACE;
425 	req.bRequest = UR_GET_DESCRIPTOR;
426 	USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */
427 	USETW(req.wIndex, ifcno);
428 	USETW(req.wLength, size);
429 	return usbd_do_request(dev, &req, d);
430 }
431 
432 usb_hid_descriptor_t *
usbd_get_hid_descriptor(struct usbd_interface * ifc)433 usbd_get_hid_descriptor(struct usbd_interface *ifc)
434 {
435 	usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
436 	struct usbd_device *dev;
437 	usb_config_descriptor_t *cdesc;
438 	usb_hid_descriptor_t *hd;
439 	char *p, *end;
440 
441 	if (idesc == NULL)
442 		return NULL;
443 	usbd_interface2device_handle(ifc, &dev);
444 	cdesc = usbd_get_config_descriptor(dev);
445 
446 	p = (char *)idesc + idesc->bLength;
447 	end = (char *)cdesc + UGETW(cdesc->wTotalLength);
448 
449 	for (; p < end; p += hd->bLength) {
450 		hd = (usb_hid_descriptor_t *)p;
451 		if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
452 			return hd;
453 		if (hd->bDescriptorType == UDESC_INTERFACE)
454 			break;
455 	}
456 	return NULL;
457 }
458 
459 usbd_status
usbd_read_report_desc(struct usbd_interface * ifc,void ** descp,int * sizep)460 usbd_read_report_desc(struct usbd_interface *ifc, void **descp, int *sizep)
461 {
462 	usb_interface_descriptor_t *id;
463 	usb_hid_descriptor_t *hid;
464 	struct usbd_device *dev;
465 	usbd_status err;
466 
467 	usbd_interface2device_handle(ifc, &dev);
468 	id = usbd_get_interface_descriptor(ifc);
469 	if (id == NULL)
470 		return USBD_INVAL;
471 	hid = usbd_get_hid_descriptor(ifc);
472 	if (hid == NULL)
473 		return USBD_IOERROR;
474 	*sizep = UGETW(hid->descrs[0].wDescriptorLength);
475 	*descp = kmem_alloc(*sizep, KM_SLEEP);
476 	if (*descp == NULL)
477 		return USBD_NOMEM;
478 	err = usbd_get_report_descriptor(dev, id->bInterfaceNumber,
479 					 *sizep, *descp);
480 	if (err) {
481 		kmem_free(*descp, *sizep);
482 		*descp = NULL;
483 		return err;
484 	}
485 	return USBD_NORMAL_COMPLETION;
486 }
487 
488 usbd_status
usbd_get_config(struct usbd_device * dev,uint8_t * conf)489 usbd_get_config(struct usbd_device *dev, uint8_t *conf)
490 {
491 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
492 	usb_device_request_t req;
493 
494 	DPRINTF("dev %p", dev, 0, 0, 0);
495 	req.bmRequestType = UT_READ_DEVICE;
496 	req.bRequest = UR_GET_CONFIG;
497 	USETW(req.wValue, 0);
498 	USETW(req.wIndex, 0);
499 	USETW(req.wLength, 1);
500 	return usbd_do_request(dev, &req, conf);
501 }
502 
503 usbd_status
usbd_bulk_transfer(struct usbd_xfer * xfer,struct usbd_pipe * pipe,uint16_t flags,uint32_t timeout,void * buf,uint32_t * size)504 usbd_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
505     uint16_t flags, uint32_t timeout, void *buf, uint32_t *size)
506 {
507 	usbd_status err;
508 
509 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
510 
511 	usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL);
512 	DPRINTFN(1, "start transfer %d bytes", *size, 0, 0, 0);
513 	err = usbd_sync_transfer_sig(xfer);
514 
515 	usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
516 	DPRINTFN(1, "transferred %d", *size, 0, 0, 0);
517 	if (err) {
518 		usbd_clear_endpoint_stall(pipe);
519 	}
520 	USBHIST_LOG(usbdebug, "<- done xfer %p err %d", xfer, err, 0, 0);
521 
522 	return err;
523 }
524 
525 usbd_status
usbd_intr_transfer(struct usbd_xfer * xfer,struct usbd_pipe * pipe,uint16_t flags,uint32_t timeout,void * buf,uint32_t * size)526 usbd_intr_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
527     uint16_t flags, uint32_t timeout, void *buf, uint32_t *size)
528 {
529 	usbd_status err;
530 
531 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
532 
533 	usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL);
534 
535 	DPRINTFN(1, "start transfer %d bytes", *size, 0, 0, 0);
536 	err = usbd_sync_transfer_sig(xfer);
537 
538 	usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
539 
540 	DPRINTFN(1, "transferred %d", *size, 0, 0, 0);
541 	if (err) {
542 		usbd_clear_endpoint_stall(pipe);
543 	}
544 	USBHIST_LOG(usbdebug, "<- done xfer %p err %d", xfer, err, 0, 0);
545 
546 	return err;
547 }
548 
549 void
usb_detach_wait(device_t dv,kcondvar_t * cv,kmutex_t * lock)550 usb_detach_wait(device_t dv, kcondvar_t *cv, kmutex_t *lock)
551 {
552 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
553 
554 	DPRINTFN(1, "waiting for dv %p", dv, 0, 0, 0);
555 	if (cv_timedwait(cv, lock, hz * 60))	// dv, PZERO, "usbdet", hz * 60
556 		printf("usb_detach_wait: %s didn't detach\n",
557 			device_xname(dv));
558 	DPRINTFN(1, "done", 0, 0, 0, 0);
559 }
560 
561 void
usb_detach_broadcast(device_t dv,kcondvar_t * cv)562 usb_detach_broadcast(device_t dv, kcondvar_t *cv)
563 {
564 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
565 
566 	DPRINTFN(1, "for dv %p", dv, 0, 0, 0);
567 	cv_broadcast(cv);
568 }
569 
570 void
usb_detach_waitold(device_t dv)571 usb_detach_waitold(device_t dv)
572 {
573 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
574 
575 	DPRINTFN(1, "waiting for dv %p", dv, 0, 0, 0);
576 	if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */
577 		printf("usb_detach_waitold: %s didn't detach\n",
578 			device_xname(dv));
579 	DPRINTFN(1, "done", 0, 0, 0, 0);
580 }
581 
582 void
usb_detach_wakeupold(device_t dv)583 usb_detach_wakeupold(device_t dv)
584 {
585 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
586 
587 	DPRINTFN(1, "for dv %p", dv, 0, 0, 0);
588 	wakeup(dv); /* XXXSMP ok */
589 }
590 
591 const usb_cdc_descriptor_t *
usb_find_desc(struct usbd_device * dev,int type,int subtype)592 usb_find_desc(struct usbd_device *dev, int type, int subtype)
593 {
594 	usbd_desc_iter_t iter;
595 	const usb_cdc_descriptor_t *desc;
596 
597 	usb_desc_iter_init(dev, &iter);
598 	for (;;) {
599 		desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
600 		if (!desc || (desc->bDescriptorType == type &&
601 			      (subtype == USBD_CDCSUBTYPE_ANY ||
602 			       subtype == desc->bDescriptorSubtype)))
603 			break;
604 	}
605 	return desc;
606 }
607 
608 /* same as usb_find_desc(), but searches only in the specified interface. */
609 const usb_cdc_descriptor_t *
usb_find_desc_if(struct usbd_device * dev,int type,int subtype,usb_interface_descriptor_t * id)610 usb_find_desc_if(struct usbd_device *dev, int type, int subtype,
611 		 usb_interface_descriptor_t *id)
612 {
613 	usbd_desc_iter_t iter;
614 	const usb_cdc_descriptor_t *desc;
615 
616 	if (id == NULL)
617 		return usb_find_desc(dev, type, subtype);
618 
619 	usb_desc_iter_init(dev, &iter);
620 
621 	iter.cur = (void *)id;		/* start from the interface desc */
622 	usb_desc_iter_next(&iter);	/* and skip it */
623 
624 	while ((desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter))
625 	       != NULL) {
626 		if (desc->bDescriptorType == UDESC_INTERFACE) {
627 			/* we ran into the next interface --- not found */
628 			return NULL;
629 		}
630 		if (desc->bDescriptorType == type &&
631 		    (subtype == USBD_CDCSUBTYPE_ANY ||
632 		     subtype == desc->bDescriptorSubtype))
633 			break;
634 	}
635 	return desc;
636 }
637