This year a slew of companies have launched competing Android tablet devices. A lot of rhetoric has been spun about how Android’s open source ecosystem gives manufacturers and consumers an advantage.

Android is open source; it can be liberally extended to incorporate new cutting edge technologies as they emerge. The platform will continue to evolve as the developer community works together to build innovative mobile applications. (Open Handset Alliance)

Unfortunately, the current crop of Android tablets aren’t nurturing open source at all.

Android Tablets

With the exception of Barnes & Noble’s Nook e-reader, a device that isn’t even really a tablet, I couldn’t find a single EDIT: I found one tablet manufacturer who was complying with the minimum of their legal open source requirements under GNU GPL. Let alone supporting community development.

Manufacturer Based In Tablets GPL Compliant Sources Available
Apad China 1+ No No
Archos France 2 Yes (see caveats below) Yes
Barnes & Noble United States 1 Yes Yes
Eken Group China 4+ No Partial
(see below)
Gome China 1 No Partial
(see below)
Moonse China 1+ No No
Pandigital United States 1 No (may change) ?
Smart Devices China 5 No Community

EDIT 2/9: Benmars posted in the comments that Archos have now released GPL source code for the Archos 7 Home Tablet. This looks to be a full kernel source release for the Rockchip RK28xx SoC, and even includes includes a prebuilt linux-x86 cross-compiler toolchain. Thank you Archos!

EDIT 31/7: In the comments, xauieous points out that while Archos have released GPL source for the ARM11/OMAP2 based “Archos 5 Internet Tablet” (aka Archos Generation 7), they are not complying with GPL for the ARM9 based “Archos 7 Home Tablet”. The contents of the “Generation 7” kernel tarball seem to bear this out. Xauieous claims Rockchip are holding out on the source for the Archos 9 Home Tablet, same as Apad.

Also, personal note to Archos: Please get a less confusing naming scheme!

EDIT 28/7: Courtesy Harald Welte @ VIA, there’s been a source drop of kernel source for WM8505-based tablets (Eken M001,M003,Gome FlyTouch, etc.) Some parts (video, SD/MMC drivers) are still binary only, Harald says he’s talking to VIA about it.

EDIT 26/7: Zebul posted a comment and drew my attention back to Archos’ GPL download section. I originally thought these were all just media player firmwares, but it turns out “Archos Generation 7” means the “Archos 5 Internet Tablet” and this tarball is a full GPL source release. Well done Archos! To their detriment, the binary firmware does not contain any obvious GPL mention – and this may mean they are still in technical breach of the GPL. The manual doesn’t mention anything either. But it’s still streets ahead of the others. Yay Archos!

(EDIT: I posted some details here. Please leave a comment if I’ve missed any tablets, or any source releases.)

What’s this GPL?

The GNU General Public License is a “copyleft” software license. Manufacturers releasing products with GPL licensed code, like the Linux kernel that underpins Android, are required to make their changes available in source code form.

Android itself isn’t GPL. Its open source Apache license does not mandate that source code has to be made available. However, all Android systems include the Linux kernel at minimum, and may also include other GPL-licensed pieces of software that are not part of the base Android distribution.

GPL source releases for these kernels make it easier for developers to build alternative operating systems, Android or otherwise, to run on the tablet hardware. It also allows improvements and changes to flow back “upstream” to the original software authors.

Why should consumers care?

The average tablet buyer isn’t an open source developer. However, having healthy open source releases means future support for these devices is guaranteed. Currently, projects like CyanogenMod make new improvements available to old Android phones whose manufacturers have already moved on. Similar community improvements could make new releases available on tablets, even though manufacturers are no longer supporting them.

Often, community Android releases are better than the original manufacturer’s. Slatedroid & ECOTOX have been releasing customised Android versions for the Eken M001 tablet which are both faster and support more features than the OEM release. Having kernel source available can only serve to make these releases better. For the Nook e-reader, community software releases allow you to view more ebook formats on your Nook, and even add totally unexpected features like Pandora Internet Radio.

Why should tablet manufacturers care?

Most manufacturers seem to be stuck in the “vendor” mindset that their hardware should remain entirely under their control, and that anyone else working on it is a problem.

However, it seems like community development almost always adds value to the hardware by extending it and adding more features. Especially in the tablet arena where there are no carriers to insist on platform lockdown to support their business model, an open platform doesn’t seem like it carries any significant drawbacks.

