Hacking the Kobo Touch


Table of Contents

  1. Intro
  2. Recovery
  3. "Activating" without Desktop App
  4. Upgrading without Desktop App
  5. Enabling Access
  6. Preventing Phoning Home
  7. Customizations
  8. Tinkering
  9. Documentation

Intro

ObCheerleading

Of the three major e-readers out today, Kobo rocks the hardest. Kobo supports the ePub standard, has released code as required by the GPL, and has made the life of the hacker surprisingly easy (not locked down, preinstalled nc and vi, git repos, support forums, ...). Go forth and buy 3.

Yes, I have a BeBook for OpenInkpot futzing, but I haven't yet gotten as excited about it...

Assumptions: Tools and Paths

For this discussion, I'll assume you use some sort of UNIX or at least have UNIX-y tools available.

For simplicity, I'll also assume you use the same mount points on your desktop machine as the Kobo uses internally.

DeviceMount point
built-in storage/mnt/onboard
SD card/mnt/sd

Assumptions: Versions

I have been working with the 1.9.x series, currently 1.9.17. Apparently there is a 2.0.0 firmware out. No idea yet how much of this works on it.

Disclaimer

If you follow any instructions here and brick your Kobo, you get to keep the pieces.

Recovery

Factory Reset

But if something does go wrong, first try to factory reset the device. The Kobo Touches have a 256MB partition dedicated to the installation, and 256MB dedicated to a factory backup partition, and the rest for the user's books. Restoring from the backup partition is wired pretty low into the device (apparently U-Boot; look in /etc/u-boot/ for restore images). To restore the device back to factory, hold down the "Home" button (the only button on the front) while inserting a paperclip in the hole on the back. Continue to hold the button until the LED on the top starts flashing light blue.

Powering off

Hold the power switch for about 5 seconds.

Rebooting

Use a paperclip to press the button in the back.

Or if you have already enabled telnet, telnet in and reboot:

$ telnet 192.168.1.69
Trying 192.168.1.69...
Connected to 192.168.1.69.
Escape character is '^]'.

(none) login: root
[root@(none) /]# reboot
[root@(none) /]# 
To escape out of the now-defunct telnet session, press Ctrl-], type quit, then Enter.

Backing Up

Kobos have a 2GB MicroSD card installed (although I have not yet completely disassembled mine to verify this). Assuming this is true, it's basically impossible to truly brick your Kobo. Keep a backup of the 2GB MicroSD image, and if anything goes terribly wrong, disassemble the device, put the MicroSD card into a PC (maybe via a USB adapter), and restore the image.

To back up the entire device, enable telnet, and use netcat.

Backing Up Settings

Backup / restore /mnt/onboard/.kobo/Kobo/Kobo\ eReader.conf and /mnt/onboard/.kobo/KoboReader.sqlite.

"Activating" without Desktop App

Before your Kobo can be upgraded (and before you can enable telnet, or perform a variety of other modifications), you (supposedly) must "set up and register" it by using the desktop application.

The Kobo wants to be associated with the desktop app presumably as another path to post the Google Analytics statistics, and to encourage use of the online bookstore, which in turn will encourage you to put the Kobo online so it can download ads. If you do not want to bother with the desktop app (or can't because you don't run Windows), this requirement can be bypassed by adding a record to the database.

  1. Connect the Kobo via USB, and mount its onboard storage on your desktop machine.
  2. Ensure you have an SQLite3 database browser installed, or some way to execute SQL. For example, sudo apt-get install sqlitebrowser
  3. Open /mnt/onboard/.kobo/KoboReader.sqlite.
  4. Execute this SQL: insert into USER values("foo", "foo", "foo", "foo", "foo");
  5. Save, unmount, and disconnect.

Upgrading without Desktop App

First obtain the upgrade zip file. If you know you want version X.Y.Z, google for kobo3-update-X.Y.Z.zip. Other people likely have already sniffed the desktop app and posted the URL. Download this. (A good list of links is on MobileRead.)

Connect the Kobo via USB, and mount its onboard storage on your desktop machine.

Unzip the upgrade file in the /mnt/onboard/.kobo directory.

Unmount and disconnect the Kobo. It should begin the upgrade.


Enabling Access (1.9.x)

WARNING: This has been tested on 1.9.x, but apparently 2.x starts wireless differently. This method will break wireless access on 2.x.

Telnet

Enabling telnet is much like doing a regular upgrade. We want to update these files on the Kobo:

/etc/inittab

