[Multi-mode Joystick] My mileage dealing with Machenike G5Pro on Linux

I have been using a Machenike G5 Pro on Linux for quite a while now. It's a multi-mode joystick that acts like a Switch Pro, an Xbox Controller or a D-Pad Controller. Wired, 2.4g or via Bluetooth.

It has gyroscope that are only exposed on Switch Mode.

This controller works out of the box on Linux, but it falls into DPad mode instantly. Which is playable, but missing features.

  1. The first connection attempt in done on Switch mode. But the Kernel refuses the connection.
dmesg output

[ 42.533577] usb 2-3: new full-speed USB device number 3 using xhci_hcd
[ 42.678206] usb 2-3: unable to read config index 0 descriptor/start: -71
[ 42.678229] usb 2-3: can't read configurations, error -71
[ 43.679800] usb 2-3: new full-speed USB device number 4 using xhci_hcd
[ 43.830594] usb 2-3: New USB device found, idVendor=2345, idProduct=e02e, bcdDevice= 1.00
[ 43.830617] usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 43.830623] usb 2-3: Product: MACHENIKE G5Pro
[ 43.830629] usb 2-3: Manufacturer: MACHENIKE
[ 43.864470] input: MACHENIKE MACHENIKE G5Pro as /devices/pci0000:00/0000:00:08.1/0000:04:00.3/usb2/2-3/2-3:1.0/0003:2345:E02E.0005/input/input38
[ 43.866879] hid-generic 0003:2345:E02E.0005: input,hidraw4: USB HID v1.10 Gamepad [MACHENIKE MACHENIKE G5Pro] on usb-0000:04:00.3-3/input0

It tries as SwitchPro, get bad descriptors, then reconnects [43.679800] in DirectInput Mode.

To fix the D-Pad mode, I made the Kernel ignore the "bad descriptors" on USB connection via usbcore parameters on /etc/default/grub.

Accept my bad built controller please

/etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="usbcore.quirks=0x057e:0x2009:ik,0x2345:0xe00b:ik,0x2345:0xe02f:ik,0x2345:0xe02d:ik"

The above are all usb ids this controller could use to connect, if you just want Nintendo mode. you can keep just usbcore.quirks=0x057e:0x2009:ik

Nintendo codes seems to be mandatory even for the other modes.

This change allows the controller to stablish a connection on Switch Mode, it uses the default usb id as Nintendo. The kernel driver in use is the official hid-nintendo.

:check_box_with_check: This driver can read vibration, home button, battery level and gyroscope flawlessly.

The cons: Nintendo Switch triggers are 0 or 1, no pressure control; buttons A-B & X-Y may be swapped on some games. [the controller can soft swap back the buttons by long press A+FN]

///

:enraged_face: Since I was about to get mad by hitting all the guard-rails on euro truck by not being able to fine control the truck speed, i started digging how to make it work on Xbox mode.

  1. The controller tries the next mode if the connection doesn't happen. So, after the kernel accepts the descriptors, if the Nintendo switch driver is not available, the controller tries Xbox Mode.

To make the controller skip Nintendo, I created a rule that blacklist the nintendo driver from booting with the system.

modprobe.d rule

/etc/modprobe.d/blacklist-hid-nintendo.conf
blacklist hid_nintendo

  1. Now, that the kernel reads usb info but have no Nintendo drivers, the controller should go to Xbox mode. Right?!
    Almost! The XPAD kernel driver doesn't know the USB Pid/Vid provided by the controller, so it would be ignored and therefore handled by the hid-generic driver. (Same as if it had fallen into dpad mode)

So, I created a udev rule that forces the controller usb ids to be handled by the xpad driver.
Wireless [2345:e02f] = Wireless & [2345:e02b] = Wired

Xpad, I choose you rule

/etc/udev/rules.d/99-machenike-to-xpad.rules
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="2345", ATTRS{idProduct}=="e02f", ATTR{driver}!="xpad", RUN+="/bin/sh -c 'echo 2345 e02f > /sys/bus/usb/drivers/xpad/new_id'"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="2345", ATTRS{idProduct}=="e02b", ATTR{driver}!="xpad", RUN+="/bin/sh -c 'echo 2345 e02b > /sys/bus/usb/drivers/xpad/new_id'"

:white_check_mark: So far, so good. Everything is working now, except for battery and gyro, the sensor is not even turned on by the controller when on xbox mode. -no Xbox has gyro- but the battery seems to be a firmware limitation.

:trophy: Starting with kernel 6.17 (Zorin18) the XPAD driver does know the usb ids for this controller. So, the last step is not necessary on newer versions. But it is yet needed to set the "Accept Bad Descriptors" quirks and the Nintendo blacklist.

Most of this, came from Arch Wiki, with some personal testing applied

Via Bluetooth, that was kinda easier. The controller has a switch on its back, so the auto mode selection is bypassed.

  • On Switch Mode, via Bluetooth, everything works as it should. No tweaks needed. [Even if nintendo driver is blacklisted]

  • On PC/iOS/Xbox mode, the controller gets connected without problems.
    It's handled by the generic driver. The Analog and Trigger axis are swapped, also some buttons are missrecognized.
    This is easily solvable via Steam Input or any remapper app.

To really fix the Xbox Mode via Bluetooth, it was needed to add the controller IDs to the code of xpadneo driver, and then patch the modded driver, via dkms.

Text to the patch

/xpadneo/hid-xpadneo/src/xpadneo/core.c

/* Machenike G5 Pro */
{ HID_BLUETOOTH_DEVICE(0x1949, 0x040A),
.driver_data = XPADNEO_QUIRK_SHARE_BUTTON },

I was able to reproduce all those steps in two Zorin 18 installations, this bluetooth method also works for Fedora.