Add support for XBox One gamecontroller, including report descriptor.
authorthfr <thfr@openbsd.org>
Mon, 21 Mar 2022 12:18:52 +0000 (12:18 +0000)
committerthfr <thfr@openbsd.org>
Mon, 21 Mar 2022 12:18:52 +0000 (12:18 +0000)
Based on previous XBox 360 controller code and NetBSD's implementation.

Tested by me and solene@.
Input by solene@ and stsp@.
ok stsp@ phessler@
ok solene@ for an earlier version.

sys/dev/usb/uhid_rdesc.h
sys/dev/usb/uhidev.c
sys/dev/usb/uhidev.h

index ecf24a6..c43bee6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uhid_rdesc.h,v 1.1 2013/10/25 03:09:59 jeremy Exp $ */
+/*     $OpenBSD: uhid_rdesc.h,v 1.2 2022/03/21 12:18:52 thfr Exp $ */
 /*     $NetBSD: ugraphire_rdesc.h,v 1.1 2000/12/29 01:47:49 augustss Exp $     */
 /*     $FreeBSD: uxb360gp_rdesc.h,v 1.3 2008/05/24 18:35:55 ed Exp $ */
 /*
@@ -273,3 +273,93 @@ static const uByte uhid_xb360gp_report_descr[] = {
     0x81, 0x01,                /*  INPUT (Constant)                    */
     0xc0,              /* END COLLECTION                       */
 };
+
+static const uByte uhid_xbonegp_report_descr[] = {
+    0x05, 0x01,                        /* USAGE PAGE (Generic Desktop)                 */
+    0x09, 0x05,                        /* USAGE (Gamepad)                              */
+    0xa1, 0x01,                        /* COLLECTION (Application)                     */
+    /* Button packet */
+    0xa1, 0x00,                        /*  COLLECTION (Physical)                       */
+    0x85, 0x20,                        /*   REPORT ID (0x20)                           */
+    /* Skip unknown field and counter */
+    0x09, 0x00,                        /*   USAGE (Undefined)                          */
+    0x75, 0x08,                        /*   REPORT SIZE (8)                            */
+    0x95, 0x02,                        /*   REPORT COUNT (2)                           */
+    0x81, 0x03,                        /*   INPUT (Constant, Variable, Absolute)       */
+    /* Payload size */
+    0x09, 0x3b,                        /*   USAGE (Byte Count)                         */
+    0x95, 0x01,                        /*   REPORT COUNT (1)                           */
+    0x81, 0x02,                        /*   INPUT (Data, Variable, Absolute)           */
+    /* 16 Buttons: 1-2=Unknown, 3=Start, 4=Back, 5-8=ABXY,
+     *                    9-12=D-Pad(Up,Dn,Lt,Rt), 13=LB, 14=RB, 15=LS, 16=RS
+     */
+    /* Skip the first 2 as they are not used */
+    0x75, 0x01,                        /*   REPORT SIZE (1)                            */
+    0x95, 0x02,                        /*   REPORT COUNT (2)                           */
+    0x81, 0x01,                        /*   INPUT (Constant)                           */
+    /* Assign buttons Start(7), Back(8), ABXY(1-4) */
+    0x15, 0x00,                        /*   LOGICAL MINIMUM (0)                        */
+    0x25, 0x01,                        /*   LOGICAL MAXIMUM (1)                        */
+    0x95, 0x06,                        /*   REPORT COUNT (6)                           */
+    0x05, 0x09,                        /*   USAGE PAGE (Button)                        */
+    0x09, 0x08,                        /*   USAGE (Button 8)                           */
+    0x09, 0x07,                        /*   USAGE (Button 7)                           */
+    0x09, 0x01,                        /*   USAGE (Button 1)                           */
+    0x09, 0x02,                        /*   USAGE (Button 2)                           */
+    0x09, 0x03,                        /*   USAGE (Button 3)                           */
+    0x09, 0x04,                        /*   USAGE (Button 4)                           */
+    0x81, 0x02,                        /*   INPUT (Data, Variable, Absolute)           */
+    /* 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)                       */
+    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-6 (Shoulder Buttons) and 9-10 (Stick Buttons) */
+    0x15, 0x00,                        /*   LOGICAL MINIMUM (0)                        */
+    0x25, 0x01,                        /*   LOGICAL MAXIMUM (1)                        */
+    0x95, 0x04,                        /*   REPORT COUNT (4)                           */
+    0x05, 0x09,                        /*   USAGE PAGE (Button)                        */
+    0x09, 0x05,                        /*   USAGE (Button 5)                           */
+    0x09, 0x06,                        /*   USAGE (Button 6)                           */
+    0x09, 0x09,                        /*   USAGE (Button 9)                           */
+    0x09, 0x0a,                        /*   USAGE (Button 10)                          */
+    0x81, 0x02,                        /*   INPUT (Data, Variable, Absolute            */
+    /* Triggers */
+    0x15, 0x00,                        /*   LOGICAL MINIMUM (0)                        */
+    0x26, 0xff, 0x03,          /*   LOGICAL MAXIMUM (1023)                     */
+    0x75, 0x10,                        /*   REPORT SIZE (16)                           */
+    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)           */
+    /* Sticks */
+    0x16, 0x00, 0x80,          /*   LOGICAL MINIMUM (-32768)                   */
+    0x26, 0xff, 0x7f,          /*   LOGICAL MAXIMUM (32767)                    */
+    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                             */
+    0x09, 0x01,                        /*   USAGE (Pointer)                            */
+    0xa1, 0x00,                        /*   COLLECTION (Physical)                      */
+    0x95, 0x02,                        /*    REPORT COUNT (2)                          */
+    0x09, 0x33,                        /*    USAGE (Rx)                                */
+    0x09, 0x34,                        /*    USAGE (Ry)                                */
+    0x81, 0x02,                        /*    INPUT (Data, Variable, Absolute)          */
+    0xc0,                      /*   END COLLECTION                             */
+    0xc0,                      /* END COLLECTION                               */
+};
index 66433a1..ebcda07 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uhidev.c,v 1.106 2021/12/03 06:34:38 anton Exp $      */
+/*     $OpenBSD: uhidev.c,v 1.107 2022/03/21 12:18:52 thfr Exp $       */
 /*     $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $     */
 
 /*
 #include <dev/usb/uhid_rdesc.h>
 int uhidev_use_rdesc(struct uhidev_softc *, usb_interface_descriptor_t *,
                int, int, void **, int *);
-#define UISUBCLASS_XBOX360_CONTROLLER 0x5d
-#define UIPROTO_XBOX360_GAMEPAD 0x01
+#define UISUBCLASS_XBOX360_CONTROLLER  0x5d
+#define UIPROTO_XBOX360_GAMEPAD                0x01
+#define UISUBCLASS_XBOXONE_CONTROLLER  0x47
+#define UIPROTO_XBOXONE_GAMEPAD                0xd0
 #endif /* !SMALL_KERNEL */
 
 #define DEVNAME(sc)            ((sc)->sc_dev.dv_xname)
