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