资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,*,*,第,6,章 嵌入式,Linux,驱动程序开发,6.1,嵌入式,Linux,的设备管理,Linux,将设备分成两大类:一类是块设备,类似磁盘以记录块或扇区为单位,成块进行输入,/,输出的设备;另一类是字符设备,类似键盘以字符为单位,逐个进行输入,/,输出的设备。网路设备是介于块设备和字符设备之间的一种特殊设备。,块设备接口仅支持面向块的,I/O,操作,所有,I/O,操作都通过在内核地址空间中的,I/O,缓冲区进行,它可以支持随机存取的功能。文件系统通常都建立在块设备上。,字符设备接口支持面向字符的,I/O,操作,由于它们不经过系统的快速缓存,所以它们负责管理自己的缓冲区结构。字符设备接口只支持顺序存取的功能,一般不能进行任意长度的,I/O,请求,而是限制,I/O,请求的长度必须是设备要求的基本块长的倍数。,处理器与设备间数据交换方式,处理器与外设之间传输数据的控制方式通常有,3,种:查询方式、中断方式和直接内存存取(,DMA,)方式。,1,查询方式,设备驱动程序通过设备的,I/O,端口空间,以及存储器空间完成数据的交换。例如,网卡一般将自己的内部寄存器映射为设备的,I/O,端口,而显示卡则利用大量的存储器空间作为视频信息的存储空间。利用这些地址空间,驱动程序可以向外设发送指定的操作指令。通常来讲,由于外设的操作耗时较长,因此,当处理器实际执行了操作指令之后,驱动程序可采用查询方式等待外设完成操作。,驱动程序在提交命令之后,开始查询设备的状态寄存器,当状态寄存器表明操作完成时,驱动程序可继续后续处理。查询方式的优点是硬件开销小,使用起来比较简单。但在此方式下,,CPU,要不断地查询外设的状态,当外设未准备好时,就只能循环等待,不能执行其他程序,这样就浪费了,CPU,的大量时间,降低了处理器的利用率。,2,中断方式,查询方式白白浪费了大量的处理器时间,而中断方式才是多任务操作系统中最有效利用处理器的方式。当,CPU,进行主程序操作时,外设的数据已存入端口的数据输入寄存器,或端口的数据输出寄存器已空,此时由外设通过接口电路向,CPU,发出中断请求信号。,CPU,在满足一定条件下,暂停执行当前正在执行的主程序,转入执行相应能够进行输入,/,输出操作的子程序,待输入,/,输出操作执行完毕之后,,CPU,再返回并继续执行原来被中断的主程序。这样,,CPU,就避免了把大量时间耗费在等待、查询外设状态的操作上,使其工作效率得以大大提高。中断方式的原理示意图如图,6.1,所示。,能够向,CPU,发出中断请求的设备或事件称为中断源。中断源向,CPU,发出中断请求,若优先级别最高,则,CPU,在满足一定的条件时,可中断当前程序的运行,保护好被中断的主程序的断点及现场信息,然后根据中断源提供的信息,找到中断服务子程序的入口地址,转去执行新的程序段,这就是中断响应。,CPU,响应中断是有条件的,如内部允许中断、中断未被屏蔽、当前指令执行完等。,CPU,响应中断以后,就会中止当前的程序,转去执行一个中断服务子程序,以完成为相应设备的服务。,系统引入中断机制后,,CPU,与外设处于“并行”工作状态,便于实现信息的实时处理和系统的故障处理。,3,直接访问内存(,DMA,)方式,利用中断,系统和设备之间可以通过设备驱动程序传送数据,但是,当传送的数据量很大时,因为中断处理上的延迟,利用中断方式的效率会大大降低。而直接内存访问(,DMA,)可以解决这一问题。,DMA,可允许设备和系统内存间在没有处理器参与的情况下传输大量数据。设备驱动程序在利用,DMA,之前,需要选择,DMA,通道并定义相关寄存器,以及数据的传输方向,即读取或写入,然后将设备设定为利用该,DMA,通道传输数据。设备完成设置之后,可以立即利用该,DMA,通道在设备和系统的内存之间传输数据,传输完毕后产生中断以便通知驱动程序进行后续处理。在利用,DMA,进行数据传输的同时,处理器仍然可以继续执行指令。,设备驱动程序的概念,设备驱动程序实际是处理和操作硬件控制器的软件,从本质上讲,是内核中具有最高特权级的、驻留内存的、可共享的底层硬件处理例程。驱动程序是内核的一部分,是操作系统内核与硬件设备的直接接口,驱动程序屏蔽了硬件的细节,完成以下功能:,对设备初始化和释放;,对设备进行管理,包括实时参数设置,以及提供对设备的操作接口;,读取应用程序传送给设备文件的数据或者回送应用程序请求的数据;,检测和处理设备出现的错误。,Linux,操作系统将所有的设备全部看成文件,并通过文件的操作界面进行操作。对用户程序而言,设备驱动程序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说,是把设备映射为一个特殊的设备文件,用户程序可以像对其他文件一样对此设备文件进行操作。这意味着:,由于每一个设备至少由文件系统的一个文件代表,因而都有一个“文件名”。,应用程序通常可以通过系统调用,open(),打开设备文件,建立起与目标设备的连接。,打开了代表着目标设备的文件,即建立起与设备的连接后,可以通过,read(),、,write(),、,ioctl,(),等常规的文件操作对目标设备进行操作。,设备文件的属性由三部分信息组成:第一部分是文件的类型,第二部分是一个主设备号,第三部分是一个次设备号。其中类型和主设备号结合在一起惟一地确定了设备文件驱动程序及其界面,而次设备号则说明目标设备是同类设备中的第几个。,由于,Linux,中将设备当做文件处理,所以对设备进行操作的调用格式与对文件的操作类似,主要包括,open(),、,read(),、,write(),、,ioctl,(),、,close(),等。应用程序发出系统调用命令后,会从用户态转到核心态,通过内核将,open(),这样的系统调用转换成对物理设备的操作。,驱动程序结构,1,自动配置和初始化子程序,用来检测所需驱动的硬件设备是否工作正常、对正常工作的设备及其相关驱动程序所需要的软件状态进行初始化。,2,服务于,I/O,请求的子程序,该子程序称为驱动程序的上半部。这部分程序在执行时,系统仍认为与进行调用的进程属于同一个进程,只是由用户态变成了核心态,可以在其中调用,sleep(),等与进程运行环境有关的函数。,3,中断服务程序,又称为驱动程序的下半部,由,Linux,系统来接收硬件中断,再由系统调用中断服务子程序。,在系统内部,,I/O,设备的存取通过一组固定的入口点来进行,入口点也可以理解为设备的句柄,就是对设备进行操作的基本函数。字符型设备驱动程序提供如下几个入口点:,open,入口点。打开设备准备,I/O,操作。对字符设备文件进行打开操作,都会调用设备的,open,入口点。,open,子程序必须对将要进行的,I/O,操作做好必要的准备工作,如清除缓冲区等。如果设备是独占的,即同一时刻只能有一个程序访问此设备,则,open,子程序必须设置一些标志以表示设备处于忙状态。,close,入口点。关闭一个设备。当最后一次使用设备完成后,调用,close,子程序。独占设备必须标记设备方可再次使用。,read,入口点。从设备上读数据。对于有缓冲区的,I/O,操作,一般是从缓冲区里读数据。对字符设备文件进行读操作将调用,read,子程序。,write,入口点。往设备上写数据。对于有缓冲区的,I/O,操作,一般是把数据写入缓冲区里。对字符设备文件进行写操作将调用,write,子程序。,ioctl,入口点。执行读、写之外的操作。,select,入口点。检查设备,看数据是否可读或设备是否可用于写数据。,select,系统调用在检查与设备文件相关的文件描述符时使用,select,入口点。,struct,file_operations,struct,module*owner;,loff_t,(*,llseek,)(,struct,file*,loff_t,int,);,ssize_t,(*read)(,struct,file*,char*,size_t,loff_t,*);,ssize_t,(*write)(,struct,file*,const char*,size_t,loff_t,*);,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,datasync,);,int,(*,fasync,)(,int,struct,file*,int,);,int,(*lock)(,struct,file*,int,struct,file_lock,*);,ssize_t,(*,readv,)(,struct,file*,const,struct,iovec,*,unsigned long,loff_t,*);,ssize_t,(*,writev,)(,struct,file*,const,struct,iovec,*,unsigned long,loff_t,*);,ssize_t,(*,sendpage,)(,struct,file*,struct,page*,int,size_t,loff_t,*,int,);,unsigned long(*,get_unmapped_area,)(,struct,file*,unsigned long,unsigned long,unsigned long,unsigned long,);,;,lseek,,移动文件指针的位置,只能用于可以随机存取的设备。,read,,进行读操作,,buf,为存放读取结果的缓冲区,,count,为所要读取的数据长度。,write,,进行写操作,与,read,类似。,select,,进行选择操作。,ioctl,,进行读、写以外的其他操作。,mmap,,用于把设备的内容映射到地址空间,一般只有块设备驱动程序使用。,open,,打开设备进行,I/O,操作。返回,0,表示成功,返回负数表示失败。,release,,即,close,操作。,struct,inode,称做索引节点数据结构,定义如下:,struct,inode,struct,list_head,i_hash,;,struct,list_head,i_list,;,struct,list_head,i_dentry,;,struct,list_head,i_dirty_buffers,;,struct,list_head,i_dirty_data_buffers,;,unsigned long,i_ino,;,atomic_t,i_count,;,kdev_t,i_dev,;,umode_t,i_mode,;,nlink_t,i_nlink,;,uid_t,i_uid,;,gid_t,i_gid,;,kdev_t,i_rdev,;,loff_t,i_size,;,time_t,i_atime,;,time_t,i_mtime,;,time_t,i_ctime,;,unsigned,int,i_blkbits,;,unsigned long,i_blksize,;,unsigned long,i_blocks,
展开阅读全文