« March 16, 2013 | Main

September 8, 2013

Patching the Linux Kernel to install the Xin-Mo Dual Arcade driver on a Raspberry Pi

These are instruction for Raspbian on the Raspberry Pi. I also have instructions for Ubuntu.

The Xin-Mo Dual Arcade is a USB interface for up to two arcade joysticks and 22 buttons. It’s a cool little device if you want to build an arcade controller for your computer or Raspberry Pi. You can get one from Ultracabs.

Unfortunately there is a bug in the Xin-Mo Dual Arcade: the values it sends for the up and left positions of the joysticks are out of range with the values it announces it would send, and Linux therefore ignores these values (it’s its right). Therefore the joystick do nothing in the up and left position.

I wrote a driver to fix that problem, as a patch to the Linux Kernel. A few people asked me for help on how to install it, hence this article.

Cliché Disclaimer: Use these instructions at your own risks. Backup your computer before you start. I am not responsible for any data loss or fried computers caused by following these instructions.

Raspbian

I used NOOBS 1.2.1 and selected Raspbian. Everything here happens in the terminal, make sure you’re logged in as an administrator (typically user pi). If a command that starts with sudo asks for your password (not normally the case on Raspbian), use the password for that administrator user. These instructions were derived from the RPi Kernel Compilation page on the Embedded Linux Wiki.

Observing the problem

First we’re going to install evtest, a tool to test the joystick:

sudo apt-get update
sudo apt-get install evtest

To try it out, connect your joystick and run the program:

evtest

It will list devices and ask you to select your joystick. Find the line that says Xin-Mo Xin-Mo Dual Arcade, type the number next to /dev/input/event (4 in this example) and Enter.

No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event4:  Xin-Mo Xin-Mo Dual Arcade
Select the device event number [0-5]: 4

Now when you move the joysticks and press buttons, it will print lines like these (for a button):

Event: time 1378629038.490828, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001
Event: time 1378629038.490828, type 1 (EV_KEY), code 288 (BTN_TRIGGER), value 1
Event: time 1378629038.490828, -------------- SYN_REPORT ------------
Event: time 1378629038.618674, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001
Event: time 1378629038.618674, type 1 (EV_KEY), code 288 (BTN_TRIGGER), value 0
Event: time 1378629038.618674, -------------- SYN_REPORT ------------

or these (for a joystick):

Event: time 1378629075.546079, type 3 (EV_ABS), code 1 (ABS_Y), value 1
Event: time 1378629075.546079, -------------- SYN_REPORT ------------
Event: time 1378629075.740176, type 3 (EV_ABS), code 1 (ABS_Y), value 0
Event: time 1378629075.740176, -------------- SYN_REPORT ------------

and nothing when you move the joysticks up or left.

Fixing the problem

Downloading the sources

First we need to install the programs needed to build the kernel:

sudo apt-get update
sudo apt-get -y dist-upgrade
sudo apt-get -y install gcc make ncurses-dev

Then we can download the source code for the kernel. We’re going to use a ‘tarball’, the rpi-3.6.y one, as proposed at the very end of the Get the kernel source section:

wget 'https://github.com/raspberrypi/linux/archive/rpi-3.6.y.tar.gz'

Extract the sources:

tar xpfvz rpi-3.6.y.tar.gz

You can now find the sources in the linux-rpi-3.6.y directory.

Applying the patch

linux-rpi-3.6.y is the directory where the source code was extracted. Enter it:

cd linux-rpi-3.6.y

Then download the patch using wget:

wget 'https://ithink.ch/blog/files/xin-mo/0001-hid-Add-new-driver-for-non-compliant-Xin-Mo-devices.patch'

and apply it:

patch -p1 < 0001-hid-Add-new-driver-for-non-compliant-Xin-Mo-devices.patch

It should display something like this:

patching file drivers/hid/Kconfig
Hunk #1 succeeded at 670 with fuzz 2 (offset -73 lines).
patching file drivers/hid/Makefile
Hunk #1 succeeded at 86 (offset -24 lines).
patching file drivers/hid/hid-core.c
Hunk #1 succeeded at 1689 (offset -47 lines).
patching file drivers/hid/hid-ids.h
Hunk #1 succeeded at 808 (offset -79 lines).
patching file drivers/hid/hid-xinmo.c

