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
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.

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: