嵌入式linux设备驱动

上传人:第*** 文档编号:52322973 上传时间:2018-08-20 格式:PPT 页数:42 大小:216.50KB
返回 下载 相关 举报
嵌入式linux设备驱动_第1页
第1页 / 共42页
嵌入式linux设备驱动_第2页
第2页 / 共42页
嵌入式linux设备驱动_第3页
第3页 / 共42页
嵌入式linux设备驱动_第4页
第4页 / 共42页
嵌入式linux设备驱动_第5页
第5页 / 共42页
点击查看更多>>
资源描述

《嵌入式linux设备驱动》由会员分享,可在线阅读,更多相关《嵌入式linux设备驱动(42页珍藏版)》请在金锄头文库上搜索。

1、三、 嵌入式Linux设备驱动1.嵌入式Linux设备驱动程序的基本原理2.如何编写嵌入式Linux设备驱动程序1.嵌入式Linux设备驱动程序的基本原理1.1 概述 1.2 设备文件 1.3 设备驱动程序模块 1.4 设备驱动程序接口 1.5 设备驱动程序接口实现过程1.1 概述设备驱动程序: l是操作系统内核和机器硬件之间的接口 l它控制着设备的操作动作 l向应用程序提供一个可用的程序接口与设备互动可见:设备驱动程序为应用程序屏蔽了硬件的细节,这样在 应用程序看来,硬件设备只是一个设备文件,应用程序 可以像操作普通文件一样对硬件设备进行操作。因此在操作系统中起着不可缺少的作用。设备驱动程序

2、结构图各种设备驱动程序构成了它们所控制的硬件和操作系 统内核之间的一个过渡层次。这个层次扎根于硬件,服务 于内核。 优点:1.极大的简化了内核的设计和应用它向外界提供了一个精心定义的接口,具体的工作将由各个设备去完成,而内核就不必亲自去与每 一个设备打交道2.屏蔽了底层硬件,方便应用程序的编写设备驱动程序(内核的一部分)的任务 :(1)对设备初始化和释放。(2)把数据从内核传送到硬件和从硬件读取数据。(3)读取应用程序传送给设备文件的数据和回送应用程序请求的数据。(4)检测和处理设备出现的错误。驱动程序与应用程序的区别1.应用程序:一般有一个main 函数,从头到尾执行一个任务;驱动程序:它没

3、有main 函数,通过使用module_init(初 始化函数名),将初始化函数加入内核全局初始化函数列表中,在内核初始化时执行驱动的初始化函数,从而完成驱动的初始化和注册,之后驱动便停止等待被应用软件调用。 驱动程序中有一个宏moudule_exit(退出处理函数名)注册退出处理函数。它在驱动退出时被调用;2.应用程序:可以和GLIBC 库连接,因此可以包含标准的头文件,比如 ;驱动程序:是不能使用标准C 库的,因此不能调用所有的C 库函数,比如输出打印函数只能使 用内核的printk 函数,包含的头文件只能是内核的头文件,比如;1.2 设备文件Linux设备驱动程,抽象了对硬件的处理,将所

4、有 外部设备看成是一类特殊文件,称之为“设备文件”每个设备文件对应有两个设备号:主设备号和次设备号(1)主设备号标识该设备的种类,也标识了该设备所使用的 驱动程序(2)次设备号标识使用同一设备驱动程序的不同硬件设备对于查看/dev 目录下的设备的主次设备号可以使用 如下命令:ls -l /dev当应用程序对某个设备文件进行系统调时: Linux内核会根据该设备文件的设备类型和主设备号调用相应的驱动程序;(从用户态进入到内核态) 再由驱动程序判断该设备的次设备号,最终完成对相应硬件的操作。所有己经注册(即已加载了驱动程序)的硬件设备的主 设备号可以从/proc/devices文件中得到。内核函数

5、mknod命令可以创建指定类型的设备文件, 同时为其分配相应的主设备号和次设备号。mknod命令的语法:mknod name type major minor其中:name : 设备文件名major: 主设备号minor: 次设备号type : 使用b或c, b代表块设备,c代表字符设备块设备与字符设备Linux操作系统下有两类主要的设备文件: 字符设备 块设备。字符设备:所有能够像字节流一样访问的设备。字符设备是以字节为单位逐个进行I/0操作的设备,在 对字符设备发出读写请求时,实际的硬件I/0紧接着就发 生了;块设备: Linux 的块设备通常是指诸如磁盘,内存, Flash 等可以容纳文

6、件系统的存储设备。块设备则是利用一块系统内存作为缓冲区,当用户 进程对设备进行读写请求时,驱动程序先查看缓冲区 中的内容,如果缓冲区中的数据能满足用户的要求就返 回相应的数据,否则就调用相应的请求函数来进行实际 的I/0操作;1.3 设备驱动程序模块Linux下的设备驱动程序可以按照两种方式进行编 译:一种是直接静态编译成内核的一部分;一种是编译成可以动态加载的模块;静态编译缺点是:会增加内核的大小;要改动内核的源文件;不能动态地卸载,不利于调试;所以通常使用模块方式从本质上来讲:模块也是内核的一部分,因为它不同于普通的应用 程序,不能调用位于用户态下的C或者C+库函数,而只 能调用Linux

7、内核提供的函数。模块的加载和卸载方式:insmod完成模块的加载;rmmod命令完成模块的卸载 具体实现是:init_ module() cleanup_ module() 具体的流程见1.5节字符设备驱动设备驱动 程序动态连动态连 接图图1.4 设备驱动程序接口Linux中设备驱动程序接口是通过特定的数据结构 (file_ operations)来完成的,其定义如下(结构体 file_operations 在头文件linux/fs.h 中定义的 ):struct file_ operations loff_ t (*llseek) (struct file*,loff_t, int);ssi

8、ze_ t (*read) (struct file*,char*,size_t, loff_ t*);ssize_ t (*write) (struct file*,connt char*,sizet, loff_t *);int (*readdir) (struct file*,void*,filldir_t);unsigned int (*poll) (struct file*,struct poll_table_struct*):int (*ioctl) (struct inode*,struct file*,unsigned intunsigned long);int (*mmap)

9、 (struct file*,struct m area struct*);int (*open) (struct inode*,struct file*);int (*flush) (struct file*);int (*release) (struct inode*,struct file*);int (*fsync) (struct file*,struct entry*):int (*fasync) (int struct file*,int);int (*check media change) (kdev_t dev);int (*revalidate)(kdev_t dev);i

10、nt (*lock) (struct file*,int, struct f门e_ lock*); 在该数据结构里,指出了设备驱动程序所提供的 入口点位置,下面讨论其中几个关键的入口点:(1)llseek,对应着用户空间里的lseek,其作用是改 变文件结构中的操作位置,显然只能用于可以随机存 取的设备。 (2)read,进行读操作,其实际上就是把数据写到用户 空间去。参数buf为存放读取结果的缓冲区,count为 所要读取的数据长度。返回值为负表示读取操作发生 错误,否则返回实际读取的字节数。 (3)write,进行写操作,与read类似。 (4)readdir,读取目录,对于设备文件来说,

11、这个字 段应该为NULL,它仅用于读且只对文件系统有用。(5) poll,允许应用程序响应来自设备的给定事件。 (6) ioctl,驱动程序特殊控制入口点,进行读、写以外 的其它操作,参数cmd为自定义的命令。它允许应用程序通过ioctl系统调用控制设备的行为或者从设备取得数据。 (7) open,是应用程序打开设备时将要调用的文件操作。返回0表示打开成功,返回负数表示失败。它对字符设备和块设备都有缺省实现,如果驱动程序没有提供open入口,则只要/dev/driver文件存在就认为打开成功。 (8) release,在设备关闭时将调用的文件操作。file_operations数据结构向Lin

12、ux操作系统注 册一组文件操作,这些文件操作定义了设备提供的 特定功能,Linux设备驱动程序可以通过该数据结 构向Linux操作系统内核报告自己代表的设备为应 用程序提供了哪些功能。对于设备驱动程序而言,可以根据需要定义特 定的操作接口,而用不着的则将其设置为NULL。1.5 设备驱动程序接口实现过程Linux的设备驱动程序接口实现过程大致可 以分为如下几个部分:驱动程序的注册与注销;设备的打开与释放;设备的读写操作;设备的控制操作;中断处理;1.5.1 驱动程序的注册与注销字符设备的注册是通过内核函数:register_ chrdev()块设备的注册是通过内核函数: register_bl

13、kdev()register_ chrdev的调用语法: int register_chrdev (unsigned int major,const char *name,struct file_ operations *fops)该函数在失败时返回值是一个负数,成功则返回内核 函数的主编号第一个参数major:是驱动程序向内核注册的主设备编号, 如果将其设置为0,则内核将给这个设备动态分配一个主 设备编号;第二个参数name:只有一个用途一就是向/proc/devices进 行注册:这个名字将出现在那里,仅此而已;最后一个参数:最有意义,它定义了设备与外界交互的方 法:特别是规定了哪些功能由

14、它自己来负责完成,又有哪 些功能需要由内核中的缺省函数来完成,设备的 打开与释放、读写操作等都是通过file_ operations中对 应的函数来实现;字符设备的注销是调用内核函数 :unregister_chrdev() 块设备的注销是调用内核函数 :unregister_ blkdev() 通过注销,将模块从内核中卸载。1.5.2 设备的打开与释放打开设备:是通过调用file_operations结构中的函数 open()来完成的,它是驱动程序用来为后面的操作完 成初始化准备工作的。在大部分驱动程序中,open() 通常需要完成下列工作: (1)检查设备相关错误,如设备尚未准备好等; (

15、2)如果是第一次打开,则初始化硬件设备; (3)识别次设备号,如果有必要则更新读写操作的当前 位置指针f_ops(file结构体中); (4)分配和填写要放在file-private_data里的数据结 构; (5) 使用计数增1;释放设备:是通过调用file_ operations结构中的 函数release()来完成的,这个设备方法有时也被 称为。close(),它的作用正好与open()相反,通 常要完成下列工作: (1) 使用计数减1; (2) 释放在file-private_ data中分配的内存; (3) 如果使用计数为0,则关闭设备;1.5.3 设备的读写操作;读和写方法都进行类

16、似的任务, 就是, 从和到 应用程序代码拷贝数据。 因此, 它们的原型相当相似: ssize_t read(struct file *filp, char _user *buff, size_t count, loff_t *offp); ssize_t write(struct file *filp, const char _user *buff, size_t count, loff_t *offp); 参数:filp 是文件指针;count是请求传输数据的长度buffer是用户空间的数据缓冲区ppos是文件中进行操作的偏移量,类型为64 位数。由于用户空间和内核空间的内存映射方式完全不 同,所以不能使用象memcpy 之类的函数,必须使用 如下函数:unsigned long copy_to_user(void *to, const

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 建筑/环境 > 工程造价

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号