FreeBSD kernel usb device Code
uhid.c
Go to the documentation of this file.
1/* $NetBSD: uhid.c,v 1.46 2001/11/13 06:24:55 lukem Exp $ */
2
3/* Also already merged from NetBSD:
4 * $NetBSD: uhid.c,v 1.54 2002/09/23 05:51:21 simonb Exp $
5 */
6
7#include <sys/cdefs.h>
8__FBSDID("$FreeBSD$");
9
10/*-
11 * SPDX-License-Identifier: BSD-2-Clause-NetBSD
12 *
13 * Copyright (c) 1998 The NetBSD Foundation, Inc.
14 * All rights reserved.
15 *
16 * This code is derived from software contributed to The NetBSD Foundation
17 * by Lennart Augustsson (lennart@augustsson.net) at
18 * Carlstedt Research & Technology.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
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/*
43 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
44 */
45
46#include "opt_hid.h"
47
48#include <sys/stdint.h>
49#include <sys/stddef.h>
50#include <sys/param.h>
51#include <sys/queue.h>
52#include <sys/types.h>
53#include <sys/systm.h>
54#include <sys/kernel.h>
55#include <sys/bus.h>
56#include <sys/module.h>
57#include <sys/lock.h>
58#include <sys/mutex.h>
59#include <sys/condvar.h>
60#include <sys/sysctl.h>
61#include <sys/sx.h>
62#include <sys/unistd.h>
63#include <sys/callout.h>
64#include <sys/malloc.h>
65#include <sys/priv.h>
66#include <sys/conf.h>
67#include <sys/fcntl.h>
68
69#include <dev/hid/hid.h>
70
71#include "usbdevs.h"
72#include <dev/usb/usb.h>
73#include <dev/usb/usbdi.h>
74#include <dev/usb/usbdi_util.h>
75#include <dev/usb/usbhid.h>
76#include <dev/usb/usb_ioctl.h>
77#include <dev/usb/usb_generic.h>
78
79#define USB_DEBUG_VAR uhid_debug
80#include <dev/usb/usb_debug.h>
81
84
85#ifdef USB_DEBUG
86static int uhid_debug = 0;
87
88static SYSCTL_NODE(_hw_usb, OID_AUTO, uhid, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
89 "USB uhid");
90SYSCTL_INT(_hw_usb_uhid, OID_AUTO, debug, CTLFLAG_RWTUN,
91 &uhid_debug, 0, "Debug level");
92#endif
93
94#define UHID_BSIZE 1024 /* bytes, buffer size */
95#define UHID_FRAME_NUM 50 /* bytes, frame number */
96
97enum {
103};
104
107 struct mtx sc_mtx;
108
112
113 uint32_t sc_isize;
114 uint32_t sc_osize;
115 uint32_t sc_fsize;
116
118
119 uint8_t sc_iface_no;
121 uint8_t sc_iid;
122 uint8_t sc_oid;
123 uint8_t sc_fid;
124 uint8_t sc_flags;
125#define UHID_FLAG_IMMED 0x01 /* set if read should be immediate */
126#define UHID_FLAG_STATIC_DESC 0x04 /* set if report descriptors are
127 * static */
128};
133
134/* prototypes */
136static device_probe_t uhid_probe;
137static device_attach_t uhid_attach;
138static device_detach_t uhid_detach;
154static struct usb_fifo_methods uhid_fifo_methods = {
155 .f_open = &uhid_open,
156 .f_close = &uhid_close,
157 .f_ioctl = &uhid_ioctl,
158 .f_ioctl_post = &uhid_ioctl_post,
159 .f_start_read = &uhid_start_read,
160 .f_stop_read = &uhid_stop_read,
161 .f_start_write = &uhid_start_write,
162 .f_stop_write = &uhid_stop_write,
163 .basename[0] = "uhid",
164};
165
166static void
168{
169 struct uhid_softc *sc = usbd_xfer_softc(xfer);
170 struct usb_page_cache *pc;
171 int actlen;
172
173 switch (USB_GET_STATE(xfer)) {
175 case USB_ST_SETUP:
176tr_setup:
177 pc = usbd_xfer_get_frame(xfer, 0);
179 0, usbd_xfer_max_len(xfer), &actlen, 0)) {
180 usbd_xfer_set_frame_len(xfer, 0, actlen);
182 }
183 return;
184
185 default: /* Error */
186 if (error != USB_ERR_CANCELLED) {
187 /* try to clear stall first */
189 goto tr_setup;
190 }
191 return;
192 }
193}
194
195static void
197{
198 struct uhid_softc *sc = usbd_xfer_softc(xfer);
199 struct usb_page_cache *pc;
200 int actlen;
201
202 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
203
204 switch (USB_GET_STATE(xfer)) {
206 DPRINTF("transferred!\n");
207
208 pc = usbd_xfer_get_frame(xfer, 0);
209
210 /*
211 * If the ID byte is non zero we allow descriptors
212 * having multiple sizes:
213 */
214 if ((actlen >= (int)sc->sc_isize) ||
215 ((actlen > 0) && (sc->sc_iid != 0))) {
216 /* limit report length to the maximum */
217 if (actlen > (int)sc->sc_isize)
218 actlen = sc->sc_isize;
220 0, actlen, 1);
221 } else {
222 /* ignore it */
223 DPRINTF("ignored transfer, %d bytes\n", actlen);
224 }
225
226 case USB_ST_SETUP:
227re_submit:
229 sc->sc_fifo.fp[USB_FIFO_RX]) != 0) {
230 usbd_xfer_set_frame_len(xfer, 0, sc->sc_isize);
232 }
233 return;
234
235 default: /* Error */
236 if (error != USB_ERR_CANCELLED) {
237 /* try to clear stall first */
239 goto re_submit;
240 }
241 return;
242 }
243}
244
245static void
246uhid_fill_set_report(struct usb_device_request *req, uint8_t iface_no,
247 uint8_t type, uint8_t id, uint16_t size)
248{
249 req->bmRequestType = UT_WRITE_CLASS_INTERFACE;
250 req->bRequest = UR_SET_REPORT;
251 USETW2(req->wValue, type, id);
252 req->wIndex[0] = iface_no;
253 req->wIndex[1] = 0;
254 USETW(req->wLength, size);
255}
256
257static void
258uhid_fill_get_report(struct usb_device_request *req, uint8_t iface_no,
259 uint8_t type, uint8_t id, uint16_t size)
260{
261 req->bmRequestType = UT_READ_CLASS_INTERFACE;
262 req->bRequest = UR_GET_REPORT;
263 USETW2(req->wValue, type, id);
264 req->wIndex[0] = iface_no;
265 req->wIndex[1] = 0;
266 USETW(req->wLength, size);
267}
268
269static void
271{
272 struct uhid_softc *sc = usbd_xfer_softc(xfer);
273 struct usb_device_request req;
274 struct usb_page_cache *pc;
275 uint32_t size = sc->sc_osize;
276 uint32_t actlen;
277 uint8_t id;
278
279 switch (USB_GET_STATE(xfer)) {
281 case USB_ST_SETUP:
282 /* try to extract the ID byte */
283 if (sc->sc_oid) {
284 pc = usbd_xfer_get_frame(xfer, 0);
286 0, 1, &actlen, 0)) {
287 if (actlen != 1) {
288 goto tr_error;
289 }
290 usbd_copy_out(pc, 0, &id, 1);
291
292 } else {
293 return;
294 }
295 if (size) {
296 size--;
297 }
298 } else {
299 id = 0;
300 }
301
302 pc = usbd_xfer_get_frame(xfer, 1);
304 0, UHID_BSIZE, &actlen, 1)) {
305 if (actlen != size) {
306 goto tr_error;
307 }
309 (&req, sc->sc_iface_no,
311
312 pc = usbd_xfer_get_frame(xfer, 0);
313 usbd_copy_in(pc, 0, &req, sizeof(req));
314
315 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
317 usbd_xfer_set_frames(xfer, size ? 2 : 1);
319 }
320 return;
321
322 default:
323tr_error:
324 /* bomb out */
326 return;
327 }
328}
329
330static void
332{
333 struct uhid_softc *sc = usbd_xfer_softc(xfer);
334 struct usb_device_request req;
335 struct usb_page_cache *pc;
336
337 pc = usbd_xfer_get_frame(xfer, 0);
338
339 switch (USB_GET_STATE(xfer)) {
341 usb_fifo_put_data(sc->sc_fifo.fp[USB_FIFO_RX], pc, sizeof(req),
342 sc->sc_isize, 1);
343 return;
344
345 case USB_ST_SETUP:
346
350 sc->sc_iid, sc->sc_isize);
351
352 usbd_copy_in(pc, 0, &req, sizeof(req));
353
354 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
355 usbd_xfer_set_frame_len(xfer, 1, sc->sc_isize);
356 usbd_xfer_set_frames(xfer, sc->sc_isize ? 2 : 1);
358 }
359 return;
360
361 default: /* Error */
362 /* bomb out */
364 return;
365 }
366}
368static const struct usb_config uhid_config[UHID_N_TRANSFER] = {
369 [UHID_INTR_DT_WR] = {
371 .endpoint = UE_ADDR_ANY,
372 .direction = UE_DIR_OUT,
373 .flags = {.pipe_bof = 1,.no_pipe_ok = 1, },
374 .bufsize = UHID_BSIZE,
375 .callback = &uhid_intr_write_callback,
376 },
377
378 [UHID_INTR_DT_RD] = {
379 .type = UE_INTERRUPT,
380 .endpoint = UE_ADDR_ANY,
381 .direction = UE_DIR_IN,
382 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
383 .bufsize = UHID_BSIZE,
384 .callback = &uhid_intr_read_callback,
385 },
386
387 [UHID_CTRL_DT_WR] = {
388 .type = UE_CONTROL,
389 .endpoint = 0x00, /* Control pipe */
390 .direction = UE_DIR_ANY,
391 .bufsize = sizeof(struct usb_device_request) + UHID_BSIZE,
392 .callback = &uhid_write_callback,
393 .timeout = 1000, /* 1 second */
394 },
395
396 [UHID_CTRL_DT_RD] = {
397 .type = UE_CONTROL,
398 .endpoint = 0x00, /* Control pipe */
399 .direction = UE_DIR_ANY,
400 .bufsize = sizeof(struct usb_device_request) + UHID_BSIZE,
401 .callback = &uhid_read_callback,
402 .timeout = 1000, /* 1 second */
403 },
404};
405
406static void
407uhid_start_read(struct usb_fifo *fifo)
408{
409 struct uhid_softc *sc = usb_fifo_softc(fifo);
410
411 if (sc->sc_flags & UHID_FLAG_IMMED) {
413 } else {
415 }
416}
417
418static void
419uhid_stop_read(struct usb_fifo *fifo)
420{
421 struct uhid_softc *sc = usb_fifo_softc(fifo);
422
425}
426
427static void
428uhid_start_write(struct usb_fifo *fifo)
429{
430 struct uhid_softc *sc = usb_fifo_softc(fifo);
431
432 if ((sc->sc_flags & UHID_FLAG_IMMED) ||
433 sc->sc_xfer[UHID_INTR_DT_WR] == NULL) {
435 } else {
437 }
438}
439
440static void
441uhid_stop_write(struct usb_fifo *fifo)
442{
443 struct uhid_softc *sc = usb_fifo_softc(fifo);
444
447}
448
449static int
450uhid_get_report(struct uhid_softc *sc, uint8_t type,
451 uint8_t id, void *kern_data, void *user_data,
452 uint16_t len)
453{
454 int err;
455 uint8_t free_data = 0;
456
457 if (kern_data == NULL) {
458 kern_data = malloc(len, M_USBDEV, M_WAITOK);
459 free_data = 1;
460 }
461 err = usbd_req_get_report(sc->sc_udev, NULL, kern_data,
462 len, sc->sc_iface_index, type, id);
463 if (err) {
464 err = ENXIO;
465 goto done;
466 }
467 if (user_data) {
468 /* dummy buffer */
469 err = copyout(kern_data, user_data, len);
470 if (err) {
471 goto done;
472 }
473 }
474done:
475 if (free_data) {
476 free(kern_data, M_USBDEV);
477 }
478 return (err);
479}
480
481static int
482uhid_set_report(struct uhid_softc *sc, uint8_t type,
483 uint8_t id, void *kern_data, void *user_data,
484 uint16_t len)
485{
486 int err;
487 uint8_t free_data = 0;
488
489 if (kern_data == NULL) {
490 kern_data = malloc(len, M_USBDEV, M_WAITOK);
491 free_data = 1;
492 err = copyin(user_data, kern_data, len);
493 if (err) {
494 goto done;
495 }
496 }
497 err = usbd_req_set_report(sc->sc_udev, NULL, kern_data,
498 len, sc->sc_iface_index, type, id);
499 if (err) {
500 err = ENXIO;
501 goto done;
502 }
503done:
504 if (free_data) {
505 free(kern_data, M_USBDEV);
506 }
507 return (err);
508}
509
510static int
511uhid_open(struct usb_fifo *fifo, int fflags)
512{
513 struct uhid_softc *sc = usb_fifo_softc(fifo);
514
515 /*
516 * The buffers are one byte larger than maximum so that one
517 * can detect too large read/writes and short transfers:
518 */
519 if (fflags & FREAD) {
520 /* reset flags */
521 mtx_lock(&sc->sc_mtx);
522 sc->sc_flags &= ~UHID_FLAG_IMMED;
523 mtx_unlock(&sc->sc_mtx);
524
525 if (usb_fifo_alloc_buffer(fifo,
526 sc->sc_isize + 1, UHID_FRAME_NUM)) {
527 return (ENOMEM);
528 }
529 }
530 if (fflags & FWRITE) {
531 if (usb_fifo_alloc_buffer(fifo,
532 sc->sc_osize + 1, UHID_FRAME_NUM)) {
533 return (ENOMEM);
534 }
535 }
536 return (0);
537}
538
539static void
540uhid_close(struct usb_fifo *fifo, int fflags)
541{
542 if (fflags & (FREAD | FWRITE)) {
544 }
545}
546
547static int
548uhid_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr,
549 int fflags)
550{
551 struct uhid_softc *sc = usb_fifo_softc(fifo);
552 struct usb_gen_descriptor *ugd;
553#ifdef COMPAT_FREEBSD32
554 struct usb_gen_descriptor local_ugd;
555 struct usb_gen_descriptor32 *ugd32 = NULL;
556#endif
557 uint32_t size;
558 int error = 0;
559 uint8_t id;
560
561 ugd = addr;
562#ifdef COMPAT_FREEBSD32
563 switch (cmd) {
564 case USB_GET_REPORT_DESC32:
565 case USB_GET_REPORT32:
566 case USB_SET_REPORT32:
567 ugd32 = addr;
568 ugd = &local_ugd;
569 usb_gen_descriptor_from32(ugd, ugd32);
570 cmd = _IOC_NEWTYPE(cmd, struct usb_gen_descriptor);
571 break;
572 }
573#endif
574
575 switch (cmd) {
577 if (sc->sc_repdesc_size > ugd->ugd_maxlen) {
578 size = ugd->ugd_maxlen;
579 } else {
580 size = sc->sc_repdesc_size;
581 }
582 ugd->ugd_actlen = size;
583 if (ugd->ugd_data == NULL)
584 break; /* descriptor length only */
585 error = copyout(sc->sc_repdesc_ptr, ugd->ugd_data, size);
586 break;
587
588 case USB_SET_IMMED:
589 if (!(fflags & FREAD)) {
590 error = EPERM;
591 break;
592 }
593 if (*(int *)addr) {
594 /* do a test read */
595
597 sc->sc_iid, NULL, NULL, sc->sc_isize);
598 if (error) {
599 break;
600 }
601 mtx_lock(&sc->sc_mtx);
603 mtx_unlock(&sc->sc_mtx);
604 } else {
605 mtx_lock(&sc->sc_mtx);
606 sc->sc_flags &= ~UHID_FLAG_IMMED;
607 mtx_unlock(&sc->sc_mtx);
608 }
609 break;
610
611 case USB_GET_REPORT:
612 if (!(fflags & FREAD)) {
613 error = EPERM;
614 break;
615 }
616 switch (ugd->ugd_report_type) {
618 size = sc->sc_isize;
619 id = sc->sc_iid;
620 break;
622 size = sc->sc_osize;
623 id = sc->sc_oid;
624 break;
626 size = sc->sc_fsize;
627 id = sc->sc_fid;
628 break;
629 default:
630 return (EINVAL);
631 }
632 if (id != 0)
633 copyin(ugd->ugd_data, &id, 1);
635 NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
636 break;
637
638 case USB_SET_REPORT:
639 if (!(fflags & FWRITE)) {
640 error = EPERM;
641 break;
642 }
643 switch (ugd->ugd_report_type) {
645 size = sc->sc_isize;
646 id = sc->sc_iid;
647 break;
649 size = sc->sc_osize;
650 id = sc->sc_oid;
651 break;
653 size = sc->sc_fsize;
654 id = sc->sc_fid;
655 break;
656 default:
657 return (EINVAL);
658 }
659 if (id != 0)
660 copyin(ugd->ugd_data, &id, 1);
662 NULL, ugd->ugd_data, imin(ugd->ugd_maxlen, size));
663 break;
664
666 *(int *)addr = 0; /* XXX: we only support reportid 0? */
667 break;
668
669 default:
670 error = ENOIOCTL;
671 break;
672 }
673#ifdef COMPAT_FREEBSD32
674 if (ugd32 != NULL)
675 update_usb_gen_descriptor32(ugd32, ugd);
676#endif
677 return (error);
678}
679
680static int
681uhid_ioctl_post(struct usb_fifo *fifo, u_long cmd, void *addr,
682 int fflags)
683{
684 int error;
685
686 switch (cmd) {
689 break;
690
691 default:
692 error = EINVAL;
693 break;
694 }
695 return (error);
696}
698static const STRUCT_USB_HOST_ID uhid_devs[] = {
699 /* generic HID class */
701 /* the Xbox 360 gamepad doesn't use the HID class */
705};
706
707static int
708uhid_probe(device_t dev)
709{
710 struct usb_attach_arg *uaa = device_get_ivars(dev);
711 int error;
712 void *buf;
713 uint16_t len;
714
715 DPRINTFN(11, "\n");
716
717 if (uaa->usb_mode != USB_MODE_HOST)
718 return (ENXIO);
719
721 if (error)
722 return (error);
723
725 return (ENXIO);
726
727 /*
728 * Don't attach to mouse and keyboard devices, hence then no
729 * "nomatch" event is generated and then ums and ukbd won't
730 * attach properly when loaded.
731 */
732 if ((uaa->info.bInterfaceClass == UICLASS_HID) &&
738 return (ENXIO);
739
740 /* Check for mandatory multitouch usages to give wmt(4) a chance */
741 if (!usb_test_quirk(uaa, UQ_WMT_IGNORE)) {
743 &buf, &len, M_USBDEV, uaa->info.bIfaceIndex);
744 /* Let HID decscriptor-less devices to be handled at attach */
745 if (!error) {
746 if (hid_locate(buf, len,
747 HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACT_MAX),
748 hid_feature, 0, NULL, NULL, NULL) &&
749 hid_locate(buf, len,
750 HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTID),
751 hid_input, 0, NULL, NULL, NULL)) {
752 free(buf, M_USBDEV);
753 return (ENXIO);
754 }
755 free(buf, M_USBDEV);
756 }
757 }
758
759 return (BUS_PROBE_GENERIC);
760}
761
762static int
763uhid_attach(device_t dev)
764{
765 struct usb_attach_arg *uaa = device_get_ivars(dev);
766 struct uhid_softc *sc = device_get_softc(dev);
767 int unit = device_get_unit(dev);
768 int error = 0;
769
770 DPRINTFN(10, "sc=%p\n", sc);
771
773
774 mtx_init(&sc->sc_mtx, "uhid lock", NULL, MTX_DEF | MTX_RECURSE);
775
776 sc->sc_udev = uaa->device;
777
778 sc->sc_iface_no = uaa->info.bIfaceNum;
780
783 UHID_N_TRANSFER, sc, &sc->sc_mtx);
784
785 if (error) {
786 DPRINTF("error=%s\n", usbd_errstr(error));
787 goto detach;
788 }
789 if (uaa->info.idVendor == USB_VENDOR_WACOM) {
790 /* the report descriptor for the Wacom Graphire is broken */
791
792 if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE) {
794 sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire_report_descr);
796
797 } else if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) {
798 static uint8_t reportbuf[] = {2, 2, 2};
799
800 /*
801 * The Graphire3 needs 0x0202 to be written to
802 * feature report ID 2 before it'll start
803 * returning digitizer data.
804 */
805 error = usbd_req_set_report(uaa->device, NULL,
806 reportbuf, sizeof(reportbuf),
808
809 if (error) {
810 DPRINTF("set report failed, error=%s (ignored)\n",
812 }
814 sc->sc_repdesc_ptr = __DECONST(void *, &uhid_graphire3_4x5_report_descr);
816 }
817 } else if ((uaa->info.bInterfaceClass == UICLASS_VENDOR) &&
820 static const uint8_t reportbuf[3] = {1, 3, 0};
821 /*
822 * Turn off the four LEDs on the gamepad which
823 * are blinking by default:
824 */
825 error = usbd_req_set_report(uaa->device, NULL,
826 __DECONST(void *, reportbuf), sizeof(reportbuf),
828 if (error) {
829 DPRINTF("set output report failed, error=%s (ignored)\n",
831 }
832 /* the Xbox 360 gamepad has no report descriptor */
834 sc->sc_repdesc_ptr = __DECONST(void *, &uhid_xb360gp_report_descr);
836 }
837 if (sc->sc_repdesc_ptr == NULL) {
840 M_USBDEV, uaa->info.bIfaceIndex);
841
842 if (error) {
843 device_printf(dev, "no report descriptor\n");
844 goto detach;
845 }
846 }
847 error = usbd_req_set_idle(uaa->device, NULL,
848 uaa->info.bIfaceIndex, 0, 0);
849
850 if (error) {
851 DPRINTF("set idle failed, error=%s (ignored)\n",
853 }
854 sc->sc_isize = hid_report_size_max
855 (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_input, &sc->sc_iid);
856
857 sc->sc_osize = hid_report_size_max
858 (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_output, &sc->sc_oid);
859
860 sc->sc_fsize = hid_report_size_max
861 (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_feature, &sc->sc_fid);
862
863 if (sc->sc_isize > UHID_BSIZE) {
864 DPRINTF("input size is too large, "
865 "%d bytes (truncating)\n",
866 sc->sc_isize);
867 sc->sc_isize = UHID_BSIZE;
868 }
869 if (sc->sc_osize > UHID_BSIZE) {
870 DPRINTF("output size is too large, "
871 "%d bytes (truncating)\n",
872 sc->sc_osize);
873 sc->sc_osize = UHID_BSIZE;
874 }
875 if (sc->sc_fsize > UHID_BSIZE) {
876 DPRINTF("feature size is too large, "
877 "%d bytes (truncating)\n",
878 sc->sc_fsize);
879 sc->sc_fsize = UHID_BSIZE;
880 }
881
882 error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx,
884 unit, -1, uaa->info.bIfaceIndex,
885 UID_ROOT, GID_OPERATOR, 0644);
886 if (error) {
887 goto detach;
888 }
889 return (0); /* success */
890
891detach:
893 return (ENOMEM);
894}
895
896static int
897uhid_detach(device_t dev)
898{
899 struct uhid_softc *sc = device_get_softc(dev);
900
902
904
905 if (sc->sc_repdesc_ptr) {
906 if (!(sc->sc_flags & UHID_FLAG_STATIC_DESC)) {
907 free(sc->sc_repdesc_ptr, M_USBDEV);
908 }
909 }
910 mtx_destroy(&sc->sc_mtx);
911
912 return (0);
913}
914
915#ifndef HIDRAW_MAKE_UHID_ALIAS
916static devclass_t uhid_devclass;
917#endif
919static device_method_t uhid_methods[] = {
920 DEVMETHOD(device_probe, uhid_probe),
921 DEVMETHOD(device_attach, uhid_attach),
922 DEVMETHOD(device_detach, uhid_detach),
923
924 DEVMETHOD_END
925};
927static driver_t uhid_driver = {
928#ifdef HIDRAW_MAKE_UHID_ALIAS
929 .name = "hidraw",
930#else
931 .name = "uhid",
932#endif
933 .methods = uhid_methods,
934 .size = sizeof(struct uhid_softc),
935};
936
937#ifdef HIDRAW_MAKE_UHID_ALIAS
938DRIVER_MODULE(uhid, uhub, uhid_driver, hidraw_devclass, NULL, 0);
939#else
940DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, NULL, 0);
941#endif
942MODULE_DEPEND(uhid, usb, 1, 1, 1);
943MODULE_DEPEND(uhid, hid, 1, 1, 1);
static int debug
Definition: cfumass.c:73
static SYSCTL_NODE(_hw_usb, OID_AUTO, dwc_otg, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "USB DWC OTG")
SYSCTL_INT(_hw_usb_dwc_otg, OID_AUTO, phy_type, CTLFLAG_RDTUN, &dwc_otg_phy_type, 0, "DWC OTG PHY TYPE - 0/1/2/3 - ULPI/HSIC/INTERNAL/UTMI+")
uint16_t len
Definition: ehci.h:41
uint8_t size
Definition: if_axge.c:89
struct @109 error
uint8_t id
Definition: if_usievar.h:4
enum pci_id_type type
device_t dev
uint64_t * addr
uint8_t sc_iface_index
Definition: uhid.c:120
struct mtx sc_mtx
Definition: uhid.c:107
uint8_t sc_oid
Definition: uhid.c:122
uint16_t sc_repdesc_size
Definition: uhid.c:117
uint32_t sc_fsize
Definition: uhid.c:115
struct usb_device * sc_udev
Definition: uhid.c:110
uint32_t sc_isize
Definition: uhid.c:113
uint8_t sc_iface_no
Definition: uhid.c:119
uint8_t sc_fid
Definition: uhid.c:123
void * sc_repdesc_ptr
Definition: uhid.c:111
uint8_t sc_flags
Definition: uhid.c:124
uint8_t sc_iid
Definition: uhid.c:121
struct usb_xfer * sc_xfer[UHID_N_TRANSFER]
Definition: uhid.c:109
uint32_t sc_osize
Definition: uhid.c:114
struct usb_fifo_sc sc_fifo
Definition: uhid.c:106
enum usb_hc_mode usb_mode
Definition: usbdi.h:432
struct usbd_lookup_info info
Definition: usbdi.h:426
struct usb_device * device
Definition: usbdi.h:430
uint8_t type
Definition: usbdi.h:238
usb_fifo_open_t * f_open
Definition: usbdi.h:535
struct usb_fifo * fp[2]
Definition: usbdi.h:554
uint16_t ugd_actlen
Definition: usb_ioctl.h:90
uint8_t ugd_report_type
Definition: usb_ioctl.h:97
uint16_t ugd_maxlen
Definition: usb_ioctl.h:89
uint8_t bIfaceNum
Definition: usbdi.h:418
uint16_t idProduct
Definition: usbdi.h:409
uint8_t bIfaceIndex
Definition: usbdi.h:417
uint8_t bInterfaceSubClass
Definition: usbdi.h:415
uint8_t bInterfaceClass
Definition: usbdi.h:414
uint8_t bInterfaceProtocol
Definition: usbdi.h:416
uint16_t idVendor
Definition: usbdi.h:408
static usb_fifo_close_t uhid_close
Definition: uhid.c:149
static usb_fifo_cmd_t uhid_start_read
Definition: uhid.c:144
#define UHID_FLAG_IMMED
Definition: uhid.c:125
static device_probe_t uhid_probe
Definition: uhid.c:135
static device_detach_t uhid_detach
Definition: uhid.c:137
MODULE_DEPEND(uhid, usb, 1, 1, 1)
static int uhid_set_report(struct uhid_softc *sc, uint8_t type, uint8_t id, void *kern_data, void *user_data, uint16_t len)
Definition: uhid.c:481
#define UHID_BSIZE
Definition: uhid.c:94
static devclass_t uhid_devclass
Definition: uhid.c:915
static void uhid_fill_set_report(struct usb_device_request *req, uint8_t iface_no, uint8_t type, uint8_t id, uint16_t size)
Definition: uhid.c:245
#define UHID_FLAG_STATIC_DESC
Definition: uhid.c:126
static usb_callback_t uhid_read_callback
Definition: uhid.c:142
static usb_fifo_open_t uhid_open
Definition: uhid.c:148
static usb_callback_t uhid_intr_write_callback
Definition: uhid.c:139
static void uhid_fill_get_report(struct usb_device_request *req, uint8_t iface_no, uint8_t type, uint8_t id, uint16_t size)
Definition: uhid.c:257
static int uhid_get_report(struct uhid_softc *sc, uint8_t type, uint8_t id, void *kern_data, void *user_data, uint16_t len)
Definition: uhid.c:449
static usb_fifo_ioctl_t uhid_ioctl_post
Definition: uhid.c:151
USB_PNP_HOST_INFO(uhid_devs)
static struct usb_fifo_methods uhid_fifo_methods
Definition: uhid.c:153
static usb_callback_t uhid_write_callback
Definition: uhid.c:141
static device_method_t uhid_methods[]
Definition: uhid.c:918
static usb_callback_t uhid_intr_read_callback
Definition: uhid.c:140
static usb_fifo_cmd_t uhid_stop_write
Definition: uhid.c:147
__FBSDID("$FreeBSD$")
static usb_fifo_cmd_t uhid_stop_read
Definition: uhid.c:145
static const struct usb_config uhid_config[UHID_N_TRANSFER]
Definition: uhid.c:367
static const uint8_t uhid_graphire_report_descr[]
Definition: uhid.c:130
MODULE_VERSION(uhid, 1)
@ UHID_INTR_DT_WR
Definition: uhid.c:98
@ UHID_N_TRANSFER
Definition: uhid.c:102
@ UHID_CTRL_DT_WR
Definition: uhid.c:100
@ UHID_INTR_DT_RD
Definition: uhid.c:99
@ UHID_CTRL_DT_RD
Definition: uhid.c:101
static const uint8_t uhid_graphire3_4x5_report_descr[]
Definition: uhid.c:131
DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, NULL, 0)
static const STRUCT_USB_HOST_ID uhid_devs[]
Definition: uhid.c:697
static device_attach_t uhid_attach
Definition: uhid.c:136
static driver_t uhid_driver
Definition: uhid.c:926
static const uint8_t uhid_xb360gp_report_descr[]
Definition: uhid.c:129
#define UHID_FRAME_NUM
Definition: uhid.c:95
static usb_fifo_ioctl_t uhid_ioctl
Definition: uhid.c:150
static usb_fifo_cmd_t uhid_start_write
Definition: uhid.c:146
#define DPRINTF(...)
Definition: umass.c:179
#define UE_INTERRUPT
Definition: usb.h:544
#define UE_DIR_ANY
Definition: usb.h:535
#define UE_ADDR_ANY
Definition: usb.h:537
#define UISUBCLASS_XBOX360_CONTROLLER
Definition: usb.h:521
#define UT_READ_CLASS_INTERFACE
Definition: usb.h:173
#define UISUBCLASS_BOOT
Definition: usb.h:454
#define UICLASS_VENDOR
Definition: usb.h:520
#define UIPROTO_XBOX360_GAMEPAD
Definition: usb.h:523
#define UE_DIR_IN
Definition: usb.h:531
#define UICLASS_HID
Definition: usb.h:453
#define UE_DIR_OUT
Definition: usb.h:532
@ USB_MODE_HOST
Definition: usb.h:778
#define UT_WRITE_CLASS_INTERFACE
Definition: usb.h:177
#define UIPROTO_MOUSE
Definition: usb.h:456
#define UE_CONTROL
Definition: usb.h:541
#define UIPROTO_BOOT_KEYBOARD
Definition: usb.h:455
void usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset, const void *ptr, usb_frlength_t len)
Definition: usb_busdma.c:166
void usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset, void *ptr, usb_frlength_t len)
Definition: usb_busdma.c:283
#define USETW2(w, b1, b0)
Definition: usb_endian.h:100
#define USETW(w, v)
Definition: usb_endian.h:77
const char * usbd_errstr(usb_error_t err)
Definition: usb_error.c:93
int ugen_fill_deviceinfo(struct usb_fifo *f, struct usb_device_info *di)
usb_error_t usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx, void **descp, uint16_t *sizep, struct malloc_type *mem, uint8_t iface_index)
Definition: usb_hid.c:113
const void * req
Definition: usb_if.m:51
INTERFACE usb
Definition: usb_if.m:35
#define USB_GET_REPORT_ID
Definition: usb_ioctl.h:247
#define USB_GET_DEVICEINFO
Definition: usb_ioctl.h:261
#define USB_SET_REPORT
Definition: usb_ioctl.h:246
#define USB_GET_REPORT
Definition: usb_ioctl.h:245
#define USB_GET_REPORT_DESC
Definition: usb_ioctl.h:243
#define USB_SET_IMMED
Definition: usb_ioctl.h:244
int usbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id, struct usb_attach_arg *uaa)
Definition: usb_lookup.c:143
@ UQ_HID_IGNORE
Definition: usb_quirk.h:51
@ UQ_KBD_IGNORE
Definition: usb_quirk.h:52
@ UQ_WMT_IGNORE
Definition: usb_quirk.h:116
@ UQ_UMS_IGNORE
Definition: usb_quirk.h:54
uint8_t usb_test_quirk(const struct usb_attach_arg *uaa, uint16_t quirk)
Definition: usb_device.c:2631
#define UHID_XB360GP_REPORT_DESCR
Definition: usb_rdesc.h:36
#define UHID_GRAPHIRE3_4X5_REPORT_DESCR
Definition: usb_rdesc.h:35
#define UHID_GRAPHIRE_REPORT_DESCR
Definition: usb_rdesc.h:34
usb_error_t usbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id)
Definition: usb_request.c:1806
usb_error_t usbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id)
Definition: usb_request.c:1834
usb_error_t usbd_req_set_idle(struct usb_device *udev, struct mtx *mtx, uint8_t iface_index, uint8_t duration, uint8_t id)
Definition: usb_request.c:1862
void usbd_transfer_submit(struct usb_xfer *xfer)
void usbd_xfer_set_frames(struct usb_xfer *xfer, usb_frcount_t n)
void usbd_transfer_unsetup(struct usb_xfer **pxfer, uint16_t n_setup)
void usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex, usb_frlength_t len)
struct usb_page_cache * usbd_xfer_get_frame(struct usb_xfer *xfer, usb_frcount_t frindex)
usb_error_t usbd_transfer_setup(struct usb_device *udev, const uint8_t *ifaces, struct usb_xfer **ppxfer, const struct usb_config *setup_start, uint16_t n_setup, void *priv_sc, struct mtx *xfer_mtx)
Definition: usb_transfer.c:987
void usbd_transfer_start(struct usb_xfer *xfer)
void * usbd_xfer_softc(struct usb_xfer *xfer)
void usbd_xfer_set_stall(struct usb_xfer *xfer)
void usbd_transfer_stop(struct usb_xfer *xfer)
void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, int *aframes, int *nframes)
usb_frlength_t usbd_xfer_max_len(struct usb_xfer *xfer)
void device_set_usb_desc(device_t dev)
Definition: usb_util.c:73
int usb_fifo_alloc_buffer(struct usb_fifo *f, uint32_t bufsize, uint16_t nbuf)
int() usb_fifo_ioctl_t(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)
Definition: usbdi.h:101
#define USB_IFACE_SUBCLASS(isc)
Definition: usbdi.h:388
void * usb_fifo_softc(struct usb_fifo *fifo)
void() usb_fifo_close_t(struct usb_fifo *fifo, int fflags)
Definition: usbdi.h:100
void usb_fifo_detach(struct usb_fifo_sc *f_sc)
#define USB_ST_SETUP
Definition: usbdi.h:502
void usb_fifo_put_data(struct usb_fifo *fifo, struct usb_page_cache *pc, usb_frlength_t offset, usb_frlength_t len, uint8_t what)
void usb_fifo_get_data_error(struct usb_fifo *fifo)
int usb_fifo_attach(struct usb_device *udev, void *priv_sc, struct mtx *priv_mtx, struct usb_fifo_methods *pm, struct usb_fifo_sc *f_sc, uint16_t unit, int16_t subunit, uint8_t iface_index, uid_t uid, gid_t gid, int mode)
usb_error_t
Definition: usbdi.h:45
@ USB_ERR_CANCELLED
Definition: usbdi.h:51
void() usb_fifo_cmd_t(struct usb_fifo *fifo)
Definition: usbdi.h:102
void usb_fifo_free_buffer(struct usb_fifo *f)
void usb_fifo_put_data_error(struct usb_fifo *fifo)
#define USB_IFACE_CLASS(ic)
Definition: usbdi.h:385
uint8_t usb_fifo_get_data(struct usb_fifo *fifo, struct usb_page_cache *pc, usb_frlength_t offset, usb_frlength_t len, usb_frlength_t *actlen, uint8_t what)
#define USB_ST_TRANSFERRED
Definition: usbdi.h:503
#define USB_IFACE_PROTOCOL(ip)
Definition: usbdi.h:391
#define USB_FIFO_RX
Definition: usbdi.h:527
void() usb_callback_t(struct usb_xfer *, usb_error_t)
Definition: usbdi.h:94
#define USB_FIFO_TX
Definition: usbdi.h:526
int() usb_fifo_open_t(struct usb_fifo *fifo, int fflags)
Definition: usbdi.h:99
#define STRUCT_USB_HOST_ID
Definition: usbdi.h:258
#define USB_GET_STATE(xfer)
Definition: usbdi.h:515
uint32_t usb_fifo_put_bytes_max(struct usb_fifo *fifo)
#define UHID_FEATURE_REPORT
Definition: usbhid.h:68
#define UHID_OUTPUT_REPORT
Definition: usbhid.h:67
#define UR_GET_REPORT
Definition: usbhid.h:45
#define UR_SET_REPORT
Definition: usbhid.h:46
#define UHID_INPUT_REPORT
Definition: usbhid.h:66