usbdi_util.c revision 1.11 1 /* $NetBSD: usbdi_util.c,v 1.11 1999/01/03 01:00:56 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/select.h>
46
47 #include <dev/usb/usb.h>
48 #include <dev/usb/usbhid.h>
49
50 #include <dev/usb/usbdi.h>
51 #include <dev/usb/usbdi_util.h>
52
53 #ifdef USB_DEBUG
54 #define DPRINTF(x) if (usbdebug) printf x
55 #define DPRINTFN(n,x) if (usbdebug>(n)) printf x
56 extern int usbdebug;
57 #else
58 #define DPRINTF(x)
59 #define DPRINTFN(n,x)
60 #endif
61
62 usbd_status
63 usbd_get_desc(dev, type, index, len, desc)
64 usbd_device_handle dev;
65 int type, index;
66 int len;
67 void *desc;
68 {
69 usb_device_request_t req;
70
71 req.bmRequestType = UT_READ_DEVICE;
72 req.bRequest = UR_GET_DESCRIPTOR;
73 USETW2(req.wValue, type, index);
74 USETW(req.wIndex, 0);
75 USETW(req.wLength, len);
76 return (usbd_do_request(dev, &req, desc));
77 }
78
79 usbd_status
80 usbd_get_config_desc(dev, conf, d)
81 usbd_device_handle dev;
82 int conf;
83 usb_config_descriptor_t *d;
84 {
85 usbd_status r;
86
87 DPRINTFN(3,("usbd_get_config_desc: conf=%d\n", conf));
88 r = usbd_get_desc(dev, UDESC_CONFIG, conf,
89 USB_CONFIG_DESCRIPTOR_SIZE, d);
90 if (r != USBD_NORMAL_COMPLETION)
91 return (r);
92 if (d->bDescriptorType != UDESC_CONFIG) {
93 DPRINTFN(-1,("usbd_get_config_desc: conf %d, bad desc %d\n",
94 conf, d->bDescriptorType));
95 return (USBD_INVAL);
96 }
97 return (USBD_NORMAL_COMPLETION);
98 }
99
100 usbd_status
101 usbd_get_config_desc_full(dev, conf, d, size)
102 usbd_device_handle dev;
103 int conf;
104 void *d;
105 int size;
106 {
107 DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf));
108 return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d));
109 }
110
111 usbd_status
112 usbd_get_device_desc(dev, d)
113 usbd_device_handle dev;
114 usb_device_descriptor_t *d;
115 {
116 DPRINTFN(3,("usbd_get_device_desc:\n"));
117 return (usbd_get_desc(dev, UDESC_DEVICE,
118 0, USB_DEVICE_DESCRIPTOR_SIZE, d));
119 }
120
121 usbd_status
122 usbd_get_device_status(dev, st)
123 usbd_device_handle dev;
124 usb_status_t *st;
125 {
126 usb_device_request_t req;
127
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));
134 }
135
136 usbd_status
137 usbd_get_hub_status(dev, st)
138 usbd_device_handle dev;
139 usb_hub_status_t *st;
140 {
141 usb_device_request_t req;
142
143 req.bmRequestType = UT_READ_CLASS_DEVICE;
144 req.bRequest = UR_GET_STATUS;
145 USETW(req.wValue, 0);
146 USETW(req.wIndex, 0);
147 USETW(req.wLength, sizeof(usb_hub_status_t));
148 return (usbd_do_request(dev, &req, st));
149 }
150
151 usbd_status
152 usbd_set_address(dev, addr)
153 usbd_device_handle dev;
154 int addr;
155 {
156 usb_device_request_t req;
157
158 req.bmRequestType = UT_WRITE_DEVICE;
159 req.bRequest = UR_SET_ADDRESS;
160 USETW(req.wValue, addr);
161 USETW(req.wIndex, 0);
162 USETW(req.wLength, 0);
163 return usbd_do_request(dev, &req, 0);
164 }
165
166 usbd_status
167 usbd_get_port_status(dev, port, ps)
168 usbd_device_handle dev;
169 int port;
170 usb_port_status_t *ps;
171 {
172 usb_device_request_t req;
173
174 req.bmRequestType = UT_READ_CLASS_OTHER;
175 req.bRequest = UR_GET_STATUS;
176 USETW(req.wValue, 0);
177 USETW(req.wIndex, port);
178 USETW(req.wLength, sizeof *ps);
179 return (usbd_do_request(dev, &req, ps));
180 }
181
182 usbd_status
183 usbd_clear_port_feature(dev, port, sel)
184 usbd_device_handle dev;
185 int port, sel;
186 {
187 usb_device_request_t req;
188
189 req.bmRequestType = UT_WRITE_CLASS_OTHER;
190 req.bRequest = UR_CLEAR_FEATURE;
191 USETW(req.wValue, sel);
192 USETW(req.wIndex, port);
193 USETW(req.wLength, 0);
194 return (usbd_do_request(dev, &req, 0));
195 }
196
197 usbd_status
198 usbd_set_port_feature(dev, port, sel)
199 usbd_device_handle dev;
200 int port, sel;
201 {
202 usb_device_request_t req;
203
204 req.bmRequestType = UT_WRITE_CLASS_OTHER;
205 req.bRequest = UR_SET_FEATURE;
206 USETW(req.wValue, sel);
207 USETW(req.wIndex, port);
208 USETW(req.wLength, 0);
209 return (usbd_do_request(dev, &req, 0));
210 }
211
212
213 usbd_status
214 usbd_set_protocol(iface, report)
215 usbd_interface_handle iface;
216 int report;
217 {
218 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
219 usbd_device_handle dev;
220 usb_device_request_t req;
221 usbd_status r;
222
223 DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
224 iface, report, id->bInterfaceNumber));
225 if (!id)
226 return (USBD_IOERROR);
227 r = usbd_interface2device_handle(iface, &dev);
228 if (r != USBD_NORMAL_COMPLETION)
229 return (r);
230 if (!id)
231 return (USBD_INVAL);
232 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
233 req.bRequest = UR_SET_PROTOCOL;
234 USETW(req.wValue, report);
235 USETW(req.wIndex, id->bInterfaceNumber);
236 USETW(req.wLength, 0);
237 return (usbd_do_request(dev, &req, 0));
238 }
239
240 usbd_status
241 usbd_set_report(iface, type, id, data, len)
242 usbd_interface_handle iface;
243 int type;
244 int id;
245 void *data;
246 int len;
247 {
248 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
249 usbd_device_handle dev;
250 usb_device_request_t req;
251 usbd_status r;
252
253 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
254 if (!ifd)
255 return (USBD_IOERROR);
256 r = usbd_interface2device_handle(iface, &dev);
257 if (r != USBD_NORMAL_COMPLETION)
258 return (r);
259 if (!ifd)
260 return (USBD_INVAL);
261 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
262 req.bRequest = UR_SET_REPORT;
263 USETW2(req.wValue, type, id);
264 USETW(req.wIndex, ifd->bInterfaceNumber);
265 USETW(req.wLength, len);
266 return (usbd_do_request(dev, &req, data));
267 }
268
269 usbd_status
270 usbd_set_report_async(iface, type, id, data, len)
271 usbd_interface_handle iface;
272 int type;
273 int id;
274 void *data;
275 int len;
276 {
277 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
278 usbd_device_handle dev;
279 usb_device_request_t req;
280 usbd_status r;
281
282 DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
283 if (!ifd)
284 return (USBD_IOERROR);
285 r = usbd_interface2device_handle(iface, &dev);
286 if (r != USBD_NORMAL_COMPLETION)
287 return (r);
288 if (!ifd)
289 return (USBD_INVAL);
290 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
291 req.bRequest = UR_SET_REPORT;
292 USETW2(req.wValue, type, id);
293 USETW(req.wIndex, ifd->bInterfaceNumber);
294 USETW(req.wLength, len);
295 return (usbd_do_request_async(dev, &req, data));
296 }
297
298 usbd_status
299 usbd_get_report(iface, type, id, data, len)
300 usbd_interface_handle iface;
301 int type;
302 int id;
303 void *data;
304 int len;
305 {
306 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
307 usbd_device_handle dev;
308 usb_device_request_t req;
309 usbd_status r;
310
311 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
312 if (!id)
313 return (USBD_IOERROR);
314 r = usbd_interface2device_handle(iface, &dev);
315 if (r != USBD_NORMAL_COMPLETION)
316 return (r);
317 if (!ifd)
318 return (USBD_INVAL);
319 req.bmRequestType = UT_READ_CLASS_INTERFACE;
320 req.bRequest = UR_GET_REPORT;
321 USETW2(req.wValue, type, id);
322 USETW(req.wIndex, ifd->bInterfaceNumber);
323 USETW(req.wLength, len);
324 return (usbd_do_request(dev, &req, data));
325 }
326
327 usbd_status
328 usbd_set_idle(iface, duration, id)
329 usbd_interface_handle iface;
330 int duration;
331 int id;
332 {
333 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
334 usbd_device_handle dev;
335 usb_device_request_t req;
336 usbd_status r;
337
338 DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
339 if (!ifd)
340 return (USBD_IOERROR);
341 r = usbd_interface2device_handle(iface, &dev);
342 if (r != USBD_NORMAL_COMPLETION)
343 return (r);
344 if (!ifd)
345 return (USBD_INVAL);
346 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
347 req.bRequest = UR_SET_IDLE;
348 USETW2(req.wValue, duration, id);
349 USETW(req.wIndex, ifd->bInterfaceNumber);
350 USETW(req.wLength, 0);
351 return (usbd_do_request(dev, &req, 0));
352 }
353
354 usbd_status
355 usbd_get_report_descriptor(dev, ifcno, repid, size, d)
356 usbd_device_handle dev;
357 int ifcno;
358 int repid;
359 int size;
360 void *d;
361 {
362 usb_device_request_t req;
363
364 req.bmRequestType = UT_READ_INTERFACE;
365 req.bRequest = UR_GET_DESCRIPTOR;
366 USETW2(req.wValue, UDESC_REPORT, repid);
367 USETW(req.wIndex, ifcno);
368 USETW(req.wLength, size);
369 return (usbd_do_request(dev, &req, d));
370 }
371
372 usb_hid_descriptor_t *
373 usbd_get_hid_descriptor(ifc)
374 usbd_interface_handle ifc;
375 {
376 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
377 usbd_device_handle dev;
378 usb_config_descriptor_t *cdesc;
379 usb_hid_descriptor_t *hd;
380 char *p, *end;
381 usbd_status r;
382
383 if (!idesc)
384 return (0);
385 r = usbd_interface2device_handle(ifc, &dev);
386 if (r != USBD_NORMAL_COMPLETION)
387 return (0);
388 cdesc = usbd_get_config_descriptor(dev);
389
390 p = (char *)idesc + idesc->bLength;
391 end = (char *)cdesc + UGETW(cdesc->wTotalLength);
392
393 for (; p < end; p += hd->bLength) {
394 hd = (usb_hid_descriptor_t *)p;
395 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
396 return (hd);
397 if (hd->bDescriptorType == UDESC_INTERFACE)
398 break;
399 }
400 return (0);
401 }
402
403 usbd_status
404 usbd_alloc_report_desc(ifc, descp, sizep, mem)
405 usbd_interface_handle ifc;
406 void **descp;
407 int *sizep;
408 #if defined(__NetBSD__)
409 int mem;
410 #elif defined(__FreeBSD__)
411 struct malloc_type *mem;
412 #endif
413
414 {
415 usb_interface_descriptor_t *id;
416 usb_hid_descriptor_t *hid;
417 usbd_device_handle dev;
418 usbd_status r;
419
420 r = usbd_interface2device_handle(ifc, &dev);
421 if (r != USBD_NORMAL_COMPLETION)
422 return (r);
423 id = usbd_get_interface_descriptor(ifc);
424 if (!id)
425 return (USBD_INVAL);
426 hid = usbd_get_hid_descriptor(ifc);
427 if (!hid)
428 return (USBD_IOERROR);
429 *sizep = UGETW(hid->descrs[0].wDescriptorLength);
430 *descp = malloc(*sizep, mem, M_NOWAIT);
431 if (!*descp)
432 return (USBD_NOMEM);
433 /* XXX should not use 0 Report ID */
434 r = usbd_get_report_descriptor(dev, id->bInterfaceNumber, 0,
435 *sizep, *descp);
436 if (r != USBD_NORMAL_COMPLETION) {
437 free(*descp, mem);
438 return (r);
439 }
440 return (USBD_NORMAL_COMPLETION);
441 }
442
443 usbd_status
444 usbd_get_config(dev, conf)
445 usbd_device_handle dev;
446 u_int8_t *conf;
447 {
448 usb_device_request_t req;
449
450 req.bmRequestType = UT_READ_DEVICE;
451 req.bRequest = UR_GET_CONFIG;
452 USETW(req.wValue, 0);
453 USETW(req.wIndex, 0);
454 USETW(req.wLength, 1);
455 return (usbd_do_request(dev, &req, conf));
456 }
457
458 static void usbd_bulk_transfer_cb __P((usbd_request_handle reqh,
459 usbd_private_handle priv, usbd_status status));
460 static void
461 usbd_bulk_transfer_cb(reqh, priv, status)
462 usbd_request_handle reqh;
463 usbd_private_handle priv;
464 usbd_status status;
465 {
466 wakeup(reqh);
467 }
468
469 usbd_status
470 usbd_bulk_transfer(reqh, pipe, flags, buf, size, lbl)
471 usbd_request_handle reqh;
472 usbd_pipe_handle pipe;
473 u_int16_t flags;
474 void *buf;
475 u_int32_t *size;
476 char *lbl;
477 {
478 usbd_private_handle priv;
479 void *buffer;
480 usbd_status r;
481 int s, error;
482
483 r = usbd_setup_request(reqh, pipe, 0, buf, *size,
484 flags, USBD_NO_TIMEOUT, usbd_bulk_transfer_cb);
485 if (r != USBD_NORMAL_COMPLETION)
486 return (r);
487 DPRINTFN(1, ("usbd_bulk_transfer: transfer %d bytes\n", *size));
488 s = splusb(); /* don't want callback until tsleep() */
489 r = usbd_transfer(reqh);
490 if (r != USBD_IN_PROGRESS) {
491 splx(s);
492 return (r);
493 }
494 error = tsleep((caddr_t)reqh, PZERO | PCATCH, lbl, 0);
495 splx(s);
496 if (error) {
497 usbd_abort_pipe(pipe);
498 return (USBD_INTERRUPTED);
499 }
500 usbd_get_request_status(reqh, &priv, &buffer, size, &r);
501 if (r != USBD_NORMAL_COMPLETION) {
502 DPRINTF(("ugenread: error=%d\n", r));
503 usbd_clear_endpoint_stall(pipe);
504 }
505 return (r);
506 }
507
508