The Treehouse Blog

cp210x on TH8581GA

on May.06, 2013, under Linux


I have an Android car radio, and this OBD2 to USB adapter.  Unfortunately, the rooted firmware currently available does not provide a cp210x kernel module that is needed to make this adapter work.  This article tries to describe the process of building and installing one.  Much of this article draws on the more general Building a Linux kernel module without the exact kernel headers and adds specifics for this particular purpose.  I strongly suggest reading that article for more of the technical details.  I don’t doubt there may be easier ways of accomplishing this, but these steps (produced through much trial-and-error and false starts) did work for me.


If you don’t need or want the how or the why, install this cp210x.ko in /system/lib/modules and run this update to change the init scripts to load it.  Use at your own risk – if you brick your radio, don’t come blaming me.  This expects you are already running Hal9k_’s rooted software update.

Building the Module

Finding the Parts

Finding Suitable Kernel Source

Since we’re trying to build a binary module for an already compiled kernel, we need to identify a very close copy of kernel source code to work with.  To my knowledge, the exact kernel source used on the Ouku has not been released.  Looking through Freescale’s website, I found a link to Linux kernel source for the SABRE tablet platform that seemed to meet the bill. The SABRE for automotive appeared to be an earlier version.

You need to sign up for a free account with Freescale, and accept their terms and conditions to obtain the download.

Finding Suitable Cross-Compiler

I originally tried compiling with the arm-linux-androideabi-4.4.3 that ships with android-ndk-r8e.  Unfortunately, the resulting modules had compatibility problems.  The solution was to use arm-linux-androideabi-4.4.0 that ships with android-ndk-r5b which can be found at

Obtaining the Kernel Configuration

The kernel provides a copy of its own configuration in the /proc/config.gz file.  Copy this file from the unit so we can use it to configure the kernel source.

Preparing to Compile

Untar the cross-compiler

$ tar jxvf android-ndk-r5b-linux-x86.tar.bz2

Setup cross-compiler environment variables

$ export ARCH=arm
$ export SUBARCH=arm
$ export CROSS_COMPILE="/path/to/android-ndk-r5b/toolchains/arm-eabi-4.4.0/prebuilt/linux-x86/bin/arm-eabi-"

Untar the source

$ tar zxvf L2.6.35_11.05.01_ER_source_bundle.tar.gz
$ tar zxvf L2.6.35_11.05.01_ER_source.tar.gz
$ cd L2.6.35_11.05.01_ER_source/pkgs
$ tar jxvf linux-
$ tar jxvf linux-

Apply provided patches

$ mv patches linux-
$ cd linux-
$ ./patches/

Configure the kernel

$ mkdir build
$ gunzip -c /path/to/config.gz > build/.config
$ make silentoldconfig prepare headers_install scripts O=build KERNELRELEASE=""

Extracting Module Symbols

Even with using this “close enough” kernel and the actual configuration from the running kernel, the module symbols used will not be identical.  We need these symbols to compile our module with for it to load successfully.

Obtain the Kernel Image

We have the uImage file from Hal9k_’s software update, so we’ll use that.  It is contained in a U-Boot image, so we need to strip the header off of it.  We’ll also want mkimage, a utility for making U-Boot images (on Fedora, this is available from the uboot-tools package).

$ mkimage -l uImage
Image Name:   Linux-
Created:      Mon Dec 10 02:34:26 2012
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    2547996 Bytes = 2488.28 kB = 2.43 MB
Load Address: 70008000
Entry Point:  70008000

$ dd if=uImage of=kernel.img bs=1 skip=64 count=70008000

Find the kernel base address

From a shell on the car radio, shortly after boot, capture the output of dmesg and look for the “.init” line. I copied it to my desktop first. The first hex address listed is the base address. In our case, it’s 0xc0008000.

