xref: /openbsd-src/sys/dev/usb/uhidev.c (revision 58fbf5d6aa35e3d66f2c32c61d2f38824a990e85)
1 /*	$OpenBSD: uhidev.c,v 1.89 2021/02/15 11:26:00 mglocker Exp $	*/
2 /*	$NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $	*/
3 
4 /*
5  * Copyright (c) 2001 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (lennart@augustsson.net) at
10  * Carlstedt Research & Technology.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * HID spec: https://www.usb.org/sites/default/files/hid1_11.pdf
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/signalvar.h>
43 #include <sys/device.h>
44 #include <sys/ioctl.h>
45 #include <sys/conf.h>
46 
47 #include <machine/bus.h>
48 
49 #include <dev/usb/usb.h>
50 #include <dev/usb/usbhid.h>
51 
52 #include <dev/usb/usbdevs.h>
53 #include <dev/usb/usbdi.h>
54 #include <dev/usb/usbdi_util.h>
55 #include <dev/usb/usbdivar.h>
56 #include <dev/usb/usb_mem.h>
57 #include <dev/usb/usb_quirks.h>
58 
59 #include <dev/usb/uhidev.h>
60 
61 #ifndef SMALL_KERNEL
62 /* Replacement report descriptors for devices shipped with broken ones */
63 #include <dev/usb/uhid_rdesc.h>
64 int uhidev_use_rdesc(struct uhidev_softc *, usb_interface_descriptor_t *,
65 		int, int, void **, int *);
66 #define UISUBCLASS_XBOX360_CONTROLLER 0x5d
67 #define UIPROTO_XBOX360_GAMEPAD 0x01
68 #endif /* !SMALL_KERNEL */
69 
70 #define DEVNAME(sc)		((sc)->sc_dev.dv_xname)
71 
72 #ifdef UHIDEV_DEBUG
73 #define DPRINTF(x)	do { if (uhidevdebug) printf x; } while (0)
74 #define DPRINTFN(n,x)	do { if (uhidevdebug>(n)) printf x; } while (0)
75 int	uhidevdebug = 0;
76 #else
77 #define DPRINTF(x)
78 #define DPRINTFN(n,x)
79 #endif
80 
81 struct uhidev_async_info {
82 	void (*callback)(void *priv, int id, void *data, int len);
83 	void *priv;
84 	void *data;
85 	int id;
86 };
87 
88 void uhidev_intr(struct usbd_xfer *, void *, usbd_status);
89 
90 int uhidev_maxrepid(void *buf, int len);
91 int uhidevprint(void *aux, const char *pnp);
92 int uhidevsubmatch(struct device *parent, void *cf, void *aux);
93 
94 int uhidev_match(struct device *, void *, void *);
95 void uhidev_attach(struct device *, struct device *, void *);
96 int uhidev_detach(struct device *, int);
97 int uhidev_activate(struct device *, int);
98 
99 void uhidev_get_report_async_cb(struct usbd_xfer *, void *, usbd_status);
100 void uhidev_set_report_async_cb(struct usbd_xfer *, void *, usbd_status);
101 
102 struct cfdriver uhidev_cd = {
103 	NULL, "uhidev", DV_DULL
104 };
105 
106 const struct cfattach uhidev_ca = {
107 	sizeof(struct uhidev_softc), uhidev_match, uhidev_attach,
108 	uhidev_detach, uhidev_activate,
109 };
110 
111 int
112 uhidev_match(struct device *parent, void *match, void *aux)
113 {
114 	struct usb_attach_arg *uaa = aux;
115 	usb_interface_descriptor_t *id;
116 
117 	if (uaa->iface == NULL)
118 		return (UMATCH_NONE);
119 	id = usbd_get_interface_descriptor(uaa->iface);
120 	if (id == NULL)
121 		return (UMATCH_NONE);
122 #ifndef SMALL_KERNEL
123 	if (id->bInterfaceClass == UICLASS_VENDOR &&
124 	    id->bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER &&
125 	    id->bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)
126 		return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
127 #endif /* !SMALL_KERNEL */
128 	if (id->bInterfaceClass != UICLASS_HID)
129 		return (UMATCH_NONE);
130 	if (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_HID)
131 		return (UMATCH_NONE);
132 
133 	return (UMATCH_IFACECLASS_GENERIC);
134 }
135 
136 void
137 uhidev_attach(struct device *parent, struct device *self, void *aux)
138 {
139 	struct uhidev_softc *sc = (struct uhidev_softc *)self;
140 	struct usb_attach_arg *uaa = aux;
141 	usb_interface_descriptor_t *id;
142 	usb_endpoint_descriptor_t *ed;
143 	struct uhidev_attach_arg uha;
144 	int size, nrepid, repid, repsz;
145 	int i, repsizes[256];
146 	void *desc = NULL;
147 	struct device *dev;
148 
149 	sc->sc_udev = uaa->device;
150 	sc->sc_iface = uaa->iface;
151 	sc->sc_ifaceno = uaa->ifaceno;
152 	id = usbd_get_interface_descriptor(sc->sc_iface);
153 
154 	sc->sc_iep_addr = sc->sc_oep_addr = -1;
155 	for (i = 0; i < id->bNumEndpoints; i++) {
156 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
157 		if (ed == NULL) {
158 			printf("%s: could not read endpoint descriptor\n",
159 			    DEVNAME(sc));
160 			return;
161 		}
162 
163 		DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d "
164 		    "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
165 		    " bInterval=%d\n",
166 		    ed->bLength, ed->bDescriptorType,
167 		    ed->bEndpointAddress & UE_ADDR,
168 		    UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
169 		    UE_GET_XFERTYPE(ed->bmAttributes),
170 		    UGETW(ed->wMaxPacketSize), ed->bInterval));
171 
172 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
173 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
174 			sc->sc_iep_addr = ed->bEndpointAddress;
175 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
176 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
177 			sc->sc_oep_addr = ed->bEndpointAddress;
178 		} else {
179 			printf("%s: unexpected endpoint\n", DEVNAME(sc));
180 			return;
181 		}
182 	}
183 
184 	/*
185 	 * Check that we found an input interrupt endpoint.
186 	 * The output interrupt endpoint is optional
187 	 */
188 	if (sc->sc_iep_addr == -1) {
189 		printf("%s: no input interrupt endpoint\n", DEVNAME(sc));
190 		return;
191 	}
192 
193 #ifndef SMALL_KERNEL
194 	if (uhidev_use_rdesc(sc, id, uaa->vendor, uaa->product, &desc, &size))
195 		return;
196 #endif /* !SMALL_KERNEL */
197 
198 	if (desc == NULL) {
199 		struct usb_hid_descriptor *hid;
200 
201 		hid = usbd_get_hid_descriptor(sc->sc_udev, id);
202 		if (hid == NULL) {
203 			printf("%s: no HID descriptor\n", DEVNAME(sc));
204 			return;
205 		}
206 		size = UGETW(hid->descrs[0].wDescriptorLength);
207 		desc = malloc(size, M_USBDEV, M_NOWAIT);
208 		if (desc == NULL) {
209 			printf("%s: no memory\n", DEVNAME(sc));
210 			return;
211 		}
212 		if (usbd_get_report_descriptor(sc->sc_udev, sc->sc_ifaceno,
213 		    desc, size)) {
214 			printf("%s: no report descriptor\n", DEVNAME(sc));
215 			free(desc, M_USBDEV, size);
216 			return;
217 		}
218 	}
219 
220 	sc->sc_repdesc = desc;
221 	sc->sc_repdesc_size = size;
222 
223 	nrepid = uhidev_maxrepid(desc, size);
224 	if (nrepid < 0)
225 		return;
226 	printf("%s: iclass %d/%d", DEVNAME(sc), id->bInterfaceClass,
227 	    id->bInterfaceSubClass);
228 	if (nrepid > 0)
229 		printf(", %d report id%s", nrepid, nrepid > 1 ? "s" : "");
230 	printf("\n");
231 	nrepid++;
232 	sc->sc_subdevs = mallocarray(nrepid, sizeof(struct uhidev *),
233 	    M_USBDEV, M_NOWAIT | M_ZERO);
234 	if (sc->sc_subdevs == NULL) {
235 		printf("%s: no memory\n", DEVNAME(sc));
236 		return;
237 	}
238 	sc->sc_nrepid = nrepid;
239 	sc->sc_isize = 0;
240 
241 	for (repid = 0; repid < nrepid; repid++) {
242 		repsz = hid_report_size(desc, size, hid_input, repid);
243 		DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz));
244 		repsizes[repid] = repsz;
245 		if (repsz > sc->sc_isize)
246 			sc->sc_isize = repsz;
247 	}
248 	sc->sc_isize += (nrepid != 1);	/* one byte for the report ID */
249 	DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize));
250 
251 	uha.uaa = uaa;
252 	uha.parent = sc;
253 	uha.reportid = UHIDEV_CLAIM_ALLREPORTID;
254 
255 	/* Look for a driver claiming all report IDs first. */
256 	dev = config_found_sm(self, &uha, NULL, uhidevsubmatch);
257 	if (dev != NULL) {
258 		for (repid = 0; repid < nrepid; repid++) {
259 			/*
260 			 * Could already be assigned by uhidev_set_report_dev().
261 			 */
262 			if (sc->sc_subdevs[repid] == NULL)
263 				sc->sc_subdevs[repid] = (struct uhidev *)dev;
264 		}
265 		return;
266 	}
267 
268 	for (repid = 0; repid < nrepid; repid++) {
269 		DPRINTF(("%s: try repid=%d\n", __func__, repid));
270 		if (hid_report_size(desc, size, hid_input, repid) == 0 &&
271 		    hid_report_size(desc, size, hid_output, repid) == 0 &&
272 		    hid_report_size(desc, size, hid_feature, repid) == 0)
273 			continue;
274 
275 		/* Could already be assigned by uhidev_set_report_dev(). */
276 		if (sc->sc_subdevs[repid] != NULL)
277 			continue;
278 
279 		uha.reportid = repid;
280 		dev = config_found_sm(self, &uha, uhidevprint, uhidevsubmatch);
281 		sc->sc_subdevs[repid] = (struct uhidev *)dev;
282 	}
283 }
284 
285 #ifndef SMALL_KERNEL
286 int
287 uhidev_use_rdesc(struct uhidev_softc *sc, usb_interface_descriptor_t *id,
288 		int vendor, int product, void **descp, int *sizep)
289 {
290 	static uByte reportbuf[] = {2, 2};
291 	const void *descptr = NULL;
292 	void *desc;
293 	int size;
294 
295 	if (vendor == USB_VENDOR_WACOM) {
296 		/* The report descriptor for the Wacom Graphire is broken. */
297 		switch (product) {
298 		case USB_PRODUCT_WACOM_GRAPHIRE:
299 			size = sizeof(uhid_graphire_report_descr);
300 			descptr = uhid_graphire_report_descr;
301 			break;
302 		case USB_PRODUCT_WACOM_GRAPHIRE3_4X5:
303 		case USB_PRODUCT_WACOM_GRAPHIRE4_4X5:
304 			uhidev_set_report(sc, UHID_FEATURE_REPORT,
305 			    2, &reportbuf, sizeof(reportbuf));
306 			size = sizeof(uhid_graphire3_4x5_report_descr);
307 			descptr = uhid_graphire3_4x5_report_descr;
308 			break;
309 		default:
310 			break;
311 		}
312 	} else if ((id->bInterfaceClass == UICLASS_VENDOR &&
313 		   id->bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER &&
314 		   id->bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)) {
315 		/* The Xbox 360 gamepad has no report descriptor. */
316 		size = sizeof(uhid_xb360gp_report_descr);
317 		descptr = uhid_xb360gp_report_descr;
318 	}
319 
320 	if (descptr) {
321 		desc = malloc(size, M_USBDEV, M_NOWAIT);
322 		if (desc == NULL)
323 			return (ENOMEM);
324 
325 		memcpy(desc, descptr, size);
326 
327 		*descp = desc;
328 		*sizep = size;
329 	}
330 
331 	return (0);
332 }
333 #endif /* !SMALL_KERNEL */
334 
335 int
336 uhidev_maxrepid(void *buf, int len)
337 {
338 	struct hid_data *d;
339 	struct hid_item h;
340 	int maxid;
341 
342 	maxid = -1;
343 	h.report_ID = 0;
344 	for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); )
345 		if (h.report_ID > maxid)
346 			maxid = h.report_ID;
347 	hid_end_parse(d);
348 	return (maxid);
349 }
350 
351 int
352 uhidevprint(void *aux, const char *pnp)
353 {
354 	struct uhidev_attach_arg *uha = aux;
355 
356 	if (pnp)
357 		printf("uhid at %s", pnp);
358 	if (uha->reportid != 0 && uha->reportid != UHIDEV_CLAIM_ALLREPORTID)
359 		printf(" reportid %d", uha->reportid);
360 	return (UNCONF);
361 }
362 
363 int uhidevsubmatch(struct device *parent, void *match, void *aux)
364 {
365 	struct uhidev_attach_arg *uha = aux;
366         struct cfdata *cf = match;
367 
368 	if (cf->uhidevcf_reportid != UHIDEV_UNK_REPORTID &&
369 	    cf->uhidevcf_reportid != uha->reportid)
370 		return (0);
371 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
372 }
373 
374 int
375 uhidev_activate(struct device *self, int act)
376 {
377 	struct uhidev_softc *sc = (struct uhidev_softc *)self;
378 	int i, rv = 0, r;
379 
380 	switch (act) {
381 	case DVACT_DEACTIVATE:
382 		for (i = 0; i < sc->sc_nrepid; i++)
383 			if (sc->sc_subdevs[i] != NULL) {
384 				r = config_deactivate(
385 				    &sc->sc_subdevs[i]->sc_dev);
386 				if (r && r != EOPNOTSUPP)
387 					rv = r;
388 			}
389 		usbd_deactivate(sc->sc_udev);
390 		break;
391 	}
392 	return (rv);
393 }
394 
395 int
396 uhidev_detach(struct device *self, int flags)
397 {
398 	struct uhidev_softc *sc = (struct uhidev_softc *)self;
399 	int i, rv = 0;
400 
401 	DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags));
402 
403 	if (sc->sc_opipe != NULL) {
404 		usbd_close_pipe(sc->sc_opipe);
405 		sc->sc_opipe = NULL;
406 	}
407 
408 	if (sc->sc_ipipe != NULL) {
409 		usbd_close_pipe(sc->sc_ipipe);
410 		sc->sc_ipipe = NULL;
411 	}
412 
413 	if (sc->sc_repdesc != NULL)
414 		free(sc->sc_repdesc, M_USBDEV, sc->sc_repdesc_size);
415 
416 	/*
417 	 * XXX Check if we have only one children claiming all the Report
418 	 * IDs, this is a hack since we need a dev -> Report ID mapping
419 	 * for uhidev_intr().
420 	 */
421 	if (sc->sc_nrepid > 1 && sc->sc_subdevs[0] != NULL &&
422 	    sc->sc_subdevs[0] == sc->sc_subdevs[1])
423 		return (config_detach(&sc->sc_subdevs[0]->sc_dev, flags));
424 
425 	for (i = 0; i < sc->sc_nrepid; i++) {
426 		if (sc->sc_subdevs[i] != NULL) {
427 			rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags);
428 			sc->sc_subdevs[i] = NULL;
429 		}
430 	}
431 
432 	return (rv);
433 }
434 
435 void
436 uhidev_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
437 {
438 	struct uhidev_softc *sc = addr;
439 	struct uhidev *scd;
440 	u_char *p;
441 	u_int rep;
442 	u_int32_t cc;
443 
444 	if (usbd_is_dying(sc->sc_udev))
445 		return;
446 
447 	usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
448 
449 #ifdef UHIDEV_DEBUG
450 	if (uhidevdebug > 5) {
451 		u_int32_t i;
452 
453 		DPRINTF(("uhidev_intr: status=%d cc=%d\n", status, cc));
454 		DPRINTF(("uhidev_intr: data ="));
455 		for (i = 0; i < cc; i++)
456 			DPRINTF((" %02x", sc->sc_ibuf[i]));
457 		DPRINTF(("\n"));
458 	}
459 #endif
460 
461 	if (status == USBD_CANCELLED || status == USBD_IOERROR)
462 		return;
463 
464 	if (status != USBD_NORMAL_COMPLETION) {
465 		DPRINTF(("%s: interrupt status=%d\n", DEVNAME(sc), status));
466 		usbd_clear_endpoint_stall_async(sc->sc_ipipe);
467 		return;
468 	}
469 
470 	p = sc->sc_ibuf;
471 	if (sc->sc_nrepid != 1)
472 		rep = *p++, cc--;
473 	else
474 		rep = 0;
475 	if (rep >= sc->sc_nrepid) {
476 		printf("uhidev_intr: bad repid %d\n", rep);
477 		return;
478 	}
479 	scd = sc->sc_subdevs[rep];
480 	DPRINTFN(5,("uhidev_intr: rep=%d, scd=%p state=0x%x\n",
481 		    rep, scd, scd ? scd->sc_state : 0));
482 	if (scd == NULL || !(scd->sc_state & UHIDEV_OPEN))
483 		return;
484 
485 	scd->sc_intr(scd, p, cc);
486 }
487 
488 void
489 uhidev_get_report_desc(struct uhidev_softc *sc, void **desc, int *size)
490 {
491 	*desc = sc->sc_repdesc;
492 	*size = sc->sc_repdesc_size;
493 }
494 
495 int
496 uhidev_open(struct uhidev *scd)
497 {
498 	struct uhidev_softc *sc = scd->sc_parent;
499 	usbd_status err;
500 	int error;
501 
502 	DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n",
503 		 scd->sc_state, sc->sc_refcnt));
504 
505 	if (scd->sc_state & UHIDEV_OPEN)
506 		return (EBUSY);
507 	scd->sc_state |= UHIDEV_OPEN;
508 	if (sc->sc_refcnt++)
509 		return (0);
510 
511 	if (sc->sc_isize == 0)
512 		return (0);
513 
514 	sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
515 
516 	/* Set up input interrupt pipe. */
517 	DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize,
518 	    sc->sc_iep_addr));
519 
520 	err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr,
521 		  USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf,
522 		  sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL);
523 	if (err != USBD_NORMAL_COMPLETION) {
524 		DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
525 		    "error=%d\n", err));
526 		error = EIO;
527 		goto out1;
528 	}
529 
530 	DPRINTF(("uhidev_open: sc->sc_ipipe=%p\n", sc->sc_ipipe));
531 
532 	sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
533 	if (sc->sc_ixfer == NULL) {
534 		DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
535 		error = ENOMEM;
536 		goto out1; // xxxx
537 	}
538 
539 	/*
540 	 * Set up output interrupt pipe if an output interrupt endpoint
541 	 * exists.
542 	 */
543 	if (sc->sc_oep_addr != -1) {
544 		DPRINTF(("uhidev_open: oep=0x%02x\n", sc->sc_oep_addr));
545 
546 		err = usbd_open_pipe(sc->sc_iface, sc->sc_oep_addr,
547 		    0, &sc->sc_opipe);
548 		if (err != USBD_NORMAL_COMPLETION) {
549 			DPRINTF(("uhidev_open: usbd_open_pipe failed, "
550 			    "error=%d\n", err));
551 			error = EIO;
552 			goto out2;
553 		}
554 
555 		DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe));
556 
557 		sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
558 		if (sc->sc_oxfer == NULL) {
559 			DPRINTF(("uhidev_open: couldn't allocate an xfer\n"));
560 			error = ENOMEM;
561 			goto out3;
562 		}
563 
564 		sc->sc_owxfer = usbd_alloc_xfer(sc->sc_udev);
565 		if (sc->sc_owxfer == NULL) {
566 			DPRINTF(("uhidev_open: couldn't allocate owxfer\n"));
567 			error = ENOMEM;
568 			goto out3;
569 		}
570 	}
571 
572 	return (0);
573 
574 out3:
575 	/* Abort output pipe */
576 	usbd_close_pipe(sc->sc_opipe);
577 out2:
578 	/* Abort input pipe */
579 	usbd_close_pipe(sc->sc_ipipe);
580 out1:
581 	DPRINTF(("uhidev_open: failed in someway"));
582 	free(sc->sc_ibuf, M_USBDEV, sc->sc_isize);
583 	scd->sc_state &= ~UHIDEV_OPEN;
584 	sc->sc_refcnt = 0;
585 	sc->sc_ipipe = NULL;
586 	sc->sc_opipe = NULL;
587 	if (sc->sc_oxfer != NULL) {
588 		usbd_free_xfer(sc->sc_oxfer);
589 		sc->sc_oxfer = NULL;
590 	}
591 	if (sc->sc_owxfer != NULL) {
592 		usbd_free_xfer(sc->sc_owxfer);
593 		sc->sc_owxfer = NULL;
594 	}
595 	if (sc->sc_ixfer != NULL) {
596 		usbd_free_xfer(sc->sc_ixfer);
597 		sc->sc_ixfer = NULL;
598 	}
599 	return (error);
600 }
601 
602 void
603 uhidev_close(struct uhidev *scd)
604 {
605 	struct uhidev_softc *sc = scd->sc_parent;
606 
607 	if (!(scd->sc_state & UHIDEV_OPEN))
608 		return;
609 	scd->sc_state &= ~UHIDEV_OPEN;
610 	if (--sc->sc_refcnt)
611 		return;
612 	DPRINTF(("uhidev_close: close pipe\n"));
613 
614 	/* Disable interrupts. */
615 	if (sc->sc_opipe != NULL) {
616 		usbd_close_pipe(sc->sc_opipe);
617 		sc->sc_opipe = NULL;
618 	}
619 
620 	if (sc->sc_ipipe != NULL) {
621 		usbd_close_pipe(sc->sc_ipipe);
622 		sc->sc_ipipe = NULL;
623 	}
624 
625 	if (sc->sc_oxfer != NULL) {
626 		usbd_free_xfer(sc->sc_oxfer);
627 		sc->sc_oxfer = NULL;
628 	}
629 
630 	if (sc->sc_owxfer != NULL) {
631 		usbd_free_xfer(sc->sc_owxfer);
632 		sc->sc_owxfer = NULL;
633 	}
634 
635 	if (sc->sc_ixfer != NULL) {
636 		usbd_free_xfer(sc->sc_ixfer);
637 		sc->sc_ixfer = NULL;
638 	}
639 
640 	if (sc->sc_ibuf != NULL) {
641 		free(sc->sc_ibuf, M_USBDEV, sc->sc_isize);
642 		sc->sc_ibuf = NULL;
643 	}
644 }
645 
646 int
647 uhidev_report_type_conv(int hid_type_id)
648 {
649 	switch (hid_type_id) {
650 	case hid_input:
651 		return UHID_INPUT_REPORT;
652 	case hid_output:
653 		return UHID_OUTPUT_REPORT;
654 	case hid_feature:
655 		return UHID_FEATURE_REPORT;
656 	default:
657 		return -1;
658 	}
659 }
660 
661 int
662 uhidev_set_report(struct uhidev_softc *sc, int type, int id, void *data,
663     int len)
664 {
665 	usb_device_request_t req;
666 	char *buf = data;
667 	int actlen = len;
668 
669 	/* Prepend the reportID. */
670 	if (id > 0) {
671 		len++;
672 		buf = malloc(len, M_TEMP, M_WAITOK);
673 		buf[0] = id;
674 		memcpy(buf + 1, data, len - 1);
675 	}
676 
677 	if (sc->sc_opipe != NULL) {
678 		usbd_setup_xfer(sc->sc_owxfer, sc->sc_opipe, 0, buf, len,
679 		    USBD_SYNCHRONOUS | USBD_CATCH, 0, NULL);
680 		if (usbd_transfer(sc->sc_owxfer)) {
681 			usbd_clear_endpoint_stall(sc->sc_opipe);
682 			actlen = -1;
683 		}
684 	} else {
685 		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
686 		req.bRequest = UR_SET_REPORT;
687 		USETW2(req.wValue, type, id);
688 		USETW(req.wIndex, sc->sc_ifaceno);
689 		USETW(req.wLength, len);
690 
691 		if (usbd_do_request(sc->sc_udev, &req, buf))
692 			actlen = -1;
693 	}
694 
695 	if (id > 0)
696 		free(buf, M_TEMP, len);
697 
698 	return (actlen);
699 }
700 
701 void
702 uhidev_set_report_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status err)
703 {
704 	struct uhidev_softc *sc = priv;
705 
706 	if (err == USBD_STALLED)
707 		usbd_clear_endpoint_stall_async(sc->sc_opipe);
708 	usbd_free_xfer(xfer);
709 }
710 
711 int
712 uhidev_set_report_async(struct uhidev_softc *sc, int type, int id, void *data,
713     int len)
714 {
715 	struct usbd_xfer *xfer;
716 	usb_device_request_t req;
717 	int actlen = len;
718 	char *buf;
719 
720 	xfer = usbd_alloc_xfer(sc->sc_udev);
721 	if (xfer == NULL)
722 		return (-1);
723 
724 	if (id > 0)
725 		len++;
726 
727 	buf = usbd_alloc_buffer(xfer, len);
728 	if (buf == NULL) {
729 		usbd_free_xfer(xfer);
730 		return (-1);
731 	}
732 
733 	/* Prepend the reportID. */
734 	if (id > 0) {
735 		buf[0] = id;
736 		memcpy(buf + 1, data, len - 1);
737 	} else {
738 		memcpy(buf, data, len);
739 	}
740 
741 	if (sc->sc_opipe != NULL) {
742 		usbd_setup_xfer(xfer, sc->sc_opipe, sc, buf, len,
743 		    USBD_NO_COPY, USBD_DEFAULT_TIMEOUT,
744 		    uhidev_set_report_async_cb);
745 		if (usbd_transfer(xfer)) {
746 			usbd_clear_endpoint_stall_async(sc->sc_opipe);
747 			actlen = -1;
748 		}
749 	} else {
750 		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
751 		req.bRequest = UR_SET_REPORT;
752 		USETW2(req.wValue, type, id);
753 		USETW(req.wIndex, sc->sc_ifaceno);
754 		USETW(req.wLength, len);
755 		if (usbd_request_async(xfer, &req, NULL, NULL))
756 			actlen = -1;
757 	}
758 
759 	return (actlen);
760 }
761 
762 int
763 uhidev_get_report(struct uhidev_softc *sc, int type, int id, void *data,
764     int len)
765 {
766 	usb_device_request_t req;
767 	char *buf = data;
768 	usbd_status err;
769 	int actlen;
770 
771 	if (id > 0) {
772 		len++;
773 		buf = malloc(len, M_TEMP, M_WAITOK|M_ZERO);
774 	}
775 
776 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
777 	req.bRequest = UR_GET_REPORT;
778 	USETW2(req.wValue, type, id);
779 	USETW(req.wIndex, sc->sc_ifaceno);
780 	USETW(req.wLength, len);
781 
782 	err = usbd_do_request_flags(sc->sc_udev, &req, buf, 0, &actlen,
783 	    USBD_DEFAULT_TIMEOUT);
784 	if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER)
785 		actlen = -1;
786 
787 	/* Skip the reportID. */
788 	if (id > 0) {
789 		memcpy(data, buf + 1, len - 1);
790 		free(buf, M_TEMP, len);
791 	}
792 
793 	return (actlen);
794 }
795 
796 void
797 uhidev_get_report_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status err)
798 {
799 	struct uhidev_async_info *info = priv;
800 	char *buf;
801 	int len = -1;
802 
803 	if (!usbd_is_dying(xfer->pipe->device)) {
804 		if (err == USBD_NORMAL_COMPLETION || err == USBD_SHORT_XFER) {
805 			len = xfer->actlen;
806 			buf = KERNADDR(&xfer->dmabuf, 0);
807 			if (info->id > 0) {
808 				len--;
809 				memcpy(info->data, buf + 1, len);
810 			} else {
811 				memcpy(info->data, buf, len);
812 			}
813 		}
814 		info->callback(info->priv, info->id, info->data, len);
815 	}
816 	free(info, M_TEMP, sizeof(*info));
817 	usbd_free_xfer(xfer);
818 }
819 
820 int
821 uhidev_get_report_async(struct uhidev_softc *sc, int type, int id, void *data,
822     int len, void *priv, void (*callback)(void *, int, void *, int))
823 {
824 	struct usbd_xfer *xfer;
825 	usb_device_request_t req;
826 	struct uhidev_async_info *info;
827 	int actlen = len;
828 	char *buf;
829 
830 	xfer = usbd_alloc_xfer(sc->sc_udev);
831 	if (xfer == NULL)
832 		return (-1);
833 
834 	if (id > 0)
835 		len++;
836 
837 	buf = usbd_alloc_buffer(xfer, len);
838 	if (buf == NULL) {
839 		usbd_free_xfer(xfer);
840 		return (-1);
841 	}
842 
843 	info = malloc(sizeof(*info), M_TEMP, M_NOWAIT);
844 	if (info == NULL) {
845 		usbd_free_xfer(xfer);
846 		return (-1);
847 	}
848 
849 	info->callback = callback;
850 	info->priv = priv;
851 	info->data = data;
852 	info->id = id;
853 
854 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
855 	req.bRequest = UR_GET_REPORT;
856 	USETW2(req.wValue, type, id);
857 	USETW(req.wIndex, sc->sc_ifaceno);
858 	USETW(req.wLength, len);
859 
860 	if (usbd_request_async(xfer, &req, info, uhidev_get_report_async_cb)) {
861 		free(info, M_TEMP, sizeof(*info));
862 		actlen = -1;
863 	}
864 
865 	return (actlen);
866 }
867 
868 usbd_status
869 uhidev_write(struct uhidev_softc *sc, void *data, int len)
870 {
871 	usbd_status error;
872 
873 	DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len));
874 
875 	if (sc->sc_opipe == NULL)
876 		return USBD_INVAL;
877 
878 #ifdef UHIDEV_DEBUG
879 	if (uhidevdebug > 50) {
880 
881 		u_int32_t i;
882 		u_int8_t *d = data;
883 
884 		DPRINTF(("uhidev_write: data ="));
885 		for (i = 0; i < len; i++)
886 			DPRINTF((" %02x", d[i]));
887 		DPRINTF(("\n"));
888 	}
889 #endif
890 	usbd_setup_xfer(sc->sc_owxfer, sc->sc_opipe, 0, data, len,
891 	    USBD_SYNCHRONOUS | USBD_CATCH, 0, NULL);
892 	error = usbd_transfer(sc->sc_owxfer);
893 	if (error)
894 		usbd_clear_endpoint_stall(sc->sc_opipe);
895 
896 	return (error);
897 }
898 
899 int
900 uhidev_ioctl(struct uhidev *sc, u_long cmd, caddr_t addr, int flag,
901     struct proc *p)
902 {
903 	struct usb_ctl_report_desc *rd;
904 	struct usb_ctl_report *re;
905 	int size;
906 	void *desc;
907 
908 	switch (cmd) {
909 	case USB_GET_REPORT_DESC:
910 		uhidev_get_report_desc(sc->sc_parent, &desc, &size);
911 		rd = (struct usb_ctl_report_desc *)addr;
912 		size = min(size, sizeof rd->ucrd_data);
913 		rd->ucrd_size = size;
914 		memcpy(rd->ucrd_data, desc, size);
915 		break;
916 	case USB_GET_REPORT:
917 		re = (struct usb_ctl_report *)addr;
918 		switch (re->ucr_report) {
919 		case UHID_INPUT_REPORT:
920 			size = sc->sc_isize;
921 			break;
922 		case UHID_OUTPUT_REPORT:
923 			size = sc->sc_osize;
924 			break;
925 		case UHID_FEATURE_REPORT:
926 			size = sc->sc_fsize;
927 			break;
928 		default:
929 			return EINVAL;
930 		}
931 		if (uhidev_get_report(sc->sc_parent, re->ucr_report,
932 		    sc->sc_report_id, re->ucr_data, size) != size)
933 			return EIO;
934 		break;
935 	case USB_SET_REPORT:
936 		re = (struct usb_ctl_report *)addr;
937 		switch (re->ucr_report) {
938 		case UHID_INPUT_REPORT:
939 			size = sc->sc_isize;
940 			break;
941 		case UHID_OUTPUT_REPORT:
942 			size = sc->sc_osize;
943 			break;
944 		case UHID_FEATURE_REPORT:
945 			size = sc->sc_fsize;
946 			break;
947 		default:
948 			return EINVAL;
949 		}
950 		if (uhidev_set_report(sc->sc_parent, re->ucr_report,
951 		    sc->sc_report_id, re->ucr_data, size) != size)
952 			return EIO;
953 		break;
954 	case USB_GET_REPORT_ID:
955 		*(int *)addr = sc->sc_report_id;
956 		break;
957 	default:
958 		return -1;
959 	}
960 	return 0;
961 }
962 
963 int
964 uhidev_set_report_dev(struct uhidev_softc *sc, struct uhidev *dev, int repid)
965 {
966 	if ((dev->sc_state & UHIDEV_OPEN) == 0)
967 		return ENODEV;
968 	if (repid >= sc->sc_nrepid)
969 		return EINVAL;
970 
971 	sc->sc_subdevs[repid] = dev;
972 	return 0;
973 }
974 
975 int
976 uhidev_unset_report_dev(struct uhidev_softc *sc, int repid)
977 {
978 	if (repid >= sc->sc_nrepid)
979 		return EINVAL;
980 
981 	sc->sc_subdevs[repid] = NULL;
982 	return 0;
983 }
984