usbdi_util.c revision 1.4 1 /* $NetBSD: usbdi_util.c,v 1.4 1998/08/02 22:30:53 augustss Exp $ */
2
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Author: Lennart Augustsson <augustss (at) carlstedt.se>
8 * Carlstedt Research & Technology
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/device.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 #include "opt_usbverbose.h"
54
55 #ifdef USB_DEBUG
56 #define DPRINTF(x) if (usbdebug) printf x
57 #define DPRINTFN(n,x) if (usbdebug>(n)) printf x
58 extern int usbdebug;
59 #else
60 #define DPRINTF(x)
61 #define DPRINTFN(n,x)
62 #endif
63
64 usbd_status
65 usbd_get_desc(dev, type, index, len, desc)
66 usbd_device_handle dev;
67 int type, index;
68 int len;
69 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(dev, conf, d)
83 usbd_device_handle dev;
84 int conf;
85 usb_config_descriptor_t *d;
86 {
87 DPRINTFN(3,("usbd_get_config_desc: conf=%d\n", conf));
88 return (usbd_get_desc(dev, UDESC_CONFIG,
89 conf, USB_CONFIG_DESCRIPTOR_SIZE, d));
90 }
91
92 usbd_status
93 usbd_get_config_desc_full(dev, conf, d, size)
94 usbd_device_handle dev;
95 int conf;
96 void *d;
97 int size;
98 {
99 DPRINTFN(3,("usbd_get_config_desc_full: conf=%d\n", conf));
100 return (usbd_get_desc(dev, UDESC_CONFIG, conf, size, d));
101 }
102
103 usbd_status
104 usbd_get_device_desc(dev, d)
105 usbd_device_handle dev;
106 usb_device_descriptor_t *d;
107 {
108 DPRINTFN(3,("usbd_get_device_desc:\n"));
109 return (usbd_get_desc(dev, UDESC_DEVICE,
110 0, USB_DEVICE_DESCRIPTOR_SIZE, d));
111 }
112
113 usbd_status
114 usbd_get_device_status(dev, st)
115 usbd_device_handle dev;
116 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(dev, st)
130 usbd_device_handle dev;
131 usb_hub_status_t *st;
132 {
133 usb_device_request_t req;
134
135 req.bmRequestType = UT_READ_CLASS_DEVICE;
136 req.bRequest = UR_GET_STATUS;
137 USETW(req.wValue, 0);
138 USETW(req.wIndex, 0);
139 USETW(req.wLength, sizeof(usb_hub_status_t));
140 return (usbd_do_request(dev, &req, st));
141 }
142
143 usbd_status
144 usbd_set_address(dev, addr)
145 usbd_device_handle dev;
146 int addr;
147 {
148 usb_device_request_t req;
149
150 req.bmRequestType = UT_WRITE_DEVICE;
151 req.bRequest = UR_SET_ADDRESS;
152 USETW(req.wValue, addr);
153 USETW(req.wIndex, 0);
154 USETW(req.wLength, 0);
155 return usbd_do_request(dev, &req, 0);
156 }
157
158 usbd_status
159 usbd_get_port_status(dev, port, ps)
160 usbd_device_handle dev;
161 int port;
162 usb_port_status_t *ps;
163 {
164 usb_device_request_t req;
165
166 req.bmRequestType = UT_READ_CLASS_OTHER;
167 req.bRequest = UR_GET_STATUS;
168 USETW(req.wValue, 0);
169 USETW(req.wIndex, port);
170 USETW(req.wLength, sizeof *ps);
171 return (usbd_do_request(dev, &req, ps));
172 }
173
174 usbd_status
175 usbd_clear_port_feature(dev, port, sel)
176 usbd_device_handle dev;
177 int port, sel;
178 {
179 usb_device_request_t req;
180
181 req.bmRequestType = UT_WRITE_CLASS_OTHER;
182 req.bRequest = UR_CLEAR_FEATURE;
183 USETW(req.wValue, sel);
184 USETW(req.wIndex, port);
185 USETW(req.wLength, 0);
186 return (usbd_do_request(dev, &req, 0));
187 }
188
189 usbd_status
190 usbd_set_port_feature(dev, port, sel)
191 usbd_device_handle dev;
192 int port, sel;
193 {
194 usb_device_request_t req;
195
196 req.bmRequestType = UT_WRITE_CLASS_OTHER;
197 req.bRequest = UR_SET_FEATURE;
198 USETW(req.wValue, sel);
199 USETW(req.wIndex, port);
200 USETW(req.wLength, 0);
201 return (usbd_do_request(dev, &req, 0));
202 }
203
204
205 usbd_status
206 usbd_set_protocol(iface, report)
207 usbd_interface_handle iface;
208 int report;
209 {
210 usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
211 usbd_device_handle dev;
212 usb_device_request_t req;
213 usbd_status r;
214
215 DPRINTFN(4, ("usbd_set_protocol: iface=%p, report=%d, endpt=%d\n",
216 iface, report, id->bInterfaceNumber));
217 r = usbd_interface2device_handle(iface, &dev);
218 if (r != USBD_NORMAL_COMPLETION)
219 return (r);
220 if (!id)
221 return (USBD_INVAL);
222 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
223 req.bRequest = UR_SET_PROTOCOL;
224 USETW(req.wValue, report);
225 USETW(req.wIndex, id->bInterfaceNumber);
226 USETW(req.wLength, 0);
227 return (usbd_do_request(dev, &req, 0));
228 }
229
230 usbd_status
231 usbd_set_report(iface, type, id, data, len)
232 usbd_interface_handle iface;
233 int type;
234 int id;
235 void *data;
236 int len;
237 {
238 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
239 usbd_device_handle dev;
240 usb_device_request_t req;
241 usbd_status r;
242
243 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
244 r = usbd_interface2device_handle(iface, &dev);
245 if (r != USBD_NORMAL_COMPLETION)
246 return (r);
247 if (!ifd)
248 return (USBD_INVAL);
249 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
250 req.bRequest = UR_SET_REPORT;
251 USETW2(req.wValue, type, id);
252 USETW(req.wIndex, ifd->bInterfaceNumber);
253 USETW(req.wLength, len);
254 return (usbd_do_request(dev, &req, data));
255 }
256
257 usbd_status
258 usbd_set_report_async(iface, type, id, data, len)
259 usbd_interface_handle iface;
260 int type;
261 int id;
262 void *data;
263 int len;
264 {
265 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
266 usbd_device_handle dev;
267 usb_device_request_t req;
268 usbd_status r;
269
270 DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
271 r = usbd_interface2device_handle(iface, &dev);
272 if (r != USBD_NORMAL_COMPLETION)
273 return (r);
274 if (!ifd)
275 return (USBD_INVAL);
276 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
277 req.bRequest = UR_SET_REPORT;
278 USETW2(req.wValue, type, id);
279 USETW(req.wIndex, ifd->bInterfaceNumber);
280 USETW(req.wLength, len);
281 return (usbd_do_request_async(dev, &req, data));
282 }
283
284 usbd_status
285 usbd_get_report(iface, type, id, data, len)
286 usbd_interface_handle iface;
287 int type;
288 int id;
289 void *data;
290 int len;
291 {
292 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
293 usbd_device_handle dev;
294 usb_device_request_t req;
295 usbd_status r;
296
297 DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
298 r = usbd_interface2device_handle(iface, &dev);
299 if (r != USBD_NORMAL_COMPLETION)
300 return (r);
301 if (!ifd)
302 return (USBD_INVAL);
303 req.bmRequestType = UT_READ_CLASS_INTERFACE;
304 req.bRequest = UR_GET_REPORT;
305 USETW2(req.wValue, type, id);
306 USETW(req.wIndex, ifd->bInterfaceNumber);
307 USETW(req.wLength, len);
308 return (usbd_do_request(dev, &req, data));
309 }
310
311 usbd_status
312 usbd_set_idle(iface, duration, id)
313 usbd_interface_handle iface;
314 int duration;
315 int id;
316 {
317 usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
318 usbd_device_handle dev;
319 usb_device_request_t req;
320 usbd_status r;
321
322 DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
323 r = usbd_interface2device_handle(iface, &dev);
324 if (r != USBD_NORMAL_COMPLETION)
325 return (r);
326 if (!ifd)
327 return (USBD_INVAL);
328 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
329 req.bRequest = UR_SET_IDLE;
330 USETW2(req.wValue, duration, id);
331 USETW(req.wIndex, ifd->bInterfaceNumber);
332 USETW(req.wLength, 0);
333 return (usbd_do_request(dev, &req, 0));
334 }
335
336 usbd_status
337 usbd_get_report_descriptor(dev, i, size, d)
338 usbd_device_handle dev;
339 int i;
340 int size;
341 void *d;
342 {
343 usb_device_request_t req;
344
345 req.bmRequestType = UT_READ_INTERFACE;
346 req.bRequest = UR_GET_DESCRIPTOR;
347 USETW2(req.wValue, UDESC_REPORT, 0);
348 USETW(req.wIndex, i);
349 USETW(req.wLength, size);
350 return (usbd_do_request(dev, &req, d));
351 }
352
353 usb_hid_descriptor_t *
354 usbd_get_hid_descriptor(ifc)
355 usbd_interface_handle ifc;
356 {
357 usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
358 usbd_device_handle dev;
359 usb_config_descriptor_t *cdesc;
360 usb_hid_descriptor_t *hd;
361 char *p, *end;
362 usbd_status r;
363
364 r = usbd_interface2device_handle(ifc, &dev);
365 if (r != USBD_NORMAL_COMPLETION)
366 return (0);
367 cdesc = usbd_get_config_descriptor(dev);
368
369 p = (char *)idesc + idesc->bLength;
370 end = (char *)cdesc + UGETW(cdesc->wTotalLength);
371
372 for (; p < end; p += hd->bLength) {
373 hd = (usb_hid_descriptor_t *)p;
374 if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
375 return (hd);
376 if (hd->bDescriptorType == UDESC_INTERFACE)
377 break;
378 }
379 return (0);
380 }
381
382 usbd_status
383 usbd_alloc_report_desc(ifc, descp, sizep, mem)
384 usbd_interface_handle ifc;
385 void **descp;
386 int *sizep;
387 int mem;
388 {
389 usb_hid_descriptor_t *hid;
390 usbd_device_handle dev;
391 usbd_status r;
392
393 r = usbd_interface2device_handle(ifc, &dev);
394 if (r != USBD_NORMAL_COMPLETION)
395 return (r);
396 hid = usbd_get_hid_descriptor(ifc);
397 if (!hid)
398 return (USBD_IOERROR);
399 *sizep = UGETW(hid->descrs[0].wDescriptorLength);
400 *descp = malloc(*sizep, mem, M_NOWAIT);
401 if (!*descp)
402 return (USBD_NOMEM);
403 r = usbd_get_report_descriptor(dev, 0, *sizep, *descp);
404 if (r != USBD_NORMAL_COMPLETION) {
405 free(*descp, mem);
406 return (r);
407 }
408 return (USBD_NORMAL_COMPLETION);
409 }
410