$ grep \.init dmesg.txt
free_area_init_node: node 0, pgdat c04f94b4, node_mem_map c0599000
Kernel command line: console=null init=/init androidboot.console=null video=mxcdi0fb:RGB24,SEIKO-WVGA ldb=off di0_primary pmem=32M,64M fbmem=5M gpu_memory=64M calibration
.init : 0xc0008000 - 0xc0037000 ( 188 kB)

Grab glandium’s extract-symvers script

$ wget

Extract the symbols

$ python -B 0xc0008000 kernel.img > Module.symvers

Compile the Module

Copy the module symbols into kernel build

$ cp /path/to/Module.symvers build/

Create a workspace elsewhere for the cp210x module

$ mkdir cp210x

Copy the cp210x source from the kernel source to your workspace

$ cd /path/to/L2.6.35_11.05.01_ER_source/pkgs/linux-
$ cp cp210x.c /path/to/cp210x

Create a Makefile

$ cd /path/to/cp210x
$ echo "obj-m = cp210x.o"> Makefile

Compile the module

$ cd /path/to/L2.6.35_11.05.01_ER_source/pkgs/linux-
$ make M=/path/to/cp210x O=build modules KERNELRELEASE=""

Testing the module

On the radio, try to install the module to make sure it loads.

# insmod cp210x.ko
# dmesg
<6>USB Serial support registered for cp210x
<6>cp210x 2-1.1:1.0: cp210x converter detected
<6>usb 2-1.1: reset full speed USB device using fsl-ehci and address 3
<6>usb 2-1.1: cp210x converter now attached to ttyUSB0
<6>usbcore: registered new interface driver cp210x
<6>cp210x: v0.09:Silicon Labs CP210x RS232 serial adaptor driver

Try using the serial port as well.

Installing the Module

While it’s great to have a working module, it quickly becomes tiresome to manually install it each time the radio boots.  To make it more permanent, we need to properly install it.

Install to the modules directory

# mount -o rw,remount /dev/block/mmcblk0p2 /system
# cp /path/to/cp210x.ko /system/lib/modules

We also need to edit the /init.rc file to cause the module to load on boot.  Unfortunately, the root file system on which it resides is the kernel’s initial ramdisk, not a file system that we can remount as writeable on the system.  Fortunately, we have this image as part of Hal9k_’s update.

Extract the initrd

Back to the desktop.

$ mkimage -l uramdisk.img
Image Name:   Android Root Filesystem
Created:      Sat Apr  6 08:49:03 2013
Image Type:   ARM Linux RAMDisk Image (gzip compressed)
Data Size:    183417 Bytes = 179.12 kB = 0.17 MB
Load Address: 70308000
Entry Point:  70308000

$ dd if=uramdisk.img of=ramdisk.img.gz bs=1 skip=64
$ gunzip ramdisk.img.gz
$ mkdir ramdisk; cd ramdisk
$ cpio -iv < ../ramdisk.img

Edit init.rc

Edit the extracted init.rc in your favorite text editor, and add the line for our new module, directly below the line for pl2303:

insmod /system/lib/modules/cp210x.ko

Rebuild the initrd

$ find . | cpio --create --format='newc' > ../newramdisk.img
$ cd .. ; gzip newramdisk.img
$ mkimage -A arm -O linux -T ramdisk -C gzip -a 70308000 -e 70308000 -n Linux -d newramdisk.img.gz new-uramdisk.img
Image Name:   Linux
Created:      Mon May  6 22:17:47 2013
Image Type:   ARM Linux RAMDisk Image (gzip compressed)
Data Size:    183159 Bytes = 178.87 kB = 0.17 MB
Load Address: 70308000
Entry Point:  70308000

Install the new initrd

Copy new-uramdisk.img to the root directory of your external microSD card on the radio.  Rename the file to uramdisk.img.  Reboot the radio, holding the volume knob and menu buttons down during the boot.  You should see an indication that the update was successful, and the radio will reboot.  The cp210x module should now be loaded on boot!

That wasn’t such a chore, was it?

:, , , , , ,

Comments are closed.

May 2013
« Apr   Jan »


Content Copyright © 2004 - 2018 Brady Alleman.
All Rights Reserved.