繼pcDuino linux移植1、2、三,成功搭建linux最小系統,抽點時間開始linux內核驅動開發之旅。因爲時間關係,基本上都是邊玩邊寫,一些還沒寫完甚至有問題,就被轉載了,以至你們看到的五花八門,但願轉載的人也及時更新。遺留的不少問題隨着時間都慢慢解決了,都是親身體驗能跑起來的,纔敢寫在這。我本身收穫了不少,但願讀到的人也能有收穫,但願能一直堅持下去。 node
開發環境
系統:ubuntu 10.04.4
單板:pcDuino(全志A10)
編譯器:arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2 linux
搭建開發環境詳見ubuntu 10.04.4開發環境配置。 git
目標
1.配置 編譯linux-3.0.62內核,串口正常輸出
2.配置內核,支持nfs掛載,啓動文件系統
3.最簡單內核驅動開發 github
這個是在pcDuino linux移植1、2、三的基礎上寫的,重點介紹內核驅動開發,其它具體移植過程再也不詳述。最基礎的裸板開發、u-boot移植以及linux移植,參考前面的文章,這裏再也不重複。 ubuntu
1、搭建驅動開發平臺 app
這裏用官方提供的源碼kernel for pcduino,我試了哈,這裏面有些經常使用的驅動,好比網卡驅動之類,在官方提供的kernel平臺再添加本身的驅動。 測試
1.準備工做 ui
獲取交叉編譯器http://code.google.com/p/smp-on-qemu/downloads/list選擇arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2並下載。而後在ubuntu下直接解壓便可,配置過程還不清楚的看Ubuntu 10.04.4開發環境配。 this
獲取linux源碼 https://github.com/pcduino/kernel 點擊linux-sunxi,跳轉到https://github.com/linux-sunxi/linux-sunxi下載linux-sunxi源碼 google
2.配置、編譯內核
打開linux-sunxi-sunxi-3.0目錄下的Makefile,修改195:
ARCH ?= ARM
CROSS_COMPILE ?= your-path/arm-2009q3/bin/arm-none-linux-gnueabi-
其中your-path是gcc-linaro-arm-linux-gnueabihf-4.8-2013.04-20130417_linux.tar.bz2的解壓路徑
change@change :~$ cd /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0$ make menuconfig
記住選中wemac support(A1x),其它不變。開始也不知道選這個,後來分析官方提供的kernel才知道的。
編譯過程超長,若是編譯過程當中遇到些問題,見pcduino linux 移植1、2、三
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0$ ls arch/arm/boot
bootp compressed Image install.sh Makefile uImage zImage
3.測試
通過pcDuino linux移植1、2、三,咱們已製做一張可啓動的tf卡,如今用咱們新的內核uImage,替換掉之前的進行測試。將上次製做的啓動卡插到PC機,彈出窗口,直接拷貝上面編譯生成的uimage到sdb1,替換掉之前的,取下tf卡插到pcduino啓動以下:
U-Boot SPL 2012.10 (Apr 19 2013 – 18:46:44)
DRAM: 1024MB
SUNXI SD/MMC: 0
U-Boot 2012.10 (Apr 19 2013 – 18:46:44) Allwinner Technology
CPU: SUNXI Family
Board: pcDuino
I2C: ready
DRAM: 1 GiB
MMC: SUNXI SD/MMC: 0
*** Warning – bad CRC, using default environment
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0
reading uEnv.txt
144 bytes read
Loaded environment from uEnv.txt
reading boot.scr
270 bytes read
Jumping to boot.scr
## Executing script at 44000000
reading script.bin
」 from mmc 0:1 ** 「script.bin
reading uImage
」 from mmc 0:1 ** 「uImage
bootm – boot application image from memory
Usage:
bootm [addr [arg ...]]
- boot application image stored in memory
passing arguments ‘arg …’; when booting a Linux kernel,
‘arg’ can be the address of an initrd image
Sub-commands to do part of the bootm sequence. The sub-commands must be
issued in the order below (it’s ok to not issue all sub-commands):
start [addr [arg ...]]
loados – load OS image
cmdline – OS specific command line processing/setup
bdt – OS specific bd_t processing
prep – OS specific prep before relocation or go
go – start OS
reading script.bin
44900 bytes read
reading uImage
4693140 bytes read
## Booting kernel from Legacy Image at 48000000 …
Image Name: Linux-3.0.62
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 4693076 Bytes = 4.5 MiB
Load Address: 40008000
Entry Point: 40008000
Verifying Checksum … OK
Loading Kernel Image … OK
OK
Starting kernel …
<6>Initializing cgroup subsys cpuset
<5>Linux version 3.0.62 (change@change ) (gcc version 4.4.1 (Sourcery G++ Lite 2009q3-67) ) #2 PREEMPT Tue May 21 22:35:22 CST 2013
CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c5387d
CPU: VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine: sun4i
<6>Memory cut off:
<6> MALI : 0x5c000000 – 0x5fffffff ( 64 MB)
<4>Ignoring unrecognised tag 0×00000000
<6>Memory Reserved:
<6> SYS : 0×43000000 – 0x4300ffff ( 64 kB)
<6> VE : 0×44000000 – 0x48ffffff ( 80 MB)
<6> G2D : 0×49000000 – 0x49ffffff ( 16 MB)
<6> LCD : 0x5a000000 – 0x5bffffff ( 32 MB)
Memory policy: ECC disabled, Data cache writeback
<6>chip-id: A10 (AW1623 revision C)
<7>On node 0 totalpages: 245760
<7>free_area_init_node: node 0, pgdat c0887ea0, node_mem_map c094e000
<7> Normal zone: 1280 pages used for memmap
<7> Normal zone: 0 pages reserved
<7> Normal zone: 146176 pages, LIFO batch:31
<7> HighMem zone: 768 pages used for memmap
<7> HighMem zone: 97536 pages, LIFO batch:31
<7>pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
<7>pcpu-alloc: [0] 0
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 243712
<5>Kernel command line: console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait loglevel=8 panic=10
<6>PID hash table entries: 4096 (order: 2, 16384 bytes)
<6>Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
<6>Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
<6>Memory: 448MB 512MB = 960MB total
<5>Memory: 833852k/833852k available, 149188k reserved, 393216K highmem
……….//省略若干,太長了
<6>mmc0: new high speed SD card at address 0260
[ 4.070000] mmc0: new high speed SD card at address 0260
<6>mmcblk0: mmc0:0260 SD 948 MiB
[ 4.090000] mmcblk0: mmc0:0260 SD 948 MiB
<6> mmcblk0: p1 p2
[ 4.100000] mmcblk0: p1 p2
<6>Console: switching to colour frame buffer device 160×45
[ 4.230000] Console: switching to colour frame buffer device 160×45
<4>regulator_init_complete: axp20_buck3: incomplete constraints, leaving on
[ 4.270000] regulator_init_complete: axp20_buck3: incomplete constraints, leaving on
<4>regulator_init_complete: axp20_buck2: incomplete constraints, leaving on
[ 4.290000] regulator_init_complete: axp20_buck2: incomplete constraints, leaving on
<4>regulator_init_complete: axp20_ldo4: incomplete constraints, leaving on
[ 4.300000] regulator_init_complete: axp20_ldo4: incomplete constraints, leaving on
<4>regulator_init_complete: axp20_ldo3: incomplete constraints, leaving on
[ 4.320000] regulator_init_complete: axp20_ldo3: incomplete constraints, leaving on
<4>regulator_init_complete: axp20_ldo2: incomplete constraints, leaving on
[ 4.330000] regulator_init_complete: axp20_ldo2: incomplete constraints, leaving on
<4>regulator_init_complete: axp20_ldo1: incomplete constraints, leaving on
[ 4.350000] regulator_init_complete: axp20_ldo1: incomplete constraints, leaving on
<6>sunxi-rtc sunxi-rtc: sunxi_rtc_gettime
[ 4.360000] sunxi-rtc sunxi-rtc: sunxi_rtc_gettime
<6>sunxi-rtc sunxi-rtc: read time 2010-1-1 0:0:9
[ 4.370000] sunxi-rtc sunxi-rtc: read time 2010-1-1 0:0:9
<6>sunxi-rtc sunxi-rtc: setting system clock to 2010-01-01 00:00:09 UTC (1262304009)
[ 4.380000] sunxi-rtc sunxi-rtc: setting system clock to 2010-01-01 00:00:09 UTC (1262304009)
<3>EXT3-fs (mmcblk0p2): error: couldn’t mount because of unsupported optional features (240)
[ 4.400000] EXT3-fs (mmcblk0p2): error: couldn’t mount because of unsupported optional features (240)
<3>EXT2-fs (mmcblk0p2): error: couldn’t mount because of unsupported optional features (244)
[ 4.420000] EXT2-fs (mmcblk0p2): error: couldn’t mount because of unsupported optional features (244)
<6>EXT4-fs (mmcblk0p2): recovery complete
[ 4.740000] EXT4-fs (mmcblk0p2): recovery complete
<6>EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[ 4.750000] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
<6>VFS: Mounted root (ext4 filesystem) on device 179:2.
[ 4.770000] VFS: Mounted root (ext4 filesystem) on device 179:2.
<6>devtmpfs: mounted
[ 4.780000] devtmpfs: mounted
<6>Freeing init memory: 164K
[ 4.790000] Freeing init memory: 164K
mount: mounting devpts on /dev/pts failed: No such file or directory
mount: mounting /dev/mmcblk0p1 on /boot failed: No such file or directory
Please press Enter to activate this console.
Processing /etc/profile… Done
/ # ls
bin etc lib mnt run sys usr
dev home linuxrc proc sbin tmp var
/ # ifconfig eth0 172.16.1.111
<4>wemac wemac.0: WARNING: no IRQ resource flags set.
[ 126.910000] wemac wemac.0: WARNING: no IRQ resource flags set.
<6>wemac wemac.0: eth0: link up, 100Mbps, full-duplex, lpa 0x45E1
[ 127.060000] wemac wemac.0: eth0: link up, 100Mbps, full-duplex, lpa 0x45E1
/ # <7>eth0: no IPv6 routers present
[ 137.860000] eth0: no IPv6 routers present
/ # ifconfig eth0
eth0 Link encap:Ethernet HWaddr 8A:CA:EF:97:41:11
inet addr:172.16.1.111 Bcast:172.16.255.255 Mask:255.255.0.0
inet6 addr: fe80::88ca:efff:fe97:4111/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:20 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:6831 (6.6 KiB) TX bytes:468 (468.0 B)
Interrupt:55 Base address:0×8000
/ # ping 172.16.1.134
PING 172.16.1.134 (172.16.1.134): 56 data bytes
64 bytes from 172.16.1.134: seq=0 ttl=64 time=11.119 ms
64 bytes from 172.16.1.134: seq=1 ttl=64 time=1.628 ms
64 bytes from 172.16.1.134: seq=2 ttl=64 time=0.866 ms
^C
— 172.16.1.134 ping statistics —
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.866/4.537/11.119 ms
/ #
看到系統基本正常啓動了,網卡工做也正常能ping通。先寫到這裏,下一步作簡單驅動開發,待續。。。而且已支持掛載,之後把本身編譯好的驅動掛載到單板pcduino,在手動加載到單板,而後寫個簡單應用程序,測試驅動。最後再編譯進內核。我是想搭建這麼個驅動開發平臺。
2、最簡單內核驅動開發
1.編寫代碼
寫一個最簡單的驅動程序,介紹驅動開發流程。先寫字符一個簡單的字符驅動代碼:first_drv.c
編寫Makefile:
其中KERN_DIR是你的內核源碼存放路徑,要根據本身狀況修改。
2.編譯驅動源碼
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv$ make
make -C /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0 M=`pwd` modules
make[1]: Entering directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0′
CC [M] /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/first_drv.o
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/first_drv.c: In function ‘first_drv_init’:
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/first_drv.c:38: warning: assignment from incompatible pointer type
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/first_drv.c: In function ‘first_drv_exit’:
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/first_drv.c:45: warning: passing argument 1 of ‘device_unregister’ from incompatible pointer type
include/linux/device.h:692: note: expected ‘struct device *’ but argument is of type ‘struct class_device *’
Building modules, stage 2.
MODPOST 1 modules
CC /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/first_drv.mod.o
LD [M] /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/first_drv.ko
make[1]: Leaving directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0′
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv$ ls
firstdrivetest.c first_drv.ko first_drv.mod.o Makefile Module.symvers
first_drv.c first_drv.mod.c first_drv.o modules.order
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv$
能夠看到生成了驅動加載模塊first_drv.ko,下面還要寫個簡單的驅動測試代碼firstdrivetest.c:
接着編譯驅動測試代碼
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv$ /home/change/tools/arm-2009q3/bin/arm-none-linux-gnueabi-gcc -o firstdrivetest firstdrivetest.c
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv$ ls
firstdrivetest first_drv.c first_drv.mod.c first_drv.o modules.order
firstdrivetest.c first_drv.ko first_drv.mod.o Makefile Module.symvers
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv$
先拷到個人主機nfs掛載目錄,不知道怎麼配置看ubuntu 10.04.4開發環境配置
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv$ cp first_drv.ko firstdrivetest /home/change/work/rootfs_dir/fs_mini/home/linux-3.0.62/pcduino/
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv$
記住編譯驅動、根文件系統、內核的交叉編譯器最好用同一套編譯器,否則會出現問題,我又遇到過。看到測試驅動的firstdrivetest也生成了。下面將其掛載到到你的單板pcduino進行測試。如今切換到單板pcduino啓動的控制檯進行掛載
/ # mount -t nfs -o nolock 172.16.1.134:/home/change/work/rootfs_dir/fs_mini /mn
t/
/ # ls /mnt/
bin etc lib mnt root sys usr
dev home linuxrc proc sbin tmp
/ # cd /mnt/home/linux-3.0.62/pcduino/
/mnt/home/linux-3.0.62/pcduino # ls
first_drv.ko firstdrivetest
/mnt/home/linux-3.0.62/pcduino #
看到掛載成功了,剛剛咱們編譯生成的first_drv.ko firstdrivetest也掛載到單板了。測試先加載驅動
/mnt/home/linux-3.0.62/pcduino # ls /dev/xyz
ls: /dev/xyz: No such file or directory
/mnt/home/linux-3.0.62/pcduino # insmod first_drv.ko
/mnt/home/linux-3.0.62/pcduino # ls /dev/xyz -l
crw——- 1 0 0 245, 0 Jan 1 00:52 /dev/xyz
/mnt/home/linux-3.0.62/pcduino #
能夠看到加載前是不存在這個xyz設備的,成功加載後出現了。再運行測試程序,測試程序很簡單就是驅動加載成功則輸出first_drv_open、first_drv_write
/mnt/home/linux-3.0.62/pcduino # ./firstdrivetest
first_drv_open
[ 3297.090000] first_drv_open
first_drv_write
[ 3297.090000] first_drv_write
/mnt/home/linux-3.0.62/pcduino #
運行firstdrivetest ,與預期效果一致,基本正常。可是後來發現還有問題,以下不能卸載驅動
/mnt/home/linux-3.0.62/pcduino # lsmod
first_drv 1473 0 – Live 0xbf000000
/mnt/home/linux-3.0.62/pcduino # rmmod first_drv
rmmod: can’t change directory to ‘/lib/modules’: No such file or directory
/mnt/home/linux-3.0.62/pcduino # rmmod first_drv.ko
rmmod: can’t change directory to ‘/lib/modules’: No such file or directory
/mnt/home/linux-3.0.62/pcduino #
遇到問題,跟着提示作,沒有’/lib/modules’那新建一個
/mnt/home/linux-3.0.62/pcduino # mkdir /lib/modules
/mnt/home/linux-3.0.62/pcduino # rmmod first_drv
rmmod: can’t change directory to ’3.0.62′: No such file or directory
又出現沒有’3.0.62′,再建立一個
/mnt/home/linux-3.0.62/pcduino # mkdir /lib/modules/3.0.62
/mnt/home/linux-3.0.62/pcduino # rmmod first_drv
/mnt/home/linux-3.0.62/pcduino # lsmod
/mnt/home/linux-3.0.62/pcduino #
OK這下解決了,我之前又遇到過,發現這麼解決最簡單,再完整測試一遍
/mnt/home/linux-3.0.62/pcduino # ./firstdrivetest
first_drv_open
[ 3841.960000] first_drv_open
first_drv_write
[ 3841.970000] first_drv_write
/mnt/home/linux-3.0.62/pcduino # rmmod first_drv
/mnt/home/linux-3.0.62/pcduino # lsmod
/mnt/home/linux-3.0.62/pcduino #
問題基本解決了,咱們的驅動開發平臺就搭建好了,之後抓緊寫其它驅動代碼。還試了一下rmmod first_drv.ko 卸載不了,仍是要用rmmod first_drv
/mnt/home/linux-3.0.62/pcduino # insmod first_drv.ko
/mnt/home/linux-3.0.62/pcduino # lsmod
first_drv 1473 0 – Live 0xbf008000
/mnt/home/linux-3.0.62/pcduino # rmmod first_drv.ko
/mnt/home/linux-3.0.62/pcduino # lsmod
first_drv 1473 0 – Live 0xbf008000
/mnt/home/linux-3.0.62/pcduino # rmmod first_drv
/mnt/home/linux-3.0.62/pcduino # lsmod
/mnt/home/linux-3.0.62/pcduino #
測試完使用halt停機
/mnt/home/linux-3.0.62/pcduino # halt
The system is going down NOW!
Sent SIGTERM to all processes
Terminated
Sent SIGKILL to all processeso #
Requesting system halt<6>[sw-ohci2]: shutdown start
[ 4290.610000] [sw-ohci2]: shutdown start
[sw-ohci2]: close clock
[ 4290.620000] [sw-ohci2]: close clock
<6>[sw-ohci2]: shutdown end
[ 4290.620000] [sw-ohci2]: shutdown end
<6>[sw-ehci2]: shutdown start
[ 4290.630000] [sw-ehci2]: shutdown start
[sw-ehci2]: Set USB Power OFF
[ 4290.640000] [sw-ehci2]: Set USB Power OFF
[sw-ehci2]: close clock
[ 4290.640000] [sw-ehci2]: close clock
<6>[sw-ehci2]: shutdown end
[ 4290.650000] [sw-ehci2]: shutdown end
<6>[sw-ohci1]: shutdown start
[ 4290.660000] [sw-ohci1]: shutdown start
[sw-ohci1]: close clock
[ 4290.660000] [sw-ohci1]: close clock
<6>[sw-ohci1]: shutdown end
[ 4290.670000] [sw-ohci1]: shutdown end
<6>[sw-ehci1]: shutdown start
[ 4290.680000] [sw-ehci1]: shutdown start
[sw-ehci1]: Set USB Power OFF
[ 4290.690000] [sw-ehci1]: Set USB Power OFF
[sw-ehci1]: close clock
[ 4290.690000] [sw-ehci1]: close clock
<6>[sw-ehci1]: shutdown end
[ 4290.700000] [sw-ehci1]: shutdown end
[NAND]shutdown
[ 4290.710000] [NAND]shutdown
nand try to shutdown 0 time
[ 4290.710000] nand try to shutdown 0 time
Nand flash shutdown ok!
[ 4290.720000] Nand flash shutdown ok!
<0>System halted.
[ 4290.720000] System halted.
一切正常,暫時還沒發現其餘問題,能夠休息了。發現問題請提出,一塊兒解決。