MalcolmStagg.com
Home    Recent Work    Science Fair    About Me    Contact Me    Software

project bdp

Overview

When I started out, I had no idea how to build Linux drivers. It turns out that now more and more drivers are being included in the kernel, either internally or as loadable kernel modules (LKM's). So for a lot of drivers, building the driver is just a matter of building the kernel.

I wanted to try to build some webcam drivers (in hopes of eventually getting Skype support on my player). I soon discovered that each LKM has a "version magic" string that must match with the kernel's for the module to load. This is to ensure stability - that the module is accessing what the kernel actually has available, etc. Also, the imported symbols in the LKM have to be exported by either the kernel or other LKM's.

In short, your build of the kernel has to pretty closely match that of the blu-ray player. This is not easy, since we don't know what all of their build options were.

First, you need to build a cross-compiler, since you are compiling a driver to run on an ARM processor.

Next, it will help to obtain the version magic string. You can get that by extracting any .ko module from your firmware and running "modinfo <kernelmodulename>" on Linux. On the S390 for me, this string was: "2.6.35 preempt mod_unload ARMv6"

Now we know it's kernel version 2.6.35. Preempt means it's realtime (or RT), which is quite common for embedded systems. There is sometimes a patch you can get for changing a traditional kernel to an RT kernel. I just found a download for the RT kernel with the patch already applied: https://kernel.googlesource.com/pub/scm/linux/kernel/git/clrkwllms/rt-linux.git/+/v2.6.35.

Now the fun part: building the kernel. Needless to say, it's best to run this on Linux. To enable cross-compiling, you can run the following commands:

export ARCH=arm
export CROSS_COMPILE=arm-unknown-linux-gnueabi-
	

Note that CROSS_COMPILE is defined as the first part of your cross-compiler binary name, before the gcc, g++, etc.

Next, it helps to find an embedded processor to base the configuration off of. Based on some digging, I figured s3c6400 would be a good candidate. This helps with some of the options. I went to the rtlinux directory and ran:

make s3c6400_defconfig
make menuconfig
	

Now in menuconfig, you have LOTS of possible options to enable/disable/modularize. My main changes were as follows:

  • Kernel features: select the preemptible kernel option
  • Kernel features: use the ARM EABI to compile
  • Kernel hacking: turn off kernel debugging
  • Device drivers: turn off I2C and SPI
  • Device drivers: turn on USB device filesystem
  • Device drivers: turn on video for linux, api 1 (deprecated), any video capture devices you want (modularize whenever possible)
  • Power management: turn on run-time pm

Next, run the following commands to build the modules:

make modules_prepare
make
	

This may take several minutes (or hours if you have a lot of modules enabled). You will find .ko files that correspond to the modules you are building

The above options are a result of a lot of trial and error. To make matters even more difficult, the firmware somehow disabled printk, so /proc/kmsg does not give a useful output for why an insmod failed.

One method that helped me debug this was to identify symbols which were undefined by the player, but defined as imports by my driver. To get the list of imported (undefined) symbols, you can run:

readelf -all <drivername> | grep UND
	

The UND keyword is next to all imported symbols. You can see which of these are exported (and which are not) by running on the player:

cat /proc/kallsyms | grep <the symbol you're searching for>
	

If the symbol is undefined, you need to disable something in the kernel options. It's not a perfect system though, because there may be something the kernel module needs to do which it is not doing. The power management option is an example of this. Analyzing undefined symbols of other kernel modules may also help you find which options need to be enabled.

For further debugging, because printk was disabled, I modified the logging/tracing macros in the driver I was compiling to use another function instead of printk. I exported this new function in my own kernel module, and got it to write the output to a file. I'll describe this in more detail later.

Eventually, I got the driver to build correctly so it's loadable. I could then copy it to a USB key, and run on the player:

insmod /mnt/sda1/v4l1-compat.ko
insmod /mnt/sda1/videodev.ko
insmod /mnt/sda1/gspca_main.ko
insmod /mnt/sda1/gspca_zc3xx.ko
	

This is the driver for my specific webcam. I could then run "cat /dev/video0" with the camera plugged in, and actually got some cool looking output! It was getting data from the camera. Now to make use of that somehow...

DISCLAIMER

Downgrading has been successfully tested. That's all I can confirm. Modifying firmware is risky, may violate EULA agreements, and can potentially brick your Blu-Ray player. Please try this at your own risk!

Copyright © 2013-2014 Malcolm Stagg