资源预览内容
第1页 / 共89页
第2页 / 共89页
第3页 / 共89页
第4页 / 共89页
第5页 / 共89页
第6页 / 共89页
第7页 / 共89页
第8页 / 共89页
第9页 / 共89页
第10页 / 共89页
亲,该文档总共89页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第5章 嵌入式设备驱动,第5章 嵌入式设备驱动,5.1 Linux下设备驱动概述 5.2 设备驱动程序的结构 5.3 字符设备驱动 5.4 LCD设备驱动 5.5 块设备驱动 5.6 键盘驱动 5.7 Linux网络驱动程序 5.8 触摸屏接口设计与Linux驱动编程,5.1 Linux下设备驱动概述,Linux系统把内核和运行在其上的应用程序分为两个层次,也就是所谓的“内核态”和“用户态”。 当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。 当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态。,因为中断处理程序将使用当前进程的内核栈。这与处于内核态的进程的状态有些类似。内核态与用户态是操作系统的两种运行级别。 Linux进程的4GB地址空间,3G-4G部分大家是共享的,是内核态的地址空间,这里存放在整个内核的代码和所有的内核模块,以及内核所维护的数据。用户运行一个程序,该程序所创建的进程开始是运行在用户态的,如果要执行文件操作,网络数据发送等操作,必须通过write,send等系统调用,这些系统调用会调用内核中的代码来完成操作,这时,必须切换到内核态,然后进入3GB-4GB中的内核地址空间去执行这些代码完成操作,完成后,切换到用户态。这样,用户态的程序就不能随意操作内核地址空间,具有一定的安全保护作用。 在内核态下,CPU可执行任何指令,在用户态下CPU只能执行非特权指令。当CPU处于内核态,可以随意进入用户态;而当CPU处于用户态,只能通过中断的方式进入内核态。一般程序一开始都是运行于用户态,当程序需要使用系统资源时,就必须通过调用软中断进入内核态。,5.1 Linux下设备驱动概述,5.1.1 设备的分类,Linux内核把系统设备被分为三类,块设备、字符设备和网络设备。 字符设备是以字符为单位输入输出数据的设备,一般不需要使用缓冲区而直接对它进行读写。 块设备是以一定大小的数据块为单位输入输出数据的,一般要使用缓冲区在设备与内存之间传送数据。 字符设备和块设备可以向文件一样被访问,例如,驱动程序都会实现open(打开)、close(关闭,或叫release)、read(读取)、write(写入)或seek(定位)等操作。 网络设备在Linux系统中一类比较特殊的设备,是通过通信网络传输数据的设备,一般指与通信网络连接的网络适配器(网卡)等。它不像字符设备和块设备那样通过对应的设备文件节点来访问,内核也不再通过read或write等系统调用去访问网络设备。Linux使用套接口(socket)以文件I/O方式提供了对网络数据的访问。,5.1 Linux下设备驱动概述,5.1.2 设备文件,Linux把所有设备都看作是特殊的文件,都纳入文件系统的范畴,例如,系统中第一个IDE硬盘使用/dev/hda来表示。系统通过处理文件的接口虚拟文件系统VFS来管理和控制各种设备。从抽象的观点出发,Linux的设备又称为设备文件。 Linux抽象了对硬件的处理,所有的硬件设备都可以作为普通文件来看待,对它们可以使用和操作文件相同,使用标准的系统调用接口来完成打开、关闭、读写和I/O控制等操作,驱动程序的主要任务也就是要实现这些系统调用函数。由于引入了设备文件这一概念,Linux为文件和设备提供了一致的用户接口,对用户来说,设备文件与普通文件并无区别。例如,用同一write()系统调用既可以向普通文件写入数据,也可以通过write()向/dev/lp0设备文件写入数据,从而把数据发给打印机。,5.1 Linux下设备驱动概述,5.1.3 主设备号与次设备号 Linux下每个设备都对应两个设备号,一个是主设备号,标识该设备的类别,也标识该设备的驱动程序;另一个是从设备号,标识使用同一个设备驱动程序的、不同的硬件设备。设备文件的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问驱动程序。 习惯上,设备文件都存在于系统的/dev目录下。使用命令#ls l /dev,可以列出系统的设备文件,下面是该命令显示的部分内容: crw- 1 root root 10, 10 Jan 30 2003 adbmouse lrwxrwxrwx 1 root root 8 Oct 10 2007 cdrom - /dev/hdc crw- 1 root root 14, 3 Jan 30 2003 dsp brw-rw- 1 root floppy 2, 0 Jan 30 2003 fd0 brw-rw- 1 root floppy 2, 4 Jan 30 2003 fd0CompaQ,5.1 Linux下设备驱动概述,5.1.3 主设备号与次设备号,例如,第一行中的设备文件名为adbmouse,这是Linux下一个鼠标的驱动程序,第一个字母为c标明是字符设备,它的主设备号是10,次设备号也是10;再如,设备文件fd0,这是Linux的软盘驱动程序,第一个字母为d,块设备,主设备号2,次设备号0。 使用命令mknod可以创建指定类型的设备文件,同时为其分配主设备号和次设备号: #mknod /dev/dsp c 14 3 命令中c表示字符设备,14是主设备号,3是次设备号。主设备号的范围是1255,次设备号可以使0255间的值。,5.1 Linux下设备驱动概述,5.1.4 设备文件系统与系统文件系统,随着Linux的发展,内核完全可以自己管理设备文件,比如“设备文件系统”(devfsdevice file system)。在Linux2.4/2.6内核中,设备文件系统可以在配制内核时定制。有了设备文件系统,Linux设备文件的创建、删除和目录层次等都由各设备驱动程序管理,再也不用手工创建设备文件节点了,再也不需要mknod时事先查找对应的主设备号了,也不要依靠复杂的脚本来管理设备文件了。有了设备文件系统,新添加或删除一个设备,比如插入一个U盘,系统就会自动地在/dev目录中创建或删除对应的设备文件节点,每个设备文件都动态地对应了一个系统上存在的设备驱动程序。 采用了设备文件系统,也带了文件设备路径兼容性方面的问题,例如,/dev/fb0是帧缓冲(framebuffer)设备,/dev/dsp是音频设备,/dev/ttyS0是系统的第一个串口设备等,但在使用设备文件系统以后,他们的路径分别变成了/dev/fb/0、/dev/sound/dsp和/dev/tts/0。不过,我们可以通过在启动脚本中加入一个简单的符号链接: ls s /dev/tb/0 /dev/fb0 ls s /dev/sound/dsp /dev/dsp ls s /dev/tts/0 /dev/ttyS0 这样就解决了对不支持设备文件系统的应用程序的兼容性问题。,5.1 Linux下设备驱动概述,5.2 设备驱动程序的结构,设备驱动程序是操作系统内核与机器硬件之间的接口,是内核的一部分,它完成以下功能:对设备初始化和释放;把数据从内核传送到硬件和从硬件读取数据;读取应用程序传送给设备文件的数据和回送应用程序请求的数据;检测和处理设备出现的错误 。,Linux的设备驱动程序在结构上可以分为三个主要组成部分: (1)自动配置和初始化子程序 (2)服务于I/O请求的子程序 (3)中断服务子程序 在操作系统内部,I/O设备的存/取是通过一组固定的入口点来进行,这组入口点是由每个设备的驱动程序提供的。具体到Linux系统,设备驱动程序所提供的这组入口点由一个文件操作结构file_operation来向系统进行说明。file_operation结构定义于内核源码include/linux/fs.h文件中。 根据具体功能划分,设备驱动程序的代码则可以划分为以下几个部分: (1)驱动程序的注册和注销。 (2)设备的打开和释放。 (3)设备的读写操作。 (4)设备的控制操作。 (5)设备的中断和轮询处理。,5.2 设备驱动程序的结构,1驱动程序的注册和注销 设备驱动程序可以在系统启动的时候初始化,也可以在需要的时候动态加载。 字符设备的初始化由chr_dev_init()完成,包括对内存(devfs_register_chrdev (MEM_MAJOR,“mem“,&memory_fops)),终端(tty_init()),打印机(lp_init()),鼠标(misc_init())等字符设备的初始化。 块设备初始化由blk_dev_init()完成,这包括对IDE硬盘(ide_init()),软盘(floppy_init()),光驱等块设备的初始化。 每个字符设备或是块设备的初始化都是通过devfs_register_chrdev()或是devfs_register_blkdev()向内核注册。在关闭字符设备或是块设备时,还需要通过devfs_unregister_chrdev()或是devfs_unregister_blkdev()从内核中注销设备。,5.2 设备驱动程序的结构,2设备的打开和释放 打开设备是由open()来完成的。例如,打印机是用lp_open()打开的,而硬盘是用hd_open()打开的。在大部分设备驱动程序中,open完成如下工作: (1)增加设备的使用计数。 (2)检查设备的相关错误,如设备尚未准备好或是类似硬件的问题。 (3)检查是首次打开,则初始化设备。 (4)识别次设备号,如有必要则更新f_op指针。 (5)如果需要,分配且设置要放在filp-private_data里的数据结构。 释放设备由release()来完成,5.2 设备驱动程序的结构,3设备的读写操作 字符设备使用各自的read()和write()来进行数据读写。例如,对虚拟终端的读写是通过vcs_read()和vcs_write()来进行数据读写的。 块设备使用通用的generic_file_read()和generic_file_write()来进行数据读写。这两个通用函数向请求表添加读写请求,内核可以通过ll_rw_block()优化请求顺序。由于是对内存缓冲区而不是设备进行操作的,因而可以加快读写请求。如果内存缓冲区内没有要读入的数据或是要将写请求写入设备,那么就要真正的执行数据传输。这是通过数据结构request_queue和request_fn()来完成(在内核源码include/linux/blkdev.h中定义)。,5.2 设备驱动程序的结构,4设备的控制操作 除了读写操作,有时还要控制设备。这可以通过设备驱动程序中的ioctl()来完成。例如IDE硬盘的控制可以通过hd_ioctl(),对光驱的控制可以通过cdrom_ioctl()。 与读写操作不同,ioctl()的用法与具体设备密切相关。以软驱的floppy_ioctl()为例(在内核源码drivers/block/floppy.c中定义): static int fd_ioctl( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param); 其中,cmd的取值及含义都是与软驱有关的,比如,FDEJECT表示弹出软盘。 除了ioctl(),设备驱动程序还可能有其他控制函数,比如llseek()等。,5.2 设备驱动程序的结构,5设备的轮询和中断处理 对于不支持中断的设备,读写时需要轮询设备状态,以及是否需要继续进行数据传输。轮询方式(polling mode)也就是查
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号