2

I'm building an adaptor to connect various video game controllers to a PC via USB. The heart of it is the Teensy 3.1 microcontroller, which uses the Cortex-M4 processor.

The M4 is able to deal with raw USB packets and thus simulate any type of USB device. I've successfully programmed it to present a composite USB device:

  • Interface 1, endpoint 1: USB serial port (for debugging) - status interface
  • Interface 1, endpoint 2: USB serial TX/RX interface
  • Interface 2, endpoint 3: HID joystick

The problem now is, I want to be able to connect several different types of game controller at once (e.g. Nintendo and Super Nintendo). In all my adaptor has more than 15 ports, which means I can't just assign one endpoint to each port, as USB allows only 16 endpoints total.

Reading the HID report descriptor spec, I get the impression that it's possible to define multiple independent devices on the same interface. However despite my best efforts, I can't seem to pull this off. Applications (such as jstest-gtk) only see a single huge joystick.

Right now I'm using this report descriptor:

static uint8_t joystick_report_desc[] = {
    0x05, 0x01,                     // Usage Page (Generic Desktop)
    0x09, 0x04,                     // Usage (Joystick)
    0xA1, 0x01,                     // Collection (Application)
        0x85, 0x01,                     // Report ID (1)
        0x15, 0x00,                     // Logical Minimum (0)
        0x25, 0x01,                     // Logical Maximum (1)
        0x75, 0x01,                     // Report Size (1)
        0x95, 0x08,                     // Report Count (8)
        0x05, 0x09,                     // Usage Page (Button)
        0x19, 0x01,                     // Usage Minimum (Button #1)
        0x29, 0x08,                     // Usage Maximum (Button #8)
        0x81, 0x02,                     // Input (variable,absolute)
    0xC0,                           // End Collection

    0x05, 0x01,                     // Usage Page (Generic Desktop)
    0x09, 0x04,                     // Usage (Joystick)
    0xA1, 0x01,                     // Collection (Application)
        0x85, 0x02,                     // Report ID (2)
        0x15, 0x00,                     // Logical Minimum (0)
        0x25, 0x01,                     // Logical Maximum (1)
        0x75, 0x01,                     // Report Size (1)
        0x95, 0x10,                     // Report Count (16)
        0x05, 0x09,                     // Usage Page (Button)
        0x19, 0x01,                     // Usage Minimum (Button #1)
        0x29, 0x10,                     // Usage Maximum (Button #16)
        0x81, 0x02,                     // Input (variable,absolute)
    0xC0,                           // End Collection
};

I had hoped that would present one joystick with 8 buttons and one with 16, but instead applications see a single joystick with 24 buttons.

Is it actually possible to define multiple independent joysticks this way?

Rena
  • 606
  • 7
  • 21
  • Is the goal to connect multiple controllers simultaneously for multiplayer games or just to let a single user swap between controllers at will? It seems like in the single controller case the Teensy could multiplex the controller inputs into a single 16-button controller. – Austin Mullins Mar 31 '15 at 18:14
  • 1
    Ideally I'd like to connect multiple controllers simultaneously. In practice probably no more than 4 would be used at once, but e.g. you might have one player using a SNES controller and one using an N64, and you'd want to be able to leave them all plugged in and just pick one up and use it. I might resort to switching between a couple at a time, but I'd much rather have all connected controllers presented as joysticks at all times. – Rena Mar 31 '15 at 19:11
  • This is a great problem. I think the easiest thing to do (honestly I don't know) would be to multiplex a few controllers into a single "player", so that you present four (or more) "players" as USB endpoints. The Teensy would then queue up input reports whenever there's activity on a controller. – Austin Mullins Mar 31 '15 at 19:17
  • That might be a good idea, though I fear it'd complicate the configuration of games/emulators. (Especially some only let you assign one button to each function, so you wouldn't be able to alternate between different controllers.) The other idea I had was to simulate a USB hub with various joystick devices connected, but that seems a lot more complicated. (Also, each virtual device would contribute toward the 127 device limit, but that's not a huge deal...) – Rena Mar 31 '15 at 19:49

1 Answers1

2

I recently implemented a similar project with mbed, and can confirm that multiple joysticks can be defined using only the report descriptor as you described.

In Windows, it should just work. With Linux, the usbhid driver needs to be loaded using the HID_QUIRK_MULTI_INPUT quirk.

# rmmod usbhid && modprobe usbhid quirks=0xVID:0xPID:0x40

Where VID is your vendor id, and PID is your product id. It should then show up as multiple joystick devices in /dev/input.

  • do you know, how (if at all) it is possible to define own names for the devices crated with this scheme? In Windows they all come up with the same name of the usb device. So all 4 gamepads get the same name. Is there some possibility to link a specific string as name to the report? – vlad_tepesch Mar 22 '23 at 17:32