4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at
9 * Carlstedt Research & Technology.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
41 #include <sys/device.h>
43 #include <dev/usb/usb.h>
44 #include <dev/usb/usbhid.h>
46 #include <dev/usb/usbdi.h>
47 #include <dev/usb/usbdi_util.h>
50 #define DPRINTF(x) if (usbdebug) logprintf x
51 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
59 usbd_get_desc(usbd_device_handle dev
, int type
, int index
, int len
, void *desc
)
61 usb_device_request_t req
;
63 DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n",
66 req
.bmRequestType
= UT_READ_DEVICE
;
67 req
.bRequest
= UR_GET_DESCRIPTOR
;
68 USETW2(req
.wValue
, type
, index
);
70 USETW(req
.wLength
, len
);
71 return (usbd_do_request(dev
, &req
, desc
));
75 usbd_get_config_desc(usbd_device_handle dev
, int confidx
,
76 usb_config_descriptor_t
*d
)
80 DPRINTFN(3,("usbd_get_config_desc: confidx=%d\n", confidx
));
81 err
= usbd_get_desc(dev
, UDESC_CONFIG
, confidx
,
82 USB_CONFIG_DESCRIPTOR_SIZE
, d
);
85 if (d
->bDescriptorType
!= UDESC_CONFIG
) {
86 DPRINTFN(-1,("usbd_get_config_desc: confidx=%d, bad desc "
88 confidx
, d
->bLength
, d
->bDescriptorType
));
91 return (USBD_NORMAL_COMPLETION
);
95 usbd_get_config_desc_full(usbd_device_handle dev
, int conf
, void *d
, int size
)
97 DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf
));
98 return (usbd_get_desc(dev
, UDESC_CONFIG
, conf
, size
, d
));
102 usbd_get_device_desc(usbd_device_handle dev
, usb_device_descriptor_t
*d
)
104 DPRINTFN(3,("usbd_get_device_desc:\n"));
105 return (usbd_get_desc(dev
, UDESC_DEVICE
,
106 0, USB_DEVICE_DESCRIPTOR_SIZE
, d
));
110 usbd_get_device_status(usbd_device_handle dev
, usb_status_t
*st
)
112 usb_device_request_t req
;
114 req
.bmRequestType
= UT_READ_DEVICE
;
115 req
.bRequest
= UR_GET_STATUS
;
116 USETW(req
.wValue
, 0);
117 USETW(req
.wIndex
, 0);
118 USETW(req
.wLength
, sizeof(usb_status_t
));
119 return (usbd_do_request(dev
, &req
, st
));
123 usbd_get_hub_status(usbd_device_handle dev
, usb_hub_status_t
*st
)
125 usb_device_request_t req
;
127 req
.bmRequestType
= UT_READ_CLASS_DEVICE
;
128 req
.bRequest
= UR_GET_STATUS
;
129 USETW(req
.wValue
, 0);
130 USETW(req
.wIndex
, 0);
131 USETW(req
.wLength
, sizeof(usb_hub_status_t
));
132 return (usbd_do_request(dev
, &req
, st
));
136 usbd_set_address(usbd_device_handle dev
, int addr
)
138 usb_device_request_t req
;
140 req
.bmRequestType
= UT_WRITE_DEVICE
;
141 req
.bRequest
= UR_SET_ADDRESS
;
142 USETW(req
.wValue
, addr
);
143 USETW(req
.wIndex
, 0);
144 USETW(req
.wLength
, 0);
145 return usbd_do_request(dev
, &req
, 0);
149 usbd_get_port_status(usbd_device_handle dev
, int port
, usb_port_status_t
*ps
)
151 usb_device_request_t req
;
153 req
.bmRequestType
= UT_READ_CLASS_OTHER
;
154 req
.bRequest
= UR_GET_STATUS
;
155 USETW(req
.wValue
, 0);
156 USETW(req
.wIndex
, port
);
157 USETW(req
.wLength
, sizeof *ps
);
158 return (usbd_do_request(dev
, &req
, ps
));
162 usbd_clear_hub_feature(usbd_device_handle dev
, int sel
)
164 usb_device_request_t req
;
166 req
.bmRequestType
= UT_WRITE_CLASS_DEVICE
;
167 req
.bRequest
= UR_CLEAR_FEATURE
;
168 USETW(req
.wValue
, sel
);
169 USETW(req
.wIndex
, 0);
170 USETW(req
.wLength
, 0);
171 return (usbd_do_request(dev
, &req
, 0));
175 usbd_set_hub_feature(usbd_device_handle dev
, int sel
)
177 usb_device_request_t req
;
179 req
.bmRequestType
= UT_WRITE_CLASS_DEVICE
;
180 req
.bRequest
= UR_SET_FEATURE
;
181 USETW(req
.wValue
, sel
);
182 USETW(req
.wIndex
, 0);
183 USETW(req
.wLength
, 0);
184 return (usbd_do_request(dev
, &req
, 0));
188 usbd_clear_port_feature(usbd_device_handle dev
, int port
, int sel
)
190 usb_device_request_t req
;
192 req
.bmRequestType
= UT_WRITE_CLASS_OTHER
;
193 req
.bRequest
= UR_CLEAR_FEATURE
;
194 USETW(req
.wValue
, sel
);
195 USETW(req
.wIndex
, port
);
196 USETW(req
.wLength
, 0);
197 return (usbd_do_request(dev
, &req
, 0));
201 usbd_set_port_feature(usbd_device_handle dev
, int port
, int sel
)
203 usb_device_request_t req
;
205 req
.bmRequestType
= UT_WRITE_CLASS_OTHER
;
206 req
.bRequest
= UR_SET_FEATURE
;
207 USETW(req
.wValue
, sel
);
208 USETW(req
.wIndex
, port
);
209 USETW(req
.wLength
, 0);
210 return (usbd_do_request(dev
, &req
, 0));
214 usbd_get_protocol(usbd_interface_handle iface
, u_int8_t
*report
)
216 usb_interface_descriptor_t
*id
= usbd_get_interface_descriptor(iface
);
217 usbd_device_handle dev
;
218 usb_device_request_t req
;
220 DPRINTFN(4, ("usbd_get_protocol: iface=%p, endpt=%d\n",
221 iface
, id
->bInterfaceNumber
));
223 return (USBD_IOERROR
);
224 usbd_interface2device_handle(iface
, &dev
);
225 req
.bmRequestType
= UT_READ_CLASS_INTERFACE
;
226 req
.bRequest
= UR_GET_PROTOCOL
;
227 USETW(req
.wValue
, 0);
228 USETW(req
.wIndex
, id
->bInterfaceNumber
);
229 USETW(req
.wLength
, 1);
230 return (usbd_do_request(dev
, &req
, report
));
234 usbd_set_protocol(usbd_interface_handle iface
, int report
)
236 usb_interface_descriptor_t
*id
= usbd_get_interface_descriptor(iface
);
237 usbd_device_handle dev
;
238 usb_device_request_t req
;
240 DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
241 iface
, report
, id
->bInterfaceNumber
));
243 return (USBD_IOERROR
);
244 usbd_interface2device_handle(iface
, &dev
);
245 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
246 req
.bRequest
= UR_SET_PROTOCOL
;
247 USETW(req
.wValue
, report
);
248 USETW(req
.wIndex
, id
->bInterfaceNumber
);
249 USETW(req
.wLength
, 0);
250 return (usbd_do_request(dev
, &req
, 0));
254 usbd_set_report(usbd_interface_handle iface
, int type
, int id
, void *data
,
257 usb_interface_descriptor_t
*ifd
= usbd_get_interface_descriptor(iface
);
258 usbd_device_handle dev
;
259 usb_device_request_t req
;
261 DPRINTFN(4, ("usbd_set_report: len=%d\n", len
));
263 return (USBD_IOERROR
);
264 usbd_interface2device_handle(iface
, &dev
);
265 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
266 req
.bRequest
= UR_SET_REPORT
;
267 USETW2(req
.wValue
, type
, id
);
268 USETW(req
.wIndex
, ifd
->bInterfaceNumber
);
269 USETW(req
.wLength
, len
);
270 return (usbd_do_request(dev
, &req
, data
));
274 usbd_set_report_async(usbd_interface_handle iface
, int type
, int id
, void *data
,
277 usb_interface_descriptor_t
*ifd
= usbd_get_interface_descriptor(iface
);
278 usbd_device_handle dev
;
279 usb_device_request_t req
;
281 DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len
));
283 return (USBD_IOERROR
);
284 usbd_interface2device_handle(iface
, &dev
);
285 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
286 req
.bRequest
= UR_SET_REPORT
;
287 USETW2(req
.wValue
, type
, id
);
288 USETW(req
.wIndex
, ifd
->bInterfaceNumber
);
289 USETW(req
.wLength
, len
);
290 return (usbd_do_request_async(dev
, &req
, data
));
294 usbd_get_report(usbd_interface_handle iface
, int type
, int id
, void *data
,
297 usb_interface_descriptor_t
*ifd
= usbd_get_interface_descriptor(iface
);
298 usbd_device_handle dev
;
299 usb_device_request_t req
;
301 DPRINTFN(4, ("usbd_get_report: len=%d\n", len
));
303 return (USBD_IOERROR
);
304 usbd_interface2device_handle(iface
, &dev
);
305 req
.bmRequestType
= UT_READ_CLASS_INTERFACE
;
306 req
.bRequest
= UR_GET_REPORT
;
307 USETW2(req
.wValue
, type
, id
);
308 USETW(req
.wIndex
, ifd
->bInterfaceNumber
);
309 USETW(req
.wLength
, len
);
310 return (usbd_do_request(dev
, &req
, data
));
314 usbd_set_idle(usbd_interface_handle iface
, int duration
, int id
)
316 usb_interface_descriptor_t
*ifd
= usbd_get_interface_descriptor(iface
);
317 usbd_device_handle dev
;
318 usb_device_request_t req
;
320 DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration
, id
));
322 return (USBD_IOERROR
);
323 usbd_interface2device_handle(iface
, &dev
);
324 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
325 req
.bRequest
= UR_SET_IDLE
;
326 USETW2(req
.wValue
, duration
, id
);
327 USETW(req
.wIndex
, ifd
->bInterfaceNumber
);
328 USETW(req
.wLength
, 0);
329 return (usbd_do_request(dev
, &req
, 0));
333 usbd_get_report_descriptor(usbd_device_handle dev
, int ifcno
,
336 usb_device_request_t req
;
338 req
.bmRequestType
= UT_READ_INTERFACE
;
339 req
.bRequest
= UR_GET_DESCRIPTOR
;
340 USETW2(req
.wValue
, UDESC_REPORT
, 0); /* report id should be 0 */
341 USETW(req
.wIndex
, ifcno
);
342 USETW(req
.wLength
, size
);
343 return (usbd_do_request(dev
, &req
, d
));
346 usb_hid_descriptor_t
*
347 usbd_get_hid_descriptor(usbd_interface_handle ifc
)
349 usb_interface_descriptor_t
*idesc
= usbd_get_interface_descriptor(ifc
);
350 usbd_device_handle dev
;
351 usb_config_descriptor_t
*cdesc
;
352 usb_hid_descriptor_t
*hd
;
357 usbd_interface2device_handle(ifc
, &dev
);
358 cdesc
= usbd_get_config_descriptor(dev
);
360 p
= (char *)idesc
+ idesc
->bLength
;
361 end
= (char *)cdesc
+ UGETW(cdesc
->wTotalLength
);
363 for (; p
< end
; p
+= hd
->bLength
) {
364 hd
= (usb_hid_descriptor_t
*)p
;
365 if (p
+ hd
->bLength
<= end
&& hd
->bDescriptorType
== UDESC_HID
)
367 if (hd
->bDescriptorType
== UDESC_INTERFACE
)
374 usbd_read_report_desc(usbd_interface_handle ifc
, void **descp
, int *sizep
,
377 usb_interface_descriptor_t
*id
;
378 usb_hid_descriptor_t
*hid
;
379 usbd_device_handle dev
;
382 usbd_interface2device_handle(ifc
, &dev
);
383 id
= usbd_get_interface_descriptor(ifc
);
386 hid
= usbd_get_hid_descriptor(ifc
);
388 return (USBD_IOERROR
);
389 *sizep
= UGETW(hid
->descrs
[0].wDescriptorLength
);
390 *descp
= malloc(*sizep
, mem
, M_NOWAIT
);
393 err
= usbd_get_report_descriptor(dev
, id
->bInterfaceNumber
,
400 return (USBD_NORMAL_COMPLETION
);
404 usbd_get_config(usbd_device_handle dev
, u_int8_t
*conf
)
406 usb_device_request_t req
;
408 req
.bmRequestType
= UT_READ_DEVICE
;
409 req
.bRequest
= UR_GET_CONFIG
;
410 USETW(req
.wValue
, 0);
411 USETW(req
.wIndex
, 0);
412 USETW(req
.wLength
, 1);
413 return (usbd_do_request(dev
, &req
, conf
));
416 Static
void usbd_bulk_transfer_cb(usbd_xfer_handle xfer
,
417 usbd_private_handle priv
, usbd_status status
);
419 usbd_bulk_transfer_cb(usbd_xfer_handle xfer
, usbd_private_handle priv
,
426 usbd_bulk_transfer(usbd_xfer_handle xfer
, usbd_pipe_handle pipe
,
427 u_int16_t flags
, u_int32_t timeout
, void *buf
,
428 u_int32_t
*size
, const char *lbl
)
433 usbd_setup_xfer(xfer
, pipe
, 0, buf
, *size
,
434 flags
, timeout
, usbd_bulk_transfer_cb
);
435 DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size
));
436 s
= splusb(); /* don't want callback until tsleep() */
437 err
= usbd_transfer(xfer
);
438 if (err
!= USBD_IN_PROGRESS
) {
442 error
= tsleep(xfer
, PZERO
| PCATCH
, lbl
, 0);
445 DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error
));
446 usbd_abort_pipe(pipe
);
447 return (USBD_INTERRUPTED
);
449 usbd_get_xfer_status(xfer
, NULL
, NULL
, size
, &err
);
450 DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size
));
452 DPRINTF(("usbd_bulk_transfer: error=%d\n", err
));
453 usbd_clear_endpoint_stall(pipe
);
458 Static
void usbd_intr_transfer_cb(usbd_xfer_handle xfer
,
459 usbd_private_handle priv
, usbd_status status
);
461 usbd_intr_transfer_cb(usbd_xfer_handle xfer
, usbd_private_handle priv
,
468 usbd_intr_transfer(usbd_xfer_handle xfer
, usbd_pipe_handle pipe
,
469 u_int16_t flags
, u_int32_t timeout
, void *buf
,
470 u_int32_t
*size
, const char *lbl
)
475 usbd_setup_xfer(xfer
, pipe
, 0, buf
, *size
,
476 flags
, timeout
, usbd_intr_transfer_cb
);
477 DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size
));
478 s
= splusb(); /* don't want callback until tsleep() */
479 err
= usbd_transfer(xfer
);
480 if (err
!= USBD_IN_PROGRESS
) {
484 error
= tsleep(xfer
, PZERO
| PCATCH
, lbl
, 0);
487 DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error
));
488 usbd_abort_pipe(pipe
);
489 return (USBD_INTERRUPTED
);
491 usbd_get_xfer_status(xfer
, NULL
, NULL
, size
, &err
);
492 DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size
));
494 DPRINTF(("usbd_intr_transfer: error=%d\n", err
));
495 usbd_clear_endpoint_stall(pipe
);
501 usb_detach_wait(device_ptr_t dv
)
503 DPRINTF(("usb_detach_wait: waiting for %s\n", USBDEVPTRNAME(dv
)));
504 if (tsleep(dv
, PZERO
, "usbdet", hz
* 60))
505 printf("usb_detach_wait: %s didn't detach\n",
507 DPRINTF(("usb_detach_wait: %s done\n", USBDEVPTRNAME(dv
)));
511 usb_detach_wakeup(device_ptr_t dv
)
513 DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVPTRNAME(dv
)));
517 const usb_cdc_descriptor_t
*
518 usb_find_desc(usbd_device_handle dev
, int type
, int subtype
)
520 usbd_desc_iter_t iter
;
521 const usb_cdc_descriptor_t
*desc
;
523 usb_desc_iter_init(dev
, &iter
);
525 desc
= (const usb_cdc_descriptor_t
*)usb_desc_iter_next(&iter
);
526 if (!desc
|| (desc
->bDescriptorType
== type
&&
527 (subtype
== USBD_CDCSUBTYPE_ANY
||
528 subtype
== desc
->bDescriptorSubtype
)))
534 /* same as usb_find_desc(), but searches only in the specified interface. */
535 const usb_cdc_descriptor_t
*
536 usb_find_desc_if(usbd_device_handle dev
, int type
, int subtype
,
537 usb_interface_descriptor_t
*id
)
539 usbd_desc_iter_t iter
;
540 const usb_cdc_descriptor_t
*desc
;
542 usb_desc_iter_init(dev
, &iter
);
544 iter
.cur
= (void *)id
; /* start from the interface desc */
545 usb_desc_iter_next(&iter
); /* and skip it */
547 while ((desc
= (const usb_cdc_descriptor_t
*)usb_desc_iter_next(&iter
))
549 if (desc
->bDescriptorType
== UDESC_INTERFACE
) {
550 /* we ran into the next interface --- not found */
553 if (desc
->bDescriptorType
== type
&&
554 (subtype
== USBD_CDCSUBTYPE_ANY
||
555 subtype
== desc
->bDescriptorSubtype
))