的定义如下:structfile_operations{structmodule*owner;loft_t(*llseek)(structfile*,loff_t,int);
ssize_t(*read)(structfile*,char*,size_t,loft_t);ssize_t(*write)(structfile*,constchar*,size_t,1off_t*);int(readdirstructinode*,structfile*,void*,filldir_t);int(*select)(structinode*,structfile*,int,selecttable*);int(*ioct1)(structinode*,structfile*,unsignedint,unsignedint);
int
(*mmap)
(struct
inode*,struct
file*,struct
vm_area_struct*);
int(*open)(structinode*,structfile*);void(*release)(structinode*,structfile*);int(*fsync)(structinode*,structfile*);};
2.2.2注册和注销模块2.2.2.1设备注册模块
staticint_nitIOdriver_init(void){intret=0:
ret=register_chrdv
&IOdriv
if(ret)
{printk(KERN_ALERT“IOdriverregisterfailure!”)}else
{printk(KERN_ALERT“IOdriverregistersuccess!”)}
returnret;}
2.2.2.2设备注销模块
staticint_exitIOdriver_exit(void){intret=0;
ret=unregister_chrdv(MAJOR_NUM,“IOdriver”);if(ret)
{printk(KERN_ALERT“IOdriverunregister
failure!”);}
else
{printk(KERN_ALERT“IOdriverunregister
success!”);}
returnret;}
·53·信息安全与技术·2012年2月
(2)中断
中断在现代计算机结构中有重要的地位,操作系统必须提供驱动程序响应中断的能力。一般是把一个中断处理程序注册到系统中,操作系统在硬件中断发生后,调用驱动程序的处理程序。Linux支持中断的共享,即多个设备共享一个中断。
(3)时钟
在实现驱动程序时,很多地方会用到时钟,例如某些协议里的超时处理,没有中断机制的硬件的轮询等。操作系统应为驱动程序提供定时机制,一般是在预定的时间过了以后,回调注册的时钟函数。
嵌入式Linux系统驱动程序开发与普通Linux没有太多区别。嵌入式设备由于硬件种类非常丰富,在缺省的内核发布版中不可能包括所有驱动程序。可以在硬件生产厂家或者Intemet上寻找驱动程序,如果找不到,可以根据一个相近硬件的驱动程序来改写。实现一个嵌入式
(MAJOR_NUM,“IOdriver”,
Linux设备驱动的大致流程如下:(1)定义主、次设备号,
也可以动态获取;(2)实现驱动初始化和清除函数,如果驱动程序采用模块方式,则要实现模块初始化和清除函数;
(3)设计所要实现的文件操作,定义file_operations结构;(4)实现所需的文件操作调用,如read、write等;(5)实现中
断服务函数,并用requestirq向内核注册;(6)将驱动编译到内核或编译成模块,用insmod命令加载;(7)生成设备节点文件。
与普通文件相比,设备文件的操作要复杂得多,不可能简单地通过read、write和llseek等来实现。所有其它类型的操作都可以通过VFS的ioctl调用来执行,为此,只需要在驱动程序中实现ioctl函数,并在其中添加相应的
case即可。通过cmd区分操作,通过arg传递参数和结果。
2.2设备驱动程序的开发流程
2.2.1设备驱动接口
Structfile_operationIOdriver_fops={read:1Odriver_read,write:IOdriver_write,};
字符设备驱动接口中关键的file_operations结构:
InformationTechnology·信息技术·软硬件
2.2.3基本入口点设备函数的具体实现2.2.3.1设备读取模块
staticssize_tIOdriver_read(structfile*file,char*buf,size_tlen,loft_t*off)
{if(__copy_to_user(bur,&IOdriver_var,sizeof(int))){retum_EFAULT;}retumsizeof(int);}
2.2.3.2设备写入模块staticssize_tIOdriver_writechar*buf,size_tlen,loff_t*off)
{if(__copy_from_user(&IOdriver_var,buf,sizeof(int)))
{retum__EFAULT;}retumsizeof(int);}
2.2.4module_init和module_exit宏module_init(IOdriver_init);module_exit(IOdriver_exit);
(structfile*file,const
(4)重新编译内核,并更新嵌入式目标系统的内核。(5)创建设备文件,重新启动嵌入式目标系统的Linux,进入目录/proc,查看devices文件,在devices文件
列出了当前系统所有的字符设备和块设备,包括设备号和设备名称,在Characterdevices的最后移行的设备是:
254IOdriver,这说明IOdriver设备已经正确地加载到了
内核。
(6)添加设备文件节点,执行如下命令,添加设备文
件节点,在此创建的设备名称用于在应用程序中访问对应的设备。如果为字符设备,设备号类型用c表示,块设备则用b表示;主设备号就是/proc/devices中的IOdriver的设备号,由于该类设备只有一个,因此次设备号为0,如果还有该类型的其他设备,则一次为1、2、3等。
4结束语
设备驱动程序是操作系统内核和机器硬件之间的接
口。内核利用驱动程序的接口完成对设备的初始化和释放,在系统内核和硬件之间传送数据,并时刻检测和处理设备出现的错误。它是操作系统最基本的组成部分,因此熟悉驱动的编写是很重要的。
3设备驱动程序编译到内核的过程
把驱动程序编译进内核的步骤如下:
参考文献
[1]宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2008.
[2]赵炯.Linux内核完全剖析--基于0.12内核[M].上海:机械工业
出版社,2009.
(1)把IOdriver.c复制到Linux-2.4.20-8/drivers/char
下,并修改该目录下的config.in文件,config.in是每个模块的配置脚本,在这个文件当中定义配置那些模块、怎样配置等,因此当添加了IO的配置后,会在内核配置时出现这个模块的配置选项。
[3]魏永明.Linux设备驱动程序[M].北京:中国电力出版社,2006.[4]吴迪.嵌入式系统原理、设计与应用[M].北京:机械工业出版社,2004.
[5]罗苑棠.嵌入式Linux应用系统开发实例精讲[M].北京:电子
工业出版社,2007.
(2)修改当前目录下的Makefile,在每个模块的Makefile中包括该模块所包含的子模块,在chardevices
中,要包括IO设备,就要告诉Makefile编译IOdriver.c并包含编译出的IOdriver.c文件,这样最后内核做链接时,才会链接进这个模块。
作者简介:
张玲玲(1985-),女,软件开发助理工程师;主要研究方向:软件设计。
(3)重新配置内核,选中IO模块执行命令makemenuconfig,进入内核配置菜单。
·54·2012年2月·www.infosting.org