Building the kernel

First, make sure the build directory is clean:

make mrproper

Then copy the current kernel configuration from your Raspberry Pi:

zcat /proc/config.gz > .config

We need to make the configuration up to date. This step might ask a lot of questions about whether to support some new features. We are going to take the default answer every time except for our Xin-Mo Dual Arcade driver. We want to make sure it’s enabled, since that’s the one we’re going through all this trouble for.

Run

make oldconfig

and when the following question pops up, type m and Enter:

Xin-Mo non-fully compliant devices (HID_XINMO) [N/m/y/?] (NEW)

For the other questions, if any, just type Enter to accept the default.

If you missed the Xin-Mo line or are not sure, you can use the menu config1 to make sure it is enabled. Type

make menuconfig

and navigate to Device Drivers -> HID support -> Special HID drivers -> Xin-Mo non-fully compliant devices and type m to enable it as a module. An <M> should be displayed next to the line:

<M> Xin-Mo non-fully compliant devices

Then select the Exit button until it asks if you want to save your nw configuration, and answer Yes.

When ready (ideally at the end of the evening), type

make ; make modules

Then the actual compilation will begin. It will go on for a long, long, long long, long, long time, so go to sleep.

Installing the new kernel

Copy the new kernel image to the boot partition, under a name different than the existing one:

sudo cp arch/arm/boot/Image /boot/kernel_new.img

Then enable it in the boot config by adding the following line to /boot/config.txt, or changing the kernel=kernel.img if it already exists:

kernel=kernel_new.img

You can do this using the nano text editor:

sudo nano /boot/config.txt

Type the kernel=kernel_new.img line on its own line or modify the existing one, then hit Control-O and the Enter to save, and Control-X to exit.

Now we need to install the modules:

mkdir ~/modules
export MODULES_TEMP=~/modules
make INSTALL_MOD_PATH=${MODULES_TEMP} modules_install

and put the files into place:

cd /lib

sudo cp -R ~/modules/lib/firmware/ .
sudo cp -R ~/modules/lib/modules/ .

Next the instructions recommend to “update your GPU firmware and libraries.” Since I didn’t spend a night recompiling the kernel to write this article, I cannot follow along as I write this, so if you started from a fresh and recent Raspbian installation, you can live dangerously and reboot (remember my disclaimer above, though). Otherwise, try and follow the instructions under Get the firmware.

And then reboot:

sudo reboot

Test the patch

Run evtest again, like above, and enjoy the result:

Event: time 1378634592.175998, type 3 (EV_ABS), code 1 (ABS_Y), value -1
Event: time 1378634592.175998, -------------- SYN_REPORT ------------
Event: time 1378634592.335920, type 3 (EV_ABS), code 1 (ABS_Y), value 0
Event: time 1378634592.335920, -------------- SYN_REPORT ------------
Event: time 1378634593.613888, type 3 (EV_ABS), code 0 (ABS_X), value -1
Event: time 1378634593.613888, -------------- SYN_REPORT ------------
Event: time 1378634593.809001, type 3 (EV_ABS), code 0 (ABS_X), value 0
Event: time 1378634593.809001, -------------- SYN_REPORT ------------
Event: time 1378634595.165686, type 3 (EV_ABS), code 3 (ABS_RX), value -1
Event: time 1378634595.165686, -------------- SYN_REPORT ------------
Event: time 1378634595.325688, type 3 (EV_ABS), code 3 (ABS_RX), value 0
Event: time 1378634595.325688, -------------- SYN_REPORT ------------
Event: time 1378634595.933826, type 3 (EV_ABS), code 2 (ABS_Z), value -1
Event: time 1378634595.933826, -------------- SYN_REPORT ------------
Event: time 1378634596.093610, type 3 (EV_ABS), code 2 (ABS_Z), value 0
Event: time 1378634596.093610, -------------- SYN_REPORT ------------

