I bought a shiny new wired XBox 360 controller so I could more easily play some
of the Humble Indie Bundle games I’ve bought. I plugged it into my Debian
machine and it lit up and created an appropriate device under /dev/input/
as
expected so that was all good. However, after it lit up, it never… un-lit,
and its blinking began to get annoying.
Let me back up and describe the controller, for people unfamilliar: the front of the 360 pad has an analogue stick (for movement) in the top-left, four face-buttons (for actions) in the top-right, a 4-way directional pad in the lower-left (generally used for mode-switching) and another analogue stick in the lower-right (for moving the camera). In the middle, there’s a Start button (for pausing, as per decades of tradition), a Back button (for no discernable purpose) and a big shiny silver X button which (when pushed) takes you back to the 360’s menu-system (if you’re using a real 360). Surrounding this shiny metal button are four bright-green LEDs, each one lighting up a quadrant of the bezel. As I understand it, when you plug a 360 pad into a real 360, it starts flashing all the LEDs simultaneously, until the system decides whether your pad will be regarded as player 1, 2, 3 or 4. Once the system has picked on, it tells the pad to just blink the relevant quadrant for a bit, then just leave that quadrant’s light on.
This doesn’t always work properly in Linux; the first time I plugged in my 360 pad it just sat there blinking every LED forever, although on subsequent connections it behaved more sensibly.
If you start poking around in the usual places for LED controls, you’ll
eventually stumble across a directory in /sys/class/leds/
with a relevant
name; because I only have one 360 pad connected, I found a directory named
/sys/class/leds/xpad0/
. Inside are two files, one named brightness
and one
named max_brightness
. If you think for five seconds, or if you go look up the
standard Linux Kernel documentation on the standard LED interface, you will
conclude that max_brightness
contains a number which represents the brightest
the LED can be, brightest
contains a number representing the current
brightness, and you can set the brightness by writing a new number into the
brightness
file:
$ cat /sys/class/leds/xpad0/brightness
0
$ cat /sys/class/leds/xpad0/max_brightness
255
It turns out this is completely wrong. Maybe it works for other, saner LED drivers, but the 360 pad doesn’t actually allow the computer to specifically control the LEDs; the computer just says “display pattern #5” (or whatever) and the pad looks up that pattern and plays it in a loop until it’s told to display some other pattern.
It turns out the 360 pad can display 14 different patterns (numbered 0-13). To
display pattern $N
, you can send that code to the 360 pad like this:
$ echo $N | sudo tee /sys/class/leds/xpad0/brightness
…where $N
should be replaced by a number from the list below, and xpad0
might change depending on how many times you’ve connected a 360 pad to your
computer since the last reboot.
Anyway, here’s the list of patterns:
0
: All LEDs off1
: Flash all LEDs 3 times, then go back to the previous display.2
: Flash the top-left LED 3 times, then leave it on.3
: Flash the top-right LED 3 times, then leave it on.4
: Flash the bottom-left LED 3 times, then leave it on.5
: Flash the bottom-right LED 3 times, then leave it on.6
: Turn on the top-left LED.7
: Turn on the top-right LED.8
: Turn on the bottom-left LED.9
: Turn on the bottom-right LED.10
: Turn on each LED, one after another, clockwise.11
: Flash the currently-active LED (on for about half a second,
off for about half a second) 15 times, then leave it on.12
: Flash the currently-active LED (on for about half a second, off for
about 3.5 seconds), forever.13
: Flash a chequer-board pattern (top-left and bottom-right, followed by
top-right and bottom left; on for about half a second, off for about half
a second) for about 10 seconds, then go back to the previous display.