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.