If these instructions helped you, I would appreciate it if you could send me a couple of pictures of your set-up so I can compile them on a web page. Drop me a note on Twitter.

1. Note: We installed the ncurses-dev package earlier required by menuconfig, but if you missed that step, you will get the following error:

 *** Unable to find the ncurses libraries or the
 *** required header files.
 *** 'make menuconfig' requires the ncurses libraries.
 ***
 *** Install ncurses (ncurses-devel) and try again.
 ***

In this case, run

sudo apt-get install ncurses-dev&nbsp;<a class="footnoteBack" href="#ref_1_250_menuconfig">&#8617;</a>

Patching the Linux Kernel to install the Xin-Mo Dual Arcade driver on Ubuntu 13.04

These are instruction for Ubuntu. I also have instructions for the Raspberry Pi.

The Xin-Mo Dual Arcade is a USB interface for up to two arcade joysticks and 22 buttons. It’s a cool little device if you want to build an arcade controller for your computer or Raspberry Pi. You can get one from Ultracabs.

Unfortunately there is a bug in the Xin-Mo Dual Arcade: the values it sends for the up and left positions of the joysticks are out of range with the values it announces it would send, and Linux therefore ignores these values (it’s its right). Therefore the joystick do nothing in the up and left position.

I wrote a driver to fix that problem, as a patch to the Linux Kernel. A few people asked me for help on how to install it, hence this article.

Cliché Disclaimer: Use these instructions at your own risks. Backup your computer before you start. I am not responsible for any data loss or fried computers caused by following these instructions.

Ubuntu

I used Ubuntu 13.04, but it should be the same for the other affected versions (12.04, 12.10). Everything here happens in the terminal, make sure you’re logged in as an administrator (typically the user you created when you installed Ubuntu). Whenever a command that starts with sudo asks for your password, use the password for that administrator user. These instructions were derived from the BuildYourOwnKernel page on the Ubuntu Wiki.

Observing the problem

First we’re going to install evtest, a tool to test the joystick:

sudo apt-get update
sudo apt-get install evtest

To try it out, connect your joystick and run the program:

evtest

It will list devices and ask you to select your joystick. Find the line that says Xin-Mo Xin-Mo Dual Arcade, type the number next to /dev/input/event (4 in this example) and Enter.

No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event4:  Xin-Mo Xin-Mo Dual Arcade
Select the device event number [0-5]: 4

Now when you move the joysticks and press buttons, it will print lines like these (for a button):

Event: time 1378629038.490828, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001
Event: time 1378629038.490828, type 1 (EV_KEY), code 288 (BTN_TRIGGER), value 1
Event: time 1378629038.490828, -------------- SYN_REPORT ------------
Event: time 1378629038.618674, type 4 (EV_MSC), code 4 (MSC_SCAN), value 90001
Event: time 1378629038.618674, type 1 (EV_KEY), code 288 (BTN_TRIGGER), value 0
Event: time 1378629038.618674, -------------- SYN_REPORT ------------

or these (for a joystick):

Event: time 1378629075.546079, type 3 (EV_ABS), code 1 (ABS_Y), value 1
Event: time 1378629075.546079, -------------- SYN_REPORT ------------
Event: time 1378629075.740176, type 3 (EV_ABS), code 1 (ABS_Y), value 0
Event: time 1378629075.740176, -------------- SYN_REPORT ------------

and nothing when you move the joysticks up or left.

Fixing the problem

Downloading the sources

First we need to install the programs needed to build the kernel1:

sudo apt-get build-dep linux-image-$(uname -r)

Then we can download the source code for the kernel:

apt-get source linux-image-$(uname -r)

It will download and extract the following files to the current directory (the numbers can vary):

linux-3.8.0
linux_3.8.0-30.44.diff.gz
linux_3.8.0-30.44.dsc
linux_3.8.0.orig.tar.gz

Applying the patch

linux-3.8.0 is the directory where the source code was extracted. Enter it:

cd linux-3.8.0

Before we start, we need to install a tool called fakeroot2:

sudo apt-get install fakeroot

Then download the patch using wget:

wget 'https://ithink.ch/blog/files/xin-mo/0001-hid-Add-new-driver-for-non-compliant-Xin-Mo-devices.patch'

and apply it:

patch -p1 < 0001-hid-Add-new-driver-for-non-compliant-Xin-Mo-devices.patch

It should display something like this:

patching file drivers/hid/Kconfig
Hunk #1 succeeded at 697 with fuzz 2 (offset -46 lines).
patching file drivers/hid/Makefile
Hunk #1 succeeded at 108 (offset -2 lines).
patching file drivers/hid/hid-core.c
Hunk #1 succeeded at 1738 (offset 2 lines).
patching file drivers/hid/hid-ids.h
Hunk #1 succeeded at 849 (offset -38 lines).
patching file drivers/hid/hid-xinmo.c

Building the kernel

Run the following commands to start the build:

fakeroot debian/rules clean
fakeroot debian/rules binary-headers binary-generic

After a short while, it should pause to ask you about enabling a new driver:

Xin-Mo non-fully compliant devices (HID_XINMO) [N/m/?] (NEW)

That’s the one we’re going through all this trouble for, so tell it to install the module by typing m and Enter.

Then the actual compilation will begin. It will take a while.

Installing the new kernel

Exit the linux-3.8.0 directory:

cd ..

Four debian packages were created (again, the numbers will vary):

linux-headers-3.8.0-30_3.8.0-30.44_all.deb
linux-headers-3.8.0-30-generic_3.8.0-30.44_amd64.deb
linux-image-3.8.0-30-generic_3.8.0-30.44_amd64.deb
linux-image-extra-3.8.0-30-generic_3.8.0-30.44_amd64.deb

Install them one by one:

sudo dpkg -i linux-headers-3.8.0-30_3.8.0-30.44_all.deb
sudo dpkg -i linux-headers-3.8.0-30-generic_3.8.0-30.44_amd64.deb
sudo dpkg -i linux-image-3.8.0-30-generic_3.8.0-30.44_amd64.deb
sudo dpkg -i linux-image-extra-3.8.0-30-generic_3.8.0-30.44_amd64.deb

And then reboot:

sudo reboot

Test the patch

Run evtest again, like above, and enjoy the result:

Event: time 1378634592.175998, type 3 (EV_ABS), code 1 (ABS_Y), value -1
Event: time 1378634592.175998, -------------- SYN_REPORT ------------
Event: time 1378634592.335920, type 3 (EV_ABS), code 1 (ABS_Y), value 0
Event: time 1378634592.335920, -------------- SYN_REPORT ------------
Event: time 1378634593.613888, type 3 (EV_ABS), code 0 (ABS_X), value -1
Event: time 1378634593.613888, -------------- SYN_REPORT ------------
Event: time 1378634593.809001, type 3 (EV_ABS), code 0 (ABS_X), value 0
Event: time 1378634593.809001, -------------- SYN_REPORT ------------
Event: time 1378634595.165686, type 3 (EV_ABS), code 3 (ABS_RX), value -1
Event: time 1378634595.165686, -------------- SYN_REPORT ------------
Event: time 1378634595.325688, type 3 (EV_ABS), code 3 (ABS_RX), value 0
Event: time 1378634595.325688, -------------- SYN_REPORT ------------
Event: time 1378634595.933826, type 3 (EV_ABS), code 2 (ABS_Z), value -1
Event: time 1378634595.933826, -------------- SYN_REPORT ------------
Event: time 1378634596.093610, type 3 (EV_ABS), code 2 (ABS_Z), value 0
Event: time 1378634596.093610, -------------- SYN_REPORT ------------

If these instructions helped you, I would appreciate it if you could send me a couple of pictures of your set-up so I can compile them on a web page. Drop me a note on Twitter.

1. And we already need to deviate from the instructions on the Ubuntu Wiki, because they tell you to download the sources first, but it will fail on a fresh install because we’re missing some tools. That shows us how carefully those instructions are written. 

2. Second deviation, they forgot about installing fakeroot

Do not meddle in the affairs of Coding Ninjas, for they are subtle and quick to anger.