Screwtape's Notepad

Controlling XBox 360 LEDs under Linux

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.

The Scenario

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.

A blind alley

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
$ cat /sys/class/leds/xpad0/max_brightness

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.

The real deal

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: