OUYA: Using own USB joysticks

I have some old Playstation 1 controllers that I'd like to use on my OUYA gaming console. Using them on the PC works via an PSX-to-USB adapter. ​

Plugging them into the OUYA unfortunately did not work; they were not detected as controllers - or at all, as it seemed. A Microsoft Sidewinder DualStrike did also not work. ​

USB device detection​

Linux PC​

Attaching the PSX adapter with controllers to a PC shows the following lsusb output: ​

ID 0810:0001 Personal Communication Systems, Inc. Dual PSX Adaptor​

dmesg shows: ​

usb 2-1.2: new low-speed USB device number 120 using ehci-pci
usb 2-1.2: New USB device found, idVendor=0810, idProduct=0001
usb 2-1.2: New USB device strings: Mfr=0, Product=2, SerialNumber=0
usb 2-1.2: Product: Twin USB Joystick
input: Twin USB Joystick as /devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1.2/2-1.2:1.0/input/input1460
input: Twin USB Joystick as /devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1.2/2-1.2:1.0/input/input1461
pantherlord 0003:0810:0001.05AC: input,hidraw2: USB HID v1.10 Joystick [Twin USB Joystick] on usb-0000:00:1d.7-1.2/input0
pantherlord 0003:0810:0001.05AC: Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>​

Input device files in /dev/input/ get created for both joysticks; /dev/input/js0 and /dev/input/js1. ​

I can then use jstest or jstest-gtk to test the controllers and see all the buttons and axes working. ​

OUYA​

Using adb to open a shell on the OUYA gives the following dmesg output: ​

[  331.002934] usb 2-1: new low speed USB device number 13 using tegra-ehci
<6>[  331.039183] usb 2-1: New USB device found, idVendor=0810, idProduct=0001
<6>[  331.046013] usb 2-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
<6>[  331.053437] usb 2-1: Product: Twin USB Joystick]]>​

That was all. Nothing more - no more dmesg output, no input files in /dev/. ​

What now?​

On the internet, many people used apps like usb/bt joystick center or tincore keymapper. The first has been removed from the google play store (I did not find an explanation why; the author did not respond to my e-mail), the second is still available. ​

But I did not want to use any of these tools. I can't look into them and do not know what they do. There just had to be a way to make it work properly. ​

Linux drivers​

After some detours, I had the idea that Linux drivers could be missing. ​

The PC's dmesg output gave a hint which ones were used: ​

pantherlord 0003:0810:0001.05AC: input,hidraw2: USB HID v1.10 Joystick​

The keywords are pantherlord, input and hidraw2. ​

input is a standard kernel module that is always enabled; otherwise no mouse/keyboard/joystick/touchpad would work. ​

pantherlord turned out to be the driver for the PSX adapter. The kernel sources tell us in drivers/hid/Kconfig: ​

config HID_PANTHERLORD
  tristate "Pantherlord/GreenAsia game controller"
  depends on USB_HID
  ---help---
    Say Y here if you have a PantherLord/GreenAsia based game controller
    or adapter.​

There is also a HIDRAW driver, which supports ​

HID devices (from the USB specification standpoint) that aren't strictly user interface devices ​

OUYA kernel configuration​

One can access the current kernel configuration at /proc/config.gz by copying from the OUYA: ​

$ adb pull /proc/config.gz
$ zless config.gz​

And there I saw it: ​

# CONFIG_HIDRAW is not set
# CONFIG_HID_PANTHERLORD is not set
# CONFIG_HID_MICROSOFT is not set​

The OUYA's Linux kernel had been built without support for my game controllers. ​

A custom OUYA linux kernel​

So it turned out that the only way to get my arcade joystick and gamepad working was to compile support for them into the kernel. ​

While HID_PANTHERLORD could be compiled as a module (tristate in the Kconfig files), HIDRAW could not - I had to re-build the whole kernel, and not only compile & copy a single module. ​

The internet contained a single, but very helpful OUYA kernel compilation howto: Builing your own Ouya Kernel by Leonardo Pires, written mid of 2014. The original announcement of this HowTo seems to be Recompilando Kernel do OUYA - Por Leonardo Pires which links to a HowTo on Google Drive. The XDA forum post seems to be a low-quality and translated version of it. ​

I had to adjust it to the current OUYA firmware version and fix some errors in it. Here is the updated one that worked 2015-06-02: ​

Preparation​

You have to enable ADB via the OUYA System / Debugging menu. ​

For the last step you have to be connected via USB to the device; uploading the kernel via network does not work. ​

Create a udev rules file for the OUYA so that you are able to communicate with the device over USB. Put the following into /etc/udev/rules.d/051-android.rules: ​

# ouya
SUBSYSTEM=="usb", ATTRS{idVendor}=="2836", MODE="0666"
# fastboot ouya
SUBSYSTEM=="usb", ATTRS{idVendor}=="0955", MODE="0666"​

Install the Android debug bridge (adb) and make it recognize the OUYA as Android device: ​

$ sudo apt-get install android-tools-adb
$ echo "0x2836" >> ~/.android/adb_usb.ini
$ adb kill-server
$ adb devices
List of devices attached
012d3a4efac56789	device

In your home directory, create a directory ouya-kernel: ​

$ cd
$ mkdir ouya-kernel
$ cd ouya-kernel

Ramdisk​

Flashing the OUYA with a new kernel requires a ramdisk file, and we can get it from the current firmware. At the time of writing this was 1.2.1427-r1. ​

