宋宝华
1引言
目前,软件工程师大致可分为两个ฐ层次:
1应用软件工程师rr:主要利用库函数和
进行应用软件的编写;
2固件工程师rrr:主要进行的移植及
设备驱动程序的设计。
般而言,固件工ื程师的要求要高于应用软件工ื程师的层次,而其中的设备驱动
编程又是程序设计中ณ比较复杂的部分,究其原因,主要包括如下几个方แ面:
1设备驱动属于内核的部分,编写设备驱动需要有定的操作
系统内核基础;
2编写设备驱动需要对硬件的原理有相当的了解,大多数情况下我们是针ฤ对
个特定的嵌入式硬件平台编写驱动的;
3设备驱动中广泛涉及到多进程并发的同步互斥等控制,容易出现b;
4๒由á于属于内核的部分,设备驱动的调试也相当复杂。
目前,市面上的设备驱动程序参考书籍非常稀缺,少有的经典是由á社区的
三位领导者rrrr编写的
rr目前该书已๐经出版到เ第3版,中ณ文译本由中国电å力出版社ุ出版。该书将设
备驱动编写技术进行了较系统的展现,但是该书所列举实例的背景过于复杂,使得读者需要
将过多的精力投放于对例子背景的理解上,很难完全集中精力于驱动程序本身。往往
需要将此书翻来覆去地研读许多遍,才能有较深的体会。
rr中ณ英文版封面
本文将仍然秉承rr书以实例为主的风格,但是实例的背景将非
常简单,以求使读者能ม将集中ณ精力于设备驱动本身,理解内核模块设
备驱动的结构设备驱动中的并发控制等内容。另外,与rr所
不同的是,针ฤ对设备驱动的实例,本文还给出了用户态的程序来访问该设备,展现设备驱动
的运行情况及用户态和内核态的交互。相信阅读完本文将为您领ๆ悟rr
书中的内容打下很好的基础。
本文中的例程除引用的以外皆由笔者亲自调试通过,主要基于的内核版本为24,
例子要在其他内核上运行只需要做少量的修改。
构建本文例程运行平台的个较好方แ法是:在平台上安装r虚拟机,
并在r虚拟机上安装ณr。注意安装的过程中ณ应该选中ณ“开发工具”和“内核开
发”二项ำ如果本文的例程要在特定的嵌入式系统中ณ运行,还应安装ณ相应的交叉编译器,并
2
包含相应的源代码,如下图:
2内核模块
设备驱动属于内核的部ຖ分,内核的个模块可以以两ä种方式被编译和加
载:
1้直接编译进内核,随同启动时加载;
2编译成个可加载和删除的模块,使用加载rb和命令类
似,但依赖于相关的配置文件,r删除。这种方式控制ๆ了内核的大小,而模块旦ຆ被
插入内核,它就和内核其他部ຖ分样。
下面我们给出个内核模块的例子:
所有模块都需要的头文件
&相关宏
_""ิ;๙
_ຕ_ຕ_
{
r"";๙
rr0่;
}
___
{
r""ิ;
3
}
__;๙
_ຕ_;
分析上述程序,发现个内核模块需包含模块初ม始化和模块卸载函数,前者在
的时候运行,后者在r的时候运行。初始化与卸载函数必须在宏_
和_ຕ使用前定义,否则会出现编译错误。
程序中ณ的_"ิ"ิ用于声明模块的许可证。
如果要把上述程序编译为个运行时加载和删ฤ除的模块,则编译命令为:
–__r_ຕ_––rr24–
由á此可见,内核模块的编译需要给指示–_ຕ_ຕr__
–参数。选项ำ跟着内核源代码中目录的路径。
下列ต命令将可加载模块:
下列命令完成相反过程:
r
如果要将其直接编译入内核,则ท需要将源代码文件拷贝入内核源代码的相
应路径里,并修改。
我们有必要补充下内核编程的些基本知识:
内存
在内核模式下,我们不能使用用户态的和r函数申请和释放内存。进
行内核编程时,最常用的内存申请和释放函数为在r文件中声明的