Few years ago I compiled kernel drivers of cheap USB-to-serial converter for my previous Android phone. It took few years of using new phone, without single custom-compiled kernel module. Now it is time to change it. By the way, I am going to describe what changed and what hacks have to be made to make the process work on stock ROM, provided by Sony.
kernel is the key
First of all, we need kernel. To be precise, kernel sources. Without that, it is really hard to be successful (I don’t want to tell it is impossible, but really hard, believe me). Because Sony is very liberal in terms of cooperation with community, they provide anything required to tinker with the device (obviously together with caution message about warranty loss, but who cares, right? 🙂 ).
First of all, we need to know, which firmware version the device uses. To be found in Android settings, as compilation number, or something like that. For me, it is 23.5.A.0.575. Then, we have to visit Open Devices downloads section and find our firmware. For me, it was a lot of scrolling, as I have no updates available for quite some time. Inside the package, there should be kernel directory, with complete kernel sources.
Where is my .config?
Next thing we need to know is, which defconfig to use. Full list should be in
arch/arm/configs. Now, in case of Sony phones, there is slight problem, as they traditionally use codenames for devices. In case of Xperia Pro, I compiled for before, it was
iyokan. For Xperia Z3 Compact, I use now, it is
Aries and the only official source of those codenames, I know, is their Github profile. Of course it would be too easy to find some mapping and searching for
z3 gives no result. Fortunately, I know my device’s codename.
$ find . -name *aries* ./include/config/mach/sony/aries.h ./arch/arm/configs/shinano_aries_defconfig ./arch/arm/mach-msm/board-sony_aries-gpiomux.c ./arch/arm/mach-msm/board-sony_aries-gpiomux.o ./arch/arm/mach-msm/bms-batterydata-aries.o ./arch/arm/mach-msm/.board-sony_aries-gpiomux.o.cmd ./arch/arm/mach-msm/.bms-batterydata-aries.o.cmd ./arch/arm/mach-msm/bms-batterydata-aries.c ./arch/arm/boot/.msm8974pro-ac-shinano_aries.dtb.cmd ./arch/arm/boot/dts/msm8974pro-ac-shinano_aries_common.dtsi ./arch/arm/boot/dts/dsi-panel-aries.dtsi ./arch/arm/boot/dts/msm8974pro-ac-shinano_aries.dtsi ./arch/arm/boot/dts/msm8974pro-ac-shinano_aries.dts ./arch/arm/boot/msm8974pro-ac-shinano_aries.dtb
As we can see, there is only one config, related to aries:
shinano_aries_defconfig (Sony’s Github profile explains that Shinano is platform name). Then, we can safely use this in defconfig phase.
Compilation (and hacking)
Once we have all the sources and kernel configuration, we can start compilation. Or actually, we cannot (probably).
Let’s see vermagic of random module already installed on a device:
# modinfo zl10353.ko filename: zl10353.ko license: GPL author: Chris Pascoe description: Zarlink ZL10353 DVB-T demodulator driver parm: debug_regs:Turn on/off frontend register dumps (default:off). parmtype: debug_regs:int parm: debug:Turn on/off frontend debugging (default:off). parmtype: debug:int depends: intree: Y vermagic: 3.4.0-perf-g43ea728 SMP preempt mod_unload modversions ARMv7
We can see at least two things that will cause troubles:
In the first case, git commit id is appended to kernel version. Unfortunately, we do not have their repository and after module compilation, we will end up with just
3.4.0. To fix the problem, we have to edit makefile and set
EXTRAVERSION to the missing part, so it should look like:
VERSION = 3 PATCHLEVEL = 4 SUBLEVEL = 0 EXTRAVERSION = -perf-g43ea728 NAME = Saber-toothed Squirrel
The second detail, forces us to compile whole kernel. Otherwise, Android kernel will try to check if the module is compatible with current kernel (using CRC checksums) and will fail on missing
module_layout symbol CRC.
In case of very simple drivers, there is a way to omit kernel compilation. However, it is not a safest way to go and serves as permanent
--force for modprobe/insmod. I advice to skip this section, unless you are really desperate (and you are not, before trying the proper way).
Go back to some random driver, like the one, we used for vermagic check, pull it to PC and issue:
$ modprobe --dump-modversions zl10353.ko 0x2067c442 module_layout 0x15692c87 param_ops_int 0xe6b3b90a arm_delay_ops 0x59e5070d __do_div64 0x5f754e5a memset 0x0fc539b8 kmalloc_caches 0x9d669763 memcpy 0x52ac1d50 kmem_cache_alloc_trace 0x27e1a049 printk 0xfbc76af9 i2c_transfer 0x037a0cba kfree 0xefd6cf06 __aeabi_unwind_cpp_pr0
From my experience, I know that
module_layout is most troublesome. So why not add it to modversions of our module? Just run (change the CRC to match modprobe output!):
echo -e '0x2067c442\tmodule_layout\tvmlinux\tEXPORT_SYMBOL_GPL' >> Module.symvers
And you should cheat kernel to trust the symbol, even if in fact it would be different in kernel compiled by you. Then, after insmodding the module, built using the same shortcut as in my previous tutorial, you should possibly see a lot of errors on your dmesg. You can hunt for the symbols, from there and chances are it will work. Haven’t tested personally and I discourage, unless you really know what you are doing. It is wiser choice to wait those few minutes for kernel to compile.
Device specific hacking
During my compilation, I had to do some more hacks, as I had problems with missing headers. This will possibly be only relevant to the specific kernel version and device pair, but just in case, I am writing it down. You can safely skip to compilation and only go back in case of problems with framebuffer for MSM processors.
Following should fix the problem:
ln -s ../../drivers/video/msm/mdss/mdss_mdp_trace.h include/trace/mdss_mdp_trace.h ln -s ../../drivers/video/msm/mdss/mdss_mdp.h include/trace/mdss_mdp.h
Now, it should be fairly easy, though time consuming. Type following commands, one after another:
ARCH=arm CROSS_COMPILE=arm-unknown-eabi- make shinano_aries_defconfig ARCH=arm CROSS_COMPILE=arm-unknown-eabi- make ARCH=arm CROSS_COMPILE=arm-unknown-eabi- make modules M=drivers/usb/serial CONFIG_USB_SERIAL=m CONFIG_USB_SERIAL_CP210X=m
If there is no unexpected error during the compilation, you should now be able to insmod your fresh module into the kernel. In case of CP2102 driver, I compiled, there are in fact two drivers:
cp210x depends on
usbserial have to be inserted first. Afterwards, if you connect the device, you should see in dmesg, it succeeded, and in case of
cp210x, there should be a name of USB tty device (most likely
/dev/ttyUSB0, as there should be no USB ttys before).
Just to prove it, that it works, below are photos of of Xperia, running Termux and minicom to connect to Cubieboard2: