第11章嵌入式Linux设备驱动程序ppt课件.ppt
《第11章嵌入式Linux设备驱动程序ppt课件.ppt》由会员分享,可在线阅读,更多相关《第11章嵌入式Linux设备驱动程序ppt课件.ppt(57页珍藏版)》请在三一办公上搜索。
1、1,第11章 嵌入式Linux设备驱动程序,2,11.4 Linux设备驱动程序开发,设备驱动程序开发流程(字符设备)模块化的驱动程序设计方式(字符设备)字符型设备驱动demo源程序分析LED驱动程序开发实例键盘驱动程序开发实例,3,11.4.1 设备驱动程序开发流程,定义主、次设备号,也可以动态获取。通过file_operations结构定义设备所需的文件操作:所定义的文件操作对应的file_operations结构体函数指针,指向相应的设备操作函数(设备驱动程序的各个函数)实现设备驱动初始化函数-申请中断(如果有)、注册设备和退出函数释放中断(如果有)、卸载设备。如果驱动程序采用模块方式,
2、则要实现模块的初始化和退出函数。实现设备所需的文件操作:相应的设备操作函数(设备驱动程序的各个函数)实现实现中断服务程序(如果有)将驱动编译到内核。如果驱动程序采用模块方式,需先编译成模块,然后加载。,4,11.4.2 模块化的驱动程序设计方式,模块机制“module”可以根据需要在不重新编译内核的情况下,将编译好的模块动态的插入运行中的内核,或者从运行中内核中将内核已经存在的一个模块移走。这种机制可以动态加载设备驱动程序到内核,为驱动程序开发调试提供了很大的方便在调试的过程中一般使用模块动态加载的方式,它的调试效率较高。当驱动调试完成后,在发行的过程就集成进内核。但编译进内核是某些驱动运行的
3、唯一方法。例如:console驱动,flash驱动和对至少一种文件系统的支持等等,5,11.4.2 模块化的驱动程序设计方式,用gcc编译成模块,要加上以下参数:-D_KERNEL_-DMODULE I$(KERNELDIR_INCLUDE)在内核运行时,可以通过lsmod 察看内核中已经动态加载的模块。而模块加载到内核和从内核中卸载可以通过以下命令实现,它们的操作对象xxxx是经过编译但没有链接的.ko 文件(实际上就是.o文件,在2.4版本及之前不用.ko文件,直接就沿用为.o文件)insmod xxxx 将编译的模块直接插入内核rmmod xxxx 将编译的模块从内核中卸载,6,11.4
4、.2 模块化的驱动程序设计方式,以驱动程序源文件为demo.c为例 驱动程序的编译(生成模块)gcc c-D_KERNEL_-DMODULE-I/usr/src/linux-2.4/include demo.c-o demo.ko 加载驱动(模块):insmod demo.ko 卸载驱动(模块):rmmod demo.ko对应的模块化驱动程序编程中,设备驱动程序源程序中必须至少提供两个宏:module_init(驱动程序初始化函数名):初始化模块的宏,在模块加载时调用module_exit(驱动程序退出函数名):卸载模块的宏,在模块卸载时调用,7,11.4.2 模块化的驱动程序设计方式,例:一
5、个简单的模块化设备驱动程序/*-mdemo.c-*/#define MODULE#include int init_module(void)printk(nhello,world!nn”);return 0;void cleanup_module(void)printk(n Bye Byenn);module_init(init_module);module_exit(cleanup_module);,8,11.4.2 模块化的驱动程序设计方式,首先通过下面命令来编译源文件mdemo.c:gcc-c-D_KERNEL_-DMODULE-o mdemo.ko mdemo.c在得到了mdemo.k
6、o模块文件后,用insmod 命令把它动态加载到内核:#insmod mdemo.ko#hello world!#rmmod mdemo.ko#Bye Bye,9,驱动程序与应用程序的区别设备驱动程序在Linux内核中以模块形式出现,与应用程序的执行过程不同,模块通常只是预先向内核注册自己,当内核需要时才被调用执行。,11.4.2 模块化的驱动程序设计方式,10,驱动程序与应用程序的区别应用程序一般有一个main函数,从头到尾执行一个任务;驱动程序却不同,它没有main函数,因为它实际上只是在内核中可供调用的函数。应用程序可以和C函数库链接,因此可以包含标准的头文件,比如、等;在驱动程序中是不
7、能使用标准C 库的,因此不能调用C库函数,只能调用内核函数。eg:比如输出打印函数只能使用内核的printk 函数,包含的头文件只能是内核的头文件,比如,11.4.2 模块化的驱动程序设计方式,11,假设有一个简单的虚拟字符型设备设备名为“demo”设备中只有一个20个字节的缓冲区drv_buf(位于内核空间),对该设备的读写操作就是对缓冲区drv_buf的操作由于没有实际的硬件设备,故不需要驱动程序的下半部分,更加不需要采用中断方式实现,11.4.3 字符型设备驱动demo源程序分析,12,demo设备的驱动程序结构,11.4.3 字符型设备驱动demo源程序分析,13,/*头文件*/#in
8、clude#include#include/*printk()*/#include/*error codes*/#include/*定义主、次设备号*/#define DEVICE_NAME“demo”/*设备名*/#define demo_MINOR 0/*定义次设备号*/static int demo_MAJOR 0/*自动获取主设备号*/设备文件系统支持#ifdefCONFIG_DEVFS_FS staticdevfs_handle_t devfs_DbDemo_dir,devfs_DbDemoRaw;#endif/*定义虚拟字符型设备demo的内存数据结构*/#define MAX_B
9、UF_LEN 20static char drv_bufMAX_BUF_LEN;/*处于内核空间*/,11.4.3 字符型设备驱动demo源程序分析,14,/*函数声明*/static int demo_init(void);/*声明初始化函数*/static void demo_exit(void);/*声明退出函数*/*设备操作函数(设备驱动程序的各个函数)声明*/static int demo_open(struct inode*inode,struct file*filp);static int demo_release(struct inode*inode,struct file*f
10、ilp);static ssize_t demo_read(struct file*filp,char*buffer,size_t count,loff_t*ppos);static ssize_t demo_write(struct file*filp,const char*buffer,size_t count);static int demo_ioctl(struct inode*inode,struct file*file,unsigned int cmd,unsigned long arg);,11.4.3 字符型设备驱动demo源程序分析,15,/*全局变量定义*/*通过file_
11、operations结构定义设备所需的文件操作:指向相应的设备操作函数(设备驱动程序的各个函数)*/static struct file_operations demo_fops=#if LINUX_KERNEL_VERSION=KERNEL_VERSION(2,4,0)owner:THIS_MODULE,#endifllseek:NULL,write:demo_write,read:demo_read,ioctl:demo_ioctl,open:demo_open,release:demo_release,;,11.4.3 字符型设备驱动demo源程序分析,16,/*实现初始化和退出函数*/
12、static int demo_init(void)int result;result=register_chrdev(demo_MAJOR,DEVICE_NAME,11.4.3 字符型设备驱动demo源程序分析,demo_fops指向file_operations结构体变量,17,在LINUX 2.4内核中引入了设备文件系统(devfs),它是文件系统的一部分。有了设备文件系统的支持,可以在设备驱动程序中自动创建设备文件(节点文件)。以前的Linux版本需要手工创建设备文件先给register_chrdev()传递0主设备号,以动态分配获得可用的主设备号后可在devfs_register()
13、中指定次设备号 devfs下,设备文件命名规则比以前的Linux版本也发生了变化,多创建了一层目录:主设备号建立一个设备目录,再将具体的设备实例建立在此目录下 Eg:串口0 设备为:/dev/tts/0,11.4.3 字符型设备驱动demo源程序分析,18,11.4.3 字符型设备驱动demo源程序分析,devfs相关函数devfs_mk_dir 函数,创建一个名为demo的设备文件目录(/dev/demo),并返回一个带有目录结构的数据结构变量devfs_DbDemo_dir。将该变量作为下一步devfs_register 函数的参数。该参数在调用设备文件系统注册清除函数devfs_unre
14、gister 时也要作为参数传入devfs_register 函数在刚才创建的demo目录下再创建一个名为0的设备文件(节点文件)。该函数的参数中,DEVFS_FL_DEFAULT 为该函数的标志选项,demo_MAJOR为注册字符设备时系统自动分配的主设备号,demo_MINOR为次设备号,S_IFCHR|S_IRUSR|S_IWUSR 为默认的文件模式,&s3c2410_fops 为传入内核的demo设备file_operations 变量。该函数返回一个devfs_handle_t 数据结构的变量devfs_DbDemoRaw。这在调用设备文件系统注册清除函数devfs_unregist
15、er 时也要作为参数传入,19,/*实现退出函数*/static void demo_exit(void)/删除设备文件(节点文件)#ifdefCONFIG_DEVFS_FS devfs_unregister(devfs_DbDemoRaw);devfs_unregister(devfs_DbDemo_dir);#endif unregister_chrdev(demo_MAJOR,DEVICE_NAME);printk(DEVICE_NAME“unloadedn);/*实现模块初始化和退出函数*/module_init(demo_init);module_exit(demo_exit);,1
16、1.4.3 字符型设备驱动demo源程序分析,20,/*实现设备所需的文件操作:相应的设备操作函数(设备驱动程序的各个函数)实现*/static int demo_open(struct inode*inode,struct file*filp)MOD_INC_USE_COUNT;/维护递增计数器,2.6不再支持/you can insert your code hereprintk(device open sucess!n);return 0;static int demo_release(struct inode*inode,struct file*filp)MOD_DEC_USE_COU
17、NT;/维护递增计数器,2.6不再支持/you can insert your code hereprintk(device releasen);return 0;,11.4.3 字符型设备驱动demo源程序分析,21,打开设备open,通常情况下完成如下工作:检查设备如果设备是首次打开,则对其进行初始化,为后续的设备操作做准备分配用于存放设备相关数据结构的内存空间一般会递增使用计数,防止文件关闭前模块被卸载(Linux 2.6不再需要)识别次设备号,11.4.3 字符型设备驱动demo源程序分析,释放设备release,与open正好相反释放由open分配的内存空间使用计数减一(Linux
18、2.6不再需要)在最后一次关闭操作时关闭设备,22,static ssize_t demo_read(struct file*filp,char*buffer,size_t count,loff_t*ppos)if(count MAX_BUF_LEN)count=MAX_BUF_LEN;/you can insert your code herecopy_to_user(buffer,drv_buf,count);printk(user read data from drivern);return count;static ssize_t demo_write(struct file*filp
19、,const char*buffer,size_t count)/you can insert your code herecopy_from_user(drv_buf,buffer,count);printk(user write data to drivern);/your code herereturn count;,11.4.3 字符型设备驱动demo源程序分析,用户空间,内核空间,/*实现设备所需的文件操作:相应的设备操作函数(设备驱动程序的各个函数)实现*/,23,读写设备(1/3):,read函数将数据从内核空间拷贝到应用程序用户空间,write函数则将数据从用户空间拷贝到内核空
20、间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);其中,filp是文件指针count是请求传输的数据长度buff是指向用户空间的缓存区,这个缓存区或者是一个存放从内核读入数据的空缓冲区,或者保存要写入到内核的数据loffp是一个指向“long offset type(长偏移量类型)”的指针,指明用户在文件中进行存取操作的位置,11.4.3 字符型设备驱动demo源程序
21、分析,24,读写设备(2/3):,问题:buff为用户空间的地址指针,处于内核空间的设备驱动程序不能直接访问其中的内容原因:用户空间的指针可能是无效的,该地址可能根本就无法映射到内核空间用户空间的内存可以被换出,因此可能会出现页面失效的问题从安全角度考虑解决办法:使用内核函数进行数据拷贝,11.4.3 字符型设备驱动demo源程序分析,25,内核数据拷贝函数unsigned long copy_to_user(void*to,const void*from,unsigned long count);unsigned long copy_from_user(void*to,const void*
22、from,unsigned long count);其中:to表示数据目的缓冲区 from表示数据源缓冲区 count表示数据长度返回值:成功,返回数据长度 失败,返回EFAULT这两个函数不仅要拷贝数据,还要检查指针有效性,读写设备(3/3):,11.4.3 字符型设备驱动demo源程序分析,26,static int demo_ioctl(struct inode*inode,struct file*file,unsigned int cmd,unsigned long arg)/you can insert your code hereprintk(ioctl runingn);swit
23、ch(cmd)case 1:printk(runing command 1 n);break;case 2:printk(runing command 2 n);break;default:printk(error cmd numbern);break;return 0;,11.4.3 字符型设备驱动demo源程序分析,/*实现设备所需的文件操作:相应的设备操作函数(设备驱动程序的各个函数)实现*/,27,ioctl函数:int(*ioctl)(struct inode*inode,struct file*filp,unsigned int cmd,unsigned long arg);其中,
24、cmd是用户传递给驱动程序的命令,arg为该命令的参数,读写以外的I/O控制操作函数:,11.4.3 字符型设备驱动demo源程序分析,28,#include#include#include#include main()int fd,num;char buf10;/打开demo设备 fd=open(/dev/demo/0,O_RDWR,S_IRUSR|S_IWUSR);if(fd!=-1)/初次读demo read(fd,buf,10);printf(The demo is%sn,buf);,应用程序:用于测试驱动程序(1/3),11.4.3 字符型设备驱动demo源程序分析,29,/写dem
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 11 嵌入式 Linux 设备 驱动程序 ppt 课件
链接地址:https://www.31ppt.com/p-2103667.html