2 * $NetBSD: usbdi_util.c,v 1.24 1999/11/17 23:00:50 augustss Exp $
3 * $NetBSD: usbdi_util.c,v 1.36 2001/11/13 06:24:57 lukem Exp $
4 * $FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.31 2003/08/24 17:55:55 obrien Exp $
5 * $DragonFly: src/sys/bus/usb/usbdi_util.c,v 1.9 2006/09/05 00:55:36 dillon Exp $
9 * Copyright (c) 1998 The NetBSD Foundation, Inc.
10 * All rights reserved.
12 * This code is derived from software contributed to The NetBSD Foundation
13 * by Lennart Augustsson (lennart@augustsson.net) at
14 * Carlstedt Research & Technology.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the NetBSD
27 * Foundation, Inc. and its contributors.
28 * 4. Neither the name of The NetBSD Foundation nor the names of its
29 * contributors may be used to endorse or promote products derived
30 * from this software without specific prior written permission.
32 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
33 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
34 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
35 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
36 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGE.
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/malloc.h>
49 #if defined(__NetBSD__) || defined(__OpenBSD__)
51 #include <sys/device.h>
52 #elif defined(__FreeBSD__) || defined(__DragonFly__)
55 #include <sys/thread2.h>
61 #include "usbdi_util.h"
64 #define DPRINTF(x) if (usbdebug) logprintf x
65 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
73 usbd_get_desc(usbd_device_handle dev, int type, int index, int len, void *desc)
75 usb_device_request_t req;
77 DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n",
80 req.bmRequestType = UT_READ_DEVICE;
81 req.bRequest = UR_GET_DESCRIPTOR;
82 USETW2(req.wValue, type, index);
84 USETW(req.wLength, len);
85 return (usbd_do_request(dev, &req, desc));
89 usbd_get_config_desc(usbd_device_handle dev, int confidx,
90 usb_config_descriptor_t *d)
94 DPRINTFN(3,("usbd_get_config_desc: confidx=%d\n", confidx));
95 err = usbd_get_desc(dev, UDESC_CONFIG, confidx,
96 USB_CONFIG_DESCRIPTOR_SIZE, d);
99 if (d->bDescriptorType != UDESC_CONFIG) {
100 DPRINTFN(-1,("usbd_get_config_desc: confidx=%d, bad desc "
102 confidx, d->bLength, d->bDescriptorType));
105 return (USBD_NORMAL_COMPLETION);
109 usbd_get_config_desc_full(usbd_device_handle dev, int conf, void *d, int size)
111 DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf));
112 return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d));
116 usbd_get_device_desc(usbd_device_handle dev, usb_device_descriptor_t *d)
118 DPRINTFN(3,("usbd_get_device_desc:\n"));
119 return (usbd_get_desc(dev, UDESC_DEVICE,
120 0, USB_DEVICE_DESCRIPTOR_SIZE, d));
124 usbd_get_device_status(usbd_device_handle dev, usb_status_t *st)
126 usb_device_request_t req;
128 req.bmRequestType = UT_READ_DEVICE;
129 req.bRequest = UR_GET_STATUS;
130 USETW(req.wValue, 0);
131 USETW(req.wIndex, 0);
132 USETW(req.wLength, sizeof(usb_status_t));
133 return (usbd_do_request(dev, &req, st));
137 usbd_get_hub_status(usbd_device_handle dev, usb_hub_status_t *st)
139 usb_device_request_t req;
141 req.bmRequestType = UT_READ_CLASS_DEVICE;
142 req.bRequest = UR_GET_STATUS;
143 USETW(req.wValue, 0);
144 USETW(req.wIndex, 0);
145 USETW(req.wLength, sizeof(usb_hub_status_t));
146 return (usbd_do_request(dev, &req, st));
150 usbd_set_address(usbd_device_handle dev, int addr)
152 usb_device_request_t req;
154 req.bmRequestType = UT_WRITE_DEVICE;
155 req.bRequest = UR_SET_ADDRESS;
156 USETW(req.wValue, addr);
157 USETW(req.wIndex, 0);
158 USETW(req.wLength, 0);
159 return usbd_do_request(dev, &req, 0);
163 usbd_get_port_status(usbd_device_handle dev, int port, usb_port_status_t *ps)
165 usb_device_request_t req;
167 req.bmRequestType = UT_READ_CLASS_OTHER;
168 req.bRequest = UR_GET_STATUS;
169 USETW(req.wValue, 0);
170 USETW(req.wIndex, port);
171 USETW(req.wLength, sizeof *ps);
172 return (usbd_do_request(dev, &req, ps));
176 usbd_clear_hub_feature(usbd_device_handle dev, int sel)
178 usb_device_request_t req;
180 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
181 req.bRequest = UR_CLEAR_FEATURE;
182 USETW(req.wValue, sel);
183 USETW(req.wIndex, 0);
184 USETW(req.wLength, 0);
185 return (usbd_do_request(dev, &req, 0));
189 usbd_set_hub_feature(usbd_device_handle dev, int sel)
191 usb_device_request_t req;
193 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
194 req.bRequest = UR_SET_FEATURE;
195 USETW(req.wValue, sel);
196 USETW(req.wIndex, 0);
197 USETW(req.wLength, 0);
198 return (usbd_do_request(dev, &req, 0));
202 usbd_clear_port_feature(usbd_device_handle dev, int port, int sel)
204 usb_device_request_t req;
206 req.bmRequestType = UT_WRITE_CLASS_OTHER;
207 req.bRequest = UR_CLEAR_FEATURE;
208 USETW(req.wValue, sel);
209 USETW(req.wIndex, port);
210 USETW(req.wLength, 0);
211 return (usbd_do_request(dev, &req, 0));
215 usbd_set_port_feature(usbd_device_handle dev, int port, int sel)
217 usb_device_request_t req;
219 req.bmRequestType = UT_WRITE_CLASS_OTHER;
220 req.bRequest = UR_SET_FEATURE;
221 USETW(req.wValue, sel);
222 USETW(req.wIndex, port);
223 USETW(req.wLength, 0);
224 return (usbd_do_request(dev, &req, 0));
229 usbd_set_protocol(usbd_interface_handle iface, int report)
231 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
232 usbd_device_handle dev;
233 usb_device_request_t req;
235 DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
236 iface, report, id->bInterfaceNumber));
238 return (USBD_IOERROR);
239 usbd_interface2device_handle(iface, &dev);
240 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
241 req.bRequest = UR_SET_PROTOCOL;
242 USETW(req.wValue, report);
243 USETW(req.wIndex, id->bInterfaceNumber);
244 USETW(req.wLength, 0);
245 return (usbd_do_request(dev, &req, 0));
249 usbd_set_report(usbd_interface_handle iface, int type, int id, void *data,
252 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
253 usbd_device_handle dev;
254 usb_device_request_t req;
256 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
258 return (USBD_IOERROR);
259 usbd_interface2device_handle(iface, &dev);
260 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
261 req.bRequest = UR_SET_REPORT;
262 USETW2(req.wValue, type, id);
263 USETW(req.wIndex, ifd->bInterfaceNumber);
264 USETW(req.wLength, len);
265 return (usbd_do_request(dev, &req, data));
269 usbd_set_report_async(usbd_interface_handle iface, int type, int id, void *data,
272 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
273 usbd_device_handle dev;
274 usb_device_request_t req;
276 DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
278 return (USBD_IOERROR);
279 usbd_interface2device_handle(iface, &dev);
280 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
281 req.bRequest = UR_SET_REPORT;
282 USETW2(req.wValue, type, id);
283 USETW(req.wIndex, ifd->bInterfaceNumber);
284 USETW(req.wLength, len);
285 return (usbd_do_request_async(dev, &req, data));
289 usbd_get_report(usbd_interface_handle iface, int type, int id, void *data,
292 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
293 usbd_device_handle dev;
294 usb_device_request_t req;
296 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
298 return (USBD_IOERROR);
299 usbd_interface2device_handle(iface, &dev);
300 req.bmRequestType = UT_READ_CLASS_INTERFACE;
301 req.bRequest = UR_GET_REPORT;
302 USETW2(req.wValue, type, id);
303 USETW(req.wIndex, ifd->bInterfaceNumber);
304 USETW(req.wLength, len);
305 return (usbd_do_request(dev, &req, data));
309 usbd_set_idle(usbd_interface_handle iface, int duration, int id)
311 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
312 usbd_device_handle dev;
313 usb_device_request_t req;
315 DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
317 return (USBD_IOERROR);
318 usbd_interface2device_handle(iface, &dev);
319 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
320 req.bRequest = UR_SET_IDLE;
321 USETW2(req.wValue, duration, id);
322 USETW(req.wIndex, ifd->bInterfaceNumber);
323 USETW(req.wLength, 0);
324 return (usbd_do_request(dev, &req, 0));
328 usbd_get_report_descriptor(usbd_device_handle dev, int ifcno,
331 usb_device_request_t req;
333 req.bmRequestType = UT_READ_INTERFACE;
334 req.bRequest = UR_GET_DESCRIPTOR;
335 USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */
336 USETW(req.wIndex, ifcno);
337 USETW(req.wLength, size);
338 return (usbd_do_request(dev, &req, d));
341 usb_hid_descriptor_t *
342 usbd_get_hid_descriptor(usbd_interface_handle ifc)
344 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
345 usbd_device_handle dev;
346 usb_config_descriptor_t *cdesc;
347 usb_hid_descriptor_t *hd;
352 usbd_interface2device_handle(ifc, &dev);
353 cdesc = usbd_get_config_descriptor(dev);
355 p = (char *)idesc + idesc->bLength;
356 end = (char *)cdesc + UGETW(cdesc->wTotalLength);
358 for (; p < end; p += hd->bLength) {
359 hd = (usb_hid_descriptor_t *)p;
360 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
362 if (hd->bDescriptorType == UDESC_INTERFACE)
369 usbd_read_report_desc(usbd_interface_handle ifc, void **descp, int *sizep,
372 usb_interface_descriptor_t *id;
373 usb_hid_descriptor_t *hid;
374 usbd_device_handle dev;
377 usbd_interface2device_handle(ifc, &dev);
378 id = usbd_get_interface_descriptor(ifc);
381 hid = usbd_get_hid_descriptor(ifc);
383 return (USBD_IOERROR);
384 *sizep = UGETW(hid->descrs[0].wDescriptorLength);
385 *descp = kmalloc(*sizep, mem, M_INTWAIT);
386 err = usbd_get_report_descriptor(dev, id->bInterfaceNumber,
393 return (USBD_NORMAL_COMPLETION);
397 usbd_get_config(usbd_device_handle dev, u_int8_t *conf)
399 usb_device_request_t req;
401 req.bmRequestType = UT_READ_DEVICE;
402 req.bRequest = UR_GET_CONFIG;
403 USETW(req.wValue, 0);
404 USETW(req.wIndex, 0);
405 USETW(req.wLength, 1);
406 return (usbd_do_request(dev, &req, conf));
409 Static void usbd_bulk_transfer_cb(usbd_xfer_handle xfer,
410 usbd_private_handle priv, usbd_status status);
412 usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
419 usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
420 u_int16_t flags, u_int32_t timeout, void *buf,
421 u_int32_t *size, char *lbl)
426 usbd_setup_xfer(xfer, pipe, 0, buf, *size,
427 flags, timeout, usbd_bulk_transfer_cb);
428 DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size));
430 err = usbd_transfer(xfer);
431 if (err != USBD_IN_PROGRESS) {
435 error = tsleep((caddr_t)xfer, PCATCH, lbl, 0);
438 DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error));
439 usbd_abort_pipe(pipe);
440 return (USBD_INTERRUPTED);
442 usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
443 DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size));
445 DPRINTF(("usbd_bulk_transfer: error=%d\n", err));
446 usbd_clear_endpoint_stall(pipe);
451 Static void usbd_intr_transfer_cb(usbd_xfer_handle xfer,
452 usbd_private_handle priv, usbd_status status);
454 usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
461 usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
462 u_int16_t flags, u_int32_t timeout, void *buf,
463 u_int32_t *size, char *lbl)
468 usbd_setup_xfer(xfer, pipe, 0, buf, *size,
469 flags, timeout, usbd_intr_transfer_cb);
470 DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size));
471 crit_enter(); /* don't want callback until tsleep() */
472 err = usbd_transfer(xfer);
473 if (err != USBD_IN_PROGRESS) {
477 error = tsleep(xfer, PCATCH, lbl, 0);
480 DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error));
481 usbd_abort_pipe(pipe);
482 return (USBD_INTERRUPTED);
484 usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
485 DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size));
487 DPRINTF(("usbd_intr_transfer: error=%d\n", err));
488 usbd_clear_endpoint_stall(pipe);
494 usb_detach_wait(device_ptr_t dv)
496 DPRINTF(("usb_detach_wait: waiting for %s\n", USBDEVPTRNAME(dv)));
497 if (tsleep(dv, 0, "usbdet", hz * 60))
498 printf("usb_detach_wait: %s didn't detach\n",
500 DPRINTF(("usb_detach_wait: %s done\n", USBDEVPTRNAME(dv)));
504 usb_detach_wakeup(device_ptr_t dv)
506 DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVPTRNAME(dv)));