Der zusammengesetzte HID-Gamepad-Deskriptor funktioniert unter Windows, aber nicht unter Linux

Ich baue einen USB-Adapter für einen alten Gamecontroller. Bisher funktioniert alles bestens. Mein HID-Deskriptor sieht so aus:

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

Jetzt möchte ich Unterstützung für bis zu 4 dieser Controller hinzufügen. Wenn ich die HID-Spezifikation richtig verstehe, besteht eine Möglichkeit darin, den Deskriptor viermal zu wiederholen, jedes Mal mit einer anderen Berichts-ID. (Ich weiß, dass ich wahrscheinlich einfach mehrere USB-Schnittstellen mit der HID-Klasse haben könnte, aber ich würde es lieber nicht so machen; mein USB-Code würde viel komplizierter werden.)

Als ich dieses versuchte, weigerte sich Linux, das Gerät als Gamepad zu erkennen. Der HID-Treiber ( hid-generic) wird geladen und der Deskriptor scheint korrekt geparst zu werden, aber es gibt keine Gerätedatei in /dev/input/.

BEARBEITEN:

Ich habe meinen Code unter Windows 7 getestet, und es sieht so aus, als ob dieses Problem tatsächlich Linux-spezifisch ist. Daher formuliere ich meine ursprüngliche Frage um:

Wie muss ich meinen HID-Deskriptor ändern, damit er sowohl unter Windows als auch unter Linux funktioniert?

Beim Einstecken des Gerätes dmesgmeldet sich folgendes:

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

Dies ist identisch mit dem, was beim Einstecken der funktionierenden 1-Controller-Version angezeigt wird. Das Gerät erscheint in lsusbmit den korrekten IDs/Deskriptoren.

Haben Sie Ihre Datenstruktur geändert, um die Berichts-ID aufzunehmen?
Ja, die Berichts-ID ist enthalten.
Sie können auf diesen Link gehen und sehen, ob es hilft, eleccelerator.com/tutorial-about-usb-hid-report-descriptors .
Hm, diese Seite empfiehlt genau das, was ich mache (siehe den Abschnitt über Gamepads für 2 Spieler). Also scheint mein genereller Ansatz richtig zu sein.
Es scheint, dass der Artikel für Windows ist. Sie können nach den Kommentaren suchen, dort möglicherweise über die Situationen unter Linux. Wenn es ein Linux-Treiberproblem ist?
Habe meine Frage aktualisiert.
Was sagen dmesg und lsusb, wenn Sie es an eine Linux-Box anschließen? Das übliche Problem ist, dass Linux sehr genau auf "Compliance" steht. Anleitungen im Netz sind das absolute Minimum, um etwas unter Windows zum Laufen zu bringen. Windows Bare Min kann niedriger sein als Linux Bare Min. Winmodems ist ein Schlüssel, USB-Audio ist ein anderer. Bluetooth auch...
Frage aktualisiert.

Antworten (2)

Nachdem ich einige Stunden in debugfs und den Kernelquellen herumgestöbert hatte, fand ich es heraus.

Wie sich herausstellte, war der Deskriptor in Ordnung, das Problem war, dass udev (aus welchen Gründen auch immer) entschieden hat, die Gerätedatei mit Nur-Root-Zugriff zu erstellen. Nachdem ich dies behoben habe, erscheint mein Gerät jetzt als 56-Tasten-8-Achsen-Gamepad, was nicht ganz das ist, was ich wollte, aber immer noch nah genug dran ist.

Damit das Gerät unter Linux als zwei separate Eingabegeräte angezeigt wird, müssen die Hersteller-ID und die Geräte-ID des Geräts mit der HID_QUIRK_MULTI_INPUTMacke im USB-HID-Treiber unter Linux eingerichtet werden. Siehe hid-quirks.c in der Linux-Kernel-Quelle für Beispiele – derzeit sind 35 Geräte mit einer Zeile wie der folgenden konfiguriert:

{ HID_USB_DEVICE(USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER), HID_QUIRK_MULTI_INPUT },

Hinweis: USB_VENDOR_ID_MOJOund sind in hid-ids.hUSB_DEVICE_ID_RETRO_ADAPTER in der Linux-Kernel-Quelle definiert . Sie müssen dort auch Ihre Anbieter- und Geräte-IDs hinzufügen.

Nachdem Sie diese Änderungen vorgenommen haben, sollten Sie in der Lage sein, Ihren Kernel oder nur den USB-Hid-Treiber, wenn es sich um ein Modul handelt, neu zu kompilieren und mehrere Eingabegeräte zu erhalten.