1 /*        $NetBSD: usbdi_util.c,v 1.88 2024/02/04 05:43:06 mrg 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@eterna23.net).
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.88 2024/02/04 05:43:06 mrg 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
usbd_get_desc(struct usbd_device * dev,int type,int index,int len,void * desc)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
usbd_get_config_desc(struct usbd_device * dev,int confidx,usb_config_descriptor_t * d)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
usbd_get_config_desc_full(struct usbd_device * dev,int conf,void * d,int size)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
usbd_get_bos_desc(struct usbd_device * dev,int confidx,usb_bos_descriptor_t * d)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
usbd_get_device_desc(struct usbd_device * dev,usb_device_descriptor_t * d)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
usbd_get_initial_ddesc(struct usbd_device * dev,usb_device_descriptor_t * desc)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
usbd_get_string_desc(struct usbd_device * dev,int sindex,int langid,usb_string_descriptor_t * sdesc,int * sizep)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
usbd_get_device_status(struct usbd_device * dev,usb_status_t * st)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
usbd_get_hub_status(struct usbd_device * dev,usb_hub_status_t * st)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
usbd_get_port_status(struct usbd_device * dev,int port,usb_port_status_t * ps)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
usbd_get_port_status_ext(struct usbd_device * dev,int port,usb_port_status_ext_t * pse)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
usbd_clear_hub_feature(struct usbd_device * dev,int sel)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
usbd_set_hub_feature(struct usbd_device * dev,int sel)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
usbd_clear_port_feature(struct usbd_device * dev,int port,int sel)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
usbd_set_port_feature(struct usbd_device * dev,int port,int sel)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
usbd_set_port_u1_timeout(struct usbd_device * dev,int port,int timeout)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
usbd_set_port_u2_timeout(struct usbd_device * dev,int port,int timeout)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
usbd_clear_endpoint_feature(struct usbd_device * dev,int epaddr,int sel)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
usbd_get_config(struct usbd_device * dev,uint8_t * conf)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
usbd_set_config(struct usbd_device * dev,int conf)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
usbd_set_address(struct usbd_device * dev,int addr)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
usbd_set_idle(struct usbd_interface * iface,int duration,int id)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
usbd_get_protocol(struct usbd_interface * iface,uint8_t * report)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
usbd_set_protocol(struct usbd_interface * iface,int report)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
usbd_set_report(struct usbd_interface * iface,int type,int id,void * data,int len)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
usbd_get_report(struct usbd_interface * iface,int type,int id,void * data,int len)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
usbd_get_report_descriptor(struct usbd_device * dev,int ifcno,int size,void * d)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 *
usbd_get_hid_descriptor(struct usbd_interface * ifc)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 (; end - p >= sizeof(*hd); p += hd->bLength) {
603                     hd = (usb_hid_descriptor_t *)p;
604                     if (hd->bLength < sizeof(*hd) || hd->bLength > end - p)
605                               break;
606                     if (hd->bLength >= USB_HID_DESCRIPTOR_SIZE(0) &&
607                         hd->bDescriptorType == UDESC_HID)
608                               return hd;
609                     if (hd->bDescriptorType == UDESC_INTERFACE)
610                               break;
611           }
612           return NULL;
613 }
614 
615 usbd_status
usbd_read_report_desc(struct usbd_interface * ifc,void ** descp,int * sizep)616 usbd_read_report_desc(struct usbd_interface *ifc, void **descp, int *sizep)
617 {
618           usb_interface_descriptor_t *id;
619           usb_hid_descriptor_t *hid;
620           struct usbd_device *dev;
621           usbd_status err;
622 
623           usbd_interface2device_handle(ifc, &dev);
624           id = usbd_get_interface_descriptor(ifc);
625           if (id == NULL)
626                     return USBD_INVAL;
627           hid = usbd_get_hid_descriptor(ifc);
628           if (hid == NULL)
629                     return USBD_IOERROR;
630           *sizep = UGETW(hid->descrs[0].wDescriptorLength);
631           if (*sizep == 0)
632                     return USBD_INVAL;
633           *descp = kmem_alloc(*sizep, KM_SLEEP);
634           err = usbd_get_report_descriptor(dev, id->bInterfaceNumber,
635                                                    *sizep, *descp);
636           if (err) {
637                     kmem_free(*descp, *sizep);
638                     *descp = NULL;
639                     return err;
640           }
641           return USBD_NORMAL_COMPLETION;
642 }
643 
644 usbd_status
usbd_bulk_transfer(struct usbd_xfer * xfer,struct usbd_pipe * pipe,uint16_t flags,uint32_t timeout,void * buf,uint32_t * size)645 usbd_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
646     uint16_t flags, uint32_t timeout, void *buf, uint32_t *size)
647 {
648           usbd_status err;
649 
650           USBHIST_FUNC();
651           USBHIST_CALLARGS(usbdebug, "start transfer %jd bytes", *size, 0, 0, 0);
652 
653           usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL);
654           err = usbd_sync_transfer_sig(xfer);
655 
656           usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
657           DPRINTFN(1, "transferred %jd", *size, 0, 0, 0);
658           if (err) {
659                     usbd_clear_endpoint_stall(pipe);
660           }
661           USBHIST_LOG(usbdebug, "<- done xfer %#jx err %jd", (uintptr_t)xfer,
662               err, 0, 0);
663 
664           return err;
665 }
666 
667 usbd_status
usbd_intr_transfer(struct usbd_xfer * xfer,struct usbd_pipe * pipe,uint16_t flags,uint32_t timeout,void * buf,uint32_t * size)668 usbd_intr_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
669     uint16_t flags, uint32_t timeout, void *buf, uint32_t *size)
670 {
671           usbd_status err;
672 
673           USBHIST_FUNC();
674           USBHIST_CALLARGS(usbdebug, "start transfer %jd bytes", *size, 0, 0, 0);
675 
676           usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL);
677 
678           err = usbd_sync_transfer_sig(xfer);
679 
680           usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
681 
682           DPRINTFN(1, "transferred %jd", *size, 0, 0, 0);
683           if (err) {
684                     usbd_clear_endpoint_stall(pipe);
685           }
686           USBHIST_LOG(usbdebug, "<- done xfer %#jx err %jd", (uintptr_t)xfer,
687               err, 0, 0);
688 
689           return err;
690 }
691 
692 void
usb_detach_waitold(device_t dv)693 usb_detach_waitold(device_t dv)
694 {
695           USBHIST_FUNC();
696           USBHIST_CALLARGS(usbdebug, "waiting for dv %#jx",
697               (uintptr_t)dv, 0, 0, 0);
698 
699           if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */
700                     aprint_error_dev(dv, "usb_detach_waitold: didn't detach\n");
701           DPRINTFN(1, "done", 0, 0, 0, 0);
702 }
703 
704 void
usb_detach_wakeupold(device_t dv)705 usb_detach_wakeupold(device_t dv)
706 {
707           USBHIST_FUNC();
708           USBHIST_CALLARGS(usbdebug, "for dv %#jx", (uintptr_t)dv, 0, 0, 0);
709 
710           wakeup(dv); /* XXXSMP ok */
711 }
712 
713 /* -------------------------------------------------------------------------- */
714 
715 void
usb_desc_iter_init(struct usbd_device * dev,usbd_desc_iter_t * iter)716 usb_desc_iter_init(struct usbd_device *dev, usbd_desc_iter_t *iter)
717 {
718           const usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
719 
720           iter->cur = (const uByte *)cd;
721           iter->end = (const uByte *)cd + UGETW(cd->wTotalLength);
722 }
723 
724 const usb_descriptor_t *
usb_desc_iter_peek(usbd_desc_iter_t * iter)725 usb_desc_iter_peek(usbd_desc_iter_t *iter)
726 {
727           const usb_descriptor_t *desc;
728 
729           if (iter->end - iter->cur < sizeof(usb_descriptor_t)) {
730                     if (iter->cur != iter->end)
731                               printf("%s: bad descriptor\n", __func__);
732                     return NULL;
733           }
734           desc = (const usb_descriptor_t *)iter->cur;
735           if (desc->bLength < USB_DESCRIPTOR_SIZE) {
736                     printf("%s: descriptor length too small\n", __func__);
737                     return NULL;
738           }
739           if (desc->bLength > iter->end - iter->cur) {
740                     printf("%s: descriptor length too large\n", __func__);
741                     return NULL;
742           }
743           return desc;
744 }
745 
746 const usb_descriptor_t *
usb_desc_iter_next(usbd_desc_iter_t * iter)747 usb_desc_iter_next(usbd_desc_iter_t *iter)
748 {
749           const usb_descriptor_t *desc = usb_desc_iter_peek(iter);
750 
751           if (desc == NULL)
752                     return NULL;
753           KASSERT(desc->bLength <= iter->end - iter->cur);
754           iter->cur += desc->bLength;
755           return desc;
756 }
757 
758 /*
759  * Return the next interface descriptor, skipping over any other
760  * descriptors.  Returns NULL at the end or on error.
761  */
762 const usb_interface_descriptor_t *
usb_desc_iter_next_interface(usbd_desc_iter_t * iter)763 usb_desc_iter_next_interface(usbd_desc_iter_t *iter)
764 {
765           const usb_descriptor_t *desc;
766 
767           while ((desc = usb_desc_iter_peek(iter)) != NULL &&
768               desc->bDescriptorType != UDESC_INTERFACE) {
769                     usb_desc_iter_next(iter);
770           }
771 
772           if ((desc = usb_desc_iter_next(iter)) == NULL ||
773               desc->bLength < sizeof(usb_interface_descriptor_t))
774                     return NULL;
775           KASSERT(desc->bDescriptorType == UDESC_INTERFACE);
776           return (const usb_interface_descriptor_t *)desc;
777 }
778 
779 /*
780  * Returns the next non-interface descriptor, returning NULL when the
781  * next descriptor would be an interface descriptor.
782  */
783 const usb_descriptor_t *
usb_desc_iter_next_non_interface(usbd_desc_iter_t * iter)784 usb_desc_iter_next_non_interface(usbd_desc_iter_t *iter)
785 {
786           const usb_descriptor_t *desc;
787 
788           if ((desc = usb_desc_iter_peek(iter)) != NULL &&
789               desc->bDescriptorType != UDESC_INTERFACE) {
790                     return usb_desc_iter_next(iter);
791           } else {
792                     return NULL;
793           }
794 }
795 
796 const usb_cdc_descriptor_t *
usb_find_desc(struct usbd_device * dev,int type,int subtype)797 usb_find_desc(struct usbd_device *dev, int type, int subtype)
798 {
799           usbd_desc_iter_t iter;
800           const usb_cdc_descriptor_t *desc;
801 
802           usb_desc_iter_init(dev, &iter);
803           for (;;) {
804                     desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter);
805                     if (desc == NULL)
806                               break;
807                     if (desc->bDescriptorType != type)
808                               continue;
809                     if (subtype == USBD_CDCSUBTYPE_ANY ||
810                         subtype == desc->bDescriptorSubtype)
811                               break;
812           }
813           return desc;
814 }
815 
816 /*
817  * Same as usb_find_desc(), but searches only in the specified
818  * interface.
819  */
820 const usb_cdc_descriptor_t *
usb_find_desc_if(struct usbd_device * dev,int type,int subtype,usb_interface_descriptor_t * id)821 usb_find_desc_if(struct usbd_device *dev, int type, int subtype,
822     usb_interface_descriptor_t *id)
823 {
824           usbd_desc_iter_t iter;
825           const usb_cdc_descriptor_t *desc;
826 
827           if (id == NULL)
828                     return usb_find_desc(dev, type, subtype);
829 
830           usb_desc_iter_init(dev, &iter);
831 
832           iter.cur = (void *)id;                  /* start from the interface desc */
833           usb_desc_iter_next(&iter);    /* and skip it */
834 
835           while ((desc = (const usb_cdc_descriptor_t *)usb_desc_iter_next(&iter))
836               != NULL) {
837                     if (desc->bDescriptorType == UDESC_INTERFACE) {
838                               /* we ran into the next interface --- not found */
839                               return NULL;
840                     }
841                     if (desc->bDescriptorType == type &&
842                         (subtype == USBD_CDCSUBTYPE_ANY ||
843                          subtype == desc->bDescriptorSubtype))
844                               break;
845           }
846           return desc;
847 }
848