Some companies, particularly the smaller Chinese ones, appear to be concerned about competitors ripping their software off into compatible hardware. From what we’ve seen with the Eken M001 though, it doesn’t seem like source availability – especially kernel source – would do much to change the situation.

Outside of e-readers, there aren’t any companies competing on custom software anyhow: for the most part the software is vanilla Android, and competition is on performance, specifications, and especially price. This seems to make an even bigger opportunity for a clever manufacturer to embrace community open-source development, and differentiate themselves from all the “me too” Android clones without incurring any actual R&D cost.

What about chipset manufacturers?

A lot of kernel development for these devices is done by the original chipset manufacturers themselves. For example, it seems like VIA authored and compiled the kernels found in all devices based on the WM8505 chipset (including Eken’s tablets and some others..) It seems like the same story is true for Rockchip, who make the chipset used in the iRobot APad & Moonse E-7001.

Chipset manufacturers aren’t required to release GPL source code to the public, provided they send sources alongside any GPL software that goes to the device manufacturer. VIA has so far chosen this path, stating all sources are released to device manufacturers (although Eken has claimed differently at least once.) In the case of RockChip, manufacturers claim RockChip isn’t even doing that much and are violating GPL themselves (see first comment).

In addition, chipset manufacturers may sometimes author custom kernel modules or other components that are not GPL licensed at all. For example, Samsung have a video acceleration kernel module that is included in the firmware for the SmartQ tablet range. These components are normally not open sourced at all.

I can think of three reasons which chipset manufacturers do not embrace open source. One is that it is simpler not to. Another is that they charge device manufacturers for access to their SDK, and preemptively releasing source takes away that revenue stream (although possibly at the expense of extra hardware sales.) The last is that they are concerned about protection of their intellectual property, although this seems unnecessary given that most of their trade secrets are captured in the hardware itself, which is in turn protected by patents.

What about Google?

Google is in an interesting position here. On the one hand, they have worked hard to make sure that above the kernel layer Android is not GPL licensed. This serves to calm worried manufacturers threatened by the idea of having to release source. It seems, sadly, like a necessary step in order for Android to receive the kind of market prominence that Google wants for it.

On the other hand, it seems hypocritical for Google to tout Android’s “open source” credentials when it seems so clear that most companies profiting from it are completely oblivious, maybe even antagonistic, to open source.

I think there may be things Google could do to encourage manufacturers to be more friendly (or at least legally compliant) with open source, without scaring them off. An idea that springs to mind, especially now Google seem to be out of the device business, is promotion & accreditation of open source friendly manufacturers who receive extra kudos and promotion from Google in exchange for giving back to the community. Some kind of base level accreditation for companies who do not violate GPL, and additional incentives for companies who give back extra to the community.

Where to from here?

There are a lot more Android devices on the horizon, from a variety of manufacturers. It is my sincere hope that, especially following the growing buzz around “open source hardware”, at least one chipset or device manufacturer decides to make a break from the pack and announce “open source friendly products & manufacturing” that includes supporting community development.

Until then, if you care about open source you may actually be better off buying an iPad than many of the devices listed above. At least Apple comply with GPL and contribute back to the open source projects that they benefit from!

(One more Eken post and I’m going to have to rename this blog to Project M001!)

EDIT: Everything here is somewhat out of date now. Jacob Stoner has released a Debian build with X11 & touchscreen support. The links are all posted on the slatedroid forum.

Debian Boots! I wish I had a keyboard!

Debian on the WM8505 netbooks has been around for a while, thanks to the efforts of #easypc’s abrasive. I needed to tweak a couple of things before his release worked on the Eken M001 tablet.

Before you begin

You probably want to start by plugging in either a USB keyboard or a serial cable. Otherwise, all Debian has to offer you is a blank login console.

Howto

Follow abrasive’s directions in the README here to set up the partitions on your SD card.

Before you boot the SD card, make the following 4 changes:

  1. In the FAT partition you made, replace script/scriptcmd with this scriptcmd file.
  2. Download the Eken official Android 1.6 upgrade from here, unzip it and copy the script/uzImage.bin file (kernel image) over script/uzImage.bin on the FAT partition you made.
  3. In the ext2 partition, edit etc/inittab and replace this line:
    #T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
    with this one:
    T0:23:respawn:/sbin/getty -L ttyS0 115200 vt100
  4. Also in the ext2 partition, run sudo mknod (mount-point-of-ext2-part)/dev/ttyS0 c 4 64(or equivalent)

(The last two steps are only strictly necessary if you want to use the serial console, but the first two are necessary all of the time.)

