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