微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 驱动学习1

驱动学习1

时间:12-01 来源:互联网 点击:

看了好长一段时间的书,开始做驱动,从简单的开始学习,实现最简单的字符设备驱动,实现的功能是对两块内存空间(物理内存)进行控制,实现读写操作。

基本的实现与很多学习驱动程序设计的方式一样,跟着别人的程序跑,自己弄明白,搞清楚其中的道理。具体的实现过程,结合注释可以看清楚。主要总结第一次写驱动过程中存在的问题,以及相应的解决方法。

字符设备驱动的基本流程:

首先,驱动函数的初始化,以及清除函数(这部分主要是按着一定的模式编程)

1、 申请主设备号,其中可以采用静态或者动态的方式申请。

2、 创建字符设备,其中包括初始化字符设备(分配设备空间),绑定相关的操作(相应的操作),最后是添加字符设备(实现所申请的设备号与设备的绑定)。

3、 设备的具体实现以及错误的处理问题。

4、 清除函数主要包含分配物理空间的释放以及设备号的释放,字符设备的注销等。

第二,主要是设备相关操作的具体实现过程。(这部分主要是涉及内核的一些知识)包含具体的文件打开,关闭,以及读写,定位操作。具体的参看源码。

第三,Makefile的基本实现(也是一定的模块,但是能够了解其中的道理)或者直接编译到内核中。

出现的问题主要是Makefile文档的设计以及加载问题。

问题一,是kmalloc函数等的运用需要相应的头文件,kmalloc的头文件是linux/slab.h,关于错误(errno.h)是与CPU体系密切相关的,因此通常是asm/errno.h,这个也是常见的问题。

问题二,是加载出错的问题。出现下面的错误,

insmod:error inserting /home/gong/program/cprogram/module/memdev/memdev.ko: -1 Device or resource busy

这个错误产生的原因主要是因为主设备号真正被别的驱动程序使用导致的。可以通过cat /proc/devices查看具体的情况

...

251 hidraw

252 usbmon

253 bsg

254 rtc

...

需要重新定义主设备号。然后重新编译,即可加载成功。

问题三,Makefile文件的设计

编译驱动有两种方法,可以采用直接内核编译的方式,这种方式主要通过修改源码中的Makefile和Kconfig实现。这种方法比较直观,但是会破坏源码的完整性。

通常采用自己编写Makefile的方式实现驱动的编译。这种方式需要了解Makefile的一些语法,同时需要了解自己的源码结构,但是这种模式具有很大的相似性,都是基于模块的设计方式。

常用的Makefile模块如下所示:

ifneq ($(KERNELRELEASE),)

obj-m := memdev.o

else

KDIR :=/opt/LinuxKernel/linux-2.6.38.1

PWD :=$(shell pwd)

default:

make -C $(KDIR) M=$(PWD) modules

clean:

rm -f *.ko *.o *.mod.o *.mod.c *.symvers

endif

具体的分析我说说自己的理解吧。首先第一句ifneq ($(KERNELRELEASE),)是实现两个变量的比较。比较两个参量是否不相等。如果不相等则执行下面的语句:obj-m := memdev.o,如果相等就执行else后面的语句。

具体的过程如下:

如果驱动代码是在内核源码中实现,那么KERNELRELEASE就是一个已知的值,具体的值是:

# Read KERNELRELEASE from include/config/kernel.release (if it exists)

KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)

KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)

但是另一个值为空,这样两个值就是不相等的,这样就执行obj-m := memdev.o。

但是如果不是在内核源码中实现,那么KERNELRELEASE就是一个空值,这样两个参数就是相等的。执行else以后的语句。

KDIR :=/opt/LinuxKernel/linux-2.6.38.1

PWD :=$(shell pwd)

上面的两句是定义两个变量,其中的KDIR是内核源码的根目录,PWD则是当前驱动代码所在的目录。

然后执行

default:

make -C $(KDIR) M=$(PWD) modules

default是一个默认的目标,没有相关的依赖,规则是make -C $(KDIR) M=$(PWD) modules

其中参数-C和M=都有各自的意义,具体的可以参看Makefile的相关资料。

我的理解就是:

-C 选项的作用是指将当前工作目录转移到你所指定的位置(页就是内核源码的根目录)

“M=dir”,内核程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成.KO文件。实现驱动程序的编译。

具体的注意事项:KERNELRELEASE这个变量不要写错,这个比较容易出错,还容易检查出来。我第一次写代码就出现了相应的错误。

需要注意的是该makefile被执行了两次,其中第一次是由于没有定义KERNELRELEASE对象,当进入到内核源码以后,这时KERNELRELEASE对象已经被定义好了,然后返回到当前的文件夹下,这时候直接执行第一句obj-m

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top