Porting Arch Linux to a WM8650 tablet

I purchased a WM8650 tablet from Ebay; it arrived running Android.

There seem to be a number of people who have got Debian running on these things, although most people seem to be using the netbook variant of the device instead of the tablet variant - it is obviously harder to use a mainstream operating system if you have not got a keyboard! However, there seems to be no single place where all the necessary information to port a distro to this device is collected in one place. So here is a list of everything I have done to get Arch Linux running on my tablet.

For what it is worth, the only information I can discover to identify the model of my WM8650 is that it has a red/green power LED; it was purchased second-hand so it is presumably not the most recent model.

Important disclaimer

The following works on my tablet. It seems that all of these devices, although similar, differ in small details of the hardware, and my tablet does not seem to be the most common hardware variant. So be prepared for some experimentation, especially in the area of configuration settings and device drivers.

WARNING

Booting from an SD card overwrites configuration values in the NAND flash memory.

The "saveenv" command in the wmt_scriptcmd file causes the values set in the "setenv" commands to be written to the NAND flash memory; the kernel then reads these values from the flash memory. So you are strongly advised to back up the original contents of the flash memory before you start.

I don't know how to back this up from the original Android (if anyone knows, please email me and I'll write it here).
From Debian, you can run cat /proc/mtd to locate the flash memory blocks with names like u-boot env. cfg. 1-SF, and then use a command such as strings /dev/mtd3 to dump their content into human-readable form; this could then be edited into a wmt_scriptcmd file in order to restore the original values.
But if you have booted Debian from an SD card, a certain amount of damage will already have been done to the configuration.

Prerequisites

You need a cross-compiler on your PC in order to build the linux kernel. I used crosstool-ng to build a suitable cross-compiler. In addition, compiling the kernel requires the mkimage program from u-boot. Here are

You might prefer to follow the instructions on the Arch ARM website in order to install the most current cross-compilation environment, but you will still also need to install u-boot on your PC.

Building the SD-card image

You need an SD card with a small FAT32 partition and the rest formatted as ext3. I do not recommend using ext2 as it is prone to corruption if the system crashes (which is quite likely at first), and ext4 is not supported by my kernel.

The ext3 partition of the SD card needs to be populated with an initial version of the ARCH file system. Probably you would want:
  http://archlinuxarm.org/os/ArchLinuxARM-armv5te-latest.tar.gz
(just mount the partition on your PC and untar this tarball into it).