$ wget http://devs-ouya-tv-prod.s3.amazonaws.com/ota/RC-OUYA-1.2.1427-r1_ota.zip
$ unzip RC-OUYA-1.2.1427-r1_ota.zip boot.img
$ wget http://www.enck.org/tools/split_bootimg_pl.txt -O split_bootimg.pl
$ perl split_bootimg.pl boot.img
$ gunzip boot.img-ramdisk.gz
$ mv boot.img-ramdisk ramdisk

split_bootimg.pl's homepage is http://www.enck.org/tools.html#split_bootimg. ​

Android NDK​

We have to cross-compile the kernel for the ARM platform; and the NDK contains the correct tools for that. ​

android-ndk-r10e did not work for me; I got a unknown CPU architecture error during kernel compilation. android-ndk-r9d did work: ​

$ wget https://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2
$ tar xjvf android-ndk-r9d-linux-x86_64.tar.bz2

OUYA kernel + configuration​

OUYA's kernel is on github, and we fetch it from there: ​

$ git clone git@github.com:ouya/ouya_1_1-kernel.git

Now we have to fetch the OUYA's kernel configuration file, which can be found at /proc/config.gz: ​

$ adb pull /proc/config.gz
$ gunzip -kc config.gz > ouya_1_1-kernel/.config

Now adjust the kernel configuration file in ouya_1_1-kernel/.config: ​

CONFIG_HIDRAW=y
CONFIG_HID_MICROSOFT=y
CONFIG_HID_PANTHERLORD=y​

The kernel can be compiled now: ​

$ export CROSS_COMPILE=/home/cweiske/ouya-kernel/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/arm-linux-androideabi-
$ export ARCH=arm
$ cd ouya_1_1-kernel
$ make
.. wait an hour ..
$ cp arch/arm/boot/zImage ../

Installing the kernel​

Make sure you're connected via USB to the OUYA.

Install the fastboot command: ​

$ apt-get install android-tools-fastboot
$ adb reboot-bootloader
$ fastboot devices -l
 012d3a4efac56789       fastboot usb:2-1.2

If fastboot gives you a no permissions warning, make sure that /etc/udev/rules.d/51-android.rules contains settings for vendor 0955 - the USB IDs change when rebooting into bootloader mode! ​

Now it's time to install the new kernel: ​

$ fastboot flash:raw boot ./zImage ./ramdisk
creating boot image...
creating boot image - 5742592 bytes
sending 'boot' (5608 KB)...
OKAY [  1.125s]
writing 'boot'...
OKAY [  1.854s]
finished. total time: 2.980s
$ fastboot reboot

If all went well, the OUYA boots up with the fresh kernel. ​

Success!​

dmesg on the OUYA shows us that the joysticks are recognized now: ​

$ adb shell
$ su
$ dmesg
<6>[  113.056632] usb 2-1: new low speed USB device number 2 using tegra-ehci
<6>[  113.104851] usb 2-1: New USB device found, idVendor=0810, idProduct=0001
<6>[  113.116743] usb 2-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
<6>[  113.124579] usb 2-1: Product: Twin USB Joystick
<6>[  113.145452] input: Twin USB Joystick as /devices/platform/tegra-ehci.2/usb2/2-1/2-1:1.0/input/input1
<6>[  113.156314] input: Twin USB Joystick as /devices/platform/tegra-ehci.2/usb2/2-1/2-1:1.0/input/input2
<6>[  113.167024] pantherlord 0003:0810:0001.0001: input,hidraw0: USB HID v1.10 Joystick [Twin USB Joystick] on usb-tegra-ehci.2-1/input0
<6>[  113.179213] pantherlord 0003:0810:0001.0001: Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>

Input mapping​

The Playstation controllers did not work immediately. The axes (up/down, left/right) did work, but the keys did not. I had to provide my own key layout file for the joysticks. ​

Creating it was easy; I installed the KeyTest Android application (link is dead) which could be downloaded as pre-compiled .apk file (archived version). ​

Then I clicked all the buttons on the OUYA controller and wrote down the scan codes. Afterwards, I wrote down the scan codes of the Playstation controllers. ​

The resulting key layout file has to get the name Vendor_0810_Product_0001.kl. ​

# PSX controller mapping
# Dual PSX Adaptor / Twin USB Joystick
# idVendor=0810, idProduct=0001
# Linux HID_PANTHERLORD driver

# X cross
key 290   BUTTON_A
# O circle
key 289   BUTTON_B
# [] square
key 291   BUTTON_X
# /\ triangle
key 288   BUTTON_Y

key 294   BUTTON_L1
key 292   BUTTON_L2
key 295   BUTTON_R1
key 293   BUTTON_R2

key 296   BUTTON_SELECT
key 297   BUTTON_START

key 298   BUTTON_THUMBL
key 299   BUTTON_THUMBR

axis 0x00 X
axis 0x01 Y
axis 0x02 HAT_X
axis 0x03 HAT_Y
axis 0x04 RZ
axis 0x05 Z​

Push it onto your OUYA into /system/usr/keylayout/: ​

$ adb push Vendor_0810_Product_0001.kl /sdcard/
$ adb shell
$ su
$ mount -o remount,rw /system
$ mv /sdcard/Vendor_0810_Product_0001.kl /system/usr/keylayout/

Now unplug and replug the USB controller - and it works! ​

Written by Christian Weiske.

Comments? Please send an e-mail.