本次实验我们开始学习驱动,首先了解什么是驱动,驱动程序全称设备驱动程序,是添加到操作系统中的特殊程序,其中包含有关硬件设备的信息。此信息能够使计算机与相应的设备进行通信。驱动程序是硬件厂商根据操作系统编写的配置文件,可以说没有驱动程序,计算机中的硬件就无法工作。那么驱动就是联系硬件也操作系统的关键所在。
本次实验要体会新增一个字符设备驱动的流程,添加驱动有两种方式,一种是在内核代码里面静态添加,随着Linux操作系统的启动而使能。另外一种是编写内核模块,将驱动编写成模块,在操作系统启动后,动态地通过安装内核模块的方式来使能驱动。(需要程序的给我留言,发邮箱)
首先,是静态的方式在内核中添加驱动程序。将编写好的字符设备驱动程序拷贝到虚拟机中(通过共享文件夹)。
然后进入linux-2.4.x/drivers/char ,将驱动程序拷贝进来,如下图所示。
然后修改 linux-2.4.x/drivers/char/Config.in文件
before bool ‘LED Manager support’ CONFIG_LEDMAN,
添加bool ‘MV_GPIO support’ CONFIG_MVGPIO 如图所示。
接着修改linux-2.4.x/drivers/char/Makefile文件
after obj-$(CONFIG_SERIAL) +=
(SERIAL),添加obj−(CONFIG_MVGPIO) += mvgpio.o 如图所示。
接着还要修改modifylinux-2.4.x/drivers/char/mem.c文件,如图所示。
最后还要修改modify vendors/Marvell/Firefox/Makefile文件,如图所示。
(这里注意驱动主设备号是254,后面使能后检查设备号可以对比)
修改完成后,添加进去的驱动程序就已经在内核了,接下来需要重新配置内核使其能够使能这个驱动,make xconfig 。更新kernel configuration, 选择进入‘Character Devices’
选择MV_GPIO support 为Y,如图所示。
然后重新编译 make ,完成后启动开发板,下载更新的内核映像,并重新启动,如图所示。
重新启动开发板后 ,可以看见内核启动时,刚刚增添的驱动程序已经使能了,在启动时回打印提示信息。对照我们的驱动程序,可以看出确实是使能了。
对比驱动代码源码。
然后检查一下设备号,跟我们在内核中添加的是一样的254。
这样我们的静态驱动就使能成功了。然后开始编译测试程序,在user/scu文件夹里面,添加测试程序testgpio.c,然后修改Makefile文件,将其添加到编译命令,如图所示。
然后在uClinux-dist目录下执行编译命令make,然后检查romfs/bin目录,如图所示,可以看见编译出来的testgpio。
然后重新下载文件系统,在重启开发板。
然后可以执行测试程序,由于是静态的驱动,所以不需要手动挂载,内核启动时直接使能,所以直接使用。用测试程序来点亮和熄灭LED灯,如图所示。
随着测试程序的控制灯的亮灭,可以看见开发板上的LED随之量灭,如图所示。
LED灭
LED亮
静态的驱动可以看见已经完成了设计和测试了。接下来要做就是动态的驱动设计了。首先需要把之前的静态驱动的设计全部去掉,如下图所示。
接下来在linux-2.4.x/drivers/char/目录下创建文件夹mvgpio ,将编写好的动态驱动程序gpio.c和Makefile文件都放到该文件夹,如图所示。
然后修改linux-2.4.x/drivers/char/Config.in如下图所示。
然后修改linux-2.4.x/drivers/char/Makefile 将刚刚创建的文件夹mvgpio添加到编译命令。
修改完成后,进行内核模块的编译和打包,make modules,但是这里发现一个问题就是,执行make modules后,驱动程序并没有被编译成一个内核模块,原因是没有进行内核配置,首先要配置内核。
现在进行内核配置,进入kernel选项,看到刚刚添加的内核驱动选项,将其选择为m(内核模块)。
然后在进行make modules就可以看见驱动程序已经编译出来了。,如下图所示。
然后将内核模块拷贝到开发板的根文件系统里面去,放到romfs/lib/modules目录。
这样动态驱动的配置就完成了,接下来下载到开发板。进入开发板的shell之后,首先查看模块信息,如图所示;可以看见是没有mvgpio的;然后手动的安装编译好的内核模块,
insmod /lib/modules/mvgpio.o ,这时可以看见安装的打印信息跟驱动程序中的是匹配的;然后再次检查模块信息,可以看见出现了mvgpio,说明内核模块安装完成,然后测试。
测试LED的量灭也是可以实现的,如下图所示。(LED图与上面一样就不放了)
到这里动态的驱动就实现了。
总结
本次实验学习了驱动的设计和使用。没有驱动,所有的硬件就不能工作,由此可见驱动是多么重要的一个环节,操作系统不同,硬件的驱动程序也不同,为了保证硬件的兼容性及增强硬件的功能就需要不断地升级驱动程序,所以学习驱动的设计是非常重要的。
本次实验学习了设计驱动的两种方式,一种是在内核代码里面静态添加,随着Linux操作系统的启动而使能。另外一种是编写内核模块,将驱动编写成模块,在操作系统启动后,动态地通过安装内核模块的方式来使能驱动。但是明显第二种方式更加的适用,在需要的时候才安装对应的驱动程序,不需要的时候则卸载掉驱动,这种在嵌入式设备驱动开发中将驱动程序以模块的形式设计出来,可以极大地提高设备使用的灵活性,可以随时扩展Linux系统的功能,需要使用新模块,不必重新编译内核,只要插入相应的模块即可,这样明显的减少了很多开发时间;另外一方面,减小Linux内核的体积,减轻启动时内核的负担。
在设计动态驱动的时候,添加驱动代码,修改内核代码完成之后一定要重新配置内核,将刚刚设计的驱动,改为内核模块的形式,然后编译内核模块,否则不选中的话,内核模块是没有编译出来的,就无法使用,这也是我之前犯的错误,找了很久的问题,才发现是这个地方没有配置到,配置完成,就可以将内核模块编译出来,然后复制到开发板使用。