资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,嵌入式应用程序设计,第,8,章 嵌入式,Linux,设备驱动编程,第,1,章 搭建嵌入式,Linux,开发环境,第,2,章 嵌入式文件,I/O,编程,第,3,章 嵌入式,Linux,多任务编程,第,4,章 嵌入式,Linux,进程间通行,第,5,章 嵌入式,Linux,多线程编程,第,6,章 嵌入式,Linux,网络编程,第,7,章,Qt,图形编程,第,8,章 嵌入式,Linux,设备驱动编程,第,9,章,Qt,聊天项目设计,课程安排,:,2,8.1,设备驱动编程基础,8.2,字符设备驱动编程,8.3 GPIO,驱动程序实例,8.4,按键驱动编程实例,8.5,小结,8.6,思考与练习,本章课程:,3,8.1.1 Linux,设备驱动概述,设备驱动概念,操作系统是通过各种驱动程序来驾驭硬件设备的,它为用户屏蔽了各种各样的设备,驱动硬件是操作系统最基本的功能,并且提供统一的操作方式。设备驱动程序是操作系统最基本的组成部分之一,在,Linux,内核源程序中也占有,60%,以上。因此,熟悉驱动的编写是很重要的。,Linux,的一个重要特点就是将所有的设备都当做文件进行处理,这一类特殊文件就是设备文件(通常在,/dev,目录下),这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作,这样就大大方便了对设备的处理。,8.1,设备驱动编程基础,4,8.1.1 Linux,设备驱动概述,Linux,系统的设备分为三类:字符设备、块设备和网络设备。,字符设备通常指像普通文件或字节流一样,以字节为单位顺序读写的设备,如并口设备、虚拟控制台等。,块设备通常指一些需要以块为单位随机读写的设备,如,IDE,硬盘、,SCSI,硬盘、光驱等。,网络设备通常是指通过网络能够与其他主机进行数据通信的设备,如网卡等。,8.1,设备驱动编程基础,5,8.1.1 Linux,设备驱动概述,设备驱动程序的特点,内核代码,内核接口,内核机制和服务,可装载,可设置,动态性,8.1,设备驱动编程基础,6,8.1.1 Linux,设备驱动概述,设备驱动程序与整个软硬件系统的关系,8.1,设备驱动编程基础,7,8.1.2 Linux,内核模块编程,设备驱动和内核模块,Linux,设备驱动属于内核的一部分,,Linux,内核的一个模块可以以两种方式被编译和加载。,直接编译进,Linux,内核,随同,Linux,启动时加载;,编译成一个可加载和删除的模块。,8.1,设备驱动编程基础,8,8.1.2 Linux,内核模块编程,模块相关命令,lsmod,列出当前系统中加载的模块,rmmod,是用于将当前模块卸载。,insmod,和,modprobe,是用于加载当前模块,8.1,设备驱动编程基础,9,8.1.2 Linux,内核模块编程,Linux,内核模块编程,一个,Linux,内核模块主要由以下几个部分组成。,模块加载函数(必须),模块卸载函数(必须),模块许可证声明(必须,模块参数(可选),模块导出符号(可选),模块作者等信息声明(可选),8.1,设备驱动编程基础,10,8.1.2 Linux,内核模块编程,Linux,内核模块编程,模块加载函数,static,int,_init,initialization_function(void,),/*,初始化代码*,/,module_init,(initialization_function,);,模块卸载函数,static void _exit,cleanup_function(void,),/*,释放代码*,/,module_exit(cleanup_function,);,8.1,设备驱动编程基础,11,8.1.2 Linux,内核模块编程,Linux,内核模块编程,通常来说,模块卸载函数要完成与模块加载函数相反的功能,若模块加载函数注册,XXX,,则模块卸载函数应该注销,XXX,。,若模块加载函数动态申请了内存,则模块卸载函数应释放该内存。,若模块加载函数申请了硬件资源(中断、,DMA,通道、,I/O,端口和,I/O,内存等,),的占用,则模块卸载函数应释放这些硬件资源。,若模块加载函数开启了硬件,则卸载函数中一般要关闭硬件。,8.1,设备驱动编程基础,12,8.1.2 Linux,内核模块编程,Linux,内核模块编程,模块参数,“,module_param,(,参数名,参数类型,参数读,/,写权限,)”,为模块定义一个参数,static char*,str_param,=Linux Module Program;,static,int,num_param,=4000;,module_param(num_param,int,S_IRUGO);,module_param(str_param,charp,S_IRUGO);,8.1,设备驱动编程基础,13,8.1.2 Linux,内核模块编程,Linux,内核模块编程,导出符号,EXPORT_SYMBOL,(,符号名,);,EXPORT_SYMBOL_GPL,(,符号名,);,模块声明与描述,MODULE_AUTHOR,(author,);,MODULE_DESCRIPTION,(description,);,MODULE_VERSION,(version_string,);,MODULE_DEVICE_TABLE,(table_info,);,MODULE_ALIAS,(alternate_name,);,8.1,设备驱动编程基础,14,8.1.2 Linux,内核模块编程,Linux,内核模块编程,模块的使用计数,Linux 2.4,内核中,模块自身通过,MOD_INC_USE_COUNT,、,MOD_DEC_USE_COUNT,宏来管理自己被使用的计数。,Linux 2.6,内核提供了模块计数管理接口,try_module_get(&module,),和,module_put,(&module),,从而取代,Linux 2.4,内核中的模块使用计数管理宏。,8.1,设备驱动编程基础,15,8.1.2 Linux,内核模块编程,Linux,内核模块编程,模块编译,我们可以为,HelloWorld,模块程序编写一个简单的,Makefile,,如下所示:,obj-m,:=,hello.o,并使用如下命令编译,HelloWorld,模块,如下所示:,$make-C/usr/src/linux-2.6.15.5/M=/,driver_study,/modules,如果当前处于模块所在的目录,以下命令与上述命令同等:,$make C/usr/src/linux-2.6.15.5 M=$(,pwd,)modules,8.1,设备驱动编程基础,16,8.1.2 Linux,内核模块编程,Linux,内核模块编程,模块与,GPL,对于自己编写的驱动等内核代码,如果不编译为模块则无法绕开,GPL,,编译为模块后企业在产品中使用模块。,8.1,设备驱动编程基础,17,8.1.2 Linux,内核模块编程,Linux,内核模块编程,内核模块示例,8.1,设备驱动编程基础,18,8.2.1,字符设备驱动编写流程,8.2,字符设备驱动编程,19,8.2.2,重要数据结构,file_operations,struct,file_operations,loff_t,(*,llseek,)(,struct,file*,loff_t,int,);,ssize_t,(*read)(,struct,file*,filp,char*buff,size_t,count,loff_t,*,offp,);,ssize_t,(*write)(,struct,file*,filp,const char*buff,size_t,count,loff_t,*,offp,);,int,(*,readdir,)(,struct,file*,void*,filldir_t,);,unsigned,int,(*poll)(,struct,file*,struct,poll_table_struct,*);,int,(*,ioctl,)(,struct,inode,*,struct,file*,unsigned,int,unsigned long);,int,(*,mmap,)(,struct,file*,struct,vm_area_struct,*);,int,(*open)(,struct,inode,*,struct,file*);,int,(*flush)(,struct,file*);,int,(*release)(,struct,inode,*,struct,file*);,int,(*,fsync,)(,struct,file*,struct,dentry,*);,int(*fasync)(int,struct file*,int);,int(*check_media_change)(kdev_t dev);,int(*revalidate)(kdev_t dev);,int,(*lock)(,struct,file*,int,struct,file_lock,*);,;,8.2,字符设备驱动编程,20,8.2.2,重要数据结构,struct,inode,结构提供了关于设备文件,/dev/driver,(假设此设备名为,driver,)的信息,,file,结构提供关于被打开的文件信息,主要用于与文件系统对应的设备驱动程序使用。,struct,file,mode_t,f_mode,;/*,标识文件是否可读或可写,,FMODE_READ,或,FMODE_WRITE*/,dev_t,f_rdev,;/*,用于,/dev/,tty,*/,off_t,f_pos,;/*,当前文件位移*,/,unsigned short,f_flags,;/*,文件标志,如,O_RDONLY,、,O_NONBLOCK,和,O_SYNC*/,unsigned short,f_count,;/*,打开的文件数目*,/,unsigned short,f_reada,;,struct,inode,*,f_inode,;/*,指向,inode,的结构指针*,/,struct,file_operations,*,f_op,;/*,文件索引指针*,/,;,8.2,字符设备驱动编程,21,8.2.3,设备驱动程序主要组成,早期版本的字符设备注册,register_chrdev,(),unregister_chrdev,(),8.2,字符设备驱动编程,22,8.2.3,设备驱动程序主要组成,早期版本的字符设备注册,unregister_chrdev,(),8.2,字符设备驱动编程,23,8.2.3,设备驱动程序主要组成,设备号相关函数,获取设备号,MAJOR(dev_t,dev);,/*,获得主设备号*,/,MINOR(dev_t,dev);,/*,获得次设备号*,/,MKDEV(int,major,int,minor);,设备注册于注销,8.2,字符设备驱动编程,24,8.2.3,设备驱动程序主要组成,设备号相关函数,获取设备号,MAJOR(dev_t,dev);,/*,获得主设备号*,/,MINOR(dev_t,dev);,/*,获得次设备号*,/,MKDEV(int,major,int,minor);,设备注册于注销,8.2,字符设备驱动编程,25,8.2.3,设备驱动程序主要组成,新版本设备注册,8.2,字符设备驱动编程,26,8.2.3,设备驱动程序主要组成,打开设备,int,(*open)(,struct,inode,*,struct,file*)
展开阅读全文