::sysinit:/etc/init.d/rcS
::respawn:/sbin/getty -L ttymxc0 115200 vt100
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::restart:/sbin/init
::sysinit:/etc/init.d/rcS2
::respawn:/usr/sbin/inetd -f /etc/inetd.conf
/etc/inetd.conf
23 stream tcp nowait root /bin/busybox telnetd -i
21 stream tcp nowait root /bin/busybox ftpd -w -S /
/etc/init.d/rcS2
#!/bin/sh
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
Create a KoboRoot.tgz with these updated files. (See my OcherBook project for such a tgz.) Put it in /mnt/onboard/.kobo. Unplug USB to do the upgrade. Reboot.

Before you put your Kobo on your wireless network, block Kobo's domains at your router. Then connect it to your network, and determine the Kobo's IP address by looking at your router.

Telnet to your Kobo, and log in as "root", with no password. Now you may want to block kobo domains on the Kobo or other customizations.

FTP

Enabling telnet should also have enabled FTP, due to inetd.conf. No username or password is required.

Enabling Access (2.x)

TODO

Preventing Phoning Home

Blocking Kobo Domains at Router

If you ever connect a stock Kobo to a wireless network, it will:

If the Kobo starts downloading an update, you can temporarily cancel it by pressing the home button. It will retry soon.

If the Kobo downloads ads, currently the only way I know to remove then is to do a factory reset and start over. If you know where ads are stored, let me know.

Best to (at least temporarily) block the following domains at your router, so you have time to work on the Kobo without it fighting you:

kobobooks.com mobile.kobobooks.com www.kobobooks.com dev.kobobooks.com
partner.dev.kobobooks.com ecimages.kobobooks.com images.kobobooks.com

Here is a sample rule for a WRT54GL router running the Tomato firmware, preventing a particular Kobo device from accessing Kobo domains:

Blocking Kobo Domains on the Kobo

The Kobo phones home every time wireless is enabled. This query checks for software updates, verifies that a "Kobo Touch" is configured to show ads, and reports statistics via Google Analytics. If you don't like this, telnet to your Kobo (as "root") and block access to various kobo domains:
[root@(none) /]# vi /etc/hosts
And edit the file to contain:
127.0.0.1 host localhost.localdomain localhost localhost localhost.localdomain
0.0.0.0 kobobooks.com mobile.kobobooks.com www.kobobooks.com dev.kobobooks.com
0.0.0.0 partner.dev.kobobooks.com ecimages.kobobooks.com images.kobobooks.com
Note that this will cause failed Google Analytics posts to accumulate in your /mnt/onboard/.kobo/Kobo/Kobo eReader.conf file. This can get quite large. The only way I have found to clear them out is to telnet into the device (as "root"), delete the GAQueue value from the file, and reboot (or paperclip) before the Nickel application can re-write its copy from memory:
[root@(none) /]# sed -i -e "s/^GAQueue=.*/GAQueue=/" /mnt/onboard/.kobo/Kobo/Kobo\ eReader.conf 
[root@(none) /]# killall nickel
[root@(none) /]# reboot

Disabling Google Analytics

While digging into the Kobo Touch, I discovered that it posts stats back via Google Analytics, and naive attempts to block these posts result in the statistics getting queued indefinitely in a config file. This file will grow without bound and be updated repeatedly in flash. Not ideal in an embedded environment.

The pending statistics are stored in /mnt/onboard/.kobo/Kobo/Kobo eReader.conf under the GAQueue label. It would be most ideal to not collect such statistics in the first place.

The core of Kobo's application is libnickel. Get a copy:

TODO

Since the Google Analytics variable is named GAQueue, perhaps functions are named similarly. Let's look for GA...

