第二章节_字符设备驱动程序幻灯片

上传人:E**** 文档编号:90213743 上传时间:2019-06-09 格式:PPT 页数:44 大小:1.24MB
返回 下载 相关 举报
第二章节_字符设备驱动程序幻灯片_第1页
第1页 / 共44页
第二章节_字符设备驱动程序幻灯片_第2页
第2页 / 共44页
第二章节_字符设备驱动程序幻灯片_第3页
第3页 / 共44页
第二章节_字符设备驱动程序幻灯片_第4页
第4页 / 共44页
第二章节_字符设备驱动程序幻灯片_第5页
第5页 / 共44页
点击查看更多>>
资源描述

《第二章节_字符设备驱动程序幻灯片》由会员分享,可在线阅读,更多相关《第二章节_字符设备驱动程序幻灯片(44页珍藏版)》请在金锄头文库上搜索。

1、上章回顾,Linux设备驱动的简介,以及分类 字符设备 块设备 网络接口 模块的应用 如何编写模块 模块相关的宏 模块和应用程序的区别 编译和装载内核模块,字符设备驱动程序,第2章,预习检查,本章目标,掌握字符设备驱动程序的基本结构和开发方法 掌握用户空间调用设备驱动程序的方法,本章结构,字符设备驱动基本结构,字符设备驱动程序,用户空间调用设备驱动程序,添加驱动程序到内核,内核配置和编译方法,添加驱动程序到内核中,主要概念和结构体,实例,字符驱动的主要组成,2-1 字符设备驱动程序基本结构,字符设备开发的基本步骤 确定主设备号和次设备号 实现字符驱动程序 实现file_operations结构

2、体 实现初始化函数,注册字符设备 实现销毁函数,释放字符设备 创建设备文件节点,2-1 字符设备驱动程序基本结构,什么是主设备号/次设备号 主设备号是内核识别一个设备的标识。 整数(占12bits),范围从0到4095,通常使用1到255 次设备号由内核使用,用于正确确定设备文件所指的设备。 整数(占20bits),范围从0到1048575,一般使用0到255,2-1 字符设备驱动程序基本结构,设备编号的内部表达 dev_t类型(32位): 用来保存设备编号(包括主设备号(12位)和次设备号(20位) 从dev_t获得主设备号和次设备号: MAJOR(dev_t); MINOR(dev_t);

3、 将主设备号和次设备号转换成dev_t类型: MKDEV(int major,int minor);,2-1 字符设备驱动程序基本结构,分配主设备号 手工分配主设备号:找一个内核没有使用的主设备号来使用。,#include int register_chrdev_region( dev_t first, unsigned int count, char *name );,要分配的设备编号范围的起始值,次设备号经常为0,所请求的连续设备编号的个数,和该编号范围关联的设备名称,2-1 字符设备驱动程序基本结构,动态分配主设备号:,#include int alloc_chrdev_resion(d

4、ev_t *dev,unsigned int firstminor, unsigned int count,char *name);,输出的设备号,要使用的被请求的第一个次设备号,2-1 字符设备驱动程序基本结构,释放设备号,void unregister_chrdev_region(dev_t first, unsigned int count);,通常在模块的清除函数中调用。,2-1 字符设备驱动程序基本结构,实现字符驱动程序 cdev 结构体,struct cdev struct kobject kobj; /* 内嵌的kobject 对象 */ struct module *owner

5、; /*所属模块*/ struct file_operations *ops; /*文件操作结构体*/ struct list_head list; dev_t dev; /*设备号*/ unsigned int count; ;,2-1 字符设备驱动程序基本结构,操作cdev的函数,void cdev_init( struct cdev *, struc t file_operations *); struct cdev *cdev_alloc(void) ; int cdev_add(st ruct cdev *, dev_t, unsigned) ; void cdev_del(stru

6、ct cdev *);,用于初始化cdev的成员,并建立cdev和file_operations之间的连接,分别向系统删除一个cdev,完成字符设备的注销,通常在模块的卸载函数中调用,分别向系统添加一个cdev,完成字符设备的注册,通常在模块加载函数中调用,函数用于动态申请一个cdev 内存,2-1 字符设备驱动程序基本结构,file_operations 结构体 字符驱动和内核的接口: 在include/linux/fs.h定义 字符驱动只要实现一个file_operations结构体 并注册到内核中,内核就有了操作此设备的能力。,2-1 字符设备驱动程序基本结构,file_operatio

7、ns的主要成员: struct module *owner: 指向模块自身 open:打开设备 release:关闭设备 read:从设备上读数据 write:向设备上写数据 ioctl:I/O控制函数 llseek:定位读写指针 mmap:映射设备空间到进程的地址空间,2-1 字符设备驱动程序基本结构,file 结构体 file结构: file_operations结构相关的一个结构体。 描述一个正在打开的设备文件。 成员: loff_t f_pos: 当前读/写位置 unsigned int f_flags 标识文件打开时,是否可读或可写 O_RDONLY O_NONBLOCK O_SYN

8、C struct file_operations *f_op 文件相关的操作,指向所实现的struct file_operations void *private_data: 私有数据指针。驱动程序可以将这个字段用于任何目的或者忽略这个字段。,2-1 字符设备驱动程序基本结构,inode 结构体 内核用inode结构在内部表示文件 Inode与file的区别 file表示打开的文件描述符 多个表示打开的文件描述符的file结构,可以指向单个inode结构。,2-1 字符设备驱动程序基本结构,Inode结构中的两个主要字段: dev_t i_rdev; 对表示设备文件的inode结构,该字段包含

9、了真正的设备编号。 struct cdev *i_cdev; struct cdev是表示字符设备的内核的内部结构。 当inode指向一个字符设备文件时,该字段包含了指向struct cdev结构的指针 从一个inode中获得主设备号和次设备号:,unsigned int iminor(struct inode *inode); unsigned int imajor(struct inode *inode);,2-1 字符设备驱动程序基本结构,注册设备 ,在模块或驱动初始化时调用 Linux-2.4 及之前 Linux-2.6,int register_chrdev(unsigned int

10、 major, const char *name, struct file_operations *fops),如何操作字符设备的接口,void cdev_init( struct cdev *, struc t file_operations *); int cdev_add(st ruct cdev *, dev_t, unsigned) ;,2-1 字符设备驱动程序基本结构,注销设备:在模块卸载时调用 Linux-2.4及之前 Linux-2.6,int unregister_chrdev(unsigned int major, const char *name);,void cdev_

11、del (struct cdev *);,2-1 字符设备驱动程序基本结构,/ /设备驱动模块加载函数 static int _init xxx_init(void) . cdev_init( / /注册设备 . ,2-1 字符设备驱动程序基本结构,/*设备驱动模块卸载函数*/ static void _exit xxx_exit(void) unregister_chrdev_region(xxx_dev_no, 1); / /释放占用的设备号 cdev_del( / /注销设备 . ,2-1 字符设备驱动程序基本结构,打开 模块使用计数加1 识别次设备号 硬件操作: 检查设备相关错误(诸如

12、设备未就绪或类似的硬件问题); 如果设备是首次打开,则对其初始化; 如果有中断操作,申请中断处理程序;,int open(struct inode *inode, struct file *filp) ;,2-1 字符设备驱动程序基本结构,关闭 模块使用计数减1 释放由open分配的,保存在filpprivate_data里的所有内容。 硬件操作: 如果申请了中断,则释放中断处理程序。 在最后一次关闭操作时关闭设备。,int release(struct inode *inode, struct file *filp) ;,2-1 字符设备驱动程序基本结构,read/write,ssize_t

13、 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);,指向用户空间的缓冲区,这个缓冲区或者保存将写入的数据,或者是一个存放新读入数据的空缓冲区。,用户在文件中存取操作的位置,2-1 字符设备驱动程序基本结构,用户空间和内核空间之间的数据拷贝过程, 不能简单的用指针操作或者memcpy来进行数据拷贝 用户空间的数据是可以被换出的,会产生一

14、个页面失效异常。 用户空间的地址无法在内核空间中使用。 用户空间和内核空间之间进行数据拷贝的函数: 如果要复制的内存是简单类型,如char、int、long 等, put_user()和get_user(),unsigned long copy_from_user(void *to, const void _user *from, unsigned long count) ; unsigned long copy_to_user(void _user *to, const void *from, unsigned long count );,2-1 字符设备驱动程序基本结构,读设备模板 ssi

15、ze_t xxx_read(struct file *filp, char _user *buf, size_t count ,loff_t*f_pos) . copy_to_user(buf, ., . ); . 写设备模板 ssize_t xxx_write(struct file *fil p, const char _user *buf , size_t count ,loff_t *f_pos) . copy_from_user(., buf, . ); . ,2-1 字符设备驱动程序基本结构,ioctl函数 为设备驱动程序执行“命令”提供了一个特有的入口点 用来设置或者读取设备的属

16、性信息。,int ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);,事先定义的IO控制命令 代码,arg为对应于cmd命令的参数,2-1 字符设备驱动程序基本结构,cmd 参数的定义 不推荐用0x1,0x2,0x3之类的值 Linux对ioctl()的cmd参数有特殊的定义 构造命令编号的宏: _IO(type,nr)用于构造无参数的命令编号; _IOR(type,nr,datatype)用于构造从驱动程序中读取数据的命令编号; _IOW(type,nr,datatype)用于写入数据的命令; _IOWR(type,nr,datatype)用于双向传输。 type和number位字段通过参数传入,而size位字段通过对datatype参数取sizeof获得。,2

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

当前位置:首页 > 高等教育 > 大学课件

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