@@ -123,6 +125,11 @@ uhidev_match(struct device *parent, void *match, void *aux)
            id->bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER &&
            id->bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)
                return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
+       if (id->bInterfaceClass == UICLASS_VENDOR &&
+           id->bInterfaceSubClass == UISUBCLASS_XBOXONE_CONTROLLER &&
+           id->bInterfaceProtocol == UIPROTO_XBOXONE_GAMEPAD) {
+               return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
+       }
 #endif /* !SMALL_KERNEL */
        if (id->bInterfaceClass != UICLASS_HID)
                return (UMATCH_NONE);
@@ -326,6 +333,13 @@ uhidev_use_rdesc(struct uhidev_softc *sc, usb_interface_descriptor_t *id,
                /* The Xbox 360 gamepad has no report descriptor. */
                size = sizeof(uhid_xb360gp_report_descr);
                descptr = uhid_xb360gp_report_descr;
+       } else if ((id->bInterfaceClass == UICLASS_VENDOR &&
+                   id->bInterfaceSubClass == UISUBCLASS_XBOXONE_CONTROLLER &&
+                   id->bInterfaceProtocol == UIPROTO_XBOXONE_GAMEPAD)) {
+               sc->sc_flags |= UHIDEV_F_XB1;
+               /* The Xbox One gamepad has no report descriptor. */
+               size = sizeof(uhid_xbonegp_report_descr);
+               descptr = uhid_xbonegp_report_descr;
        }
 
        if (descptr) {
@@ -585,6 +599,25 @@ uhidev_open(struct uhidev *scd)
                        error = ENOMEM;
                        goto out3;
                }
+
+#ifndef SMALL_KERNEL
+               /* XBox One controller initialization */
+               if (sc->sc_flags & UHIDEV_F_XB1) {
+                       uint8_t init_data[] = { 0x05, 0x20, 0x00, 0x01, 0x00 };
+                       size_t init_data_len = sizeof(init_data);
+                       usbd_setup_xfer(sc->sc_oxfer, sc->sc_opipe, 0,
+                           init_data, init_data_len,
+                           USBD_SYNCHRONOUS | USBD_CATCH, USBD_NO_TIMEOUT,
+                           NULL);
+                       err = usbd_transfer(sc->sc_oxfer);
+                       if (err != USBD_NORMAL_COMPLETION) {
+                               DPRINTF(("uhidev_open: xb1 init failed, "
+                               "error=%d\n", err));
+                               error = EIO;
+                               goto out3;
+                       }
+               }
+#endif /* !SMALL_KERNEL */
        }
 
        return (0);
index 8960e0e..b09bf8b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uhidev.h,v 1.40 2021/11/22 11:30:16 anton Exp $       */
+/*     $OpenBSD: uhidev.h,v 1.41 2022/03/21 12:18:52 thfr Exp $        */
 /*     $NetBSD: uhidev.h,v 1.3 2002/10/08 09:56:17 dan Exp $   */
 
 /*
@@ -55,6 +55,9 @@ struct uhidev_softc {
        struct uhidev **sc_subdevs;
 
        int sc_refcnt;
+
+       u_int sc_flags;
+#define UHIDEV_F_XB1   0x0001          /* Xbox One controller */
 };
 
 struct uhidev {