El descriptor de gamepad HID compuesto funciona en Windows pero no en Linux

Estoy construyendo un adaptador USB para un viejo controlador de juegos. Hasta ahora todo funciona bien. Mi descriptor HID se ve así:

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                     */

Ahora quiero agregar soporte para hasta 4 de estos controladores. Si entiendo correctamente la especificación HID, una forma de hacerlo es repetir el descriptor 4 veces, cada vez con una ID de informe diferente. (Sé que probablemente podría tener múltiples interfaces USB con la clase HID, pero preferiría no hacerlo de esa manera; mi código USB se volvería mucho más complicado).

Cuando probé este Linux se negó a reconocer el dispositivo como un gamepad. El controlador HID ( hid-generic) está cargado y el descriptor parece analizarse correctamente, pero no hay ningún archivo de dispositivo en /dev/input/.

EDITAR:

Probé mi código en Windows 7 y parece que este problema es específico de Linux. Así que estoy reformulando mi pregunta original:

¿Cómo necesito modificar mi descriptor HID para que funcione tanto en Windows como en Linux?

Al enchufar el dispositivo, dmesginforma esto:

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

Esto es idéntico a lo que dice cuando se conecta la versión de 1 controlador en funcionamiento. El dispositivo aparece en lsusb, con los ID/descriptores correctos.

¿Ha cambiado su estructura de datos para incluir el ID del informe?
Sí, el ID del informe está incluido.
Puede ir a este enlace y ver si ayuda, eleccelerator.com/tutorial-about-usb-hid-report-descriptors .
Hm, ese sitio recomienda precisamente lo que estoy haciendo (ver la sección sobre gamepads para 2 jugadores). Así que mi enfoque general parece ser correcto.
Parece que el artículo es para Windows. Puede ir a los comentarios, puede haber sobre las situaciones en Linux. Si es un problema de controladores de Linux?
Actualicé mi pregunta.
¿Qué dicen dmesg y lsusb cuando lo conectas a una caja de Linux? El problema habitual es que Linux es muy particular en cuanto al "cumplimiento". Las guías en la red son lo mínimo necesario para que algo funcione en Windows. Windows bare min puede ser más bajo que Linux bare min. Winmodems es clave, usb audio es otro. Bluetooth también...
Pregunta actualizada.

Respuestas (2)

Después de algunas horas de hurgar en debugfs y las fuentes del kernel, lo descubrí.

Como resultado, el descriptor estaba bien, el problema fue que udev (por el motivo que sea) decidió crear el archivo del dispositivo con acceso de solo root. Después de solucionar esto, mi dispositivo ahora aparece como un gamepad de 56 botones y 8 ejes, que no es exactamente lo que quería, pero aún así se parece lo suficiente.

Para que el dispositivo se muestre como dos dispositivos de entrada separados en Linux, el id_proveedor y el id_dispositivo del dispositivo deben configurarse con la HID_QUIRK_MULTI_INPUTpeculiaridad en el controlador USB HID en Linux. Consulte hid-quirks.c en la fuente del kernel de Linux para ver ejemplos: actualmente hay 35 dispositivos configurados con una línea como:

{ HID_USB_DEVICE(USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER), HID_QUIRK_MULTI_INPUT },

Nota: USB_VENDOR_ID_MOJOy USB_DEVICE_ID_RETRO_ADAPTERestán definidos en hid-ids.h en el código fuente del kernel de Linux. También deberá agregar las identificaciones de su proveedor y dispositivo allí.

Después de realizar estos cambios, debería poder volver a compilar su kernel o solo el controlador USB-hid si es un módulo y obtener múltiples dispositivos de entrada.