$ arm-2010q1/bin/arm-linux-objdump  -T ~/libnickel.so.1.0.0 | c++filt | grep GA
...
008e24ac g    DF .text  000004d4  Base        EventEngine::fireGAEvent(GAEventType const&, QMap)
fireGAEvent sounds promising. Disassemble some, so I know the bytes that start this function, to be used as a landmark:
$ arm-2010q1/bin/arm-linux-objdump  -d ~/libnickel.so.1.0.0 | less
...
008e24ac <_ZN11EventEngine11fireGAEventERK11GAEventType4QMapI7QString8QVariantE>:
  8e24ac:       e92d4ff0        push    {r4, r5, r6, r7, r8, r9, sl, fp, lr}
  8e24b0:       e59f44b8        ldr     r4, [pc, #1208] ; 8e2970 <_ZN11EventEngine11fireGAEventERK11GAEventType4QMapI7QString8QVariantE+0x4c4>
  8e24b4:       e59f54b8        ldr     r5, [pc, #1208] ; 8e2974 <_ZN11EventEngine11fireGAEventERK11GAEventType4QMapI7QString8QVariantE+0x4c8>
...
Now fire up the binary editor, and go to offset 0x8e24ac.
008E24AC F0 4F 2D E9 B8 44 9F E5 B8 54 9F E5 04 40 8F E0 05 30 94 E7 .O-..D...T...@...0..
008E24C0 B0 64 9F E5 3C D0 4D E2 02 70 A0 E1 03 50 A0 E1 0C 00 8D E5 .d..<.M..p...P......

Yes, that looks correct. Remember, the Kobo runs the ARM in little endian mode, so 0xe92d4ff0 is stored in memory backwards. To return from a function, do bx lr:
e12fff1e        bx      lr
So change the prior dump to:
008E24AC 1E FF 2F E1 B8 44 9F E5 B8 54 9F E5 04 40 8F E0 05 30 94 E7 ../..D...T...@...0..
008E24C0 B0 64 9F E5 3C D0 4D E2 02 70 A0 E1 03 50 A0 E1 0C 00 8D E5 .d..<.M..p...P......

Save, upload, reboot, and enjoy no overflowing GAQueue variables.

Customizations

Personalizing the Sleep Screen

My wife and I both have Kobos. To avoid mixups, I personalized the sleep screen with our names. The sleep screen is part of Kobo's "nickel" application, which is closed source, so all I could trivially do was binary editing. This truly is more of a "hack" than engineering... nevertheless, here's how:
  1. Enable telnet and ftp.
  2. ftp to the Kobo to get the Nickel library:
    ftp kobo
    cd /usr/local/Kobo
    get libnickel.so.1.0.0
  3. On your local machine, ensure you have some binary editing tool. On Linux, one I like is bvi: apt-get install bvi.
  4. Open libnickel.so.1.0.0 in your binary editor and search for the string "Sleep Mode". Replace it with your own text, but be sure to NOT change the size of the file. (Making the string longer is possible, but if you're not comfortable with disassembling ARM code... don't.) If your string is shorter, terminate it with a NULL or center it with spaces. Save.

    For example, here I have changed mine to read "Chuck's":

    010E0160  65 70 69 6E 67 2D 62 6C 61 63 6B 2E 70 6E 67 00 eping-black.png.
    010E0170  66 6F 6E 74 3A 20 69 74 61 6C 69 63 20 34 34 70 font: italic 44p
    010E0180  78 20 47 65 6F 72 67 69 61 20 3B 00 20 43 68 75 x Georgia ;. Chu
    010E0190  63 6B 27 73 20 00 00 00 51 57 69 64 67 65 74 20 ck's ...QWidget
    010E01A0  7B 20 63 6F 6C 6F 72 3A 20 72 67 62 28 32 35 35 { color: rgb(255 
  5. ftp to the Kobo, and upload the modified file:
    ftp kobo
    cd /usr/local/Kobo
    put libnickel.so.1.0.0
  6. Restart the Kobo. You can either paperclip it, or telnet in (as "root") and reboot.

Tinkering

Keeping Wireless Alive

The nickel application powers off wireless, and eventually puts the device to sleep. To avoid this while you explore, stop the nickel process: killall nickel. To restore, reboot.

You may, of course, want to have it plugged in via USB so the battery doesn't drain if you leave wireless on for a long time.

Displaying Images

$ ffmpeg -i input.jpg -vf transpose=2 -f rawvideo -pix_fmt rgb565 -s 600x800 -y output.raw
$ ftp kobo
ftp> cd /tmp
ftp> put output.raw
ftp> quit
$ telnet kobo
$ cat /tmp/input.raw | /usr/local/Kobo/pickel showpic

e-Ink Display

The Kobo Touch uses the i.MX508 SoC.

The Linux kernel sources, including drivers for this SoC, are available from KoboLabs:

$ git clone https://github.com/kobolabs/Kobo-Reader.git
$ cd KoboLabs/hw/imx506/cls/
$ tar -zxf ...

Documentation

Freescale

Go to freescale.com and download "i.MX50 EVK Linux Documentation Bundle". (Ridiculously, I had to use IE to register; probably uses bad Javascript.) Untar. Find mx50_linux.pdf.

Specs

Kobo Touch: i.MX508

Kobo Wireless: Display controller: Epson S1D13521 S1D13521 driver on GitHub