Skip to content

Commit

Permalink
core, quirks: Add heuristics to detect GameSir Nova controllers
Browse files Browse the repository at this point in the history
GameSir Nova uses random MAC OUIs. But looking at samples we probably
can detect those controllers by checking the descriptor length and
masking the OUI for a specific value.

See `docs/heuristics/gamesir-nova.md`.

Fixes: #484
Tested-by: https://github.com/BakaJzon
Signed-off-by: Kai Krakow <[email protected]>
  • Loading branch information
kakra committed Nov 28, 2024
1 parent 8ce85bf commit 38cd846
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 7 deletions.
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ options hid_xpadneo quirks=3E:42:6C:xx:xx:xx+6

This controller uses emulated profile switching support (see below).

This manufacturer uses random MAC addresses, so we cannot rely on known OUIs. Heuristics try to detect this controller.


## Profile Switching

Expand Down
11 changes: 11 additions & 0 deletions docs/heuristics/gamesir-nova.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# GameSir Nova OUIs

Gamesir Nova uses random MAC OUIs. We collect them here to implement a
working heuristic matcher.

| OUI | Bit representation | descriptor length
| ------------ | --------------------------------------- | -----------------
| 3E:42:6C | `0011 1110 : 0100 0010 : 0110 1100` | 283
| ED:BC:9A | `1110 1101 : 1011 1100 : 1001 1010` | 283
| 6A:07:14 | `0110 1010 : 0000 0111 : 0001 0100` | 283
| **AND mask** | **`0010 1000 : 0000 0000 : 0000 0000`** | **mask 0x28**
24 changes: 17 additions & 7 deletions hid-xpadneo/src/hid-xpadneo.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,17 +98,11 @@ struct quirk {
};

static const struct quirk xpadneo_quirks[] = {
DEVICE_OUI_QUIRK("3E:42:6C",
XPADNEO_QUIRK_NO_PULSE | XPADNEO_QUIRK_NO_MOTOR_MASK |
XPADNEO_QUIRK_NO_TRIGGER_RUMBLE),
DEVICE_OUI_QUIRK("98:B6:EA",
XPADNEO_QUIRK_NO_PULSE | XPADNEO_QUIRK_NO_TRIGGER_RUMBLE |
XPADNEO_QUIRK_REVERSE_MASK),
DEVICE_OUI_QUIRK("A0:5A:5D", XPADNEO_QUIRK_NO_HAPTICS),
DEVICE_OUI_QUIRK("E4:17:D8", XPADNEO_QUIRK_NO_HAPTICS | XPADNEO_QUIRK_NO_TRIGGER_RUMBLE),
DEVICE_OUI_QUIRK("ED:BC:9A",
XPADNEO_QUIRK_NO_PULSE | XPADNEO_QUIRK_NO_MOTOR_MASK |
XPADNEO_QUIRK_NO_TRIGGER_RUMBLE),
DEVICE_OUI_QUIRK("E4:17:D8", XPADNEO_QUIRK_SIMPLE_CLONE),
};

struct usage_map {
Expand Down Expand Up @@ -1042,6 +1036,8 @@ static int xpadneo_event(struct hid_device *hdev, struct hid_field *field,
static int xpadneo_init_hw(struct hid_device *hdev)
{
int i, ret;
u8 oui_byte;
char oui[3] = { };
struct xpadneo_devdata *xdata = hid_get_drvdata(hdev);

if (!xdata->gamepad) {
Expand Down Expand Up @@ -1105,6 +1101,20 @@ static int xpadneo_init_hw(struct hid_device *hdev)
}
kernel_param_unlock(THIS_MODULE);

/*
* copy the first two characters from the uniq ID (MAC address) and
* expect it being too big to copy, then `kstrtou8()` converts the
* uniq ID "aa:bb:cc:dd:ee:ff" to u8, so we get the first OUI byte
*/
if ((xdata->original_rsize == 283)
&& (strscpy(oui, xdata->gamepad->uniq, sizeof(oui)) == -E2BIG)
&& (kstrtou8(oui, 16, &oui_byte) == 0)
&& XPADNEO_OUI_MASK(oui_byte, XPADNEO_OUI_MASK_GAMESIR_NOVA)
&& ((xdata->quirks & XPADNEO_QUIRK_SIMPLE_CLONE) == 0)) {
hid_info(hdev, "enabling heuristic GameSir Nova quirks\n");
xdata->quirks |= XPADNEO_QUIRK_SIMPLE_CLONE;
}

if (xdata->quirks > 0)
hid_info(hdev, "controller quirks: 0x%08x\n", xdata->quirks);

Expand Down
5 changes: 5 additions & 0 deletions hid-xpadneo/src/xpadneo.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ do { \
#define XPADNEO_QUIRK_REVERSE_MASK 128

#define XPADNEO_QUIRK_NO_HAPTICS (XPADNEO_QUIRK_NO_PULSE|XPADNEO_QUIRK_NO_MOTOR_MASK)
#define XPADNEO_QUIRK_SIMPLE_CLONE (XPADNEO_QUIRK_NO_HAPTICS|XPADNEO_QUIRK_NO_TRIGGER_RUMBLE)

/* MAC OUI masks */
#define XPADNEO_OUI_MASK(oui,mask) (((oui)&(mask))==(mask))
#define XPADNEO_OUI_MASK_GAMESIR_NOVA 0x28

/* timing of rumble commands to work around firmware crashes */
#define XPADNEO_RUMBLE_THROTTLE_DELAY msecs_to_jiffies(50)
Expand Down

0 comments on commit 38cd846

Please sign in to comment.