Then pop the card in and you should boot into Debian! The instructions on the bento-linux Wiki for X11 work as well, although I found I needed a window manager (like xfce4) installed before X11 would stay launched.

Default XFCE4 on my M001 tablet

EDIT: If you’re having trouble booting from SD, I just had an experience where uboot was refusing to load ‘scriptcmd’ even though it was correct. I had to reformat the FAT partition and re-copy the files. Not sure what that was about, but might be worth trying if your Debian suddenly refuses to boot.

Notes

The new scriptcmd adds the kernel command line arg “console=ttyS0,115200n8” to the command line. Seems unnecessary, but I couldn’t get it to boot successfully at all without this addition.

If you don’t replace the netbook kernel with the one from Eken, you won’t get any graphics display. Although debian will still run fine through the serial port. I’m guessing the netbook kernel has the LCD buffer at a different address.

Eken boots android with mem=109M on the command line whereas abrasive has used mem=112M. I don’t know if the Android version is allocating extra space for framebuffer double buffering, or something else. I haven’t noticed any differences yet so I’m running with mem=109M.

I haven’t tried the optional scriptcmd.install to install Debian to the internal flash, yet. I’m guessing you may need to repartition the mtd to get full use, as the Android partitioning scheme uses two partitions.

Pro tip: to see the insides of a scriptcmd file run ‘tail -c +73 scriptcmd’

Disk access when running from the SD card is sloooow (at least for slow SD cards like mine.) Don’t know if running from internal flash is any better.

I’m guessing that the framebuffer works normally in the Debian install because it isn’t using double-buffering, which is necessary for Android to work. I don’t know if ‘abrasive’ had to do anything special to get the ‘fbcon’ console module to work, I’m going to try and find out though!

EDIT: Jacob Stoner has come up with a small program to init the touchscreen, and a more recent version of evtouch that works for input. info here, init program & recent evtouch. He says he’s going to come out with an installable package (no serial/keyboard required) shortly.

I had a quick try at copying across the wm9715-api.ko & wm9715-ts_800_480.ko touchscreen modules from the Eken firmware, and using them with the package xserver-xorg-input-evtouch to provide a touchscreen mouse. No luck, though. The ‘evtest’ utility shows screen presses coming in, but no X/Y coordinates. A better approach might be to compile the the Wolfson OSS drivers against the 2.6.29 kernel headers.

Finally,

Want a quick laugh?


~# modinfo wm9715-api.ko
filename: wm9715-api.ko
author: VIA ShenZhen MCE SW Team
license: GPL
description: WM9715 api for the driver of touchscreen and battery

GPL, huh? This is kind of “GPL” where noone releases any source code. Ho ho ho! Thanks VIA, Wondermedia & Eken.

“Derek” posted up a comment yesterday:

I have a EKEN M001, which will not unlock the screen by pressing MENU.

I have tried reseting the EKEN M001 by pressing the Reset button on the back ofthe MID, but te screen stays unlocked.

The top of the screen says: “Demo Version” when the GUI appears, does this need a Operating System update. If so, hpw can this be done.

Short Answer

I think your tablet has failed its internal licensing check. Try to return it to the retailer that you bought it from. If you now connect it to the internet, it will “phone home” to a company in Shenzhen, China.

EDIT: Before you give up try connecting to the internet for a while and leave it connected. It seems like sometimes “phoning home” will verify that it’s a legit install and then the message will go away.

Long Answer

This is a coincidence, because just yesterday I was looking at the decompiled Eken libraries posted to slatedroid by ‘bushing’. Hidden in there is licensing code that verifies the Eken is running on genuine hardware. I think it works like this:

  • The Eken has a serial number loaded into its CPU (a WMT system parameter in the SoC.)
  • The serial number maps to the hardware (MAC) address of the onboard wireless adapter.
  • At startup, the Eken loads the serial number and compares it with the serial number it calculates from the wireless adapter.
  • If they do not match, it locks and throws up “Demo Purpose Only” (possibly “Demo version has expired” on the latest firmware.) It will also continually try to “phone home” with some details about the device (see below.)

I think all of this is to prevent someone putting their firmware into another device, unlicensed. The code is obfuscated (intentionally hidden in the source) in the hope that a casual shanzhai observer will miss it.

From looking around the internet, it looks like quite a few devices are turning up brand new with “Demo Purpose Only”. The only easy thing to do is to return it to the retailer that you bought it from.