At this stage you also need to make the various configuration file changes that are needed to set up the Arch system (e.g. setting the hostname in /etc/hostname, selecting the daemons to be run, and so on. In particular you should add a line like this to /etc/fstab

  /dev/mmcblk0p1 /boot vfat defaults 0 0
so that the FAT32 partition is mounted as /boot.

Workaround for missing accept4 system call

The kernel for the WM8650 does not support the accept4 system call, which is used by udevd. As a workaround, we need to install a LD_PRELOAD library that fakes the missing OS call.
Download libaccept4.so and put it in /usr/lib, then create a file /etc/ld.so.preload containing the line:

  /usr/lib/libaccept4.so

This library is also available as an Arch ARM package; the source code is here.

Building the kernel

There is some kernel source code available from Wondermedia. It does not exactly correspond to the kernel binary that came with it, but it is better than nothing.
The latest version of the source code can be downloaded from here:

  ftp://ftp.gpl-devices.org/pub/vendors/Wondermedia/WM8650/KERNEL-DS_ANDROID_2.6.32_WM8650.111209.1514.tgz
This code is incomplete: it includes several binary blobs for which there is no source. However, it seems that there was an earlier source release which has been removed, but which can still be obtained from a mirror:
  http://projectgus.com/files/wm8650/KERNEL-DS_ANDROID_2.6.32_WM8650.110408.1903.tgz
The earlier version is complete; the source files that are missing in the later version have got GPL headers, so there should be no problem using them.

This is rather an old version of the kernel, and it cannot easily be updated because it has diverged considerably from the official kernel sources; however I found that it will still work with the current (October 2012) version of Arch after a little patching. The patching fixes:

Build the kernel using this PKGBUILD and associated files. Note that I have hacked the PKGBUILD file so that it will build an "arm" package even when run on an x86_64 machine.

There is no wireless chip driver in the Wondermedia source code, so my kernel PKGBUILD also builds this driver using source code from the Ralink website; although this is GPL code it is not easy to download automatically from their website, so the PKGBUILD downloads it from my home file server; this will not work for you, but you can get the missing file from here

The hardware boots by reading a configuration file named wmt_scriptcmd from the first partition of the SD card; this in turn specifies the name of the kernel file and the parameters to be passed to it.
You will need to manually unpack the kernel package file onto the SD card; the uImage and wmt_scriptcmd files go into the FAT32 partition; everything else goes into the main partition.

The WM8650 should then boot off the SD card. You should be able to log in using a USB keyboard; if you've got sshd installed and you are really lucky, you might even be able to log in across a wired network connection.

The X Window System

The issue here is that the touchscreen is a multi-touch device (or at least it pretends to be - I haven't seen more than one touch point reported by it) and the regular X Windows evdev does not understand the multi-touch events that the touchscreen driver supplies. There are multi-touch input driver for X Windows but they mostly seem to be designed for the "type B" protocol, whereas our driver uses the more primitive "type A" protocol.

My solution was to write my own driver; it is based on the example driver code here using ideas from this driver. My driver is not a multitouch driver, but understands the multitouch protocol; it supports simulating mouse button clicks by "tapping". You can download my driver from here:

  xf86-input-utktouch-0.1.0.tar.gz

The driver simulates a single button: a short "tap" on the screen produces a click on the button; a longer "touch" in a single place produces a button-down event, so that you can then move the mouse cursor with the button held down, for drag-and-drop (lifting the stylus will release the button).
The behaviour of the driver can be modified by 3 parameters:

  name            default         purpose
  TapTime         150             Maximum length of "tap" for button click
  DragTime        500             Minimum length of "touch" for drag-and-drop
  WiggleRoom      10              How many pixels the cursor is allowed to move
                                  during a "tap" or "touch"

To load the driver, add a file to /etc/X11/xorg.conf.d with the following contents:

  Section "InputClass"
          Identifier "utktouch"
          MatchProduct "utk_touch"  
          Driver "utktouch"
          Option "TapTime" "150"
          Option "DragTime" "500"
          Option "WiggleRoom" "10"
  EndSection

  Section "InputClass"
          Identifier "gsensor"
          MatchProduct "g-sensor"  
          Option "Ignore" "on"
  EndSection
The second section in this file causes the X server to ignore the gravity sensor, which otherwise appears as a second mouse (see below).

If, like me, you've got a tablet with no keyboard, you will probably want to configure it to automatically log on a user and go straight into X. I recommend the openbox window manager, which is lightweight enough to be usable on such a slow machine.

Keys

I added the module kpad to the list of modules to be loaded in a file in /etc/modules-load.d. This caused a new input device /dev/input/event2 to appear. This receives input events when you press the keys: the events are:

  kernel event    xorg event

  Menu            XF86MenuKB
  VolumeUp        XF86AudioRaiseVolume
  VolumeDown      XF86AudioLowerVolume
  Back            XF86Back
(the Back event is generated by the unlabelled key on the front face of the device).
Most window managers can be configured so that pressing a keyboard key launches an arbitrary action. I configured the window manager so that the Menu key pops up a menu, and the Back key launches a virtual keyboard (the xvkbd program). I also configured it so that the VolumeUp and VolumeDown keys act as left and right mouse button presses. There doesn't seem to be any way of doing this using the X keyboard layout utilities, so I configured the window manager to run xdotool -click 1 on pressing one key, and xdotool -click 3 on pressing the other.

Gravity sensor

I loaded the driver for this by adding the gsensor_mma7660_md module (I added it to a list in /etc/modules-load.d). There are several modules with names starting with "gsensor", so you might need to choose a different one.
This creates an entry in /dev/input that simulates a mouse, returning X, Y and Z values that represent the rotation about the various axes.
It would be nice to use this input to drive xrandr to rotate the screen as the tablet is turned, as happens in Android; unfortunately the fbdev screen driver in X does not support xrandr rotation.

Touchscreen calibration

Download, build and install the tslib package from here (you can use this PKGBUILD file).
Then download my input plugin from here. Build and install the plugin, then add this line to the tslib configuration file /etc/ts.conf:

  module_raw utktouch
The calibration program ts_calibrate will compete with X Windows for input, so you need to run it (as root) from a ssh prompt, having shut down X Windows first.

The ts_calibrate will create an output file /etc/pointercal.

Finally, the program touchpad_init (supplied with my plugin) reads this calibration file and loads it into the driver.
To run this program on boot, you need to make a systemd service file named /etc/systemd/service/touchpad_init with the following contents:

  [Unit]
  Description=Configure touchpad

  [Service]
  Type=oneshot
  RemainAfterExit=yes
  ExecStart=/usr/local/bin/touchpad_init

  [Install]
  WantedBy=multi-user.target
and then run systemctl enable touchpad_init.

Note: if your touchscreen input is not /dev/event/input0 then you have to pass the correct device to ts_calibrate in an environment variable; for example

  TSLIB_TSDEVICE=/dev/input/event1 ts_calibrate

Hardware clock

Addendum 16/Nov-2012: there was a bug in the kernel code for setting the hardware clock, that caused the date to be wrong by one month after a reboot. I have added a fix for this to my kernel patch.

Contact

You can contact me at mailto:john AT pond-weed DOT com.