转载只为记录经典之<linux驱动简介 >

来源:互联网 发布:mac文件夹无故消失 编辑:程序博客网 时间:2024/03/29 22:28
linux驱动简介
Linux设备驱动程序是内核的一部分,它完成以下功能:
?        对设备初始化和释放
? 把数据从内核传送到硬件和从硬件读取数据
?        读取应用程序传送给设备文件的数据和回送应用程序请求的数据
?        检测和处理设备出现的错误。
系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。Linux设备驱动程序为应用程序屏蔽了硬件细节,在应用程序看来,Linux硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。每个设备驱动程序都具有以下几个特性:
1.        具有一整套的和硬件设备通讯的例程,并且提供给操作系统一套标准的软件接口;
2.        具有一个可以被操作系统动态地调用和移除的自包含组件;
3.        可以控制和管理用户程序和物理设备之间的数据流。
驱动类型
Linux设备分为三种:字符设备、块设备和网络设备。
字符设备是指存取时没有缓存,只能顺序访问的设备,一般不能进行任意长度的I/O请求。典型的字符设备包括鼠标、串行口、键盘等。字符设备接口支持面向字符的I/0操作,它不经过系统的快速缓存,所以它们负责管理自己的缓冲区结构。下面所描述的I2C接口属于字符设备。
块设备的读/写都有缓存来支持,并且块设备必须能够随机存取,字符设备则没有这个要求。块设备主要是针对磁盘等慢速设备设计的,以免损耗过多的CPU时间来等待。
网络设备在Linux里做专门的处理。Linux的网络系统主要是基于BSD Unix的Socket机制。在系统和驱动程序之间定义有专门的数据结构进行数据的传递。系统里支持对发送资料和接受资料的缓存,提供流量控制机制,提供对多协议的支持。
主次设备号
Linux给每个设备都分配一个主设备和次设备号。主设备号一般用来定义这个设备的类型。例如软驱的主设备号是2,并行端口的主设备号是6。次设备号是一个8位的数字,它指定一个特定的设备,例如一台电脑可以有2个软驱,它们都有主设备号2,但是第一个软驱的次设备号为1,而第二个软驱的次设备号为2。
在任何程序使用设备驱动程序之前,设备驱动程序应该向系统进行登记,以便系统在适当的时候调用。向系统增加一个驱动程序即给它一个主设备号,这一过程在驱动程序(模块)的初始化过程中完成,调用如下函数:
int register chrdev(major,*name ,*fops)
参数major是所请求的主设备号,name是设备的名字,它们将在/proc/devices文件中出现,fops是一个指向跳转表的指针,利用这个跳转表完成对设备函数的调用。
从系统中卸载一个模块时,应该释放主设备号。这一操作可以在cleanup_module中调用如下函数完成:
int unregister chrdev (major,*name)
参数是要释放的主设备号和相应的设备名。内核对与这个名字和设备号对应的名字进行比较,如果不同或者主设备号超出了允许的范围或是并未分配给这个设备,内核返回ENINVAL。
文件操作
Linux具有设备的无关性,它把每个设备都抽象为文件系统的一个文件。Linux为每个设备在/dev目录建立一个文件。例如,第一个软驱在文件系统中的文件名为/dev/fd。可以使用以下命令来建立设备文件:
mknod  /dev/device_name  device_type  major_number  ninor_number
其中device_name是此设备的文件,device_type是设备的类型(c表示字符设备,b表示块设备)。
Linux系统把设备当作文件一样来访问,访问文件和设备有以下函数:seek、read、write、poll、io-control、memory map、open、flush、release、check、lock等。编写设备驱动程序的主要工作就是编写子函数,并填充file-operations的各个域。并不一定要实现所有的函数,只需要实现设备必须的函数就可以了。
设备驱动使用类型为struct file_operations的一个数据结构来与上面的文件访问函数对应。一般的字符设备驱动程序适用的file-operations结构如下:
struct file_operation dev_fiops{
dev_lseek,
dev_read,
dev_write,
dev_ioctl,
dev_open,
dev_release,
};
lseek:用来修改一个文件当前的读写位置,并将新位置做为返回值返回。出错时返回一个负的返回值。
open:来为以后的操作完成作初始化准备工作的。此外,open还增加设备计数(MOD_INC_USE_COUNT),以便防止文件在关闭前模块被卸载出内核。大部分驱动程序中open完成如下工作:
检查设备相关错误,如设备未就绪或类似的硬件问题。
如果是首次打开,初始化设备。
识别次设备号,如有必要更新fop指针。
分配和填写要放在file->private_data里的数据结构。增加使用计数。驱动程序从来不知道被打开的设备名字,它仅仅知道设备号。
release:使用计数减1,释放在file->private_data中open分配的内存,在最后一次关闭操作时关闭设备。如果open没有被调用,release也不会调用。它们在系统调用间的关系保证了模块使用计数永远是一致的(MOD_INC_USE_COUNT和MOD_DEC_USE_COUNT)。
read、write:通过这两个函数可以像使用文件那样向设备传送数据,ssize(*write)(*filp, *buff, count, *offp)和 ssize(*read)(*filp, *buff, count, *offp)其中filp是文件指针,buff是指向用户的缓冲区,count是传入数据的长度,offp是用户在文件中的位置。当成功时返回值就是写入或读取的数据长度。用write函数向打开的文件写数据,用read函数从打开的文件中读数据,完成到用户空间和来自用户空间的整个数据段的复制。
利用函数copy_to_user和copy_from_user来完成用户空间和内核空间数据的传输。
Unsigned long copy_to_user(*to, *from, count)和unsigned long copy_from_user(*to, *from, count)其中to是指向数据目的缓冲区,from是指向数据源缓冲区,count是数据的长度。当成功时,返回值就是写入或读出长度,失败返回-EFAULT。
ioctl:最常用的通过设备驱动完成控制动作的方法。ioctl的调用为驱动程序执行“命令”提供了一个与设备相关的入口点。与read和其他方法不同,ioctl是与设备相关的,允许应用程序访问被驱动硬件的特殊功能:配置设备以及进入或退出操作模式,这些控制操作通常无法通过read/write文件操作完成。
 
 
http://wang11qiang11.blog.163.com/blog/static/9803010920090855656308/
原创粉丝点击