On Sat, Jan 09, 2021 at 10:50:35AM -0700, Thomas Frohwein wrote:
> Hi,
> 
> This diff adds support for the XBox One gamecontroller in a similar way
> to what we have for the (older) XBox 360 controller [1][2]. This diff
> is based on the pertinent code in NetBSD's uhidev.c.
> 
> Similarities include that the device doesn't provide a report
> descriptor, so this diff adds one to uhid_rdesc.h.
> 
> The biggest difference (that held this up for a while) is that the
> controller needs an init byte sequence to "wake up."
> 
> The original report descriptor from NetBSD just maps the buttons and
> axes in the order that they appear in the report. I modified the report
> descriptor to assign the buttons/axes in the most logical order for
> compatibility, which results in the same layout that we already have
> for the XBox 360 controller.
> 
> The addition of the member sc_flags to struct uhidev_softc follows the
> NetBSD example.
> 
> I have tested this with usbhidctl(1), sdl2-jstest (from sdl-jstest
> package), and a couple of SDL2 games (Owlboy, Cryptark).
> 
> If you have an XBox One controller, the easiest way to test is with:
> 
> $ usbhidctl -f /dev/uhidX -l
> 
> Make sure to pick the right uhid device and that you have read
> permissions for it.
> 
> Of course, this works only with the controller connected via USB, and
> doesn't magically add wireless support.
> 
> If you test actual SDL2 applications, the button layout will likely
> default to an odd configuration. I am simultaneously preparing a diff
> for sdl2-2.0.14p0 that improves recognition and automatic mapping and
> solves any issues with XBox One default button layout.

I have an update to this diff. 2 testers used a more recent XBox One
controller model (model number 1708 in both cases) and ran into
problems with the original diff. Below is a new diff that uses a longer
5-byte init sequence taken from Linux' xpad.c [1], compared to the
2-byte sequence from NetBSD's uhidev.c that I offered in the initial
diff. This fixed the issue for the 2 testers.

My own XBox One controller is model number 1537 and still works with
this diff.

[1] https://github.com/paroj/xpad/blob/master/xpad.c#L479

Index: uhid_rdesc.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhid_rdesc.h,v
retrieving revision 1.1
diff -u -p -r1.1 uhid_rdesc.h
--- uhid_rdesc.h        25 Oct 2013 03:09:59 -0000      1.1
+++ uhid_rdesc.h        9 Jan 2021 15:11:30 -0000
@@ -272,4 +272,94 @@ static const uByte uhid_xb360gp_report_d
     0x95, 0x01,                /*  REPORT COUNT (1)                    */
     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: uhidev.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhidev.c,v
retrieving revision 1.83
diff -u -p -r1.83 uhidev.c
--- uhidev.c    31 Aug 2020 12:26:49 -0000      1.83
+++ uhidev.c    9 Jan 2021 15:11:30 -0000
@@ -63,8 +63,10 @@
 #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)
@@ -124,6 +126,11 @@ uhidev_match(struct device *parent, void
            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);
@@ -306,6 +313,13 @@ uhidev_use_rdesc(struct uhidev_softc *sc
                /* 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) {
@@ -557,6 +571,23 @@ uhidev_open(struct uhidev *scd)
                        DPRINTF(("uhidev_open: couldn't allocate owxfer\n"));
                        error = ENOMEM;
                        goto out3;
+               }
+
+               /* XBox One controller initialization */
+               if (sc->sc_flags & UHIDEV_F_XB1) {
+                       uint8_t init_data[] = { 0x05, 0x20, 0x00, 0x01, 0x00 };
+                       int 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;
+                       }
                }
        }
 
Index: uhidev.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhidev.h,v
retrieving revision 1.25
diff -u -p -r1.25 uhidev.h
--- uhidev.h    25 Aug 2018 18:32:05 -0000      1.25
+++ uhidev.h    9 Jan 2021 15:11:30 -0000
@@ -61,6 +61,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 {

Reply via email to