On 10/20 03:52, Martin Pieuchot wrote: > Hi Jeremy, > > On 18/10/13(Fri) 09:11, Jeremy Evans wrote: > > This was originally submitted by Joe Gidi in November 2010, based on a > > FreeBSD commit by Ed Schouten from back in December 2005. See > > http://marc.info/?l=openbsd-tech&m=128924886803756&w=2 for previous > > thread. The only comment was from tedu@, that SMALL_KERNEL should be > > added, which I've done but I'm not sure correctly. > > > > Tested on amd64 using usbhidctl and some SDL-based emulators (mednafen, > > snes9x-gtk, desmume). The controller works fine except that the > > directional pad is not processed as a hat but as a series of buttons > > (that usbhidctl sees but SDL seems not to recognize). Also, the bottom > > L/R triggers are axes instead of buttons. > > > > I've built a release with this, and checked that the amd64 floppy > > still fits. > > Good stuff, some comments below.
Martin, Thanks for responding. Here's a new diff that incorporates most of your suggestions. Unfortunately, using the existing quirks infrastructure doesn't work correctly, because the quirks API is based on device manufacturer and vendor, and matching on that instead of interface subclass and protocol appears to not work correctly. When you plug in the controller with my original diff and the first diff below, you get: uhidev0 at uhub3 port 3 configuration 1 interface 0 "\M-)Microsoft Corporation Controller" rev 2.00/1.10 addr 2 uhidev0: iclass 255/93 uhid0 at uhidev0: input=20, output=0, feature=0 ugen0 at uhub3 port 3 configuration 1 "\M-)Microsoft Corporation Controller" rev 2.00/1.10 addr 2 As you can see, the controller shows up as both a uhid and a ugen. With the second diff below, when you plugin the controller, it attaches as follows: uhidev0 at uhub3 port 3 configuration 1 interface 0 "\M-)Microsoft Corporation Controller" rev 2.00/1.10 addr 2 uhidev0: iclass 255/93 uhid0 at uhidev0: input=20, output=0, feature=0 uhidev1 at uhub3 port 3 configuration 1 interface 1 "\M-)Microsoft Corporation Controller" rev 2.00/1.10 addr 2 uhidev1: iclass 255/93 uhid1 at uhidev1: input=20, output=0, feature=0 uhidev2 at uhub3 port 3 configuration 1 interface 2 "\M-)Microsoft Corporation Controller" rev 2.00/1.10 addr 2 uhidev2: iclass 255/93 uhid2 at uhidev2: input=20, output=0, feature=0 uhidev3 at uhub3 port 3 configuration 1 interface 3 "\M-)Microsoft Corporation Controller" rev 2.00/1.10 addr 2 uhidev3: no input interrupt endpoint In this case uhid0 appears to work, but uhid1 and uhid2 do not: $ usbhidctl -f 1 -a usbhidctl: USB_GET_REPORT (probably not supported by device): Input/output error Anyway, let me know what you think about the first diff, or if I'm doing something wrong with the second diff that is causing it to attach multiple times. Thanks, Jeremy Working diff: Index: uhidev.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uhidev.c,v retrieving revision 1.46 diff -u -p -r1.46 uhidev.c --- uhidev.c 20 Sep 2013 15:34:50 -0000 1.46 +++ uhidev.c 20 Oct 2013 18:23:37 -0000 @@ -55,8 +55,13 @@ #include <dev/usb/uhidev.h> -/* Report descriptor for broken Wacom Graphire */ +#ifndef SMALL_KERNEL +/* Replacement report descriptors for devices shipped with broken ones */ #include <dev/usb/ugraphire_rdesc.h> +#include <dev/usb/uxb360gp_rdesc.h> +#define UISUBCLASS_XBOX360_CONTROLLER 0x5d +#define UIPROTO_XBOX360_GAMEPAD 0x01 +#endif /* !SMALL_KERNEL */ #ifdef UHIDEV_DEBUG #define DPRINTF(x) do { if (uhidevdebug) printf x; } while (0) @@ -99,8 +104,17 @@ uhidev_match(struct device *parent, void if (uaa->iface == NULL) return (UMATCH_NONE); id = usbd_get_interface_descriptor(uaa->iface); - if (id == NULL || id->bInterfaceClass != UICLASS_HID) - return (UMATCH_NONE); + if (id == NULL) + return (UMATCH_NONE); + if (id->bInterfaceClass != UICLASS_HID) { +#ifndef SMALL_KERNEL + /* The Xbox 360 gamepad doesn't use the HID class. */ + if (id->bInterfaceClass != UICLASS_VENDOR || + id->bInterfaceSubClass != UISUBCLASS_XBOX360_CONTROLLER || + id->bInterfaceProtocol != UIPROTO_XBOX360_GAMEPAD) +#endif /* !SMALL_KERNEL */ + return (UMATCH_NONE); + } if (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_HID) return (UMATCH_NONE); if (uaa->matchlvl) @@ -180,6 +194,7 @@ uhidev_attach(struct device *parent, str /* XXX need to extend this */ descptr = NULL; +#ifndef SMALL_KERNEL if (uaa->vendor == USB_VENDOR_WACOM) { static uByte reportbuf[] = {2, 2, 2}; @@ -200,7 +215,15 @@ uhidev_attach(struct device *parent, str /* Keep descriptor */ break; } + } else if (id->bInterfaceClass == UICLASS_VENDOR && + id->bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER && + id->bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD) { + /* The Xbox 360 gamepad has no report descriptor. */ + size = sizeof uhid_xb360gp_report_descr; + descptr = uhid_xb360gp_report_descr; } +#endif /* !SMALL_KERNEL */ + if (descptr) { desc = malloc(size, M_USBDEV, M_NOWAIT); Index: uxb360gp_rdesc.h =================================================================== RCS file: uxb360gp_rdesc.h diff -N uxb360gp_rdesc.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ uxb360gp_rdesc.h 20 Oct 2013 18:24:41 -0000 @@ -0,0 +1,125 @@ +/* $OpenBSD$ */ +/*- + * Copyright (c) 2005 Ed Schouten <e...@freebsd.org> + * 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 AUTHOR 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. + * + * $FreeBSD: src/sys/dev/usb/uxb360gp_rdesc.h,v 1.3 2008/05/24 18:35:55 ed Exp $ + */ + +/* + * The descriptor has no output report format, thus preventing you from + * controlling the LEDs and the built-in rumblers. + */ +static const uByte uhid_xb360gp_report_descr[] = { + 0x05, 0x01, /* USAGE PAGE (Generic Desktop) */ + 0x09, 0x05, /* USAGE (Gamepad) */ + 0xa1, 0x01, /* COLLECTION (Application) */ + /* Unused */ + 0x75, 0x08, /* REPORT SIZE (8) */ + 0x95, 0x01, /* REPORT COUNT (1) */ + 0x81, 0x01, /* INPUT (Constant) */ + /* Byte count */ + 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) */ + /* D-Pad */ + 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 */ + /* Buttons 5-11 */ + 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, 0x07, /* REPORT COUNT (7) */ + 0x05, 0x09, /* USAGE PAGE (Button) */ + 0x09, 0x08, /* USAGE (Button 8) */ + 0x09, 0x07, /* USAGE (Button 7) */ + 0x09, 0x09, /* USAGE (Button 9) */ + 0x09, 0x0a, /* USAGE (Button 10) */ + 0x09, 0x05, /* USAGE (Button 5) */ + 0x09, 0x06, /* USAGE (Button 6) */ + 0x09, 0x0b, /* USAGE (Button 11) */ + 0x81, 0x02, /* INPUT (Data, Variable, Absolute) */ + /* Unused */ + 0x75, 0x01, /* REPORT SIZE (1) */ + 0x95, 0x01, /* REPORT COUNT (1) */ + 0x81, 0x01, /* INPUT (Constant) */ + /* Buttons 1-4 */ + 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, 0x01, /* USAGE MINIMUM (Button 1) */ + 0x29, 0x04, /* USAGE MAXIMUM (Button 4) */ + 0x81, 0x02, /* INPUT (Data, Variable, Absolute) */ + /* Triggers */ + 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 SIZE (2) */ + 0x05, 0x01, /* USAGE PAGE (Generic Desktop) */ + 0x09, 0x32, /* USAGE (Z) */ + 0x09, 0x35, /* USAGE (Rz) */ + 0x81, 0x02, /* INPUT (Data, Variable, Absolute) */ + /* Sticks */ + 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) */ + 0x95, 0x04, /* REPORT COUNT (4) */ + 0x05, 0x01, /* USAGE PAGE (Generic Desktop) */ + 0x09, 0x30, /* USAGE (X) */ + 0x09, 0x31, /* USAGE (Y) */ + 0x09, 0x33, /* USAGE (Rx) */ + 0x09, 0x34, /* USAGE (Ry) */ + 0x81, 0x02, /* INPUT (Data, Variable, Absolute) */ + /* Unused */ + 0x75, 0x30, /* REPORT SIZE (48) */ + 0x95, 0x01, /* REPORT COUNT (1) */ + 0x81, 0x01, /* INPUT (Constant) */ + 0xc0, /* END COLLECTION */ +}; Broken diff using quirks: Index: uhidev.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uhidev.c,v retrieving revision 1.46 diff -u -p -r1.46 uhidev.c --- uhidev.c 20 Sep 2013 15:34:50 -0000 1.46 +++ uhidev.c 20 Oct 2013 17:21:47 -0000 @@ -55,8 +55,11 @@ #include <dev/usb/uhidev.h> -/* Report descriptor for broken Wacom Graphire */ +#ifndef SMALL_KERNEL +/* Replacement report descriptors for devices shipped with broken ones */ #include <dev/usb/ugraphire_rdesc.h> +#include <dev/usb/uxb360gp_rdesc.h> +#endif /* !SMALL_KERNEL */ #ifdef UHIDEV_DEBUG #define DPRINTF(x) do { if (uhidevdebug) printf x; } while (0) @@ -99,9 +102,14 @@ uhidev_match(struct device *parent, void if (uaa->iface == NULL) return (UMATCH_NONE); id = usbd_get_interface_descriptor(uaa->iface); - if (id == NULL || id->bInterfaceClass != UICLASS_HID) + if (id == NULL) return (UMATCH_NONE); - if (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_HID) + if (id->bInterfaceClass != UICLASS_HID) { +#ifndef SMALL_KERNEL + if (!(usbd_get_quirks(uaa->device)->uq_flags & UQ_FORCE_HID)) +#endif /* !SMALL_KERNEL */ + return (UMATCH_NONE); + } else if (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_HID) return (UMATCH_NONE); if (uaa->matchlvl) return (uaa->matchlvl); @@ -180,6 +188,7 @@ uhidev_attach(struct device *parent, str /* XXX need to extend this */ descptr = NULL; +#ifndef SMALL_KERNEL if (uaa->vendor == USB_VENDOR_WACOM) { static uByte reportbuf[] = {2, 2, 2}; @@ -200,7 +209,13 @@ uhidev_attach(struct device *parent, str /* Keep descriptor */ break; } + } else if (uaa->vendor == USB_VENDOR_MICROSOFT && + uaa->product == USB_PRODUCT_MICROSOFT_XBOX360_CONTROLLER) { + /* The Xbox 360 gamepad has no report descriptor. */ + size = sizeof uhid_xb360gp_report_descr; + descptr = uhid_xb360gp_report_descr; } +#endif /* !SMALL_KERNEL */ if (descptr) { desc = malloc(size, M_USBDEV, M_NOWAIT); Index: usb_quirks.c =================================================================== RCS file: /cvs/src/sys/dev/usb/usb_quirks.c,v retrieving revision 1.68 diff -u -p -r1.68 usb_quirks.c --- usb_quirks.c 8 Mar 2013 02:21:43 -0000 1.68 +++ usb_quirks.c 20 Oct 2013 16:48:30 -0000 @@ -171,6 +171,10 @@ const struct usbd_quirk_entry { ANY, { UQ_MS_BAD_CLASS | UQ_MS_LEADING_BYTE }}, { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WLNOTEBOOK2, ANY, { UQ_MS_BAD_CLASS | UQ_MS_LEADING_BYTE }}, +#ifndef SMALL_KERNEL + { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_XBOX360_CONTROLLER, + ANY, { UQ_FORCE_HID }}, +#endif /* !SMALL_KERNEL */ { 0, 0, 0, { 0 } } }; Index: usb_quirks.h =================================================================== RCS file: /cvs/src/sys/dev/usb/usb_quirks.h,v retrieving revision 1.16 diff -u -p -r1.16 usb_quirks.h --- usb_quirks.h 19 Jul 2010 05:08:37 -0000 1.16 +++ usb_quirks.h 20 Oct 2013 16:24:07 -0000 @@ -49,6 +49,7 @@ struct usbd_quirks { #define UQ_MS_LEADING_BYTE 0x00010000 /* mouse sends unknown leading byte */ #define UQ_EHCI_NEEDTO_DISOWN 0x00020000 /* must hand device over to USB 1.1 if attached to EHCI */ +#define UQ_FORCE_HID 0x00040000 /* device claims not uhid, but is */ }; extern const struct usbd_quirks usbd_no_quirk; Index: usbdevs.h =================================================================== RCS file: /cvs/src/sys/dev/usb/usbdevs.h,v retrieving revision 1.618 diff -u -p -r1.618 usbdevs.h --- usbdevs.h 7 Oct 2013 05:39:11 -0000 1.618 +++ usbdevs.h 20 Oct 2013 16:40:21 -0000 @@ -2868,6 +2868,7 @@ #define USB_PRODUCT_MICROSOFT_WLNOTEBOOK 0x00b9 /* Wireless Optical Mouse (Model 1023) */ #define USB_PRODUCT_MICROSOFT_WLNOTEBOOK3 0x00d2 /* Wireless Optical Mouse 3000 (Model 1049) */ #define USB_PRODUCT_MICROSOFT_WLNOTEBOOK2 0x00e1 /* Wireless Optical Mouse 3000 (Model 1056) */ +#define USB_PRODUCT_MICROSOFT_XBOX360_CONTROLLER 0x028e /* XBOX 360 Controller */ #define USB_PRODUCT_MICROSOFT_XBOX360 0x0292 /* XBOX 360 WLAN */ #define USB_PRODUCT_MICROSOFT_LIFECAM 0x074a /* Microsoft LifeCam */ Index: uxb360gp_rdesc.h =================================================================== RCS file: uxb360gp_rdesc.h diff -N uxb360gp_rdesc.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ uxb360gp_rdesc.h 20 Oct 2013 16:59:26 -0000 @@ -0,0 +1,125 @@ +/* $OpenBSD$ */ +/*- + * Copyright (c) 2005 Ed Schouten <e...@freebsd.org> + * 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 AUTHOR 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. + * + * $FreeBSD: src/sys/dev/usb/uxb360gp_rdesc.h,v 1.3 2008/05/24 18:35:55 ed Exp $ + */ + +/* + * The descriptor has no output report format, thus preventing you from + * controlling the LEDs and the built-in rumblers. + */ +static const uByte uhid_xb360gp_report_descr[] = { + 0x05, 0x01, /* USAGE PAGE (Generic Desktop) */ + 0x09, 0x05, /* USAGE (Gamepad) */ + 0xa1, 0x01, /* COLLECTION (Application) */ + /* Unused */ + 0x75, 0x08, /* REPORT SIZE (8) */ + 0x95, 0x01, /* REPORT COUNT (1) */ + 0x81, 0x01, /* INPUT (Constant) */ + /* Byte count */ + 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) */ + /* D-Pad */ + 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 */ + /* Buttons 5-11 */ + 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, 0x07, /* REPORT COUNT (7) */ + 0x05, 0x09, /* USAGE PAGE (Button) */ + 0x09, 0x08, /* USAGE (Button 8) */ + 0x09, 0x07, /* USAGE (Button 7) */ + 0x09, 0x09, /* USAGE (Button 9) */ + 0x09, 0x0a, /* USAGE (Button 10) */ + 0x09, 0x05, /* USAGE (Button 5) */ + 0x09, 0x06, /* USAGE (Button 6) */ + 0x09, 0x0b, /* USAGE (Button 11) */ + 0x81, 0x02, /* INPUT (Data, Variable, Absolute) */ + /* Unused */ + 0x75, 0x01, /* REPORT SIZE (1) */ + 0x95, 0x01, /* REPORT COUNT (1) */ + 0x81, 0x01, /* INPUT (Constant) */ + /* Buttons 1-4 */ + 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, 0x01, /* USAGE MINIMUM (Button 1) */ + 0x29, 0x04, /* USAGE MAXIMUM (Button 4) */ + 0x81, 0x02, /* INPUT (Data, Variable, Absolute) */ + /* Triggers */ + 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 SIZE (2) */ + 0x05, 0x01, /* USAGE PAGE (Generic Desktop) */ + 0x09, 0x32, /* USAGE (Z) */ + 0x09, 0x35, /* USAGE (Rz) */ + 0x81, 0x02, /* INPUT (Data, Variable, Absolute) */ + /* Sticks */ + 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) */ + 0x95, 0x04, /* REPORT COUNT (4) */ + 0x05, 0x01, /* USAGE PAGE (Generic Desktop) */ + 0x09, 0x30, /* USAGE (X) */ + 0x09, 0x31, /* USAGE (Y) */ + 0x09, 0x33, /* USAGE (Rx) */ + 0x09, 0x34, /* USAGE (Ry) */ + 0x81, 0x02, /* INPUT (Data, Variable, Absolute) */ + /* Unused */ + 0x75, 0x30, /* REPORT SIZE (48) */ + 0x95, 0x01, /* REPORT COUNT (1) */ + 0x81, 0x01, /* INPUT (Constant) */ + 0xc0, /* END COLLECTION */ +};