原文出處:劉建文 | 學術半·IT歌·文(http://arttech.us)
我是一位理論帝,想問題做事情更多的會從形而上的角度入手。這個結論的證據之一,是從我研究學習嵌入式Linux近一年後才決定購一臺掌上電腦做實驗。年初的時候就有朋友建議我購一塊開發板,通過做實驗快速掌握開發技術。但我並不以爲然,首先,我認爲基本功更重要,開發技術可短期內習得;什麼是基本功,對內核結構的深度把握,對硬件的透徹理解;其次,我想我花三五百購塊開發板做完後還有什麼用?前一個想法的結果是十月底我才購一臺機器做實驗,後一想法的結果是我購的是諾基亞的n800,而不一次性的祼機板。
到目前爲止我在n800上做了兩個簡單的實驗,本文記錄實驗全程,不求同和,但求錄之以照後來人。
第一個實驗交叉編譯一個hello模塊到n800上,驗證開發環境和開發硬件等的可用性;第二個實驗是定製一個新內核到n800上,新內核中觸摸屏和小鍵盤以模塊形式加載,而非默認的內置。
Nokia N800 設備元信息
- OMAP2420 microprocessor with a native speed of 400 MHz
- Memory : 128 MiB of RAM and 256 MiB of flash memory
- Connectivity : IEEE 802.11 b/g, Bluetooth 2.0 (DUN, OPP, FTP, HFP, HID profiles as well as A2DP/AVRCP and PAN via third party emulation), and USB 2.0 OTG high-speed.
- Display & resolution: pressure-sensitive resistive touch-screen LCD 4.1 inches 800×480 at 225 dpi
- Expansion : 2 full-sized Secure Digital card slots
- Camera : built-in pop-up rotating webcam.
- Audio : microphone, stereo speakers, FM radio tuner, 3.5-mm headphone jack (compatible with standard stereo headphones, but also containing a fourth pin with microphone input).
主要設備芯片(控制器)型號
- OMAP2420 N8x0 System-on-chip
- TMS320 C55x N8x0 DSP
- OMAP video N8x0 Video output
- PowerVR MBX N8x0 OpenGL ES and OpenVG acceleration
- OMAP Boot Tags N8x0 Provides boot information from bootloader (NOLO)
- OMAP MMC N8x0 SD/MMC cards
- tcm825x N8x0 Webcam + i2c bus
- tea5761 N800 FM radio
- blizzard N8x0 LCD controller
- menelaus N8x0 GPIO extender + i2c bus + ???
- tmp105 N8x0 Temperature sensor (menelaus GPIO)
- McSPI N8x0 SPI bus
- Sharp LS041Y3 N8x0 LCD panel (compatible with MIPID)
- cx3110x / stlc4550 N8x0 802.11b/g WiFi
- tsc2301 N800 Touchscreen + Keypad + GPIO + Audio
- OneNAND N8x0 Flash memory
- TUSB6010 N8x0 USB
開發過程
- 搭建開發環境
- 定義項目佈局
- 搭建交叉編譯開發環境
- 通過USB互聯n800和開發PC
- 實驗一——hello測試模塊
- 實驗二——定製模塊化內核
- 編譯內核及驅動模塊
- 修改initramfs
- 燒製
搭建開發環境
定義項目佈局
- 項目主目錄:~/n800
- kernel src:~/n800/maemo/kernel-source-diablo/kernel-source
- 交叉編譯工具鏈:~/n800/cross-tools
- 輔助構建工具:~/n800/build-tools
- 測試項目:~/n800/projects/hello_module | modulize_kernel
搭建交叉編譯開發環境
1. 下載maemo4.1源碼和補丁 :http://repository.maemo.org/pool/maemo4.1.2/free/k/kernel-source-diablo/
2. 解包並進補:
$ patch -p2 < kernel-source-diablo_2.6.21-200842maemo1.diff
3. 安裝pre-build交叉編譯工具鏈 :http://www.codesourcery.com/sgpp/lite/arm/releases/2005q3-2
這是一個商業免費版預編譯工具鏈,直接解壓到~/n800/cross-toolchain/下即可
4. 添加shell搜索路徑
$ export PATH=~/n800/cross-toolchain/bin:$PATH
5. 測試源碼樹與交叉編譯工具鏈的可用性
$cd ~/n800/maemo/kernel-source-diablo/kernel-source
$cp arch/arm/configs/nokia_2420_defconfig .confg
$make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- bzImage
此官方源碼竟然有一個符號聲明丟失:scripts/mod/sumversion.c PATH_MAX undeclared
修復辦法:modifying linux-2.6.x/scripts/mod/sumversion.c, and adding #include <limits.h> fixes this issue.
成功編譯內核後證明交叉編譯工具鏈和源碼樹可用。編譯源碼樹一遍爲編譯外部模塊作準備(也可以通過執行kbuild接口 make modules_prepare) ,因爲編譯外部模塊會對內核的一些信息有依賴,像內核輸出符號(Module.symvers)。詳見內核文檔Document/kbuild/modules.txt
--- 2.4 Preparing the kernel tree for module build
To make sure the kernel contains the information required to build external modules the target 'modules_prepare' must be used. 'modules_prepare' exists solely as a simple way to prepare a kernel source tree for building external modules. Note: modules_prepare will not build Module.symvers even if CONFIG_MODVERSIONS is set. Therefore a full kernel build needs to be executed to make module versioning work.
通過USB互聯n800和開發PC(我用的是fedora 13)
fedora 一端
1.enable USB networking support in the kernel.
# # USB Network Adapters #
CONFIG_USB_USBNET=m
CONFIG_USB_NET_CDCETHER=m
2.安裝usbnet模塊
Linux-PC: $ modprobe usbnet
3.配置usb網絡接口
通過ifup的配置文件(/etc/sysconfig/network-scripts/ifcfg-usb0)實現:
DEVICE=usb0
BOOTPROTO=static
IPADDR=192.168.2.14
# IPADDR=10.0.1.2/24 should imply this ...
# but its support code seems to be buggy.
BROADCAST=192.168.2.255
NETMASK=255.255.255.0
NETWORK=192.168.2.0
# this is likely to break sometime
GATEWAY=192.168.2.1
ONBOOT=yes
4.啓用網絡接口
Linux-PC: $ ifup usb0
n800一端
1.取得root權限並安裝ether_over_usb模塊(g_ether.ko):
取得root權限的方法有兩種,第一,開啓機器的R&D模式,使用gainroot;第二種這是安裝rootsh包,直接用root命令最得權限:
Nokia-N800: $ id uid=29999(user) gid=29999 (users)
#if use r&d mode
Nokia-N800: $ sudo /usr/sbin/gainroot
#or use rootsh
Nokia-N800: $ root
Nokia-N800: # insmod /mnt/initfs/lib/modules/2.6.18-omap1/g_ether.ko
2.啓用網絡接口
Nokia-N800: # ifup usb0
3.測試連通性
Nokia-N800: # ping 192.168.2.14
如果不通,再插拔一下USB線
使用ssh登陸
Linux-PC $ssh -l root 192.168.2.15
pw:111111 (此密碼在安裝OpenSSH時設置)
傳送文件 Linux-PC $ scp ~/n800/projects/modulize_kernel/tsc2301_kp.ko [email protected]:
實驗一——hello測試模塊
1. 編寫源文件hello_mod.c
01
/* hello_mod.c */
02
#include <linux/init.h>
03
#include <linux/module.h>
04
#include <linux/kernel.h>
05
06
static int
hello_init
(
void
)
07
{
08
printk
(
KERN_ALERT "Hello, world
/n
"
);
09
return
0
;
10
}
11
12
static void
hello_exit
(
void
)
13
{
14
printk
(
KERN_ALERT "Goodbye, cruel world
/n
"
);
15
}
16
17
module_init
(
hello_init);
18
module_exit
(
hello_exit);
19
MODULE_LICENSE
(
"GPL"
);
2. 編寫kbuild Makefile
01
# Makefile for the hello module
02
obj-m :=
hello_mod.o
03
KDIR :=
~/
n800/
maemo/
kernel-source-diablo/
kernel-source
04
PWD := $(
shell
pwd)
05
default:
06
$(
MAKE) -
C $(
KDIR)
M=$(
PWD)
modules
3. 編譯
$ cd ~/n800/projects/hello_module
$ export PATH=~/n800/cross-toolchain/bin:$PATH
$ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
4.測試把編譯得到的hello_mod.ko 通過ssh下載到n800進行測試,過程略。
實驗二——定製模塊化內核
編譯內核及驅動模塊
1. 配置內核
配置任務是把小鍵盤和觸摸屏的驅動改爲模塊,官方內核是build-in 的。
$ cd ~/n800/maemo/kernel-source-diablo/kernel-source
$ cp arch/arm/configs/nokia_2420_defconfig .config
# 配置文件庫(arch/arm/configs)還有一個n800_defconfig,此配置不適合OS2008
$ make menuconfig
2. 配置項如下,可以在配置程序內查找其所在位置,配置過程略
CONFIG_KEYBOARD_TSC2301=m
CONFIG_TOUCHSCREEN_TSC2301=m
3. 檢查配置結果:
$ cat .config | grep TSC2301
CONFIG_KEYBOARD_TSC2301=m
CONFIG_TOUCHSCREEN_TSC2301=m
CONFIG_SPI_TSC2301=y
CONFIG_SPI_TSC2301_AUDIO=y
4. 編譯內核
$ export PATH=~/n800/cross-toolchain/bin:$PATH
$ export ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
$ make zImage
$ cp arch/arm/boot/zImage ~/n800/projects/modulize_kernel
5. 編譯模塊
$ INSTALL_MOD_PATH=~/n800/projects/modulize_kernel
$ make modules
$ make modules_install
修改initramfs
initramfs是kernel 的[前根文件系統]引導功能(他們用了一個新概念叫early-userspace)的2.6版新實現,前2.6版的是衆所周知的initrd。 initramfs不再是核外的一個虛擬盤,而是核內的內存根文件系統一個鏡像,filesystem是使用緩存機制實現的tempfs。簡單的理解是,initramfs是正在內存中運行的內核的根文件系統被轉存(object dump)到磁盤上的映像。爲了實現更好靈活性,新版內核的[前根文件系統]還是提供了[核內核外]配置的方式。核外配置的表象與initrd很像,但是完全不同的概念,內核使用完全不同的代碼解讀前根文件系統,initramfs只是一個cpio檔,被bootloader調入內存後,內核會自動識別,進行鏈接。
1. 下載固件( http://tablets-dev.nokia.com/nokia_N800.php )並解包至 ~/n800/firmware
2. 下載並安裝官方的擦寫程序flash3.5(這裏也可以使用一個開源的擦寫程序0xFFFF)直接解壓到~/n800/build-tools/flasher/即可
- flash3.5:http://tablets-dev.nokia.com/maemo-dev-env-downloads.php
- 0xFFFF:http://www.nopcode.org/0xFFFF/?p=home
3. 解包固件至./firmware/43-7-fiasco
$ cd ~/n800/firmware
$ mkdir 43-7-fiasco;cd 43-7-fiasco
$ ~n800/build-tools/flasher-3.5 -F ~/n800/firmware/RX-34_DIABLO_5.2008.43-7_PR_COMBINED_MR0_ARM.bin -u
4. initramfs.jffs2 是jffs2鏡像,先作成虛擬盤
$ mknod /tmp/mtdblock0 b 31 0
$ mkdir /mnt/initfs
$ modprobe loop
$ losetup /dev/loop0 ~/n800/firmware/43-7-fiasco/initfs-0.95.22-200842maemo1w38b3
$ modprobe mtdblock
$ modprobe block2mtd
# Note the ,128KiB is needed (on 2.6.26 at least) to set the eraseblock size.
$ echo "/dev/loop0,128KiB" > /sys/module/block2mtd/parameters/block2mtd
$ modprobe jffs2
$ mount -t jffs2 /tmp/mtdblock0 /mnt/initfs/
5. 虛擬盤不能直接修改,必須拷出來,修改後再用MTD tool(mkfs.jffs2)重製作initramfs 鏡像
$ mkdir /mnt/tmp/initramfs
$ cp -a /mnt/initfs/ /mnt/tmp/initramfs
6. 拷貝驅動模塊並修改啓動腳本linuxrc
$ cp ~/n800/projects/modulize_kernel/tsc2301_kp.ko /mnt/tmp/initramfs/lib/modules/omapXXX/
$ cp ~/n800/projects/modulize_kernel/tsc2301_ts.ko /mnt/tmp/initramfs/lib/modules/omapXXX/
$ echo "insmod $MODULE_PATH/tsc2301_kp.ko" >> /mnt/tmp/initramfs/linuxrc
$ echo "insmod $MODULE_PATH/tsc2301_kp.ko" >> /mnt/tmp/initramfs/linuxrc
7. 重製作initramfs 鏡像(http://sources.redhat.com/jffs2/ )
$ mkfs.jffs2 -n -r /mnt/tmp/initramfs -e 20000 -o rootfs.jffs2
P.S. 事後發現原來可以直接在n800的maemo上修改,要修改,得行把initramfs閃存分區重掛接爲可讀寫:
Nokia-N800: # mount -o remount,rw /dev/mtdblock3 /mnt/initramfs
燒製
$ cd ~/n800/build-tools/
$ flash3.5 -k ~/n800/projects/modulize_kernel/zImage -f
#提示接入n800,把n800接好USB線,按住HOME鍵再開機
$ flash3.5 -n ~/n800/projects/modulize_kernel/initramfs.jffs2 -f -R
重啓後測試,測試過程略。