您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > 第二章 字符设备驱动程序
上章回顾Linux设备驱动的简介,以及分类字符设备块设备网络接口模块的应用如何编写模块模块相关的宏模块和应用程序的区别编译和装载内核模块字符设备驱动程序第2章预习检查本章目标掌握字符设备驱动程序的基本结构和开发方法掌握用户空间调用设备驱动程序的方法本章结构字符设备驱动基本结构字符设备驱动程序用户空间调用设备驱动程序添加驱动程序到内核内核配置和编译方法添加驱动程序到内核中主要概念和结构体实例字符驱动的主要组成2-1字符设备驱动程序基本结构字符设备开发的基本步骤确定主设备号和次设备号实现字符驱动程序实现file_operations结构体实现初始化函数,注册字符设备实现销毁函数,释放字符设备创建设备文件节点2-1字符设备驱动程序基本结构什么是主设备号/次设备号主设备号是内核识别一个设备的标识。整数(占12bits),范围从0到4095,通常使用1到255次设备号由内核使用,用于正确确定设备文件所指的设备。整数(占20bits),范围从0到1048575,一般使用0到2552-1字符设备驱动程序基本结构设备编号的内部表达dev_t类型(32位):用来保存设备编号(包括主设备号(12位)和次设备号(20位))从dev_t获得主设备号和次设备号:MAJOR(dev_t);MINOR(dev_t);将主设备号和次设备号转换成dev_t类型:MKDEV(intmajor,intminor);2-1字符设备驱动程序基本结构分配主设备号手工分配主设备号:找一个内核没有使用的主设备号来使用。#includelinux/fs.hintregister_chrdev_region(dev_tfirst,unsignedintcount,char*name);要分配的设备编号范围的起始值,次设备号经常为0所请求的连续设备编号的个数和该编号范围关联的设备名称2-1字符设备驱动程序基本结构动态分配主设备号:#includelinux/fs.hintalloc_chrdev_resion(dev_t*dev,unsignedintfirstminor,unsignedintcount,char*name);输出的设备号要使用的被请求的第一个次设备号2-1字符设备驱动程序基本结构释放设备号voidunregister_chrdev_region(dev_tfirst,unsignedintcount);通常在模块的清除函数中调用。2-1字符设备驱动程序基本结构实现字符驱动程序cdev结构体structcdev{structkobjectkobj;/*内嵌的kobject对象*/structmodule*owner;/*所属模块*/structfile_operations*ops;/*文件操作结构体*/structlist_headlist;dev_tdev;/*设备号*/unsignedintcount;};2-1字符设备驱动程序基本结构操作cdev的函数voidcdev_init(structcdev*,structfile_operations*);structcdev*cdev_alloc(void);intcdev_add(structcdev*,dev_t,unsigned);voidcdev_del(structcdev*);用于初始化cdev的成员,并建立cdev和file_operations之间的连接分别向系统删除一个cdev,完成字符设备的注销,通常在模块的卸载函数中调用分别向系统添加一个cdev,完成字符设备的注册,通常在模块加载函数中调用函数用于动态申请一个cdev内存2-1字符设备驱动程序基本结构file_operations结构体字符驱动和内核的接口:在include/linux/fs.h定义字符驱动只要实现一个file_operations结构体并注册到内核中,内核就有了操作此设备的能力。2-1字符设备驱动程序基本结构file_operations的主要成员:structmodule*owner:指向模块自身open:打开设备release:关闭设备read:从设备上读数据write:向设备上写数据ioctl:I/O控制函数llseek:定位读写指针mmap:映射设备空间到进程的地址空间2-1字符设备驱动程序基本结构file结构体file结构:file_operations结构相关的一个结构体。描述一个正在打开的设备文件。成员:loff_tf_pos:当前读/写位置unsignedintf_flags标识文件打开时,是否可读或可写O_RDONLYO_NONBLOCKO_SYNCstructfile_operations*f_op文件相关的操作,指向所实现的structfile_operationsvoid*private_data:私有数据指针。驱动程序可以将这个字段用于任何目的或者忽略这个字段。2-1字符设备驱动程序基本结构inode结构体内核用inode结构在内部表示文件Inode与file的区别file表示打开的文件描述符多个表示打开的文件描述符的file结构,可以指向单个inode结构。2-1字符设备驱动程序基本结构Inode结构中的两个主要字段:dev_ti_rdev;对表示设备文件的inode结构,该字段包含了真正的设备编号。structcdev*i_cdev;structcdev是表示字符设备的内核的内部结构。当inode指向一个字符设备文件时,该字段包含了指向structcdev结构的指针从一个inode中获得主设备号和次设备号:unsignedintiminor(structinode*inode);unsignedintimajor(structinode*inode);2-1字符设备驱动程序基本结构注册设备,在模块或驱动初始化时调用Linux-2.4及之前Linux-2.6intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops)如何操作字符设备的接口voidcdev_init(structcdev*,structfile_operations*);intcdev_add(structcdev*,dev_t,unsigned);2-1字符设备驱动程序基本结构注销设备:在模块卸载时调用Linux-2.4及之前Linux-2.6intunregister_chrdev(unsignedintmajor,constchar*name);voidcdev_del(structcdev*);2-1字符设备驱动程序基本结构//设备驱动模块加载函数staticint__initxxx_init(void){...cdev_init(&xxx_dev.cdev,&xxx_fops);//初始化cdevxxx_dev.cdev.owner=THIS_MODULE;//获取字符设备号if(xxx_major){register_chrdev_region(xxx_dev_no,1,DEV_NAME);}else{alloc_chrdev_region(&xxx_dev_no,0,1,DEV_NAME);}ret=cdev_add(&xxx_dev.cdev,xxx_dev_no,1);//注册设备...}2-1字符设备驱动程序基本结构/*设备驱动模块卸载函数*/staticvoid__exitxxx_exit(void){unregister_chrdev_region(xxx_dev_no,1);//释放占用的设备号cdev_del(&xxx_dev.cdev);//注销设备...}2-1字符设备驱动程序基本结构打开模块使用计数加1识别次设备号硬件操作:检查设备相关错误(诸如设备未就绪或类似的硬件问题);如果设备是首次打开,则对其初始化;如果有中断操作,申请中断处理程序;intopen(structinode*inode,structfile*filp);2-1字符设备驱动程序基本结构关闭模块使用计数减1释放由open分配的,保存在filpprivate_data里的所有内容。硬件操作:如果申请了中断,则释放中断处理程序。在最后一次关闭操作时关闭设备。intrelease(structinode*inode,structfile*filp);2-1字符设备驱动程序基本结构read/writessize_tread(structfile*filp,char__user*buff,size_tcount,loff_t*offp);ssize_twrite(structfile*filp,constchar__user*buff,size_tcount,loff_t*offp);指向用户空间的缓冲区,这个缓冲区或者保存将写入的数据,或者是一个存放新读入数据的空缓冲区。用户在文件中存取操作的位置2-1字符设备驱动程序基本结构用户空间和内核空间之间的数据拷贝过程,不能简单的用指针操作或者memcpy来进行数据拷贝用户空间的数据是可以被换出的,会产生一个页面失效异常。用户空间的地址无法在内核空间中使用。用户空间和内核空间之间进行数据拷贝的函数:如果要复制的内存是简单类型,如char、int、long等,put_user()和get_user()unsignedlongcopy_from_user(void*to,constvoid__user*from,unsignedlongcount);unsignedlongcopy_to_user(void__user*to,constvoid*from,unsignedlongcount);2-1字符设备驱动程序基本结构读设备模板ssize_txxx_read(structfile*filp,char__user*buf,size_tcount,loff_t*f_pos){...copy_to_user(buf,...,...);...}写设备模板ssize_txxx_write(structfile*filp,constchar__user*buf,size_tcount,loff_t*f_pos){...copy_from_user(...,buf,...);...}2-1字符设备驱动程序基本结构ioctl函数为设备驱动程序执行“命令”提供了一个特有的入口点用来设置或者读取设备的属性信息。intioctl(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg);事先定义的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获得。设备类型(type)序列号(number)方向(direction)数据尺寸(size)8bit8bit2bit13/14bit2-1字符设备驱动程序基本结构Ioctl函数模板intxxx_ioctl(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg){...switch(cmd){caseXXX_CMD1:...break;caseXXX_CMD2:...break;default:///*不能支持的命令*/return-ENOTTY;}return0;}阶段总结本节介绍了字符设备驱动结
本文标题:第二章 字符设备驱动程序
链接地址:https://www.777doc.com/doc-3973238 .html