The OUYA's servers were shut down in 2019,
and Google shut down the servers for its Stadia
game console in
january 2023.
I thought it would be cool to use the controller of one dead console
on a resurrected dead gaming console :)
Bluetooth
The Stadia controllers did connect directly to Google's internet servers via WiFi and only used Bluetooth for initial setup. After shutdown, Google provided a website that let you install a controller firmware update, finally making the controller a standard Bluetooth one.
The Stadia controller only supports Bluetooth Low Energy
(BLE).
The OUYA
contains
a AzureWave AW-NH660 chipset that is based on BCM4330,
whose datasheet says it is
forward-compatible with the impending Bluetooth Low Energy operating mode
.
Android supports BLE
starting from version 4.3:
Bluetooth Low Energy (BLE), available in Android 4.3 and later, creates short connections between devices to transfer bursts of data
The OUYA runs Android 4.1, so you cannot use BLE controllers on an OUYA.
USB
The Stadia controller has a USB-C port. Connecting it to the OUYA's own USB-A port gives you a partially working controller: The d-pad, right thumb stick and L2+R2 do not work at all - only the left thumb stick works.
A custom key layout file is needed, just as I did before with a playstation controller.
Key layout file creation
Connect the controller via USB to your Android device and then run getevent -i in a terminal, e.g. via adb shell:
$ getevent -i add device 2: /dev/input/event0 bus: 0003 vendor 18d1 product 9400 version 0111 name: "Google LLC Stadia Controller rev. A" location: "usb-tegra-ehci.2-1/input1" id: "99200YCAC2LJ5L" version: 1.0.1 events: KEY (0001): 0072 0073 00a4 0130 0131 0133 0134 0136 0137 013a 013b 013c 013d 013e 0140 0141 0142 0143 ABS (0003): 0000 : value 0, min 1, max 255, fuzz 0, flat 15, resolution 0 0001 : value 0, min 1, max 255, fuzz 0, flat 15, resolution 0 0002 : value 0, min 1, max 255, fuzz 0, flat 15, resolution 0 0005 : value 0, min 1, max 255, fuzz 0, flat 15, resolution 0 0009 : value 0, min 0, max 255, fuzz 0, flat 15, resolution 0 000a : value 0, min 0, max 255, fuzz 0, flat 15, resolution 0 0010 : value 0, min -1, max 1, fuzz 0, flat 0, resolution 0 0011 : value 0, min -1, max 1, fuzz 0, flat 0, resolution 0 MSC (0004): 0004 input props: <none>
Here we see that the controller has 18 buttons (keys) and 8 axes.
Now run getevent without parameters, press the buttons and axes and make notes of their IDs:
$ getevent [...] /dev/input/event1: 0004 0004 00090001 /dev/input/event1: 0001 0130 00000001 /dev/input/event1: 0003 0000 0000007f /dev/input/event1: 0003 0001 0000007f /dev/input/event1: 0000 0000 00000000 /dev/input/event1: 0004 0004 00090001 /dev/input/event1: 0001 0130 00000000 /dev/input/event1: 0003 0000 0000007c /dev/input/event1: 0003 0001 0000007d /dev/input/event1: 0000 0000 00000000
Here button A was pressed and released - it has the Linux key code 0x130. Doing that for all the buttons gives us this list:
A 0x130 B 0x131 X 0x133 Y 0x134 ... 0x13a === 0x13b L1/LB 0x136 R1/RB 0x137 L3 0x13d R3 0x13e Stadia 0x13c
Now do the same for the axes:
D-Pad left-right 0010 up-down 0011 Left stick left-right 0000 up-down 0001 Right stick left-right 0002 up-down 0005 Left trigger 000a Right trigger 0009
And this is all the information needed to write the key layout file:
# Google Stadia Controller via USB key 0x130 BUTTON_A key 0x131 BUTTON_B key 0x133 BUTTON_X key 0x134 BUTTON_Y #L1 key 0x136 BUTTON_L1 #R1 key 0x137 BUTTON_R1 #L3 Stick key 0x13d BUTTON_THUMBL #R3 Stick key 0x13e BUTTON_THUMBR #Stadia symbol key 0x13c HOME #=== key 0x13b MENU #... key 0x13a BACK #D-pad axis 0x10 HAT_X axis 0x11 HAT_Y #Left stick axis 0x00 X axis 0x01 Y #Right stick axis 0x02 Z axis 0x05 RZ axis 0x0a LTRIGGER axis 0x09 RTRIGGER
Copy that file into /system/usr/keylayout/:
$ adb push Vendor_18d1_Product_9400.kl /sdcard/ $ adb shell $ su $ mount -o remount,rw /system $ mv /sdcard/Vendor_18d1_Product_9400.kl /system/usr/keylayout/
Simply unplugging and replugging makes Android load the custom key layout file instead of Generic.kl, and all buttons work.
Bluetooth with 8BitDo USB Wireless Adapter 2
8BitDo sells the USB Wireless Adapter 2, which bridges Bluetooth controllers to USB ports with the added benefit of letting you customize the button mappings. It supports Bluetooth Low Energy and - since firmware v1.04 - the Stadia controller:
Added support for Google Stadia Controller. (The controller is required to update to the Bluetooth mode firmware, it does not support vibration)
The adapter can behave differently depending on its mode, which can be switched when holding ··· and the directional pad keys for 3 seconds. You will see the adapter's red LED flash.
Supported modes as of firmware 1.06:
- ··· + d-pad left
- DInput mode (USB ID 2dc8:3105, "8BitDo 8BitDo Receiver")
- ··· + d-pad up
- Xinput mode (USB ID 2dc8:3106, "8BitDo 8BitDo Receiver")
- ··· + d-pad down
- PSC/PSX mode (USB ID 054c:0cda, "Sony Interactive Entertainment Controller")
- ··· + d-pad right
- Mac mode (USB ID 054c:05c4, "8BitDo 8BitDo Receiver")
- ··· + LB (Left shoulder button L1)
- Switch mode (USB ID 057e:2009, "Nintendo Co., Ltd. Pro Controller")
I opted to use Dinput mode (··· + d-pad left), and could use the Stadia USB key layout file without changes - I only had to give it a new name to match the USB IDs: Vendor_2dc8_Product_3105.kl!
Dive into Linux input mapping
On Android, multiple stages of input mapping take place:
- Controller reports button bits
- Linux input driver map those bits to key codes
- Android maps Linux key codes to Android key codes via key layout files
Controller key bits
On Linux and Android you can see the keys a controller supports by inspecting its device information:
$ cat /proc/bus/input/devices I: Bus=0003 Vendor=2dc8 Product=3105 Version=0111 N: Name="8BitDo 8BitDo Receiver" P: Phys=usb-tegra-ehci.2-1/input0 S: Sysfs=/devices/platform/tegra-ehci.2/usb2/2-1/2-1:1.0/input/input8 U: Uniq=E417D86076B0 H: Handlers=js0 event1 B: PROP=0 B: EV=1b B: KEY=7fff0000 0 0 0 0 0 0 0 0 0 $ cat /sys/devices/platform/tegra-ehci.2/usb2/2-1/2-1\:1.0/input/input8/capabilities/key 7fff0000 0 0 0 0 0 0 0 0 0
This key bit mask value 7fff0000 in bits is:
1111111111111110000000000000000
which are 15 buttons/keys.
Linux key codes
The input driver selected by Linux then takes care of mapping the bits onto key codes. You can inspect this information in the /sys/ file system as well:
$ cat /sys/devices/platform/tegra-ehci.2/usb2/2-1/2-1\:1.0/input/input8/modalias input:b0003v2DC8p3105e0111-e0,1,3,4,k130,131,132,133,134,135,136,137,138,139,13A,13B,13C,13D,13E,ra0,1,2,5,9,A,10,11,m4,lsfw
With the help of the Linux kernel sources input.c and input.h this can be decoded:
b0003 #bustype v2DC8 #vendor p3105 #product e0111- #version e0,1,3,4, #evbit k130,131,132,133,134,135,136,137,138,139,13A,13B,13C,13D,13E, #keybit r a0,1,2,5,9,A,10,11, #relbit m4, #mscbit l #ledbit s #sndbit f #ffbit w #swbit
The key codes that were used for the key map file above are already visible here.
Not a gamepad
During development of my key layout file I got the following message from the OUYA framework's input handler:
E/OuyaInputMapper( 548): onInputDeviceAdded device=5 not found D/ControllerInputDeviceListener( 565): InputDevice 8BitDo 8BitDo Receiver (id: 5, desc: 9c597667366a6b3d65e77ad35e1bc1f757d19732) is not a gamepad...
It turned out that I had used Android key code values (2xx range) instead of Linux key codes (3xx/0x13x range) in the key layout file as keys. After correcting the codes to 0x130 and above, the controller was correctly detected as gamepad.
Orange light
When the Stadia controller is connected via USB to the OUYA and the Stadia button glows orange instead of white, then you have to reboot the OUYA.
This often happens when connecting the USB cable 5+ minutes after bootup.