Skip to content

Instantly share code, notes, and snippets.

@pavel-kirienko
Forked from dnmodder/fixcontroller.py
Last active May 14, 2024 09:15
Show Gist options
  • Save pavel-kirienko/86b9d039151405451130a0fb3896887c to your computer and use it in GitHub Desktop.
Save pavel-kirienko/86b9d039151405451130a0fb3896887c to your computer and use it in GitHub Desktop.
Use Microsoft X-Box 360 Gamepad with GNU/Linux
# By default, X-Box 360-compatible controllers are detectable but dysfunctional because they expect the host
# to send a particular USB control transfer with some sort of initialization command.
# This udev rule will invoke a trivial Python script automatically when the gamepad is connected that emits
# the required initialization command.
#
# Integration:
# 1. Put this rule into /etc/udev/rules.d/51-xbox-gamepad.rules
# 2. Install pyusb for the root's Python: sudo pip install pyusb
# 3. Reload udev rules as root: udevadm control --reload-rules && udevadm trigger
#
# If you are on a systemd-based distro, you can use this for troubleshooting:
# 1. Enable verbose logging: udevadm control --log-priority=info
# 2. Watch the logs while connecting the device: journalctl -f
#
# Inspired by Darvin Delgado's https://gist.github.com/dnmodder/de2df973323b7c6acf45f40dc66e8db3
ACTION=="add", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="028e", \
RUN+="/usr/bin/env python3 -c 'for d in __import__(\"usb\").core.find(find_all=True, idVendor=0x045e, idProduct=0x028e): d.ctrl_transfer(0xc1, 0x01, 0x0100, 0x00, 0x14)'"
@adessein
Copy link

Thanks for sharing.
I had to adapt your script, probably because my user does not have the rights to access USB.
Here is what I did:

SUBSYSTEM=="usb", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="028e", MODE="0666"

ACTION=="add", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="028e", \
RUN+="/usr/bin/env python3 -c 'import usb.core; dev = usb.core.find(idVendor=0x045e, idProduct=0x028e); dev.ctrl_transfer(0xc1, 0x01, 0x0100, 0x00, 0x14)'"

@pavel-kirienko
Copy link
Author

Ah, yes indeed, it makes sense. I'm not sure though, can you not define MODE="0666" in the same rule like this:

ACTION=="add", ATTRS{idVendor}=="045e", ATTRS{idProduct}=="028e", MODE="0666" \
RUN+="/usr/bin/env python3 -c 'for d in __import__(\"usb\").core.find(find_all=True, idVendor=0x045e, idProduct=0x028e): d.ctrl_transfer(0xc1, 0x01, 0x0100, 0x00, 0x14)'"

If you validated it I would update the snippet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment