您的当前位置:首页正文

基于linux2.6内核的字符设备驱动程序设计

2020-06-27 来源:钮旅网
・计算机技术・ 基于linux2.6内核的字符设备驱动程序设计 周来超 傅成华 刘宏玉 (四JII理工学院 四川I自贡 643000) [摘 要]设备驱动程序在嵌入 ̄Linux中起着重大的作用,它提供了操作系统和硬件设备之间的交互的接El,能够让软件开发人员 不用知道底层硬件的特性,就能方便地进行上层软件的开发。本文基于嵌入 ̄(Linux2.6内核,对字符驱动程序的开发做出详细的讲解, 给出了linux2.6内核下字符设备程序开发的步骤,并写出了字符设备驱动开发的一般模块。 [关键词]嵌入式Linux2 6内核 字符设备驱动 [中图分类号]TP339 [文献标识码]A [文章编号]1007-9416(2010)07—001O一02 1引言 嵌入式Linux支持多种体系结构,拥有 丰富的软件资源,支持多任务,有着完善的 网络通讯、图形、文件管理机制,更加重要 的是它能通过灵活剪裁来定制Linux内核, 使它能够满足各种不同环境下硬件要求。 以上种种的优点使它被广泛的应用于工业 生产中。但是由于嵌入式Linux操作系统本 身没有对种类繁多的硬件一一提供驱动, 在开发过程当中更没有通用的驱动程序可 以使用,这就要求我们能够根据自己硬件 设备特点独立开发设备驱动。 linux支持3类硬件设备:字符设备、块 设备及网络接口。字符设备是指那些无需 缓冲直接读写的设备,可以像文件一样访 问的字符设备。本文重点讲述了在Linux2. 6内核下,编写字符设备驱动程序的步骤和 一些方法。 2 cdev结构体 存linux2.6内核中,使用cdev结构体描 述一个字符设备,cdev结构体定义如下: struct cdev { struct kobject kobj; 豫 , struct module owner; /十所属模块}/ struct fileoperations ops;/十文件操作 结构体 / ’ struct list_head list; dev—t dev; /十设备号十/ unsigned int count; }; cdev结构体的dev—t成员定义了设备号, 为32位,其中l 2位为主设备号,20位为此设 备号。使用下列宏可以从dev—t获得主设备 号和次设备号: MAJ0R(dev t dev) MINOR(dev—t dev) 而使用宏MKDEV(int major,int minor) 则可以通过主设备号和次设备号生成 3 file—operat ions结构体 file—operations结构体中的成员函数是 字符设备驱动程序设计的主要内容,这些 函数实际会在应用程序进行linux的open()、 write()、read()、close()等系统调用时最终被 调用。以下是该结构体当中的一些主要成 员: struct fileoperations { lofft(十llseek)(struct file},loff—t 0 数字技术与应用 int);//用来修改文件当前读写位置 in (*op en)(struct inode ,street file .);//打开文件 ssizet(*read)(struct file},char user {,sizet,lofft ); //从设备中同步读取数据 ssizet(*write)(struct file}.char user },sizet,lofft{); //向设备发送数据 unsigned int(*pol1)(struct file十,struct polltable struct ): //轮询函数,判断目前是否可以进行 非阻塞的读取或写入 int(*ioct1)(struct inode},struct file 十,unsigned int,unsigned long);//执行 设备IO控制命令 int( mmaP)(struct file , struct vmarea struct ); //用于请求将设备内存映射到进程地 址空间 4设备号的分配和释放 在调用cdev—add()函数向系统注册字符 设备之前,应首先调用register—chrdev—reg ion()或者alloc—chrdev—region()函数向系统 申请设备号,以下是这两个函数的原型: int register——chrdev——region(dev——t from, unsigned count,const char*name); int allocchrdevregion(dev——t*dev, unsigned baseminor,unsigned count,const char*name); registerchrdevregion()函数用于已知 其实设备的设备号的情况,而alloc—chrdev region()用于设备号未知,向系统动态申请 未被占用的设备号的情况,函数调用成功 之后,会把得到的设备号放入第一个参数d ev当中。alloc—chrdev—region()会自动避开设 备号重复的冲突。 而在调用cdev—del()函数从系统注销字 符设备之后,应该调用unregister—chrdev—r egion()函数来释放原先申请的设备号,其 函数原型为: void unregister——chrdev——region(dev——t from,unsigned count); 5字符设备驱动模块加载与卸载 函数 在linux中,字符设备驱动由字符设备 驱动模块加载和卸载函数,以及file—operat ions结构体中的成员函数组成。 在字符设备驱动模块加载函数中应该 实现设备号的申请和cdev的注册,而在卸 载函数中应该实现设备号的释放和cdev的 注销。通常是为设备定义一个与设备相关 的结构体,其中包含设备所涉及到的cdev、 私有数据及信号量等信息。如下所示: / 设备结构体 / struct XXX——devt f struct cdev cdev; …… //该设备其他的私有数据和 信号量的信息的定义 }XXX—dev; 模块加载和卸载函数的形式如下: /+设备驱动模块加载函数 / static intinit XXXinit(void) { cdevinit(&xxxdev.cdev,&xxx—fops); x x xd e v . c d e v. owner=THISMODULE; …………………//获取字符设备号 if(xxx—major) f register—chrdevregion(xxx—dev—no, 1,DEVNAME); ・} eles r L allocchrdev—region(&xxx—dev_no,0, 1,DEV NAME); } ret=Cdevadd(&XXX—dev.cdeV, XXXdevno,1); //注册设备 j / 设备驱动模块卸载函数 / static void一一exit XXX—exit(void) f unregisterchrdevregion(xxx_dev_no, 1); cdev del(&xxx dev.cdev); //注 销设备 …… 的 露 薮perat。ons结构体中 fileoperations结构体中的成员函数是 字符设备驱动与内核的接口,是用户空间 对linux进行系统调用的最终落实者。编写 相应的函数,通过向file—operations结构体赋 值,来实现内核对设备的open()、read()、 write()、ioctlO操作。以下是ioctl()函数实现 模型: int xxx__ioctl(struct[node*inode,struct flie*filp,unsigned int cmd,unsigned long arg) { ・计算机技术・ DW多维层次结构的汇总性设计 孙晓敏 任广伟 (贵州大学计算机科学与信息学院 贵州贵阳 5 50025) 【摘 要]层次是多维数据的一个重要组成部分。在数据仓库和OLAP中提供了研究不同级别的明细数据。不同的明细数据可以通过 上卷和下钻操作实现。为了实现不同层次的汇总性,本文采用几种类型的层次及不同级别的数据依赖性,探讨在数据仓库基础上实施 立体层次机制的逻辑计划。根据相应的执行维层次结构上的依赖的算法,实现不同层次的汇总性,用以保证聚合的正确性。本文的创新 点在于从数据依赖出发去实现层次的汇总性。 【关键词]DW OLAP 数据依赖 汇总性 [中图分类号】U664 [文献标识码]A [文章编号]1007-9416(2010)07-001l-02 引言 为重点研究方面。 称的,如图1即为对称的。反之,当所有的 OLAP允许DW中的数据进行动态操作 层次水平都不是强制的,即有可能的路径 与更新。DW数据的聚合可以通过实施维度 不包括各个等级或者有父母水平没有孩子 层次结构的汇总性来实现。本文学习和研 性,归属性 1维层次结构一结构性,汇总 的,那么这个简单的层次结构立体不对称, 究不同类型的层次结构以及聚合的正确性 立体维层次结构及分类在之前已经有 如图2所示。我们称不对称的这些等级不具 问题。为了确保汇总性,在不对称的层次上 相应研究。简单维层次结构是树型结构。例 备完全汇总性。 实施依赖关系也是本文讨论的一部分。关 如把一对多的父子关系生成维层次树。如 层次多重性指从最低层到最顶部的路 系逻辑方案中的机制,如何实现维层次结 果存在一个从最底层到顶端单一的路径, 径有多条,即表示在不同的水平之中存在 构,以及执行规定的依赖的运算法则也将 并且各级都是强制的(即它具有完全汇总 d 多对一的父子关系,如图3中表示(左图中 在以下章节进行介绍。为了实现层次产生 性并且沿着各水平的聚合操作是平凡的),CO0 O  结点4存在两个父亲1和2,右图中结点5有 2 和操纵的实施机制,DW逻辑中的元数据成 那么我们称这个简单的维层次结构树是对 e V 薅父亲2和3)。这种多维层次结构与不对称 2 一、 e 立体层次一样也不具有完全汇总性。 …一一t 一 2●22/①  M 现目前最重要目标是设计正确的汇总 \ / \  / \ ~--42 03-?一[= 1 , 、 e 性,这是为了确保OLAP和其他环境中的维 ( C】 C2 层次结构。汇总性要求水平属性是不相交 净…一 CNIu I.I.£; 的或者说是不完整的,也就是说每个元素 必须是分配给上级的元素。这是由相关性 西 ③ ④ 图4维层次结构表构造 分析的维度中的属性决定的。在D w逻辑 图1 对称立体层次图2不对称立体层 表1 DW的多维层次的元数据 j 担 达到的目的 /④ ⑨⑨ Traverse Relationship() 从表中的关系获得关系表的主键 Create Hierarchy Table() 创建维层次表 Generate Hierarchy Table() 嫡过主键与外键z间的关系插^记录到维层次衰 Child with Mutiple Parents() 检查维层次表中多维儿子的父亲 图3立体多维层次结构 Parents with Mutiple Children() 检查维层次表中多维父亲的孩子们 switch(cmd) / 设备驱动模块卸载函数+/ { static void一一exit XXX—exit(void){……} case XXX—cmd1: 7设备驱动程序设计 module—init(xxx—init)l 以上对linux2.6内核下字符设备驱动 module—exit(xxx—exit); break; 程序设计中的一些重要数据结构及其在具 case XXX—cmd2: 体的驱动程序中编程的用法做了详细的介 8结语 绍,具有一般性,下面就以上的内容给出在 本文重点讲了基于linux2.6内核下的 breakI linux2.6内核下,设备驱动程序开发的C代 设备驱动程序设计的步骤,详细的分析了 default: //不能识别的命令 码模块: 内核中有关的数据结构,并给出了相应的 return ENOTTY; …… //必要的头文件,由要开发的 使用模型。最后,结合本文给出的方法,给 ' J 驱动决定 出了编写驱动程序的C代码框架。 , J MODULELICENSE(“GPL”); 接下来就是定义一个file—operations的 ssziet XXX—read(struct file}.char [参考文献] 实例,并把具体设备驱动的函数与 user十,size—t count,loff—t{fops){ 【1】ALESSANDR0 RUBINI,等,魏永 file……………… operations结构体中的成员函数联系起 //相关代码实现 } 明,等译.LINUX设备驱动程序[M].中国电 来,可以这么做: //具体的设备驱动相关函数的实现 力出版社,2002. struct file——operations XXX——fops= struct file—operations XXXfops={ { ……… ); [2]于明,范书瑞,曾祥烨.ARM9嵌入 式系统设计与开发教程【M】.北京:电子工 .owner=THIS—M0DULE. //给file—operations成员赋值 业出版社,2006. .read=xxxread, struct XXXdev—t{………}XXX~dev;/ 【3】华清远见嵌入式培训中心,嵌入式 .write=xxxwrite, /定义设备结构体 Linux应用程序开发标准教程(第二版)fM】. .ioctl=xxxioctl, /+设备驱动模块加载函数+/ 人民邮电出版社,2009. .open=xxx_open, static int __init xxxinit(VOid) f……………………} 【4】商斌,Linux设备驱动开发入门与编 程实践[M】.北京:电子工业出版社,2009. 数字技术与应用 

因篇幅问题不能全部显示,请点此查看更多更全内容