Linux设备驱动程序简介.ppt
《Linux设备驱动程序简介.ppt》由会员分享,可在线阅读,更多相关《Linux设备驱动程序简介.ppt(49页珍藏版)》请在冰豆网上搜索。
![Linux设备驱动程序简介.ppt](https://file1.bdocx.com/fileroot1/2022-10/7/484becd3-9109-4dab-b372-4e695cc83ad6/484becd3-9109-4dab-b372-4e695cc83ad61.gif)
让驱动程序不再神秘,Linux下的设备驱动程序,Linux简介,Linux是类UNIX操作系统的一个分支,最初是由Linus于1991年为基于Intel80386的IBM兼容机开发的。
Linux只是一个内核的标识,不同于我们平时所说的RedHatLinux,TurbLinux等发行版本,这些发行版本除了内核外还包括了不同的外部应用程序以方便用户使用和管理操作系统。
(我们以RedHat为例),什么是设备驱动程序,设备驱动程序就是外部设备的软件抽象,或者说是软件表现,系统调用接口,设备1,设备2,设备3,驱动1,驱动2,驱动3,用户程序,用户空间,内核空间,内核子系统,其它模块,其它模块,硬件,驱动程序有什么用,设备驱动程序都是一个个独立的“黑盒子”,使某个特定的硬件响应一个定义良好的内部编程接口,同时完全隐藏了设备的工作细节。
用户操作通过一组标准化的系统调用完成。
驱动程序就是将这些调用映射到作用于实际硬件的设备特定的操作上。
操作系统内核的功能,进程管理内存管理文件系统设备控制网络功能,操作系统内核的功能,进程管理:
内核的进程管理活动就是在单个或多个CPU上实现多个进程的抽象。
内存管理:
内核在有限的可用内存资源上为每个进程都创建了一个虚拟寻址空间。
文件系统:
Linux(Unix)中的每个对象几乎都可以被看作文件。
内核在没有结构的硬件上构造结构化的文件系统,所构造的文件系统抽象在整个系统中被广泛使用。
另外,Linux支持多种文件系统类型,如符合Linux标准的ext2文件系统和常用的FAT文件系统等。
网络功能:
大部分网络操作都和具体进程无关数据包的传入是异步事件。
所以网络功能也必须由操作系统来管理设备控制:
几乎每个系统操作最终都会映射到物理设备上。
除了处理器、内存以及其它很有限的几个实体外,所有设备控制操作都由与被控制设备相关的代码来完成,这段代码就叫做设备驱动程序,操作系统内核的功能,模块化的驱动程序,为了使系统更有效的运行,Linux支持内核的动态扩展,即在系统运行时给内核增加新的功能(模块)。
驱动程序就是几个可以模块化的功能之一。
这也是Linux下驱动程序与Windows下驱动程序的最大区别。
什么是模块,模块是一段没有链接的目标代码(.o),它可由insmod程序(installmodule)动态的链接到正在运行的内核。
链接后,它就成了内核的一部分,直到用rmmod程序解除链接。
系统内核,驱动程序,系统内核,驱动程序,将驱动程序加入到内核中,系统内核,核心模块与应用程序的对比,世界上最简单的驱动程序,#defineMODULE#includeintinit_module(void)printk(“HelloWorld!
n”);return0;voidcleanup_module(void)printk(“Goodbye!
n”);,root#gccchelloworld.c(因为c表示只生成目标文件,不进行连接)root#insmodhelloworld.oHelloWorld!
root#lsmod(显示拥有的模块)ModuleSizeUsedbyhelloworld4640(unused),root#rmmodhelloworld(卸载模块)Goodbye!
设备驱动程序分类,字符设备块设备网络接口设备,字符设备,字符设备是能够像字节流(例如文件)一样被访问的设备,一般不使用缓存技术。
字符设备驱动程序实现这种特性至少需要实现open、close、read和write系统调用。
块设备,对块设备来说,最大的不同就是能够容纳文件系统(例如磁盘),并且大都使用缓存技术。
块设备和字符设备的区别仅仅在于内核内部管理数据的方式,也就是内核和驱动程序的接口不同。
然而这些差异对用户是透明的。
另外,块设备的接口必须支持挂载(mount)文件系统。
网络接口,任何网络事务都要经过一个网络接口来完成。
网络接口由内核中的网络子系统驱动,负责发送和接收数据包,但它无需了解每项事务是如何映射到实际传送的数据包的。
内核和网络驱动程序之间的通信完全不同于内核和字符以及块设备驱动程序之间的通信,内核调用一套和数据包传输相关的函数,而不是read、write等。
初识两个结构,File结构:
在内核中标识一个打开的设备file_operations结构:
用于访问驱动程序的函数如果用面向对象的概念来考虑问题,那么file可以看作一个对象,而操作它的函数(由file_operations结构标识)就是对象的方法。
File结构,file结构是在中定义的一个数据结构,用来代表一个打开的文件(包括设备文件和普通文件)。
它与用户空间程序中的FILE没有任何关联。
Structfilemode_tf_mode,Loff_tf_pos,unsignedintf_flags,structfile_operations*f_op,void*private_data,structdentry*f_dentry,file_operations结构,file_operations结构是一个定义在中的函数指针数组。
每个文件都通过file结构中的f_op字段与它自己的函数集相关联。
这些函数负责系统调用的实现,而这个结构负责系统调用的映射。
Structfile_operationsssize_t(*read)(structfile*,char*,size_t,loff_t*),ssize_t(*write)(structfile*,char*,size_t,loff_t*)int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong),int(*open)(structinode*,strctfile*),这两个数据结构是我们理解一个驱动程序的最基本的数据结构。
file结构是系统生成的,编写驱动程序时会用就行。
而file_operations是要开发者自己来写的。
这个数据结构是我们学习的重点,它可采用如下的方式来声明:
structfile_operationsmydev_fops=llseek:
mydev_llseek,read:
mydev_read,write:
mydev_write,ioctl:
mydev_ioctl,open:
mydev_open,release:
mydev_release,;,设备驱动在系统内部的组织,主设备号次设备号在系统中,设备类型和主设备号唯一标识驱动程序,而次设备号是由主设备号确定的驱动程序来使用的,它对系统没有任何意义。
在驱动程序中,次设备号用来区分共享同一驱动的不同设备或者不同功能。
驱动程序向系统注册,intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);在传统方式下,向系统添加一个驱动程序必须首先为其分配一个主设备号。
参数major就是显式的为该驱动分配的主设备号。
也可以动态的分配(major0)。
一个完整的驱动程序框架,#include#include#include#include#include#defineDEV_NAMETestDevice#defineDEV_MAJOR0#defineREAD_BUF_SIZExxx#defineWRITE_BUF_SIZExxx,intmajor=DEV_MAJORstructMydeviceconstchar*name;/*设备的名字*/unsignedintmajor;/*主设备号*/unsignedintminor;/*次设备号*/devfs_handle_tdevfs;/*设备文件节点*/unsignedchar*read_buffer;/*读缓冲区*/unsignedchar*write_buffer;/*写缓冲区*/wait_queue_head_tread_queue;/*读等待队列*/wait_queue_head_twrite_queue;/*写等待队列*/structsemaphoresem;/*竞态时用到的信号量*/;,intmy_open(structinode*inode,structfile*filp)structMydevice*dev=kmalloc(sizeof(structMydevice),GFP_KERNEL);if(dev=NULL)printk(KERN_ALERTallocatedevicememoryfailed.n);return(-ENOMEM);dev-name=DEV_NAME;dev-major=MAJOR(inode-i_rdev);dev-minor=MINOR(inode-i_rdev);dev-read_buffer=kmalloc(sizeof(READ_BUF_SIZE),GFP_KERNEL);if(dev-read_buffer=NULL)printk(KERN_ALERTallocatereadbuffermemoryfailed.n);dev-write_buffer=kmalloc(sizeof(WRITE_BUF_SIZE),GFP_KERNEL);if(dev-read_buffer=NULL)printk(KERN_ALERTallocatewritebuffermemoryfailed.n);init_waitqueue_head(,intmy_release(structinode*inode,structfile*filp)structMydevice*dev=filp-private_data;if(dev-read_buffer!
=NULL)kfree(dev-read_buffer);if(dev-write_buffer!
=NULL)kfree(dev-write_buffer);kfree(dev);MOD_DEC_USE_COUNT;printk(ThefunctionofMyreleasehasbeencalled!
n);return0;,ssize_tmy_read(structfile*filp,char*buf,size_tcount,loff_t*offp)char*pdata=kmalloc(sizeof(count),GFP_KERNEL);if(pdata=NULL)return(-ENOMEM);copy_to_user(buf,pdata,count);*offp+=count;printk(ThefunctionofMyreadhasbeencalled!
n);returncount;,ssize_tmy_write(structfile*filp,char*buf,size_tcount,loff_t*offp)char*pdata=kmalloc(sizeof(count),GFP_KERNEL);if(pdata=NULL)return(-ENOMEM);copy_from_user(pdata,buf,count);*offp+=count;printk(ThefunctionofMyreadhasbeencalled!
n);returncount;,intmy_ioctl(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg)switch(cmd)case1:
printk(Thisiscommand1!
n);break;case2:
printk(Thisiscommand2!
n);break;case3:
printk(Thisiscommand3!
n);break