It is possible some retailers are selling fake or refurbished units (maybe they swapped the WiFi unit or the CPU daughterboard out.) In other cases like this, it looks like units may be shipping from Eken with invalid serial numbers (poor quality control?) Finally, in cases like this it seems that temporary problems with the WiFi may trigger this behaviour for a while, then it fixes itself.

Eken Phone Home

I found it quite surprising that the unit tries to phone home if it thinks its license is invalid. It phones home with 3 details:

  • A username & password which is decoded from the file /data/wmtpref/custkey (in the firmware itself.)
  • The MAC address of the wireless adapter

… the very odd thing is that the unit does not phone home to Eken. It phones home to a company called Aiteer, who are also based in Shenzhen but do not seem to have any published relationship with Eken. Aiteer’s web site doesn’t say anything about software development, but I can only guess that they did the firmware development for Eken and possibly related MID/tablet devices using the WM8505 chipset.

Other Thoughts

It’s odd that the firmware locks the user out and tries to phone home, because if the user is locked out then it’s unlikely that they’re going to be able to connect to the internet. Maybe I missed a detail in my reverse-engineering, and the lockout only kicks in every few minutes or something.

Although “phoning home” is pretty common, software phoning home without the knowledge or consent of the user is less common and is often regarded as unethical. I’m glad that in this case no personal information is being sent back, but clearly we’re at the mercy of the manufacturers in this regard. Unlike mainstream manufacturers, companies like Eken have no corporate presence outside of their factory in China – in other countries, the laws that protect consumers are effectively powerless. If you hypothetically did find out that an unscrupulous shanzhai was stealing your personal details, there is no real recourse you could take.

The license check code was obfuscated in the library (libui.so in this case) so that a casual observer would not see it. For example, nothing unusual showed up when I ran ‘strings’ the other day. However, a tiny bit more reverse-engineering shows up a helper method calling base64_decode to decode each of the string constants related to the license check.

The code used to decode the username & password from the customer key, as well as the code used to calculate the serial number, are both trivially simple and anyone with some C programming knowledge can decipher them from the decompiled dump in an hour or two. For this reason, I think that the manufacturers only put in this protection to avoid casual copying of their firmware into another product – anyone serious about ripping them off could spend a couple of hours and generate their own serial numbers, and disable the “phone home” feature, without needing to modify the binary code at all.

Because the serial number is tied to the MAC, I don’t think anyone will be able to replace the WiFi module at all – even though you own the product.

It bothers me a lot that Eken are going to lengths to protect the tiny amount of proprietary code in their product, while not doing anything to fulfill either the legal obligations or the spirit of the substantial open source parts of the product. It bothers me doubly so now that they’ve locked out the root serial console in the latest (1.7.4) firmware release. How do they think that this helps their product?

On an Arduino or other AVR, EEPROM access is a bit fiddly if you want to store different types of data. In this blog post, I’ll show you a quick trick to use when you have lots of structured data to store in EEPROM.

Alternatives

First, the existing alternatives:

  • Arduino has EEPROM, which is simple but it only reads/writes single bytes.
  • Arduino Playground has two templated functions that let you read/write anything. However, you need to know the offset of whatever you are accessing. Also, I find C++ templates a bit icky for this use case.
  • One level deeper, avr-libc has a more complex API for other kinds of integers, and buffers. However, you still need to remember offsets & sizes.
  • The EEMEM keyword works like PROGMEM to let you flag things as stored in the EEPROM. Which is nice, but you still need to pass size and offset whenever you read a value.

Technique

This technique uses a single ‘struct’ to represent the entire contents of your EEPROM, so you can then use macros to read and write fields.

You define a struct called __eeprom_data that describes your EEPROM:

struct __eeprom_data {
  int first;
  int second[64]; 
  boolean third;
  char fourth[buf_len];
}

Then use macros eeprom_read & eeprom_write to read and write each field:

int x;
eeprom_write(-7, first);
eeprom_read(x, first);

Full Example


/*
 * Copy and paste this block of #include & #defines into your code to use
 * this technique.
 *
 * (Don't worry too much about reading the macros, read through the
 * examples below instead.)
 */

