之前我们一直是在虚拟机ubuntu环境中测试我们的first_drv驱动模块,但是这不是我们的开发方向,在刚开始的学习中我们避免搭建过多的环境,因此选择了只在ubuntu中测试驱动。
我们的模式是:
[first_drv.c]-->[使用ubuntu内核源码编译]-->[first_drv.ko(可运行于虚拟机)]-->
[ 安装到虚拟机中 ]-->[ hello world! ]-->[ 从虚拟机中卸载 ]-->[ goodbye world... ]
但是我们的最终目标是在arm微处理器平台上运行驱动程序。
因此我们需要改成如下模式:
[first_drv.c]-->[使用arm-kernel内核源码编译]-->[first_drv.ko(可运行于arm-kernel)]
-->[ 安装到arm-kernel中 ]-->[ hello world! ]-->[ 从arm-kernel中卸载 ]-->[ goodbye world... ]
这里需要解释下什么是arm-kernel(这是我临时起的名字),我们拟定使用的arm微处理器是S3C2440,在S3C2440外接的内存中有一块区域是linux内核运行的区域,而在这片内存区域中运行的代码叫做uImage,这个uImage是我们在虚拟机ubuntu环境中编译出来的,依据什么编译的呢?依据内核源码,哪个内核源码呢?就是之前说过的/work/kernel/linux-2.6.22.6目录下的内核源码。
我们要使用这个内核源码来编译first_drv.c的话,那就必须修改Makefile了。
打开/work/my_drivers/frist_drv/1th目录下我们写的的Makefile:
KERN_VER = $(shell uname -r) KERN_DIR = /lib/modules/$(KERN_VER)/build #KERN_DIR = /work/kernel/linux-2.6.22.6 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
我们之前注释了/work/kernel/linux-2.6.22.6路径,现在我们取消对它的注释,并且改为注释前两行,改动如下所示:
#KERN_VER = $(shell uname -r) #KERN_DIR = /lib/modules/$(KERN_VER)/build KERN_DIR = /work/kernel/linux-2.6.22.6
所保存Makefile,执行make,生成最新的first_drv.ko,而这个first_drv.ko是可以被安装到S3C2440的linux内核中的,为什么S3C2440的linux内核认可我们的first_drv.ko呢?因为S3C2440的linux内核本身就是uImage,而这个uImage本身也是依靠/work/kernel/linux-2.6.22.6目录下的内核源码编译出来的,uImage和first_drv.ko出自同门,S3C2440的linux内核当然认可first_drv驱动模块啦。
关于这一点,相信我已经讲得足够清楚了。
好的,我们把这uImage事先烧写到了arm开发板上,驱动模块也已经生成了,现在正躺在ubuntu的磁盘目录/work/my_drivers/frist_drv/1th/上,那这个驱动模块first_drv要怎样才能安装到arm开发板的linux内核中去呢?
我们总不能给arm开发板外接个键盘,然后输入insmod first_drv.ko吧?
其实,我们在开发驱动更多的时候是这样做的:
在虚拟机上制作一个最小根文件系统(路径暂定为:/work/mini_fs),并且制作它的映像文件(fs_mini.yaffs2),烧写到开发板中,我们把开发板串口线接到电脑,给开发板上电,启动内核,可以通过SecureCRT串口终端来观察内核的输出信息,最后啮合挂接了最小根文件系统时,在SecureCRT串口终端上输入ls、cd等命令测试最小根文件系统,基本与我们在虚拟机ubuntu环境中的操作一样。
那么要怎么做,才能让开发板的linux内核访问到另一个系统(虚拟机ubuntu)磁盘目录中的first_drv.ko呢?
一个比较好的办法就是通过网络来进行访问。
现在我们的开发板中已经具备一个最小根文件系统,这与ubuntu的文件系统类似,相当于它的阉割版,我们在/work目录下建好ko_file这个文件夹,然后将/work/my_drivers/frist_drv/1th/目录下的first_drv.ko复制到/work/ko_file/目录下。
然后,我们就可以通过NFS方式把ubuntu中的/work/ko_file/目录下的first_drv.ko挂接到开发板的最小根文件系统的/mnt目录下,当然,不是随便来个目录就可以直接被NFS挂接的,如何才能使/work/ko_file/目录被挂接呢?
我们在当前/work/my_drivers/frist_drv/1th/目录下执行:sudo vi /etc/exports,改动如下:
# /etc/exports: the access control list for filesystems which may be exported # to NFS clients. See exports(5). # # Example for NFSv2 and NFSv3: # /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check) # # Example for NFSv4: # /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check) # /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check) # /work/ko_file *(rw,sync,no_root_squash)
其中,第11行就是我们所加上的内容,这个配置文件将把/work/ko_file目录下的内容配置为可以进行NFS挂接。
接下来,重启NFS服务,执行:sudo /etc/init.d/nfs-kernel-server restart
这样我们就可以通过开发板上的最小根文件系统挂接/work/ko_file目录下的内容了,在内核启动成功后,会挂接yffs2最小根文件系统,SecureCRT串口终端上末行显示:
Please press Enter to activate this console.
输入回车,即进入linux的命令行界面。
顺带一提,当前网络环境是这样的:
windows电脑通过无线网卡接收路由器的无线信号(我这里的IP是:192.168.2.224);
windows中的ubuntu虚拟机通过桥接方式联网(我这里的IP是:192.168.2.110);
拿一根网线,一端接到路由器的LAN口,一端接到开发板上(我这里的IP是:192.168.2.100)。
执行ifconfig eth0 192.168.2.100(这是开发板的IP地址)
接着执行ping 192.168.2.110(这是ubuntu虚拟机的IP地址)
最后执行mount -t nfs -o nolock 192.168.2.110:/drv/ko_file /mnt
回车后,如果没有异样,说明挂载成功。
在SecureCRT串口终端上执行:ls /mnt
打印了first_drv.ko
这说明/work/ko_file/目录下的first_drv.ko已经挂接到开发板的最小根文件系统的/mnt目录下面了,而这个first_drv.ko就是我们在/work/my_drivers/frist_drv/1th/目录下执行make生成的那个first_drv.ko。