寻找严肃、沉默和专注的力量。
分类: LINUX
2013-02-03 15:51:48
概述
操作系统的目的之一就是将系统硬件设备细节从用户视线中隐藏起来。例如虚拟文件系统对各种类型已安装的文件系统提供了统一的视图而屏蔽了具体底层细节。
CPU 并不是系统中唯一的智能设备,每个物理设备都拥有自己的控制器。每个硬件控制器都有各自的控制和状态寄存器(CSR)并且各不相同。在Linux 中管理硬件设备控制器的代码并没有放置在每个应用程序中而是由内核统一管理。这些处理和管理硬件控制器的软件就是设备驱动。Linux 核心设备驱动是一组运行在特权级上的内存驻留底层硬件处理共享库。正是它们负责管理各个设备。
设备驱动的一个基本特征是设备处理的抽象概念。所有硬件设备都被看成普通文件;可以通过和操纵普通文件相同的标准系统调用来打开、关闭、读取和写入设备。Linux 支持三类硬件设备:字符、块及网络设备。字符设备指那些无需缓冲直接读写的设备,如系统的串口设备/dev/ttyS0,/dev/ttyS1等。块设备则仅能以块为单位读写,典型的块大小为512 或1024 字节。块设备的存取是通过buffercache 来进行并且可以进行随机访问,即不管块位于设备中何处都可以对其进行读写。块设备可以通过其设备相关文件进行访问,但更为平常的访问方法是通过文件系统。只有块设备才能支持可安装文件系统。网络设备可以通过BSD 套接口访问。
这些存在于内核中的不同的设备驱动具有一些共性:
1.核心代码:设备驱动是内核的一部分,象内核中其它代码一样,出错将导致系统的严重损伤。
2.核心接口:设备驱动必须为Linux 内核或者其从属子系统提供一个标准接口。
3.核心机制与服务:设备驱动可以使用标准的核心服务如内存分配、中断发送和等待队列等等。
4.动态可加载:多数Linux 设备驱动可以在核心模块发出加载请求时加载,同时在不再使用时卸载。
5.可配置:Linux 设备驱动可以连接到核心中。当核心被编译时,哪些核心被连入核心是可配置的。
6.动态性:当系统启动及设备驱动初始化时将查找它所控制的硬件设备。
轮询与中断
设备被执行某个命令时,设备驱动可以从轮询方式和中断方式中选择一种以判断设备是否已经完成此命令。轮询方式意味着需要经常读取设备的状态,一直到设备状态表明请求已经完成为止。如果设备驱动被连接进入核心,这时使用轮询方式将会带来灾难性后果:核心将在此过程中无所事事,直到设备完成此请求。但是轮询设备驱动可以通过使用系统定时器,使核心周期性调用设备驱动中的某个例程来检查设备状态。
使用定时器是轮询方式中最好的一种,但更有效的方法是使用中断。基于中断的设备驱动会在它所控制的硬件设备需要服务时引发一个硬件中断。在/proc/interrupts 文件中你可以看到设备驱动所对应的中断号及类型。
对中断资源的请求在驱动初始化时就已经完成。如何将中断发送给CPU 本身取决于体系结构,但是在多数体系结构中,中断以一
种特殊模式发送同时还将阻止系统中其它中断的产生。设备驱动在其中断处理过程中作的越少越好,这样Linux 核心将能很快的处理完中断并返回中断前的状态中。为了在接收中断时完成大量工作,设备驱动必须能够使用核心的底层处理例程或者任务队列来对以后需要调用的那些例程进行排队。
直接内存访问(DMA)
数据量比较少时,使用中断驱动设备驱动程序能顺利地在硬件设备和内存之间交换数据。例如波特率为9600 的modem 可以每毫秒传输一个字符。如果硬件设备引起中断和调用设备驱动中断所消耗的中断时延比较大(如2 毫秒)则系统的综合数据传输率会很低。
直接内存存取(DMA)是解决此类问题的有效方法。DMA 控制器可以在不受处理器干预的情况下在设备和系统内存之间高速传输数据。
PC 机的ISA DMA 控制器有8 个DMA 通道,其中七个可以由设备驱动使用。每个DMA 通道具有一个16 位的地址寄存器和一个16 位的记数寄存器。为了初始化数据传输,设备驱动将设置DMA 通道地址和记数寄存器以描叙数据传输方向以及读写类型。然后通知设备可以在任何时候启动DMA 操作。传输结束时设备将中断PC。在传输过程中CPU 可以转去执行其他任务。
设备驱动使用DMA 时必须十分小心。首先DMA 控制器没有任何虚拟内存的概念,它只存取系统中的物理内存。同时用作DMA 传输缓冲的内存空间必须是连续物理内存块。这意味着不能在进程虚拟地址空间内直接使用DMA。但是你可以将进程的物理页面加锁以防止在DMA操作过程中被交换到交换设备上去。另外DMA 控制器所存取物理内存有限。DMA 通道地址寄存器代表DMA 地址的高16 位而页面寄存器记录的是其余8 位。所以DMA 请求被限制到内存最低16M 字节中。
DMA 通道是非常珍贵的资源,一共才有7 个并且还不能够在设备驱动间共享。与中断一样,设备驱动必须找到它应该使用那个DMA 通道。有些设备使用固定的DMA 通道。有时设备的DMA 通道可以由跳线来设置,许多以太网设备使用这种技术。设计灵活的设备将告诉系统它将使用哪个DMA 通道,此时设备驱动仅需要从DMA 通道中选取即可。
内存
设备驱动必须谨慎使用内存。由于它属于核心,所以不能使用虚拟内存。系统接收到中断信号时或调度底层任务队列处理过程时,设备驱动将开始运行,而当前进程会发生改变。设备驱动不能依赖于任何运行的特定进程,即使当前是为该进程工作。与核心的其它部分一样,设备驱动使用数据结构来描叙它所控制的设备。这些结构被设备驱动代码以静态方式分配,但会增大核心而引起空间的浪费。多数设备驱动使用核心中非页面内存来存储数据。
请求分配核心内存时Linux 需要完成许多额外的工作。如果系统中空闲内存数量较少,则可能需要丢弃些物理页面或将其写入交换设备。一般情况下Linux 将挂起请求者并将此进程放置到等待队列中直到系统中有足够的物理内存为止。不是所有的设备驱动(或者真正的Linux 核心代码)都会经历这个过程,所以如分配核心内存的请求不能立刻得到满足,则此请求可能会失败。如果设备驱动希望在此内存中进行DMA,那么它必须将此内存设置为DMA 使能的。
设备驱动与核心的接口
Linux 核心与设备驱动之间必须有一个以标准方式进行互操作的接口。每一类设备驱动:字符设备、块设备及网络设备都提供了通用接口以便在需要时为核心提供服务。
Linux 动态性很强。每次Linux 核心启动时如遇到不同的物理设备将需要不同的物理设备驱动。Linux 允许通过配置脚本在核心重建时将设备驱动包含在内。设备驱动在启动初始化时可能会发现系统中根本没有任何硬件需要控制。其它设备驱动可以在必要时作为核心模块动态加载到。为了处理设备驱动的动态属性,设备驱动在初始化时将其注册到核心中去。Linux 维护着已注册设备驱动表作为和设备驱动的接口。这些表中包含支持此类设备例程的指针和相关信息。
硬盘
磁盘驱动器提供了一个永久性存储数据的方式,将数据保存在旋转的盘片上。物理硬盘可进一步划分成分区。一个分区是一大组为特殊目的而分配的扇区。对磁盘进行分区使得磁盘可以同时被几个操作系统或不同目的使用。许多Linux 系统具有三个分区:DOS
文件系统分区,EXT2 文件系统分区和交换分区。硬盘分区用分区表来描叙;表中每个入口用磁头、扇区及柱面号来表示分区的起始与结束。对于用DOS 格式化的硬盘有4 个主分区表。但不一定所有的四个入口都被使用。fdisk支持3 中分区类型:主分区、扩展分区及逻辑分区。扩展分区并不是真正的分区,它只不过包含了几个逻辑分区。扩展和逻辑分区用来打破四个主分区的限制。
网络设备
网络设备,即Linux 的网络子系统,是一个发送与接收数据包的实体。它一般是一个象以太网卡的物理设备。有些网络设备如loopback 设备仅仅是一个用来向自身发送数据的软件。
每个网络设备都用一个device 结构来表示。网络设备驱动在核心启动初始化网络时将这些受控设备登记到Linux 中。device 数据结构中包含有有关设备的信息以及用来支持各种网络协议的函数地址指针。这些函数主要用来使用网络设备传输数据。设备使用标准网络支持机制来将接收到的数据传递到适当的协议层。所有传输与接收到的网络数据用一个sk_buff 结构来表示,这些灵活的数据结构使得网络协议头可以更容易的添加与删除。