4

I am building an USB adapter for an old game controller. So far everything is working fine. My HID descriptor looks like this:

0x05, 0x01,  /* USAGE_PAGE (Generic Desktop)       */
0x09, 0x05,  /* USAGE (Game Pad)                   */
0xa1, 0x01,  /* COLLECTION (Application)           */
0xa1, 0x03,  /*   COLLECTION (Report)              */
0x85, 0x01,  /*     REPORT_ID (1)                  */
0x05, 0x09,  /*     USAGE_PAGE (Button)            */
0x19, 0x01,  /*     USAGE_MINIMUM (Button 1)       */
0x29, 0x0e,  /*     USAGE_MAXIMUM (Button 14)      */
0x15, 0x00,  /*     LOGICAL_MINIMUM (0)            */
0x25, 0x01,  /*     LOGICAL_MAXIMUM (1)            */
0x95, 0x0e,  /*     REPORT_COUNT (14)              */
0x75, 0x01,  /*     REPORT_SIZE (1)                */
0x81, 0x02,  /*     INPUT (Data,Var,Abs)           */
0x95, 0x01,  /*     REPORT_COUNT (1)               */
0x75, 0x02,  /*     REPORT_SIZE (2)                */
0x81, 0x03,  /*     INPUT (Cnst)                   */
0xa1, 0x00,  /*     COLLECTION (Physical)          */
0x05, 0x01,  /*       USAGE_PAGE (Generic Desktop) */
0x09, 0x30,  /*       USAGE (X)                    */
0x09, 0x31,  /*       USAGE (Y)                    */
0x15, 0x00,  /*       LOGICAL_MINIMUM (0)          */
0x25, 0x64,  /*       LOGICAL_MAXIMUM (100)        */
0x75, 0x08,  /*       REPORT_SIZE (8)              */
0x95, 0x02,  /*       REPORT_COUNT (2)             */
0x81, 0x02,  /*       INPUT (Data,Var,Abs)         */
0xc0,        /*     END_COLLECTION                 */
0xc0,        /*   END_COLLECTION                   */
0xc0         /* END_COLLECTION                     */

Now I want to add support for up to 4 of these controllers. If I understand the HID spec correctly, one way to do this is to repeat the descriptor 4 times, each time with a different report ID. (I know I could probably just have multiple USB interfaces with the HID class, but I'd rather not do it that way; my USB code would get a great deal more complicated.)

When I tried this Linux refused to recognize the device as a gamepad. The HID driver (hid-generic) is loaded, and the descriptor seems to be parsed correctly, but there is no device file in /dev/input/.

EDIT:

I tested my code on Windows 7, and it looks like this problem is indeed Linux specific. So I am reformulating my original question:

How do I need to modify my HID descriptor, so it works on both Windows and Linux?

When plugging the device in, dmesg reports this:

usb 3-6: new low-speed USB device number 8 using xhci_hcd
usb 3-6: ep 0x81 - rounding interval to 64 microframes, ep desc says 80 microframes
input: XYZ Adapter as /devices/pci0000:00/0000:00:14.0/usb3/3-6/3-6:1.0/0003:16C0:05DC.0009/input/input20
hid-generic 0003:16C0:05DC.0009: input,hidraw4: USB HID v1.01 Gamepad [XYZ Adapter] on usb-0000:00:14.0-6/input0

This is identical to what it says when plugging in the working 1-controller version. The device appears in lsusb, with the correct IDs/descriptors.

puyawsiht
  • 101
  • 1
  • 6
  • Have you changed your data structure to include the report ID? – diverger Dec 07 '14 at 13:23
  • Yes, the report ID is included. – puyawsiht Dec 07 '14 at 13:30
  • You can go this link and see if it help, http://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/. – diverger Dec 07 '14 at 13:38
  • Hm, that site recommends precisely what I am doing (see the section about 2-player gamepads). So my general approach seems to be right. – puyawsiht Dec 07 '14 at 14:03
  • It seems the article is for Windows. You can go for the comments, there may about the situations on Linux. If it's Linux drivers problem? – diverger Dec 07 '14 at 14:05
  • Updated my question. – puyawsiht Dec 07 '14 at 15:05
  • what does dmesg and lsusb say when you plug it in on a linux box? The usual problem is linux is very particular about "compliance" Guides around the net are the bare minimum to get something working on windows. Windows bare min can be lower than linux bare min. Winmodems is a key one, usb audio is another. Bluetooth as well... –  Dec 07 '14 at 15:14
  • Question updated. – puyawsiht Dec 07 '14 at 15:47

2 Answers2

6

After some hours of poking around in debugfs and the kernel sources, I figured it out.

As it turns out the descriptor was fine, the problem was that udev (for whatever reason) decided the create the device file with root-only access. After fixing this, my device now appears as a 56-button 8-axis gamepad, which is not quite what I wanted, but still close enough.

puyawsiht
  • 101
  • 1
  • 6
2

In order to make the device show up as two separate input devices in linux, the device's vendor_id and device_id need to be set up with the HID_QUIRK_MULTI_INPUT quirk in the USB HID driver in Linux. See hid-quirks.c in the linux kernel source for examples - there are currently 35 devices configured with a line like:

{ HID_USB_DEVICE(USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER), HID_QUIRK_MULTI_INPUT },

Note: USB_VENDOR_ID_MOJO and USB_DEVICE_ID_RETRO_ADAPTER are defined in hid-ids.h in the linux kernel source. You will need to add your vendor and device IDs in there too.

After making these changes, you should be able to recompile your kernel or just the USB-hid driver if it's a module, and get multiple input devices.

stonecrusher
  • 123
  • 4