xref: /openbsd/sys/dev/usb/usbdi_util.c (revision 91f110e0)
1 /*	$OpenBSD: usbdi_util.c,v 1.35 2014/03/07 18:57:23 mpi Exp $ */
2 /*	$NetBSD: usbdi_util.c,v 1.40 2002/07/11 21:14:36 augustss Exp $	*/
3 /*	$FreeBSD: src/sys/dev/usb/usbdi_util.c,v 1.14 1999/11/17 22:33:50 n_hibma 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  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/device.h>
40 
41 #include <machine/bus.h>
42 
43 #include <dev/usb/usb.h>
44 #include <dev/usb/usbhid.h>
45 
46 #include <dev/usb/usbdi.h>
47 #include <dev/usb/usbdi_util.h>
48 #include <dev/usb/usbdivar.h>
49 
50 #ifdef USB_DEBUG
51 #define DPRINTF(x)	do { if (usbdebug) printf x; } while (0)
52 #define DPRINTFN(n,x)	do { if (usbdebug>(n)) printf x; } while (0)
53 extern int usbdebug;
54 #else
55 #define DPRINTF(x)
56 #define DPRINTFN(n,x)
57 #endif
58 
59 static void
60 usbd_interface2device_handle(struct usbd_interface *iface,
61     struct usbd_device **dev)
62 {
63 	*dev = iface->device;
64 }
65 
66 usbd_status
67 usbd_get_desc(struct usbd_device *dev, int type, int index, int len, void *desc)
68 {
69 	usb_device_request_t req;
70 
71 	DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n", type, index,
72 	    len));
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_device_status(struct usbd_device *dev, usb_status_t *st)
84 {
85 	usb_device_request_t req;
86 
87 	req.bmRequestType = UT_READ_DEVICE;
88 	req.bRequest = UR_GET_STATUS;
89 	USETW(req.wValue, 0);
90 	USETW(req.wIndex, 0);
91 	USETW(req.wLength, sizeof(usb_status_t));
92 	return (usbd_do_request(dev, &req, st));
93 }
94 
95 usbd_status
96 usbd_get_hub_status(struct usbd_device *dev, usb_hub_status_t *st)
97 {
98 	usb_device_request_t req;
99 
100 	req.bmRequestType = UT_READ_CLASS_DEVICE;
101 	req.bRequest = UR_GET_STATUS;
102 	USETW(req.wValue, 0);
103 	USETW(req.wIndex, 0);
104 	USETW(req.wLength, sizeof(usb_hub_status_t));
105 	return (usbd_do_request(dev, &req, st));
106 }
107 
108 usbd_status
109 usbd_get_hub_descriptor(struct usbd_device *dev, usb_hub_descriptor_t *hd,
110     uint8_t nports)
111 {
112 	usb_device_request_t req;
113 	uint16_t len = USB_HUB_DESCRIPTOR_SIZE + (nports + 1) / 8;
114 
115 	req.bmRequestType = UT_READ_CLASS_DEVICE;
116 	req.bRequest = UR_GET_DESCRIPTOR;
117 	USETW2(req.wValue, UDESC_HUB, 0);
118 	USETW(req.wIndex, 0);
119 	USETW(req.wLength, len);
120 	return (usbd_do_request(dev, &req, hd));
121 }
122 
123 usbd_status
124 usbd_set_address(struct usbd_device *dev, int addr)
125 {
126 	usb_device_request_t req;
127 
128 	req.bmRequestType = UT_WRITE_DEVICE;
129 	req.bRequest = UR_SET_ADDRESS;
130 	USETW(req.wValue, addr);
131 	USETW(req.wIndex, 0);
132 	USETW(req.wLength, 0);
133 	return usbd_do_request(dev, &req, 0);
134 }
135 
136 usbd_status
137 usbd_get_port_status(struct usbd_device *dev, int port, usb_port_status_t *ps)
138 {
139 	usb_device_request_t req;
140 
141 	req.bmRequestType = UT_READ_CLASS_OTHER;
142 	req.bRequest = UR_GET_STATUS;
143 	USETW(req.wValue, 0);
144 	USETW(req.wIndex, port);
145 	USETW(req.wLength, sizeof *ps);
146 	return (usbd_do_request(dev, &req, ps));
147 }
148 
149 usbd_status
150 usbd_clear_hub_feature(struct usbd_device *dev, int sel)
151 {
152 	usb_device_request_t req;
153 
154 	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
155 	req.bRequest = UR_CLEAR_FEATURE;
156 	USETW(req.wValue, sel);
157 	USETW(req.wIndex, 0);
158 	USETW(req.wLength, 0);
159 	return (usbd_do_request(dev, &req, 0));
160 }
161 
162 usbd_status
163 usbd_set_hub_feature(struct usbd_device *dev, int sel)
164 {
165 	usb_device_request_t req;
166 
167 	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
168 	req.bRequest = UR_SET_FEATURE;
169 	USETW(req.wValue, sel);
170 	USETW(req.wIndex, 0);
171 	USETW(req.wLength, 0);
172 	return (usbd_do_request(dev, &req, 0));
173 }
174 
175 usbd_status
176 usbd_clear_port_feature(struct usbd_device *dev, int port, int sel)
177 {
178 	usb_device_request_t req;
179 
180 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
181 	req.bRequest = UR_CLEAR_FEATURE;
182 	USETW(req.wValue, sel);
183 	USETW(req.wIndex, port);
184 	USETW(req.wLength, 0);
185 	return (usbd_do_request(dev, &req, 0));
186 }
187 
188 usbd_status
189 usbd_set_port_feature(struct usbd_device *dev, int port, int sel)
190 {
191 	usb_device_request_t req;
192 
193 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
194 	req.bRequest = UR_SET_FEATURE;
195 	USETW(req.wValue, sel);
196 	USETW(req.wIndex, port);
197 	USETW(req.wLength, 0);
198 	return (usbd_do_request(dev, &req, 0));
199 }
200 
201 usbd_status
202 usbd_get_protocol(struct usbd_interface *iface, u_int8_t *report)
203 {
204 	usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
205 	struct usbd_device *dev;
206 	usb_device_request_t req;
207 
208 	DPRINTFN(4, ("usbd_get_protocol: iface=%p, endpt=%d\n", iface,
209 	    id->bInterfaceNumber));
210 	if (id == NULL)
211 		return (USBD_IOERROR);
212 	usbd_interface2device_handle(iface, &dev);
213 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
214 	req.bRequest = UR_GET_PROTOCOL;
215 	USETW(req.wValue, 0);
216 	USETW(req.wIndex, id->bInterfaceNumber);
217 	USETW(req.wLength, 1);
218 	return (usbd_do_request(dev, &req, report));
219 }
220 
221 usbd_status
222 usbd_set_protocol(struct usbd_interface *iface, int report)
223 {
224 	usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface);
225 	struct usbd_device *dev;
226 	usb_device_request_t req;
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 	usbd_interface2device_handle(iface, &dev);
233 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
234 	req.bRequest = UR_SET_PROTOCOL;
235 	USETW(req.wValue, report);
236 	USETW(req.wIndex, id->bInterfaceNumber);
237 	USETW(req.wLength, 0);
238 	return (usbd_do_request(dev, &req, 0));
239 }
240 
241 usbd_status
242 usbd_set_report(struct usbd_interface *iface, int type, int id, void *data,
243     int len)
244 {
245 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
246 	struct usbd_device *dev;
247 	usb_device_request_t req;
248 
249 	DPRINTFN(4, ("usbd_set_report: len=%d\n", len));
250 	if (ifd == NULL)
251 		return (USBD_IOERROR);
252 	usbd_interface2device_handle(iface, &dev);
253 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
254 	req.bRequest = UR_SET_REPORT;
255 	USETW2(req.wValue, type, id);
256 	USETW(req.wIndex, ifd->bInterfaceNumber);
257 	USETW(req.wLength, len);
258 	return (usbd_do_request(dev, &req, data));
259 }
260 
261 usbd_status
262 usbd_set_report_async(struct usbd_interface *iface, int type, int id,
263     void *data, int len)
264 {
265 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
266 	struct usbd_device *dev;
267 	usb_device_request_t req;
268 
269 	DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len));
270 	if (ifd == NULL)
271 		return (USBD_IOERROR);
272 	usbd_interface2device_handle(iface, &dev);
273 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
274 	req.bRequest = UR_SET_REPORT;
275 	USETW2(req.wValue, type, id);
276 	USETW(req.wIndex, ifd->bInterfaceNumber);
277 	USETW(req.wLength, len);
278 	return (usbd_do_request_async(dev, &req, data));
279 }
280 
281 usbd_status
282 usbd_get_report(struct usbd_interface *iface, int type, int id, void *data,
283     int len)
284 {
285 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
286 	struct usbd_device *dev;
287 	usb_device_request_t req;
288 
289 	DPRINTFN(4, ("usbd_get_report: len=%d\n", len));
290 	if (ifd == NULL)
291 		return (USBD_IOERROR);
292 	usbd_interface2device_handle(iface, &dev);
293 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
294 	req.bRequest = UR_GET_REPORT;
295 	USETW2(req.wValue, type, id);
296 	USETW(req.wIndex, ifd->bInterfaceNumber);
297 	USETW(req.wLength, len);
298 	return (usbd_do_request(dev, &req, data));
299 }
300 
301 usbd_status
302 usbd_set_idle(struct usbd_interface *iface, int duration, int id)
303 {
304 	usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface);
305 	struct usbd_device *dev;
306 	usb_device_request_t req;
307 
308 	DPRINTFN(4, ("usbd_set_idle: %d %d\n", duration, id));
309 	if (ifd == NULL)
310 		return (USBD_IOERROR);
311 	usbd_interface2device_handle(iface, &dev);
312 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
313 	req.bRequest = UR_SET_IDLE;
314 	USETW2(req.wValue, duration, id);
315 	USETW(req.wIndex, ifd->bInterfaceNumber);
316 	USETW(req.wLength, 0);
317 	return (usbd_do_request(dev, &req, 0));
318 }
319 
320 usbd_status
321 usbd_get_report_descriptor(struct usbd_device *dev, int ifcno, int size,
322     void *d)
323 {
324 	usb_device_request_t req;
325 
326 	req.bmRequestType = UT_READ_INTERFACE;
327 	req.bRequest = UR_GET_DESCRIPTOR;
328 	USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */
329 	USETW(req.wIndex, ifcno);
330 	USETW(req.wLength, size);
331 	return (usbd_do_request(dev, &req, d));
332 }
333 
334 struct usb_hid_descriptor *
335 usbd_get_hid_descriptor(struct usbd_interface *ifc)
336 {
337 	usb_interface_descriptor_t *idesc = usbd_get_interface_descriptor(ifc);
338 	struct usbd_device *dev;
339 	usb_config_descriptor_t *cdesc;
340 	struct usb_hid_descriptor *hd;
341 	char *p, *end;
342 
343 	if (idesc == NULL)
344 		return (0);
345 	usbd_interface2device_handle(ifc, &dev);
346 	cdesc = usbd_get_config_descriptor(dev);
347 
348 	p = (char *)idesc + idesc->bLength;
349 	end = (char *)cdesc + UGETW(cdesc->wTotalLength);
350 
351 	for (; p < end; p += hd->bLength) {
352 		hd = (struct usb_hid_descriptor *)p;
353 		if (p + hd->bLength <= end && hd->bDescriptorType == UDESC_HID)
354 			return (hd);
355 		if (hd->bDescriptorType == UDESC_INTERFACE)
356 			break;
357 	}
358 	return (0);
359 }
360 
361 usbd_status
362 usbd_read_report_desc(struct usbd_interface *ifc, void **descp, int *sizep,
363     int mem)
364 {
365 	usb_interface_descriptor_t *id;
366 	struct usb_hid_descriptor *hid;
367 	struct usbd_device *dev;
368 	usbd_status err;
369 
370 	usbd_interface2device_handle(ifc, &dev);
371 	id = usbd_get_interface_descriptor(ifc);
372 	if (id == NULL)
373 		return (USBD_INVAL);
374 	hid = usbd_get_hid_descriptor(ifc);
375 	if (hid == NULL)
376 		return (USBD_IOERROR);
377 	*sizep = UGETW(hid->descrs[0].wDescriptorLength);
378 	*descp = malloc(*sizep, mem, M_NOWAIT);
379 	if (*descp == NULL)
380 		return (USBD_NOMEM);
381 	err = usbd_get_report_descriptor(dev, id->bInterfaceNumber, *sizep,
382 	    *descp);
383 	if (err) {
384 		free(*descp, mem);
385 		*descp = NULL;
386 		return (err);
387 	}
388 	return (USBD_NORMAL_COMPLETION);
389 }
390 
391 usbd_status
392 usbd_get_config(struct usbd_device *dev, u_int8_t *conf)
393 {
394 	usb_device_request_t req;
395 
396 	req.bmRequestType = UT_READ_DEVICE;
397 	req.bRequest = UR_GET_CONFIG;
398 	USETW(req.wValue, 0);
399 	USETW(req.wIndex, 0);
400 	USETW(req.wLength, 1);
401 	return (usbd_do_request(dev, &req, conf));
402 }
403 
404 void
405 usb_detach_wait(struct device *dv)
406 {
407 	DPRINTF(("usb_detach_wait: waiting for %s\n", dv->dv_xname));
408 	if (tsleep(dv, PZERO, "usbdet", hz * 60))
409 		printf("usb_detach_wait: %s didn't detach\n", dv->dv_xname);
410 	DPRINTF(("usb_detach_wait: %s done\n", dv->dv_xname));
411 }
412 
413 void
414 usb_detach_wakeup(struct device *dv)
415 {
416 	DPRINTF(("usb_detach_wakeup: for %s\n", dv->dv_xname));
417 	wakeup(dv);
418 }
419