#include <avr/eeprom.h>
#define eeprom_read_to(dst_p, eeprom_field, dst_size) eeprom_read_block(dst_p, (void *)offsetof(__eeprom_data, eeprom_field), MIN(dst_size, sizeof((__eeprom_data*)0)->eeprom_field))
#define eeprom_read(dst, eeprom_field) eeprom_read_to(&dst, eeprom_field, sizeof(dst))
#define eeprom_write_from(src_p, eeprom_field, src_size) eeprom_write_block(src_p, (void *)offsetof(__eeprom_data, eeprom_field), MIN(src_size, sizeof((__eeprom_data*)0)->eeprom_field))
#define eeprom_write(src, eeprom_field) { typeof(src) x = src; eeprom_write_from(&x, eeprom_field, sizeof(x)); }
#define MIN(x,y) ( x > y ? y : x )

const int buflen = 32;

/*
 * __eeprom_data is the magic name that maps all of the data we are 
 * storing in our EEPROM
 */
struct __eeprom_data {
  int first;
  int second; 
  boolean third;
  char fourth[buflen];
  char fifth[buflen];
};


void setup()
{
   Serial.begin(57600);

   /*
    * Writing simple variables to the EEPROM becomes simple
    *
    * First argument is the value to write, second argument is which field
    * (in __eeprom_data) to write to.
    */
   int q = 132;
   eeprom_write(q, first);
   eeprom_write(5958, second);
   eeprom_write(false, third);
   eeprom_write("Hello from EEPROM!", fourth);

   /*
    * You can even write from a pointer address if need be
    *
    * First argument is the pointer to write from.
    * Second argument is the field (in __eeprom_data) 
    * to write to.
    * Third argument is the buffer length
    */
    const char * buf = "Another hello looks like this";
    eeprom_write_from(buf, fifth, strlen(buf)+1);


    int a, b;
    boolean c;
    char d[buflen], e[buflen];
    char *e_p = e;
    
    /*
     * Reading back is just as simple. First argument is the variable to read
     * back to, the second argument is the field (in __eeprom_data) to read
     * from.
     */
    eeprom_read(a, first);
    eeprom_read(b, second);
    eeprom_read(c, third);
    eeprom_read(d, fourth);
    
    /*
     * You can read back to a pointer address, if you need to.
     */
    eeprom_read_to(e_p, fifth, buflen);
    

    Serial.println(a);
    Serial.println(b);
    Serial.println(c ? "TRUE" : "FALSE");
    Serial.println(d);
    Serial.println(e_p);
    
    /*
     * The eeprom_write macros do bounds checking, 
     * so you can't overrun a buffer.
     *
     * In __eeprom_data, 'third' is a one-byte boolean, but 
     * eeprom_write knows this so only the first char 'T' is written
     * to EEPROM
     */
    eeprom_write("This is a buffer overflow", third);
    
    /*
     * If you have an array, like char[], you can write & read a single
     * array entry from a particular constant index
     *
     * Unfortunately, it only works for constant indexes not variables.
     * eeprom_write('X', fourth[x]) does not work with these macros.
     */
    eeprom_write('X', fourth[3]);
    eeprom_read(d, fourth);
    char x;
    eeprom_read(x, fourth[3]);
    Serial.println(d);
    Serial.println(x);
}

void loop() { }

(This is Arduino code, obviously if you’re using avr-libc directly then you can rewrite it for that.)

Downsides

The downsides of this technique (as I see them) are:

  • Uses macro magic (so a bit icky.)
  • Overkill if you only need to store one type of data in EEPROM, but useful if you have lots of different types.

Initial Values

When you start up, you need to know if the data in EEPROM is data that your program saved, or something else. There are a few different ways to deal with this.

EEMEM

EEMEM provides a way for you to set default values easily in your code:

EEMEM struct __eeprom_data initial_data EEMEM = { 
  1, // first
  2, // second
  false, // third
  "Initial fourth", // fourth
   "Initial fifth" // fifth
};

Via avr-objcopy & avrdude you can generate a .eep file and flash it to the AVR. This is nice, but it won’t work if you’re using the Arduino IDE because (as of version 0018) it doesn’t generate .eep files properly, and it also doesn’t support flashing them.

It’s a good option if you’re using your own Makefile, though.

“Magic” number

The other way is to check for and expect a “magic” value somewhere in the EEPROM data. Something like:

// Change this any time the EEPROM content changes
const long magic_number = 0x5432;

struct __eeprom_data {
  long magic; // should be set to magic_number
  int first;
  int second; 
}

void setup() {
  long magic;
  eeprom_read(magic, magic);
  if(magic != magic_number)
    initialise_eeprom();
}

void initialise_eeprom() {
  eeprom_write(0, first);
  eeprom_write(0, second);
  eeprom_write(magic_number, magic);
}