Sat Jul 30 12:15:44 2011 UTC ()
add support for game controllers in "XInput" mode, they are basically
HID devices without a report descriptor
(jmcneill)
diff -r1.50 -r1.51 src/sys/dev/usb/uhidev.c
diff -r0 -r1.1 src/sys/dev/usb/xinput_rdesc.h
--- src/sys/dev/usb/uhidev.c 2011/07/20 19:27:53 1.50
+++ src/sys/dev/usb/uhidev.c 2011/07/30 12:15:44 1.51
| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: uhidev.c,v 1.50 2011/07/20 19:27:53 ryoon Exp $ */ | | 1 | /* $NetBSD: uhidev.c,v 1.51 2011/07/30 12:15:44 jmcneill Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | | 8 | * by Lennart Augustsson (lennart@augustsson.net) at |
9 | * Carlstedt Research & Technology. | | 9 | * Carlstedt Research & Technology. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
| @@ -25,50 +25,52 @@ | | | @@ -25,50 +25,52 @@ |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | /* | | 33 | /* |
34 | * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf | | 34 | * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.50 2011/07/20 19:27:53 ryoon Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.51 2011/07/30 12:15:44 jmcneill Exp $"); |
39 | | | 39 | |
40 | #include <sys/param.h> | | 40 | #include <sys/param.h> |
41 | #include <sys/systm.h> | | 41 | #include <sys/systm.h> |
42 | #include <sys/kernel.h> | | 42 | #include <sys/kernel.h> |
43 | #include <sys/malloc.h> | | 43 | #include <sys/malloc.h> |
44 | #include <sys/signalvar.h> | | 44 | #include <sys/signalvar.h> |
45 | #include <sys/device.h> | | 45 | #include <sys/device.h> |
46 | #include <sys/ioctl.h> | | 46 | #include <sys/ioctl.h> |
47 | #include <sys/conf.h> | | 47 | #include <sys/conf.h> |
48 | | | 48 | |
49 | #include <dev/usb/usb.h> | | 49 | #include <dev/usb/usb.h> |
50 | #include <dev/usb/usbhid.h> | | 50 | #include <dev/usb/usbhid.h> |
51 | | | 51 | |
52 | #include <dev/usb/usbdevs.h> | | 52 | #include <dev/usb/usbdevs.h> |
53 | #include <dev/usb/usbdi.h> | | 53 | #include <dev/usb/usbdi.h> |
54 | #include <dev/usb/usbdi_util.h> | | 54 | #include <dev/usb/usbdi_util.h> |
55 | #include <dev/usb/hid.h> | | 55 | #include <dev/usb/hid.h> |
56 | #include <dev/usb/usb_quirks.h> | | 56 | #include <dev/usb/usb_quirks.h> |
57 | | | 57 | |
58 | #include <dev/usb/uhidev.h> | | 58 | #include <dev/usb/uhidev.h> |
59 | | | 59 | |
60 | /* Report descriptor for broken Wacom Graphire */ | | 60 | /* Report descriptor for broken Wacom Graphire */ |
61 | #include <dev/usb/ugraphire_rdesc.h> | | 61 | #include <dev/usb/ugraphire_rdesc.h> |
| | | 62 | /* Report descriptor for game controllers in "XInput" mode */ |
| | | 63 | #include <dev/usb/xinput_rdesc.h> |
62 | | | 64 | |
63 | #include "locators.h" | | 65 | #include "locators.h" |
64 | | | 66 | |
65 | #ifdef UHIDEV_DEBUG | | 67 | #ifdef UHIDEV_DEBUG |
66 | #define DPRINTF(x) if (uhidevdebug) printf x | | 68 | #define DPRINTF(x) if (uhidevdebug) printf x |
67 | #define DPRINTFN(n,x) if (uhidevdebug>(n)) printf x | | 69 | #define DPRINTFN(n,x) if (uhidevdebug>(n)) printf x |
68 | int uhidevdebug = 0; | | 70 | int uhidevdebug = 0; |
69 | #else | | 71 | #else |
70 | #define DPRINTF(x) | | 72 | #define DPRINTF(x) |
71 | #define DPRINTFN(n,x) | | 73 | #define DPRINTFN(n,x) |
72 | #endif | | 74 | #endif |
73 | | | 75 | |
74 | Static void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); | | 76 | Static void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); |
| @@ -80,26 +82,29 @@ int uhidev_match(device_t, cfdata_t, voi | | | @@ -80,26 +82,29 @@ int uhidev_match(device_t, cfdata_t, voi |
80 | void uhidev_attach(device_t, device_t, void *); | | 82 | void uhidev_attach(device_t, device_t, void *); |
81 | void uhidev_childdet(device_t, device_t); | | 83 | void uhidev_childdet(device_t, device_t); |
82 | int uhidev_detach(device_t, int); | | 84 | int uhidev_detach(device_t, int); |
83 | int uhidev_activate(device_t, enum devact); | | 85 | int uhidev_activate(device_t, enum devact); |
84 | extern struct cfdriver uhidev_cd; | | 86 | extern struct cfdriver uhidev_cd; |
85 | CFATTACH_DECL2_NEW(uhidev, sizeof(struct uhidev_softc), uhidev_match, | | 87 | CFATTACH_DECL2_NEW(uhidev, sizeof(struct uhidev_softc), uhidev_match, |
86 | uhidev_attach, uhidev_detach, uhidev_activate, NULL, uhidev_childdet); | | 88 | uhidev_attach, uhidev_detach, uhidev_activate, NULL, uhidev_childdet); |
87 | | | 89 | |
88 | int | | 90 | int |
89 | uhidev_match(device_t parent, cfdata_t match, void *aux) | | 91 | uhidev_match(device_t parent, cfdata_t match, void *aux) |
90 | { | | 92 | { |
91 | struct usbif_attach_arg *uaa = aux; | | 93 | struct usbif_attach_arg *uaa = aux; |
92 | | | 94 | |
| | | 95 | /* Game controllers in "XInput" mode */ |
| | | 96 | if (USBIF_IS_XINPUT(uaa)) |
| | | 97 | return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; |
93 | if (uaa->class != UICLASS_HID) | | 98 | if (uaa->class != UICLASS_HID) |
94 | return (UMATCH_NONE); | | 99 | return (UMATCH_NONE); |
95 | if (usbd_get_quirks(uaa->device)->uq_flags & UQ_HID_IGNORE) | | 100 | if (usbd_get_quirks(uaa->device)->uq_flags & UQ_HID_IGNORE) |
96 | return (UMATCH_NONE); | | 101 | return (UMATCH_NONE); |
97 | return (UMATCH_IFACECLASS_GENERIC); | | 102 | return (UMATCH_IFACECLASS_GENERIC); |
98 | } | | 103 | } |
99 | | | 104 | |
100 | void | | 105 | void |
101 | uhidev_attach(device_t parent, device_t self, void *aux) | | 106 | uhidev_attach(device_t parent, device_t self, void *aux) |
102 | { | | 107 | { |
103 | struct uhidev_softc *sc = device_private(self); | | 108 | struct uhidev_softc *sc = device_private(self); |
104 | struct usbif_attach_arg *uaa = aux; | | 109 | struct usbif_attach_arg *uaa = aux; |
105 | usbd_interface_handle iface = uaa->iface; | | 110 | usbd_interface_handle iface = uaa->iface; |
| @@ -203,26 +208,30 @@ uhidev_attach(device_t parent, device_t | | | @@ -203,26 +208,30 @@ uhidev_attach(device_t parent, device_t |
203 | * returning digitizer data. | | 208 | * returning digitizer data. |
204 | */ | | 209 | */ |
205 | usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 2, | | 210 | usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 2, |
206 | &reportbuf, sizeof reportbuf); | | 211 | &reportbuf, sizeof reportbuf); |
207 | | | 212 | |
208 | size = sizeof uhid_graphire3_4x5_report_descr; | | 213 | size = sizeof uhid_graphire3_4x5_report_descr; |
209 | descptr = uhid_graphire3_4x5_report_descr; | | 214 | descptr = uhid_graphire3_4x5_report_descr; |
210 | break; | | 215 | break; |
211 | default: | | 216 | default: |
212 | /* Keep descriptor */ | | 217 | /* Keep descriptor */ |
213 | break; | | 218 | break; |
214 | } | | 219 | } |
215 | } | | 220 | } |
| | | 221 | if (USBIF_IS_XINPUT(uaa)) { |
| | | 222 | size = sizeof uhid_xinput_report_descr; |
| | | 223 | descptr = uhid_xinput_report_descr; |
| | | 224 | } |
216 | | | 225 | |
217 | if (descptr) { | | 226 | if (descptr) { |
218 | desc = malloc(size, M_USBDEV, M_NOWAIT); | | 227 | desc = malloc(size, M_USBDEV, M_NOWAIT); |
219 | if (desc == NULL) | | 228 | if (desc == NULL) |
220 | err = USBD_NOMEM; | | 229 | err = USBD_NOMEM; |
221 | else { | | 230 | else { |
222 | err = USBD_NORMAL_COMPLETION; | | 231 | err = USBD_NORMAL_COMPLETION; |
223 | memcpy(desc, descptr, size); | | 232 | memcpy(desc, descptr, size); |
224 | } | | 233 | } |
225 | } else { | | 234 | } else { |
226 | desc = NULL; | | 235 | desc = NULL; |
227 | err = usbd_read_report_desc(uaa->iface, &desc, &size, | | 236 | err = usbd_read_report_desc(uaa->iface, &desc, &size, |
228 | M_USBDEV); | | 237 | M_USBDEV); |
/* $NetBSD: xinput_rdesc.h,v 1.1 2011/07/30 12:15:44 jmcneill Exp $ */
/*-
* Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Descriptor from http://euc.jp/periphs/xbox-pad-report-desc.txt
*/
#define USBIF_IS_XINPUT(uaa) \
((uaa)->class == UICLASS_VENDOR && \
(uaa)->subclass == 0x5d && \
(uaa)->proto == 0x01)
static const uByte uhid_xinput_report_descr[] = {
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x05, /* Usage (Game Pad) */
0xa1, 0x01, /* Collection (Application) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x3a, /* Usage (Counted Buffer) */
0xa1, 0x02, /* Collection (Logical) */
0x75, 0x08, /* Report Size (8) */
0x95, 0x01, /* Report Count (1) */
0x81, 0x01, /* Input (Constant) */
0x75, 0x08, /* Report Size (8) */
0x95, 0x01, /* Report Count (1) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x3b, /* Usage (Byte Count) */
0x81, 0x01, /* Input (Constant) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x01, /* Usage (Pointer) */
0xa1, 0x00, /* Collection (Physical) */
0x75, 0x01, /* Report Size (1) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x35, 0x00, /* Physical Minimum (0) */
0x45, 0x01, /* Physical Maximum (1) */
0x95, 0x04, /* Report Count (4) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x90, /* Usage (D-pad Up) */
0x09, 0x91, /* Usage (D-pad Down) */
0x09, 0x93, /* Usage (D-pad Left) */
0x09, 0x92, /* Usage (D-pad Right) */
0x81, 0x02, /* Input (Data,Variable,Absolute) */
0xc0, /* End Collection */
0x75, 0x01, /* Report Size (1) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x35, 0x00, /* Physical Minimum (0) */
0x45, 0x01, /* Physical Maximum (1) */
0x95, 0x04, /* Report Count (4) */
0x05, 0x09, /* Usage Page (Button) */
0x19, 0x07, /* Usage Minimum (Button 7) */
0x29, 0x0a, /* Usage Maximum (Button 10) */
0x81, 0x02, /* Input (Data,Variable,Absolute) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x08, /* Report Count (8) */
0x81, 0x01, /* Input (Constant) */
0x75, 0x08, /* Report Size (8) */
0x15, 0x00, /* Logical Minimum (0) */
0x26, 0xff, 0x00, /* Logical Maximum (255) */
0x35, 0x00, /* Physical Minimum (0) */
0x46, 0xff, 0x00, /* Physical Maximum (255) */
0x95, 0x06, /* Report Count (6) */
0x05, 0x09, /* Usage Page (Button) */
0x19, 0x01, /* Usage Minimum (Button 1) */
0x29, 0x06, /* Usage Minimum (Button 6) */
0x81, 0x02, /* Input (Data,Variable,Absolute) */
0x75, 0x08, /* Report Size (8) */
0x15, 0x00, /* Logical Minimum (0) */
0x26, 0xff, 0x00, /* Logical Maximum (255) */
0x35, 0x00, /* Physical Minimum (0) */
0x46, 0xff, 0x00, /* Physical Maximum (255) */
0x95, 0x02, /* Report Count (2) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x32, /* Usage (Z) */
0x09, 0x35, /* Usage (Rz) */
0x81, 0x02, /* Input (Data,Variable,Absolute) */
0x75, 0x10, /* Report Size (16) */
0x16, 0x00, 0x80, /* Logical Minimum (-32768) */
0x26, 0xff, 0x7f, /* Logical Maximum (32767) */
0x36, 0x00, 0x80, /* Physical Minimum (-32768) */
0x46, 0xff, 0x7f, /* Physical Maximum (32767) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x01, /* Usage (Pointer) */
0xa1, 0x00, /* Collection (Physical) */
0x95, 0x02, /* Report Count (2) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x30, /* Usage (X) */
0x09, 0x31, /* Usage (Y) */
0x81, 0x02, /* Input (Data,Variable,Absolute) */
0xc0, /* End Collection */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x01, /* Usage (Pointer) */
0xa1, 0x00, /* Collection (Physical) */
0x95, 0x02, /* Report Count (2) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x33, /* Usage (Rx) */
0x09, 0x34, /* Usage (Ry) */
0x81, 0x02, /* Input (Data,Variable,Absolute) */
0xc0, /* End Collection */
0xc0, /* End Collection */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x3a, /* Usage (Counted Buffer) */
0xa1, 0x02, /* Collection (Logical) */
0x75, 0x08, /* Report Size (8) */
0x95, 0x01, /* Report Count (1) */
0x91, 0x01, /* Output (Constant) */
0x75, 0x08, /* Report Size (8) */
0x95, 0x01, /* Report Count (1) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x3b, /* Usage (Byte Count) */
0x91, 0x01, /* Output (Constant) */
0x75, 0x08, /* Report Size (8) */
0x95, 0x01, /* Report Count (1) */
0x91, 0x01, /* Output (Constant) */
0x75, 0x08, /* Report Size (8) */
0x15, 0x00, /* Logical Minimum (0) */
0x26, 0xff, 0x00, /* Logical Maximum (255) */
0x35, 0x00, /* Physical Minimum (0) */
0x46, 0xff, 0x00, /* Physical Maximum (255) */
0x95, 0x01, /* Report Count (1) */
0x06, 0x00, 0xff, /* Usage Page (vendor-defined) */
0x09, 0x01, /* Usage (1) */
0x91, 0x02, /* Output (Data,Variable,Absolute) */
0x75, 0x08, /* Report Size (8) */
0x95, 0x01, /* Report Count (1) */
0x91, 0x01, /* Output (Constant) */
0x75, 0x08, /* Report Size (8) */
0x15, 0x00, /* Logical Minimum (0) */
0x26, 0xff, 0x00, /* Logical Maximum (255) */
0x35, 0x00, /* Physical Minimum (0) */
0x46, 0xff, 0x00, /* Physical Maximum (255) */
0x95, 0x01, /* Report Count (1) */
0x06, 0x00, 0xff, /* Usage Page (vendor-defined) */
0x09, 0x02, /* Usage (2) */
0x91, 0x02, /* Output (Data,Variable,Absolute) */
0xc0, /* End Collection */
0xc0, /* End Collection */
};