usbdi_util.c revision 1.25 1 /* $NetBSD: usbdi_util.c,v 1.25 1999/11/18 23:32:34 augustss Exp $ */
2 /* $FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.14 1999/11/17 22:33:50 n_hibma Exp $ */
3
4 /*
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Lennart Augustsson (augustss (at) carlstedt.se) at
10 * Carlstedt Research & Technology.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #if defined(__NetBSD__) || defined(__OpenBSD__)
46 #include <sys/proc.h>
47 #include <sys/device.h>
48 #elif defined(__FreeBSD__)
49 #include <sys/bus.h>
50 #endif
51
52 #include <dev/usb/usb.h>
53 #include <dev/usb/usbhid.h>
54
55 #include <dev/usb/usbdi.h>
56 #include <dev/usb/usbdi_util.h>
57
58 #ifdef USB_DEBUG
59 #define DPRINTF(x) if (usbdebug) logprintf x
60 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
61 extern int usbdebug;
62 #else
63 #define DPRINTF(x)
64 #define DPRINTFN(n,x)
65 #endif
66
67 usbd_status
68 usbd_get_desc(dev, type, index, len, desc)
69 usbd_device_handle dev;
70 int type, index;
71 int len;
72 void *desc;
73 {
74 usb_device_request_t req;
75
76 req.bmRequestType = UT_READ_DEVICE;
77 req.bRequest = UR_GET_DESCRIPTOR;
78 USETW2(req.wValue, type, index);
79 USETW(req.wIndex, 0);
80 USETW(req.wLength, len);
81 return (usbd_do_request(dev, &req, desc));
82 }
83
84 usbd_status
85 usbd_get_config_desc(dev, conf, d)
86 usbd_device_handle dev;
87 int conf;
88 usb_config_descriptor_t *d;
89 {
90 usbd_status err;
91
92 DPRINTFN(3,("usbd_get_config_desc: conf=%d\n", conf));
93 err = usbd_get_desc(dev, UDESC_CONFIG, conf,
94 USB_CONFIG_DESCRIPTOR_SIZE, d);
95 if (err)
96 return (err);
97 if (d->bDescriptorType != UDESC_CONFIG) {
98 DPRINTFN(-1,("usbd_get_config_desc: conf %d, bad desc %d\n",
99 conf, d->bDescriptorType));
100 return (USBD_INVAL);
101 }
102 return (USBD_NORMAL_COMPLETION);
103 }
104
105 usbd_status
106 usbd_get_config_desc_full(dev, conf, d, size)
107 usbd_device_handle dev;
108 int conf;
109 void *d;
110 int size;
111 {
112 DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf));
113 return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d));
114 }
115
116 usbd_status
117 usbd_get_device_desc(dev, d)
118 usbd_device_handle dev;
119 usb_device_descriptor_t *d;
120 {
121 DPRINTFN(3,("usbd_get_device_desc:\n"));
122 return (usbd_get_desc(dev, UDESC_DEVICE,
123 0, USB_DEVICE_DESCRIPTOR_SIZE, d));
124 }
125
126 usbd_status
127 usbd_get_device_status(dev, st)
128 usbd_device_handle dev;
129 usb_status_t *st;
130 {
131 usb_device_request_t req;
132
133 req.bmRequestType = UT_READ_DEVICE;
134 req.bRequest = UR_GET_STATUS;
135 USETW(req.wValue, 0);
136 USETW(req.wIndex, 0);
137 USETW(req.wLength, sizeof(usb_status_t));
138 return (usbd_do_request(dev, &req, st));
139 }
140
141 usbd_status
142 usbd_get_hub_status(dev, st)
143 usbd_device_handle dev;
144 usb_hub_status_t *st;
145 {
146 usb_device_request_t req;
147
148 req.bmRequestType = UT_READ_CLASS_DEVICE;
149 req.bRequest = UR_GET_STATUS;
150 USETW(req.wValue, 0);
151 USETW(req.wIndex, 0);
152 USETW(req.wLength, sizeof(usb_hub_status_t));
153 return (usbd_do_request(dev, &req, st));
154 }
155
156 usbd_status
157 usbd_set_address(dev, addr)
158 usbd_device_handle dev;
159 int addr;
160 {
161 usb_device_request_t req;
162
163 req.bmRequestType = UT_WRITE_DEVICE;
164 req.bRequest = UR_SET_ADDRESS;
165 USETW(req.wValue, addr);
166 USETW(req.wIndex, 0);
167 USETW(req.wLength, 0);
168 return usbd_do_request(dev, &req, 0);
169 }
170
171 usbd_status
172 usbd_get_port_status(dev, port, ps)
173 usbd_device_handle dev;
174 int port;
175 usb_port_status_t *ps;
176 {
177 usb_device_request_t req;
178
179 req.bmRequestType = UT_READ_CLASS_OTHER;
180 req.bRequest = UR_GET_STATUS;
181 USETW(req.wValue, 0);
182 USETW(req.wIndex, port);
183 USETW(req.wLength, sizeof *ps);
184 return (usbd_do_request(dev, &req, ps));
185 }
186
187 usbd_status
188 usbd_clear_hub_feature(dev, sel)
189 usbd_device_handle dev;
190 int sel;
191 {
192 usb_device_request_t req;
193
194 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
195 req.bRequest = UR_CLEAR_FEATURE;
196 USETW(req.wValue, sel);
197 USETW(req.wIndex, 0);
198 USETW(req.wLength, 0);
199 return (usbd_do_request(dev, &req, 0));
200 }
201
202 usbd_status
203 usbd_set_hub_feature(dev, sel)
204 usbd_device_handle dev;
205 int sel;
206 {
207 usb_device_request_t req;
208
209 req.bmRequestType = UT_WRITE_CLASS_DEVICE;
210 req.bRequest = UR_SET_FEATURE;
211 USETW(req.wValue, sel);
212 USETW(req.wIndex, 0);
213 USETW(req.wLength, 0);
214 return (usbd_do_request(dev, &req, 0));
215 }
216
217 usbd_status
218 usbd_clear_port_feature(dev, port, sel)
219 usbd_device_handle dev;
220 int port, sel;
221 {
222 usb_device_request_t req;
223
224 req.bmRequestType = UT_WRITE_CLASS_OTHER;
225 req.bRequest = UR_CLEAR_FEATURE;
226 USETW(req.wValue, sel);
227 USETW(req.wIndex, port);
228 USETW(req.wLength, 0);
229 return (usbd_do_request(dev, &req, 0));
230 }
231
232 usbd_status
233 usbd_set_port_feature(dev, port, sel)
234 usbd_device_handle dev;
235 int port, sel;
236 {
237 usb_device_request_t req;
238
239 req.bmRequestType = UT_WRITE_CLASS_OTHER;
240 req.bRequest = UR_SET_FEATURE;
241 USETW(req.wValue, sel);
242 USETW(req.wIndex, port);
243 USETW(req.wLength, 0);
244 return (usbd_do_request(dev, &req, 0));
245 }
246
247
248 usbd_status
249 usbd_set_protocol(iface, report)
250 usbd_interface_handle iface;
251 int report;
252 {
253 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
254 usbd_device_handle dev;
255 usb_device_request_t req;
256 usbd_status err;
257
258 DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
259 iface, report, id->bInterfaceNumber));
260 if (id == NULL)
261 return (USBD_IOERROR);
262 err = usbd_interface2device_handle(iface, &dev);
263 if (err)
264 return (err);
265 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
266 req.bRequest = UR_SET_PROTOCOL;
267 USETW(req.wValue, report);
268 USETW(req.wIndex, id->bInterfaceNumber);
269 USETW(req.wLength, 0);
270 return (usbd_do_request(dev, &req, 0));
271 }
272
273 usbd_status
274 usbd_set_report(iface, type, id, data, len)
275 usbd_interface_handle iface;
276 int type;
277 int id;
278 void *data;
279 int len;
280 {
281 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
282 usbd_device_handle dev;
283 usb_device_request_t req;
284 usbd_status err;
285
286 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
287 if (ifd == NULL)
288 return (USBD_IOERROR);
289 err = usbd_interface2device_handle(iface, &dev);
290 if (err)
291 return (err);
292 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
293 req.bRequest = UR_SET_REPORT;
294 USETW2(req.wValue, type, id);
295 USETW(req.wIndex, ifd->bInterfaceNumber);
296 USETW(req.wLength, len);
297 return (usbd_do_request(dev, &req, data));
298 }
299
300 usbd_status
301 usbd_set_report_async(iface, type, id, data, len)
302 usbd_interface_handle iface;
303 int type;
304 int id;
305 void *data;
306 int len;
307 {
308 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
309 usbd_device_handle dev;
310 usb_device_request_t req;
311 usbd_status err;
312
313 DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
314 if (ifd == NULL)
315 return (USBD_IOERROR);
316 err = usbd_interface2device_handle(iface, &dev);
317 if (err)
318 return (err);
319 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
320 req.bRequest = UR_SET_REPORT;
321 USETW2(req.wValue, type, id);
322 USETW(req.wIndex, ifd->bInterfaceNumber);
323 USETW(req.wLength, len);
324 return (usbd_do_request_async(dev, &req, data));
325 }
326
327 usbd_status
328 usbd_get_report(iface, type, id, data, len)
329 usbd_interface_handle iface;
330 int type;
331 int id;
332 void *data;
333 int len;
334 {
335 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
336 usbd_device_handle dev;
337 usb_device_request_t req;
338 usbd_status err;
339
340 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
341 if (id == NULL)
342 return (USBD_IOERROR);
343 err = usbd_interface2device_handle(iface, &dev);
344 if (err)
345 return (err);
346 req.bmRequestType = UT_READ_CLASS_INTERFACE;
347 req.bRequest = UR_GET_REPORT;
348 USETW2(req.wValue, type, id);
349 USETW(req.wIndex, ifd->bInterfaceNumber);
350 USETW(req.wLength, len);
351 return (usbd_do_request(dev, &req, data));
352 }
353
354 usbd_status
355 usbd_set_idle(iface, duration, id)
356 usbd_interface_handle iface;
357 int duration;
358 int id;
359 {
360 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
361 usbd_device_handle dev;
362 usb_device_request_t req;
363 usbd_status err;
364
365 DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
366 if (ifd == NULL)
367 return (USBD_IOERROR);
368 err = usbd_interface2device_handle(iface, &dev);
369 if (err)
370 return (err);
371 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
372 req.bRequest = UR_SET_IDLE;
373 USETW2(req.wValue, duration, id);
374 USETW(req.wIndex, ifd->bInterfaceNumber);
375 USETW(req.wLength, 0);
376 return (usbd_do_request(dev, &req, 0));
377 }
378
379 usbd_status
380 usbd_get_report_descriptor(dev, ifcno, repid, size, d)
381 usbd_device_handle dev;
382 int ifcno;
383 int repid;
384 int size;
385 void *d;
386 {
387 usb_device_request_t req;
388
389 req.bmRequestType = UT_READ_INTERFACE;
390 req.bRequest = UR_GET_DESCRIPTOR;
391 USETW2(req.wValue, UDESC_REPORT, repid);
392 USETW(req.wIndex, ifcno);
393 USETW(req.wLength, size);
394 return (usbd_do_request(dev, &req, d));
395 }
396
397 usb_hid_descriptor_t *
398 usbd_get_hid_descriptor(ifc)
399 usbd_interface_handle ifc;
400 {
401 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
402 usbd_device_handle dev;
403 usb_config_descriptor_t *cdesc;
404 usb_hid_descriptor_t *hd;
405 char *p, *end;
406 usbd_status err;
407
408 if (idesc == NULL)
409 return (0);
410 err = usbd_interface2device_handle(ifc, &dev);
411 if (err)
412 return (0);
413 cdesc = usbd_get_config_descriptor(dev);
414
415 p = (char *)idesc + idesc->bLength;
416 end = (char *)cdesc + UGETW(cdesc->wTotalLength);
417
418 for (; p < end; p += hd->bLength) {
419 hd = (usb_hid_descriptor_t *)p;
420 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
421 return (hd);
422 if (hd->bDescriptorType == UDESC_INTERFACE)
423 break;
424 }
425 return (0);
426 }
427
428 usbd_status
429 usbd_alloc_report_desc(ifc, descp, sizep, mem)
430 usbd_interface_handle ifc;
431 void **descp;
432 int *sizep;
433 #if defined(__NetBSD__) || defined(__OpenBSD__)
434 int mem;
435 #elif defined(__FreeBSD__)
436 struct malloc_type *mem;
437 #endif
438
439 {
440 usb_interface_descriptor_t *id;
441 usb_hid_descriptor_t *hid;
442 usbd_device_handle dev;
443 usbd_status err;
444
445 err = usbd_interface2device_handle(ifc, &dev);
446 if (err)
447 return (err);
448 id = usbd_get_interface_descriptor(ifc);
449 if (id == NULL)
450 return (USBD_INVAL);
451 hid = usbd_get_hid_descriptor(ifc);
452 if (hid == NULL)
453 return (USBD_IOERROR);
454 *sizep = UGETW(hid->descrs[0].wDescriptorLength);
455 *descp = malloc(*sizep, mem, M_NOWAIT);
456 if (*descp == NULL)
457 return (USBD_NOMEM);
458 /* XXX should not use 0 Report ID */
459 err = usbd_get_report_descriptor(dev, id->bInterfaceNumber, 0,
460 *sizep, *descp);
461 if (err) {
462 free(*descp, mem);
463 return (err);
464 }
465 return (USBD_NORMAL_COMPLETION);
466 }
467
468 usbd_status
469 usbd_get_config(dev, conf)
470 usbd_device_handle dev;
471 u_int8_t *conf;
472 {
473 usb_device_request_t req;
474
475 req.bmRequestType = UT_READ_DEVICE;
476 req.bRequest = UR_GET_CONFIG;
477 USETW(req.wValue, 0);
478 USETW(req.wIndex, 0);
479 USETW(req.wLength, 1);
480 return (usbd_do_request(dev, &req, conf));
481 }
482
483 static void usbd_bulk_transfer_cb __P((usbd_xfer_handle xfer,
484 usbd_private_handle priv, usbd_status status));
485 static void
486 usbd_bulk_transfer_cb(xfer, priv, status)
487 usbd_xfer_handle xfer;
488 usbd_private_handle priv;
489 usbd_status status;
490 {
491 wakeup(xfer);
492 }
493
494 usbd_status
495 usbd_bulk_transfer(xfer, pipe, flags, timeout, buf, size, lbl)
496 usbd_xfer_handle xfer;
497 usbd_pipe_handle pipe;
498 u_int16_t flags;
499 u_int32_t timeout;
500 void *buf;
501 u_int32_t *size;
502 char *lbl;
503 {
504 usbd_status err;
505 int s, error;
506
507 usbd_setup_xfer(xfer, pipe, 0, buf, *size,
508 flags, timeout, usbd_bulk_transfer_cb);
509 DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size));
510 s = splusb(); /* don't want callback until tsleep() */
511 err = usbd_transfer(xfer);
512 if (err != USBD_IN_PROGRESS) {
513 splx(s);
514 return (err);
515 }
516 error = tsleep((caddr_t)xfer, PZERO | PCATCH, lbl, 0);
517 splx(s);
518 if (error) {
519 DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error));
520 usbd_abort_pipe(pipe);
521 return (USBD_INTERRUPTED);
522 }
523 usbd_get_xfer_status(xfer, 0, 0, size, &err);
524 DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size));
525 if (err) {
526 DPRINTF(("usbd_bulk_transfer: error=%d\n", err));
527 usbd_clear_endpoint_stall(pipe);
528 }
529 return (err);
530 }
531
532 void
533 usb_detach_wait(dv)
534 device_ptr_t dv;
535 {
536 DPRINTF(("usb_detach_wait: waiting for %s\n", USBDEVPTRNAME(dv)));
537 if (tsleep(dv, PZERO, "usbdet", hz * 60))
538 printf("usb_detach_wait: %s didn't detach\n",
539 USBDEVPTRNAME(dv));
540 DPRINTF(("usb_detach_wait: %s done\n", USBDEVPTRNAME(dv)));
541 }
542
543 void
544 usb_detach_wakeup(dv)
545 device_ptr_t dv;
546 {
547 DPRINTF(("usb_detach_wakeup: for %s\n", USBDEVPTRNAME(dv)));
548 wakeup(dv);
549 }
550