新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 嵌入式数据采集系统中的ADS8364驱动程序设计

嵌入式数据采集系统中的ADS8364驱动程序设计

作者:时间:2012-03-23来源:网络收藏

4 的驱动程序设计概述

4.1 驱动程序的LKM实现机制

内核提供了两种机制来开发,一种是直接把驱动程序编译进内核,成为内核的一部分。另一种是通过LKM(Loadable Kernel Module,即可加载模块化机制)来开发可动态加载和卸载的驱动模块[3]。驱动程序如果编译进内核的话,会增加内核的大小,还要改动内核的源文件,而且不能动态的卸载,不利于调试,所以本系统把的驱动程序编写成了 LKM型驱动程序(就是把的驱动程序作为一个独立的单元模块,在使用时可以使用insmod命令加载到核心中,用完后使用rmmod命令卸载的那种)。

4.2 驱动程序的注册与注销

向系统增加一个驱动程序则意味着要赋予它一个主设备号,这一赋值过程是在驱动程序模块的初始化中完成的。ADS8364的初始化入口函数定义如下:

int _init ads8364_init_module(void)全功能版J-LINK ARM仿真器V6.0

{ …..

ret = register_chrdev(11, ADS8364, ad_fops);

……}

在用insmod命令将编译好的模块调入内存时,ads8364_init_module( )函数被调用。在这里,ads8364_init_module( )只做了一件事,它调用函数register_chrdev( )向内核注册该。函数register_chrdev()定义在linux/fs-h> 中。register_chrdev需要三个参数,参数一是希望获得的设备号,如果是零的话,系统将自动选择一个没有被占用的设备号作为该的主设备号并返回。参数二是设备文件名,这个名字必须插入到/dev目录中,并与驱动程序的主设备号和次设备号相连。参数三用来登记驱动程序实际执行操作的函数的指针。如果登记成功,返回设备的主设备号,不成功,返回一个负值。在此,我们选用当前不用的设备号11作为ADS8364的主设备号,设备名为 ADS8364。

在关闭或块设备时,还需要通过unregister_chrdev( )从内核中注销设备,并释放主设备号。在用rmmod卸载该驱动模块时,cleanup_module函数被调用,它释放字符设备ADS8364在系统字符设备表中占有的表项。

void ads8364_cleanup_module(void)

{ unregister_chrdev(11, ADS8364); info("ADS8364 cleanup module ok!"); }

4.3 file_operations结构体的设计

中,字符设备向内核提供的接口函数集就是文件操作集file_operations结构体。在Linux系统中,打开的设备在内核内部由设备文件file结构标识,内核使用file_operations(文件操作)结构访问驱动程序的函数。每个文件都与自己的函数集相关联(通过包含指向file_operations结构的f_ops指针段实现),这些操作主要负责系统调用的实现[4]。为了使驱动程序在结构的定义发生变化时更具可移植性,并且使得代码更加紧凑且易读,我们首先采用标记化格式声明ADS8364的file_operations结构:

static struct file_operations ad_fops = {全功能版J-LINK ARM仿真器V6.0

owner: THIS_MODULE,/* ad_fops所属的设备模块 */

read:ads8364_read,/*从设备中读数据*/

poll:ads8364_poll, /*查询设备状态*/

ioctl:ads8364_ioctl,/*设备I/O控制*/全功能版J-LINK ARM仿真器V6.0

open:ads 8364_open,/*打开设备操作*/

release:ads 8364_release,/*释放操作*/

};

file_operations结构体把系统调用和驱动程序关联起来。这个结构的每一个成员的名字都对应着一个系统调用。用户进程利用系统调用在对设备文件进行诸如read、write、open等操作时,系统调用通过设备文件的主设备号找到相应的,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数。这就是ADS8364驱动程序工作的基本原理。既然是这样,则编写的主要工作就是编写子函数,并填充 file_operations的各个域。下面我们就把file_operations的各个域的功能和主要调用函数加以介绍。

1)设备I/O控制操作函数

与普通文件相比,设备文件的操作要复杂得多,不可能简单地通过 read、write 和llseek 等来实现。所有其它类型的操作都可以通过VFS的ioctl调用来执行,函数定义如下:

static int ads8364_ioctl(struct inode * inode, struct file *filp, unsigned int cmd, unsigned long arg)

ads8364_ioctl是ADS8364驱动程序中对设备的I/O通道进行管理的函数。其中参数inode就是用户程序打开ADS8364时使用open函数返回的文件标示符,cmd就是用户程序对ADS8364的控制命令,它是唯一联系用户程序命令和驱动程序支持的途径,该函数通过cmd区分操作,通过arg传递参数和结果。在驱动程序中实现的ads8364_ioctl函数体内,有一个switch{case}结构,每一个case对应一个命令码,做出一些相应的操作。 ads8364_ioctl的设计的关键就是,如何将cmd命令码在用户程序里生成以及在驱动程序里的解析,所以switch{case}结构在 ads8364_ioctl中至关重要,因为对设备的I/O控制都是通过这一部分的代码实现的。

linux操作系统文章专题:linux操作系统详解(linux不再难懂)


评论


相关推荐

技术专区

关闭