继pcDuino linux移植一、二、三,成功搭建linux最小系统,抽点时间开始linux内核驱动开发之旅。由于时间关系,基本上都是边玩边写,一些还没写完甚至有问题,就被转载了,以致大家看到的五花八门,希望转载的人也及时更新。遗留的很多问题随着时间都慢慢解决了,都是亲身体验能跑起来的,才敢写在这。我自己收获了很多,希望读到的人也能有收获,希望能一直坚持下去。
开发环境
系统:ubuntu 10.04.4
单板:pcDuino(全志A10)
编译器:arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2
搭建开发环境详见ubuntu 10.04.4开发环境配置。
目标
1.配置 编译linux-3.0.62内核,串口正常输出
2.配置内核,支持nfs挂载,启动文件系统
3.最简单内核驱动开发
这个是在pcDuino linux移植一、二、三的基础上写的,重点介绍内核驱动开发,其它具体移植过程不再详述。最基础的裸板开发、u-boot移植以及linux移植,参考前面的文章,这里不再重复。
一、搭建驱动开发平台
这里用官方提供的源码kernel for pcduino,我试了哈,这里面有些常用的驱动,比如网卡驱动之类,在官方提供的kernel平台再添加自己的驱动。
1.准备工作
获取交叉编译器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开发环境配。
获取linux源码 https://github.com/pcduino/kernel 点击linux-sunxi,跳转到https://github.com/linux-sunxi/linux-sunxi下载linux-sunxi源码
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 移植一、二、三
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移植一、二、三,我们已制作一张可启动的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,在手动加载到单板,然后写个简单应用程序,测试驱动。最后再编译进内核。我是想搭建这么个驱动开发平台。
二、最简单内核驱动开发
1.编写代码
写一个最简单的驱动程序,介绍驱动开发流程。先写字符一个简单的字符驱动代码:first_drv.c
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <asm/uaccess.h>
- #include <asm/irq.h>
- #include <asm/io.h>
- #include <mach/gpio.h>
- #include <mach/hardware.h>
- #include <linux/device.h>
- static struct class *firstdrv_class;
- static struct class_device *firstdrv_class_dev;
- static int first_drv_open(struct inode *inode, struct file *file)
- {
- printk(“first_drv_open\n”);
- return 0;
- }
- static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
- {
- printk(“first_drv_write\n”);
- return 0;
- }
- static struct file_operations first_drv_fops ={
- .owner = THIS_MODULE,
- .open = first_drv_open,
- .write = first_drv_write,
- };
- int major;
- static int first_drv_init(void)
- {
- major = register_chrdev(0, ”first_drv”, &first_drv_fops);
- firstdrv_class = class_create(THIS_MODULE, ”firstdrv”);
- firstdrv_class_dev = device_create(firstdrv_class,NULL,MKDEV(major, 0), NULL, ”xyz”);
- return 0;
- }
- static void first_drv_exit(void)
- {
- unregister_chrdev(major,”first_drv”);
- device_unregister(firstdrv_class_dev);
- class_destroy(firstdrv_class);
- }
- module_init(first_drv_init);
- module_exit(first_drv_exit);
- MODULE_LICENSE(“GPL”);
编写Makefile:
- KERN_DIR = /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0
- all:
- make -C $(KERN_DIR) M=`pwd` modules
- clean:
- make -C $(KERN_DIR) M=`pwd` modules clean
- rm -rf modules.order
- obj-m += first_drv.o
其中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:
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdio.h>
- int main(int argc, char **argv)
- {
- int fd;
- int val = 1;
- fd = open(“/dev/xyz”, O_RDWR);
- if(fd < 0)
- {
- printf(“can’t open!\n”);
- }
- write(fd, &val, 4);
- return 0;
- }
接着编译驱动测试代码
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.
一切正常,暂时还没发现其他问题,可以休息了。发现问题请提出,一起解决。
来源:oschina
链接:https://my.oschina.net/u/1174645/blog/142282