Linux 版 (精华区)
发信人: netiscpu (网中自由鸟), 信区: Linux
标 题: Linux实用教程(部分)(5)
发信站: 哈工大紫丁香 (Thu May 20 18:07:22 1999), 转信
第十二章
硬件和设备驱动程序
Linux 最初在 i386 平台上开发,i386 平台也是其主要支持的计算机硬件平台,但是
,Linux 也同时支持其他类型的 CPU,例如 Alpha AXP、PowerPC 以及 MIPS R4600 等
CPU。
计算机中,CPU 是核心组件,但是完整的计算机还包括其他一些组件,这些组件共同协
调完成用户任务。总线为不同类型的组件提供通讯途径。到目前为止,出现了许多总线
类型,例如 ISA、PCI 等。本章主要介绍 Linux 对 PCI 总线的支持。
对计算机的输入输出设备进行管理和控制是操作系统的主要功能之一。操作系统必须向
设备提供操作指令,还需要处理来自设备的中断请求。一般来说,操作系统还要为程序
提供设备的访问接口。Linux 通过设备驱动程序为应用程序提供了统一抽象的接口,从
而隐藏了大量不同设备之间的区别和细节。本章介绍 Linux 对硬件中断的处理以及对
设备驱动程序的支持。
在 Linux 的安装和系统维护中,会遇到许多与特定硬件或设备相关的问题。这些问题
的正确解决建立在对相关概念的正确理解之上。本章讲述 Linux 系统中常见的设备以
及一些相关概念。
12.1 处理器和总线
Linux 主要为 i386 系列处理器开发。Linux 使用了这种处理器的“保护模式”,在这
种模式下,处理器可以支持许多高级特性,从而使多任务和虚拟内存的实现成为可能。
众所周知,Intel 的 80x86 系列处理器只有 386 以上的处理器才支持保护模式,因此
,Linux 不能运行在以 8088 为处理器的 PC 或 PC/XT机上。因为 AMD 和Cyrix 生产
的一些芯片和80386 是兼容的,因此,Linux 也可以运行在 AMD K6 等作为处理器的
PC 机上。
Linux 内核主要由 C 语言编写,因此,将 Linux 移植到其他平台上是比较容易的,而
且,Linux 内核源代码的组织也使移植过程更加容易。到目前为止,Linux 所支持的其
他类型的 CPU有:Alpha AXP、PowerPC 以及 MIPS R4600 等。
总线是将计算机中不同类型的硬件组织在一起,并为它们提供通讯保证的计算机关键硬
件。总线定义了硬件之间进行通讯的“协议”,遵循同一种协议的硬件可在同一条总线
上协调工作。从物理上看,总线由计算机主板上传送信号的线路以及附属的控制芯片组
成。各种设备大多以控制卡的形式插在总线槽上。总线协议包括一些物理上的约定,例
如电气特性以及控制卡尺寸等,另外,总线协议也定义了总线上的信号时序以及总线的
最大数据传输速率(以MHz为单位)等特性。不同的协议形成了不同的总线。在流行 P
C 机中,常见的总线类型如表 12-1 所示。
表 12-1 PC 中的常见总线类型
名称
说明
ISA 总线
ISA 是“工业标准结构”的英文缩写。ISA 总线是当前应用最为广泛的总线类型。最
初用于 IBM 的PC AT 机中,一次可传输 16 位数据,最大的数据传输率为 5MB/sec。
VESA 局部总线
VESA 是“视频电子标准协会”的英文缩写。VESA 局部总线,也即 VLB,可提供处理
器和视频卡之间的高速数据传输,典型的 VLB 传输速率为 30MB/sec。
EISA 总线
EISA 是“扩展工业标准结构”的英文缩写。EISA 总线的传输速率为 30MB/sec。但该
总线很少使用。
PCI 总线
PCI 是“外设组件互连接”的英文缩写。PCI 是最新的高性能总线。它的时钟频率为
33 MHz,一次可传输 64 位数据。如果 PCI 总线用来传输 32 位数据,可获得 33 *
4 = 132 MB/sec 的传输速率。
Linux 支持上述四种总线类型,但尚不支持 MCA 总线(微通道结构总线)。
PCI 总线现在广泛使用在基于 Pentium 的计算机中,一方面是因为该总线的数据吞吐
量大,另一方面是因为该总线和具体的处理器无关,也就是说,同一个 PCI 设备,既
可以使用在 i386 计算机中,也可以使用在 Alpha AXP 计算机中。PCI 总线的设计也
使各种 PCI 外设卡可直接插入 PCI 总线槽中,而不需要考虑各种额外的特殊逻辑,例
如,ISA 设备中的跳线设置。但是,正因为 PCI 总线的灵活性,所以需要操作系统额
外的软件支持。
12.2 Linux 对 PCI 总线的支持
12.2.1 PCI 总线的结构
如图 12-1 所示,是一个简单的 PCI 系统的逻辑示意图。每条 PCI 总线上的设备数目
是有一定限制的,因此该系统使用 PCI-PCI 桥将不同的 PCI 总线粘合在一起。不同的
PCI 总线有唯一的编号,CPU 处于 PCI 0 号总线上。为了和老的 ISA 设备兼容,利
用 PCI-ISA 桥可在 PCI 总线上连接 ISA 总线。利用 PCI-PCI 桥和PCI-ISA 桥,可以
突破单个 PCI 总线的限制而连接许多设备。一般而言,服务器和桌面计算机的 PCI 总
线拓扑结构是不同的。
我们知道,ISA 设备有两种地址空间,一种是 I/O 端口空间,另一种是存储器空间。
和 ISA 设备相比较,PCI设备有三种地址空间,分别是:I/O 端口空间、存储器空间和
配置空间。不同的 CPU 类型对地址空间类型的支持不同,i386 处理器的 I/O 端口和
存储器空间是分开的,利用不同的处理器指令操作这些地址;Alpha AXP 处理器却只有
存储器空间,也就是说,端口的输入输出和内存访问的指令是一样的。因此,Alpha A
XP 处理器利用一种独特的内存映射方式将部分虚拟地址空间映射为 PCI 的地址空间。
图 12-1 简单的 PCI 系统拓扑图
图 12-2 PCI 设备的设备头结构
PCI 的前两种地址空间和 ISA 的两种地址空间类似,设备驱动程序利用这些地址空间
在系统和设备之间通讯。除此之外,PCI 设备,包括 PCI-PCI 桥和 PCI-ISA 桥都包含
称为“配置头”的数据结构,这些数据结构包含在 PCI 设备的配置空间中。配置头在
配置空间中的位置和相应的 PCI 插槽相关,系统可以利用这些配置头判断相应的 PCI
插槽中是否存在 PCI 设备。
图 12-2 是设备头的结构示意图。一般而言,设备头的长度为 256 字节,利用与特定
硬件相关的代码可读取这些设备头。根据其中的信息,操作系统可为每个已插入 PCI
插槽的 PCI 设备分配 PCI I/O 端口的数量、地址,以及PCI 存储器的长度和起始位置
(由基地址寄存器定义),也可以配置 PCI 设备的中断以及中断请求线。但是只有专
门为特定硬件系统设计的配置代码才可以读取和设置这些信息,在 i386 系统中,这种
代码通常由系统 BIOS 提供。详细信息可参见有关的 PCI 总线规范。
12.2.2 Linux 中 PCI 设备的初始化
Linux 中的 PCI 设备初始代码可划分为如下三个部分:PCI BIOS、PCI 修正和 PCI 设
备驱动程序。PCI BIOS 由一组标准的 PCI 设备访问功能函数组成,这些代码对不同的
平台来说是一样的。PCI 修正部分为非 Intel 的系统所特有。对基于 Intel 的系统来
说,系统引导时,可由系统 BIOS 完整配置 PCI 系统,而对 Alpha AXP 系统而言,需
要利用 PCI 修正代码来完成 PCI 系统的配置。PCI 设备驱动程序实际并不是一个真正
的设备驱动程序,它只在引导时由操作系统调用进行 PCI 设备的初始化。下面主要描
述 PCI 设备驱动程序。
图 12-3 Linux 内核中的 PCI 数据结构
PCI 设备驱动程序利用 PCI BIOS 的功能函数在系统中扫描所有的 PCI 设备(包括两
种桥设备),并建立如图 12-3 所示的数据结构,该数据结构实际是图 12-1 所示系统
PCI 拓扑结构的一个写照。
图 12-3 中的数据结构对应于图 12-1 所示的 PCI 系统。PCI 初始化代码首先扫描 P
CI 0 号总线,为每个可能的 PCI 插槽读取设备头中的制造商标识和设备标识。如果发
现一个已填充有效标识信息的设备头,则说明对应的 PCI 插槽中有合法的 PCI 设备,
因此,系统为该设备建立一个 pci_dev 结构。同一总线上所有的 pci_dev 数据结构形
成了一个 pci_devices 链表。
如果在搜索 0 号总线时发现 PCI-PCI 桥设备,则系统会建立一个 pci_bus 结构,并
和代表 PCI 0 号总线的 pci_bus 结构以及 pci_dev 结构一起形成一个由 pci_root
所指的树形结构。接下来,初始化代码将继续在次总线上扫描其他 PCI 设备,直到扫
描完所有的 PCI 设备为止。如果在次总线上发现有 PCI-PCI 桥设备,则初始化代码会
继续扫描从属总线。
12.3 计算机和设备间的数据交换方式
12.3.1 查询和中断
如前所述,不管是 ISA 设备还是 PCI 设备,设备驱动程序通过设备的 I/O 端口空间
以及存储器空间完成数据的交换。例如,网卡一般将自己的内部寄存器映射为设备的
I/O 端口,而显示卡则利用大量的存储器空间作为视频信息的存储空间。利用这些地址
空间,驱动程序可以向外设发送指定的操作命令,例如要求硬盘控制器将磁头移动到指
定的柱面。通常来讲,外设的操作耗时较长,因此,当 CPU 实际执行了命令指令之后
,驱动程序可采用两种方式等待外设完成操作。一种是查询方式,驱动程序在提交命令
之后,就开始查询设备的状态寄存器,当状态寄存器表明操作完成时,驱动程序可继续
后续处理。另一种方式是利用中断,驱动程序提交命令之后,立即进入休眠状态(即放
弃 CPU 的使用权,而其他进程就有机会运行了),设备结束操作之后,会产生中断信
号,操作系统则根据设备的中断信号负责唤醒驱动程序。显然,查询方式白白浪费了大
量的 CPU 时间,而中断方式才是多任务操作系统中最有效利用 CPU 的方式。
12.3.2 直接内存访问
利用中断,系统和设备之间可以通过设备驱动程序传送数据,但是,当传送数据量很大
时,因为中断处理上的延迟,利用中断的方式就不太有效了。例如,SCSI 硬盘可在 1
秒之内传输 50 MB 的数据,而通常的中断延迟(中断产生到相应的设备驱动程序被调
用之间的时间)大约为 2 毫秒,显然,利用中断对整体数据传输速度的影响是非常大
的。
利用“直接内存访问(DMA)”可解决这一问题。DMA 可允许设备和系统内存之间在不
经处理器参与之下传输大量数据。在 PC 中,有8个 DMA 通道,设备驱动程序可使用其
中的 7 个。每个 DMA 通道有一个 16 位的地址寄存器和一个 16 位的计数寄存器,可
分别用来定义一次 DMA 操作的系统内存起始地址和内存大小。设备驱动程序在利用 D
MA 之前,需要选择 DMA 通道并定义上述寄存器以及数据的传输方向,即读取或写入,
然后将设备设定为利用该 DMA 通道传输数据。设备完成操作之后,立即就可以利用该
DMA 通道在设备和系统内存之间传输数据。传输完毕之后产生中断以便通知设备驱动
程序进行后续处理。在利用 DMA 进行数据传输的同时,CPU 仍然可以继续执行指令。
在利用 DMA 进行数据传输时,有几个需要注意的问题:
1. DMA 地址寄存器代表系统物理地址的低 16 位,加上页寄存器中的高 8 位地址,
DMA 所能访问的地址限制在低 16 MB(早期的 DMA 控制器限制更严重)。
2. 因为在 DMA 操作时,CPU 仍然在执行指令,因此要防止写入的物理内存区域被虚
拟内存机制交换到交换空间中,这可通过锁定相应的物理页避免。
3. DMA 通道是有限资源。有些设备固定使用同一个通道,例如,软盘驱动器使用通道
2;有些设备可通过硬件跳线选择 DMA 通道;另外一些设备则更加灵活,它可以使用
任何一个空闲的 DMA 通道,为此,Linux 内核为每个 DMA 通道维护一个 dma_chan 数
据结构,根据该结构中的信息可判断指定的 DMA 通道是否已被分配。
12.4 中断及中断处理
图 12-4 32 位 i386 PC的中断处理硬件
如上所述,查询方式实际是同步驱动设备的方式,而中断方式实际是异步驱动设备的方
式,利用中断,系统可更加有效地利用 CPU。本节讲述 Linux 是如何处理中断的。
12.4.1 中断处理硬件
CPU 在一些外部硬件的帮助下处理中断。中断处理硬件和具体的系统相关,但一般而言
,这些硬件系统和 i386 处理器的中断系统在功能上是一致的。图 12-4 所示是 PC-A
T 微机中的中断处理硬件。
外部设备产生的中断实际是电平的变化信号,信号的变化出现在中断控制器的 IRQ(中
断请求)管脚上,这一信号首先由中断控制器处理。中断控制器可以响应多个中断输入
,它的输出连接到 CPU 的 INT 管脚,CPU 在该管脚上的电平变化可通知处理器产生了
中断。如果 CPU 这时可以处理中断,CPU 会通过 INTA(中断确认)管脚上的信号通知
中断控制器已接受中断,这时,中断控制器可将一个 8 位数据放置在数据总线上,这
一 8 位数据也称为中断向量号,CPU 依据中断向量号和中断描述符表(IDT)中的信息
自动调用相应的中断服务程序。图 12-4 中,两个中断控制器级联了起来,从属中断控
制器的输出连接到了主中断控制器的第 3 个中断信号输入,这样,该系统可处理的外
部中断数量最多可达 15 个,图的右边是 i386 PC 中各中断输入管脚的一般分配。
中断控制器中的控制寄存器实际映射到了 CPU 的 I/O 地址空间中,通过对寄存器的设
置,可设定中断控制器屏蔽某些中断,也可以指定中断控制器的特殊响应方式,因此,
中断控制器也称为可编程中断控制器。在 Linux 中,两个中断控制器初始设置为固定
优先级的中断响应方式。有关可编程控制器的详细信息可参阅有关的资料。
12.4.2 Linux 的中断处理软件
图 12-5 Linux 的中断处理数据结构
在 i386 系统中,Linux 启动时要设置系统的中断描述符表,即 IDT。IDT 中包含各个
中断(以及异常,诸如浮点运算溢出)的服务程序地址,中断服务程序地址由 Linux
提供。每个设备驱动程序可以在图 12-5 所示的结构(irq_action)中注册自己的中断
及中断处理程序地址。Linux 的中断服务程序根据 irq_action 中的注册信息调用相应
的设备驱动程序的中断处理程序。和硬件相关的中断处理代码隐藏在中断服务程序中,
这样,设备驱动程序的中断处理程序可在不同平台之间方便移植。一般而言,CPU 在处
理中断时,首先要在堆栈中保存与 CPU 指令执行相关的寄存器(例如指令计数寄存器
),然后调用中断服务程序,中断服务程序结束时再恢复这些寄存器。
irq_action 实际是一个数组,其中包含指向 irqaction 的指针,每个数组元素分别定
义一个 IRQ。Linux 内核提供相应的操作函数,设备驱动程序可调用这些操作函数设置
相应的中断处理函数。一般在系统启动时,由各个设备驱动程序通过如下途径获取相关
的设备 IRQ 并设置对应的 irq_action 数组元素所指向的 irqaction 结构:
1. 对某些设备,例如软盘驱动器,其 IRQ 是固定的。软盘驱动器的 IRQ 为 6。
2. 设备驱动程序可通过探测程序自动探测某些 ISA 设备的IRQ。
3. 不能自动探测的 ISA 设备,可通过启动参数指定设备的IRQ。
4. 对 PCI 设备,设备的配置头信息中已经存在有相应的设备 IRQ,设备驱动程序只
需读取该配置信息。
对 ISA 设备 IRQ 的探测过程如下。设备驱动程序要求设备完成某项可导致中断的操作
,然后,系统打开所有未被分配的中断。如果设备产生中断,系统将接收到该中断,然
后通过读取中断控制器的状态寄存器可得知该中断对应的 IRQ,它就是 ISA 设备的 I
RQ。当然,这种探测方式在某些情况下是无法正常工作的,例如,当 ISA 设备的 I/O
地址空间也未知时,就无法利用这种方式。这种情况经常发生在配置 ISA 网络卡的时
候,这时就需要利用启动参数指定设备的 IRQ 和 I/O 端口地址。
对 PCI 设备,由于可方便获得设备配置头信息中的 IRQ,因此设置工作相对容易些。
但因为 PCI 设备只能在四个引脚(分别为A、B、C和D)上产生中断,所以当系统中有
四个以上的 PCI 设备时,就会发生 IRQ 重叠的情况。这时,irq_action 数组中的某
个元素会同时指向多个 irqaction 结构(见图 12-5),而当产生该 IRQ 中断时,Li
nux 会依次调用每个 irqaction 指定的中断处理程序。
在设备驱动程序的中断处理过程中,设备驱动程序读取设备状态寄存器的值,从而可了
解操作结果。在某些特定情况下,设备驱动程序还要进行其他处理,但中断处理过程中
只读取设备状态,以便能够快速结束中断处理。如果还要进行其他处理,会通过下面要
讲到的内核机制在适当的时候进行。
12.5 设备驱动程序
12.5.1 设备驱动程序的概念
在多任务操作系统中,有很多理由需要内核建立应用程序和设备之间的抽象接口,而不
是由应用程序直接操作硬件。为此,操作系统一般提供设备驱动程序来专门完成对特定
硬件的控制。设备驱动程序实际是处理或操作硬件控制器的软件,从本质上讲,它们是
内核中具有高特权级的、驻留内存的、可共享的底层硬件处理例程。
在 Linux 系统中,一个基本的特点是它抽象了设备处理。所有对硬件设备的操作和通
常的文件一样,利用标准的系统调用可在设备上进行打开、关闭、读取或写入操作。系
统中的每个设备由“设备特殊文件”来代表。例如,/dev/hda 代表系统中的第一个 I
DE 硬盘,而 /dev/sda1 则代表系统中 SCSI 硬盘上的第一个分区。每个由相同的设备
驱动程序控制的设备具有相同的主设备号,而次设备号则用来区分同类设备中不同的设
备。设备特殊文件的 VFS 索引节点中包含设备号信息。如果通过系统调用访问设备,
则内核可通过该 VFS 索引节点中的设备号信息调用适当的设备驱动程序。
Linux 中的设备分为字符设备、块设备和网络设备三种。字符设备是不通过缓冲而直接
进行读取和写入操作的设备。块设备只能以块(通常为 512 字节或 1024 字节)的倍
数大小读取或写入。对块设备的访问一般通过缓冲区高速缓存访问,并且可随机访问。
网络设备一般通过 BSD 套接字接口访问,详细内容将在第十四章中讲述。
尽管 Linux 中很多类型的设备驱动程序,但它们有一些共同的特点,如表 12-2 所示
。
表 12-2 Linux 设备驱动程序的共同特点
作为内核的一部分
设备驱动程序作为内核的一部分而存在,因此“恶意”的驱动程序会破坏系统。
提供内核接口
设备驱动程序要为内核或内核的子系统提供标准接口。
利用内核机制和服务
设备驱动程序要使用一些诸如内存分配、中断传输及等待队列等内核机制和服务。
可装载
大部分设备驱动程序可作为内核模块在必要时装入,而不再需要时卸载。
可配置
Linux 设备驱动程序可内建到内核中,可在编译时指定内建的设备驱动程序。
动态性
如果装载的设备驱动程序启动时没有找到对应的设备,则该设备驱动程序只是占用了
一些系统内存,对系统并没有害处。
12.5.2 设备驱动程序的内存分配
设备驱动程序作为内核的一部分,不能使用虚拟内存,因此也不能依赖于任何一个进程
运行。和内核的其他部分一样,设备驱动程序也利用各种数据结构跟踪所控制的设备。
这些数据结构可作为驱动程序代码的一部分而静态分配,但这种方法会导致内核变大,
甚至浪费内存。为此,大部分驱动程序利用内核提供的服务函数动态分配和释放非分页
的系统内存。内核以 2 的幂为大小分配内存,例如 128 字节或 512 字节。驱动程序
要求的字节数被圆整到下一个页块边界上,这样,释放的物理内存可以重新组合成大的
页块。
当系统内存较少时,内核会通过交换操作将某些物理内存页交换到交换空间中,为此,
内核会将请求分配的驱动程序暂时挂起,直到有足够的内存时才分配内存并返回成功值
。但是,有时驱动程序不允许内存分配上的延迟,因此,可请求内核在这种情况下返回
失败值。另外,当驱动程序需要分配用来进行 DMA 操作的内存时,须指定该内存应当
是可进行 DMA 操作的内存(处于低 16MB 地址空间中)以便能正确分配内存。
12.5.3 设备驱动程序和内核的接口
每种类型的驱动程序,不管它们是字符设备、块设备还是网络设备,均为内核提供相同
的调用接口。于是,内核可以以相同的方式处理非常不同的设备,例如,内核可通过相
同的函数调用让 SCSI 和 IDE 硬盘完成相同的工作。表 12-2 还说明了 Linux 设备驱
动程序具备的其他一些特点。为了实现这些特点,Linux 为每种不同类型的设备驱动程
序维护相应的数据结构,以便定义统一的接口并实现驱动程序的可装载性、动态性等。
对字符设备而言,Linux 内核维护一个 chrdevs 结构体数组,该数组的元素实际是 d
evice_struct 结构(图 12-6)。主设备号用作访问 chrdevs 数组的索引,例如,tt
y 设备的主设备号为 4。每个 device_struct 结构包含两部分信息。name 是设备驱动
程序注册的设备名称;另一部分包含设备的标准操作例程集,其中的操作例程由设备驱
动程序定义,并分别完成指定的设备操作。
图 12-6 Linux 内核维护的字符设备数据结构
当代表某个字符设备的设备特殊文件被打开时,内核负责进行一些设置工作,以便能够
调用正确的设备操作例程。和其他普通的文件或目录一样,设备文件也由 VFS 索引节
点代表。VFS 索引节点中包含设备的主设备号和次设备号,每个 VFS 节点和一组文件
操作函数的指针关联。系统在建立一个代表字符设备文件的 VFS 索引节点时,该 VFS
节点的文件操作函数指针被设置为默认的字符设备操作函数指针。这时实际只有一个
文件操作函数被定义,即文件的打开操作。应用程序打开某个字符特殊文件时,该打开
操作将使用 VFS 节点中的主设备号在 chrdevs 数组中检索相应的设备操作函数地址,
同时在进程的文件数据结构中建立一个 file 结构(参见第十一章),该结构的文件操
作函数指针指向设备驱动程序定义的设备操作函数指针。此后,应用程序在该设备特殊
文件上进行的读取、写入等操作就映射到了特定的字符设备操作。
和字符设备类似,Linux 内核利用 blkdevs 数组记录所有的块设备,每个数组元素也
是一个 device_struct 结构体,主设备也当作数组索引使用。在 device_struct 结构
体中,块设备驱动程序为通常的文件操作提供接口。除此之外,块设备在内核中的数据
结构比字符设备要复杂一些,主要是因为内核为块设备提供缓冲区高速缓存,实际的读
写操作由缓冲区缓存协调调用,因此,还需要驱动程序为缓冲区缓存提供接口。为此,
内核利用 blk_dev 数组(图 12-7)定义这些接口。访问该数组的索引仍然是主设备号
,每个块设备驱动程序在 blk_dev 数组的相应位置填充 dlk_dev_struct 结构。blk_
dev_struct 结构包含一个处理请求的函数地址,以及一个指向 request 结构体的指针
。实际上,多个 request 结构形成了一个链表,而每个 request 结构代表由缓冲区高
速缓存请求设备读取或写入的请求信息。
图 12-7 Linux 块设备驱动程序的数据结构
每当缓冲区缓存要从注册设备中读取数据或向设备写入数据时,缓冲区缓存就会在 bl
k_dev_struct 中添加一个 request 结构。从图 12-7 可看出,每个 request 结构中
包含一个指向 buffer_head 结构的指针,每个 buffer_head 结构定义要读取或写入的
数据块。进行读写操作时,buffer_head 结构由缓冲区缓存锁定,这时,等待该缓冲区
操作结束的进程被阻塞。当请求被添加到空的请求队列时,驱动程序的请求函数(req
uest_fn)被调用,由该函数完成请求队列的处理。
当驱动程序完成请求处理之后,它从 request 结构中移去 buffer_head 结构并标志该
结构包含新数据,然后解锁 buffer_head 结构。对 buffer_head 结构的解锁将唤醒所
有正在等待该操作完成的进程。
request 结构并不是动态分配的,每次需要新的 request 时,该结构从一个大的静态
all_request 链表中取得,对应的请求被处理之后,该结构标志为空闲的 request 结
构。
12.5.4 网络设备
网络设备由 Linux 的网络子系统使用,其重要功能是数据的发送和接收。Linux 系统
中的网络设备和一般的硬件设备有如下不同之处:
某些网络设备是硬件设备,而有些网络设备则是软件设备,并不存在实际的硬件设备与
之对应,如回环设备。 一般块设备或字符设备特殊文件可以通过 mknod 命令建立,而
网络设备只有在系统引导时发现和初始化之后才存在。 Linux 内核利用 device 数据
结构来描述网络设备。在系统引导期间,网络设备驱动程序在 Linux 的网络子系统进
行初始化时注册设备信息。device 数据结构中包含了设备信息,以及一些用来传输数
据的函数地址。在 Linux 网络子系统中传输和接收的数据包,均由 sk_buff 数据结构
代表。在第十四章中,我们将详细介绍网络子系统中的数据结构及其数据传输,本小节
主要讲述 device 数据结构和网络设备的初始化。
1. 网络设备数据结构
device 数据结构中包含如表 12-3 所示的设备信息。
表 12-3 device 数据结构包含的主要信息
名称
系统在引导时发现并初始化网络设备之后,网络设备文件的名称自动出现在 /dev 目
录中。网络设备的名称遵循一定的标准,每个名称代表设备的类型,而同一类型的设备
从 0 开始编号,例如,所有的以太网设备名称为 /dev/eth0、/dev/eth1 和 /dev/et
h2 等。常见网络设备有:
/dev/ethN 以太网设备
/dev/slN SLIP 设备
/dev/pppN PPP 设备
/dev/lo 回环设备
总线信息
其中包括设备驱动程序用来控制设备的信息。如下所示:
中断请求 该设备使用的中断请求号
基地址 该设备使用的控制和状态寄存器的基地址
DMA 通道 该设备使用的 DMA 通道
接口标志
接口标志描述了网络设备的特征和能力。如下所示:
IFF_UP 接口已经过初始化,正在运行
IFF_BROADCAST device 中的广播地址有效
IFF_DEBUG 设备调试能力打开
IFF_LOOPBACK 该设备是回环设备
IFF_POINTTOPOINT 该设备是点到点链路设备(PPP 和 SLIP 设备)
IFF_NOTRAILERS 无网络追踪器
IFF_RUNNING 资源已分配
IFF_NOARP 不支持 ARP(地址解析协议)
IFF_PROMISC 设备处于混杂接收模式,设备将忽略数据包的目标地址信息而接收所有的
数据包
IFF_ALLMULTI 接收所有的 IP 多点传送帧
IFF_MULTICAST 可以接收 IP 多点传送帧
协议信息
这类信息描述网络协议层如何使用设备:
mtu 网络可以传输的最大的数据包尺寸,不包括必须添加的链路层头数据。该值可以由
某些协议层(如 IP)用来选择合适的数据包大小。
地址族 设备支持的地址族。常见的协议族是 AF_INET,即 Internet 地址族。
类型 描述设备所连接的网络介质的硬件接口类型。Linux 网络设备支持的介质类型包
括:以太网、令牌环、X.25、SLIP、PPP 和 Apple Localtalk 等。
地址 和网络设备相关的地址信息,包括 IP 地址。
数据包队列
包含了等待由该网络设备发送的 sk_buff 数据包队列。
支持函数
每个设备包含了一组标准的例程,协议层可以将这些例程当作设备链路层的部分而调
用。其中包括设置、帧传输例程,以及添加标准数据帧头和收集统计信息的例程。ifc
onfig 命令使用这些统计信息。
2. 网络设备的初始化
和其他的 Linux 设备驱动程序一样,网络设备也可以建立到 Linux 内核中。每个可能
的网络设备由 device 数据结构代表,所有的 device 数据结构包含在由 dev_base 指
针指向的设备链表中。网络协议层需要网络设备完成特定的工作时,调用保存在 devi
ce 数据结构中的网络设备服务例程。但在最开始,每个 device 设备中只包含一个初
始化或检测例程的地址。
网络设备驱动程序有两个问题需要解决。首先,并不是所有建立到 Linux 内核中的网
络设备驱动程序均有相应的可控制设备。其次,不管底层设备是哪种硬件型号,以太网
设备始终以 /dev/eth0、/dev/eth1 等方式命名。第一个问题容易解决,当系统引导时
,每个网络设备的初始化例程被调用,该初始化例程可返回一个值表明是否存在该设备
所描述的实际硬件,若不存在,只需将该设备在 dev_base 链表中的节点删除。反之,
网络设备驱动程序填充 device 结构中的其余信息以及支持函数。
第二个问题,即网络设备特殊文件名称的动态分配问题,解决起来稍微复杂一些。在设
备链表中,一共有 8 个标准的入口,从 eth0,eth1 一直到 eth7。它们的初始化例程
均是一样的,该例程依次调用内核中的以太网设备驱动程序,当某个驱动程序发现对应
的以太网设备时,则从 eth0 开始依次填充空闲的device 数据结构。这时,网络设备
驱动程序还要初始化物理硬件,搜集有关的总线信息。有时,一个驱动程序会找到多个
可控制的网络设备,这种情况下,它将填充多个 /dev/ethN device 数据结构。当所有
8 个标准的 /dev/ethN 全部分配之后,就不再继续检测其他的以太网设备。
下面的小节主要包括一些常见硬件及其相关概念,同时介绍相关系统工具,这些内容对
正确安装和维护 Linux 系统有相当大的帮助。
12.6 硬盘
如图 12-8 所示是硬件的物理结构示意图。从图中可以看出,硬盘实际是由多个“磁盘
片”组成的,每个磁盘片均有两个“面”。在磁盘出厂低级格式化之前,每个面上均匀
分布磁粉。经过低级格式化之后,每个面上的磁粉被组织成一圈圈的“磁道”,而磁道
又被划分成为“扇区”, 扇区是真正保存数据的地方,各磁道上的扇区数是相同的。
另外,硬盘还有一个术语称为“柱面”,它指的是由所有面上的同一磁道假象形成的几
何柱面,该几何柱面的轴就是盘片的旋转轴。每个面对应有一个磁头,用来感应磁道上
磁粉的磁极方向,经过其他电路处理可将磁粉的磁极转化为计算机能够识别的二进制数
据。磁头能够沿盘片的径向移动,在盘片旋转运动的辅助下,磁头可以读取盘片上所有
扇区中的数据。“磁盘控制器”完成对来自 CPU 的命令的解释,并控制磁头的移动和
读写。
如果我们知道了硬盘的磁头个数、柱面个数、每磁道上的扇区个数(这些参数称为硬盘
的“几何参数”)以及每扇区上可存储的字节数,就可以计算出这个硬盘的容量。例如
,某计算机的磁头个数为 128,每磁道上的扇区个数为 63,一共有 788 个柱面,每扇
区可容纳 512 字节,因此,该硬盘的容量为 128 ′ 63 ′ 788 ′ 512 = 3,253,469
,184(字节)= 3102.75(兆字节)。
图 12-8 硬盘的物理结构示意图
上面所举的例子中,该硬盘一共有 128 个磁头,也就是说,它一共有 64 个磁盘片。
但根据常识,薄薄的硬盘中不可能存在这样多的磁盘片。实际上,现在常见的大容量硬
盘的这些参数并不对应于实际的物理参数。这样定义的原因是由于 PC 机早期 BIOS 设
计上的一个缺陷。早期的 BIOS 在 CMOS RAM 中存放这些参数,由于 CMOS RAM 的容量
有限,初始设计为不能存放大于 1024 的磁道个数(那时的硬盘容量一般为 40 MB)。
但是,随技术的发展,硬盘的容量越来越大,这主要是磁道个数增多的原因,而不是磁
头个数增加的原因。为了和原有的 BIOS 兼容,硬盘制造商仍然利用小于 1024 的磁道
数定义硬盘参数,而通过增加磁头数等方法保证所定义的逻辑参数能够和物理参数匹配
。同时,随着磁道数的增多,又引入了另一个问题。处于盘片中心处的磁道周长小,而
处于盘片外沿的磁道周长大,这样,外沿磁道上可容纳的扇区个数比处于中心处的磁道
可容纳的扇区个数要多。硬盘制造厂商为了尽量增加硬盘容量,实际所采用的也是变化
的扇区数。但是,无论硬盘的实际构造如何,硬盘制造商却始终给出符合上述结构的逻
辑参数,从而保证硬盘访问软件在一定程度上的一致性,而逻辑参数到物理参数的转换
则由!硬盘控制器完成。
上面所讲的问题主要出现在 IDE 接口的硬盘中,这种硬盘也是当今 PC 机中使用最为
广泛的硬盘。SCSI 硬盘是另外一种可提供大容量、高速度数据访问的硬盘。这种硬盘
没有 IDE 硬盘这样的问题,它利用顺序号定位扇区,而顺序号到物理磁头、柱面、扇
区的转换由硬盘控制器完成,由于这一原因,操作系统对 IDE 和 SCSI 硬盘的驱动程
序各不相同。
磁头的跨磁道读写一般因为需要径向移动而需要花费大量的时间,这一般用“平均寻道
时间”来衡量。如果一个硬盘的平均寻道时间很长,则说明硬盘的速度很低。在文件系
统的组织中,操作系统一般会尽量将同一个文件的数据放置在连续的扇区中,这样,磁
头在读取过程中可以少一些寻道时间,从而提高硬盘的整体速度。然而,随着文件的删
除和扇区的重新分配,一些文件就无法保证存储在连续的扇区中,这时,硬盘的读写速
度将受到影响。这种情况一般称为“磁盘的碎片化”。许多操作系统都包含一些可通过
对文件存储扇区的整理而降低碎片化程度的系统工具。
在 Linux 中,每个硬盘由单独的设备文件表示。通常,可有两个或四个硬盘,这一般
取决于 PC 的主板和 BIOS。这些硬盘分别由 /dev/hda、/dev/hdb、/dev/hdc 和/dev
/hdd 表示。而 SCSI 硬盘的个数则不受上述限制,每个 SCSI 总线上可以有 7 个 SC
SI 设备,因而可最多连接 7 个硬盘,分别由 /dev/sda、dev/sdb、dev/sdc、dev/sd
d、dev/sde、dev/sdf 和 dev/sdg 表示。
12.7 软盘
软盘的结构和硬盘类似,只是软盘的磁头包含在驱动器内部,而盘片却是可以从驱动器
中拿出的,因而软盘也称“可移动介质”。因为软盘只有一个盘片,因此,软盘盘面一
般固定为 2 个,而磁道、扇区数量的不同也将软盘分为不同的类型。现在最常见的是
3? 英寸大小的 1.44 MB 软盘。这种软盘一般称为双面高密度盘,Linux 中表示为 /d
ev/fd0H1440, H 表示高密度,1440 表示容量为 1440 K字节,约为 1.44 M字节,fd
0 则表示 BIOS 定义的第一个软盘驱动器(DOS 中的A: 驱动器)。其他种类的软盘也
按上面的方法表示,例如 /dev/fd1D720,表示第二个软盘驱动器,双面双密度容量为
720 K字节的软盘。
所有的软盘种类总共约有 9 种,但 Linux 可通过特殊的设备文件自动检测插入的软盘
种类,即 /dev/fd0 和 /dev/fd1。因此,一般利用这两个设备文件访问软盘驱动器。
12.8 格式化和分区
12.8.1 格式化
如上所述,磁盘在能够使用之前,必须首先经过低级格式化,低级格式化的目的是将磁
盘上的磁粉组织成规定的磁道和扇区,经过低级格式化的磁盘才可以使用。“低级格式
化”一词,实际来自 MS-DOS,因为 DOS 的 FORMAT 命令一般完成两个步骤,一是低级
格式化,二是建立文件系统。为了区分这两个过程,建立文件系统的过程又称为“高级
格式化”。在 Linux 中,这两个步骤是分开进行的,分别称为“格式化”和“建立文
件系统”,因此,下面的描述中我们严格区分“格式化”和“建立文件系统”这两个术
语。
硬盘在出厂时,已经经过了格式化,一般不需要再次进行格式化,经常性的格式化会减
低硬盘的使用寿命。
因为硬盘构造上的差别,硬盘的格式化通常需要特殊的程序来完成,在 DOS 中,这种
功能一般由 BIOS 或特殊的 DOS 程序提供,而在 Linux 中,这两种方法都不太容易利
用。和硬盘比较起来,软盘经常被格式化,同时,软盘的格式化也比较容易实现,这是
因为软盘驱动器的构造较硬盘驱动器透明。可利用下面的命令格式化软盘:
$ fdformat /dev/fd0H1440
Double-sided, 80 tracks, 18 sec/track. Total capacity 1440 KB.
Formatting ... done
Verifying ... done
$
在上述命令中,通过命令参数指定了要格式化的软盘参数:双面双密度、1440 K字节,
并且插入第一个驱动器中。如果要使用 /dev/fd0 这一可自动检测的设备文件,则需要
利用 setfdprm 命令指定软盘参数:
$ setfdprm /dev/fd0 1440/1440
利用 setfdprm,还可以为特殊软盘指定格式信息。
利用 fdformat 格式化软盘时,这一程序还可检验软盘上的坏扇区。通过在扇区上写入
、读出并比较来检验扇区。如果某个扇区经过多次检验仍然错误的话,则认为该扇区为
坏扇区,fdformat 会在这种情况下终止检验并退出。
磁盘上的坏扇区信息一般由文件系统维护,以免将来使用坏扇区保存数据。对于硬盘,
少量的坏扇区还可以在(低级)格式化过程中由磁盘驱动器维护,写入坏扇区的数据,
硬盘驱动器会自动映射到其他正常的扇区中。但这样会降低硬盘的性能。如果硬盘上的
坏扇区数量较多,且集中出现在某处,则可以通过分区避免使用这些坏扇区。由于操作
系统一般使用“块”来分配存储空间(一个块一般是两个连续的扇区),因此,文件系
统中实际维护的是坏块的信息。
不管是软盘或硬盘,都可以利用 badblocks 命令检查坏块。例如:
$ badblocks /dev/fd0H1440 1440
718
719
$
在上面的例子中,badblocks 报告 718 和 719 两个块是坏块,但不对这两个块作任何
标记。如果上述软盘中包含文件系统,则应当利用 fsck 将坏块信息添加到由文件系统
维护的坏块表中,如果该软盘不包含文件系统,则利用 mkfs 命令建立文件系统时,会
自动检查并建立坏块表。
12.8.2 分区
硬盘可以划分为不同的“分区”,每个分区当作单独的硬盘一样操作。对硬盘进行分区
的原因有:
硬盘很大,分区可提高硬盘的访问效率。例如,对 FAT 分区来说,低于 400 MB 的分
区性能较好。 需要安装多个操作系统。例如,如果要在某台计算机的同一张硬盘上同
时安装 Windows 95 和 Linux 两种操作系统,就必须对该硬盘进行分区,并将两个操
作系统安装在不同的分区中。 为方便管理而分区。在不同的分区上放置不同的文件系
统,可方便系统管理和维护。 在安装操作系统时,分区可能是最重要的步骤之一。如
果要建立多重引导(多个操作系统)系统,必须了解每个操作系统对分区的要求,并认
真制定分区计划。为此,必须掌握有关分区的概念和术语。(注:这些概念是 i386 平
台所特有的,对于其他平台的计算机,例如 Alpha 工作站,分区、引导的方法不同。
)
1. 主引导记录、引导扇区和分区表
硬盘的分区信息包含在硬盘的第一个扇区中,也即第一个面的第一个磁道的第一个扇区
中。通常将硬盘的第一个扇区称为“主引导记录 (MBR)”。主引导记录中实际包含了
一小段程序,系统 BIOS 读取主引导记录,然后执行。该程序首先读取“分区表”,判
断活动分区(即标记为可引导的分区),然后读取活动分区的第一个扇区。活动分区的
第一个扇区又称为“引导扇区”,其概念和作用与主引导记录类似,但由于主引导记录
的特殊地位而拥有一个特殊名称。引导扇区负责装入并启动操作系统。
分区的方法实际和硬件无关,也和 BIOS 无关,但是如果要让来自不同软件制作者的操
作系统安装在同一个计算机中,没有一个分区的标准是不行的。当然,有些操作系统不
遵循这样的标准,因此也很难和其他操作系统共存。Linux 现在可以和 Microsoft 的
操作系统共存,它实际遵循 IBM PC 机的硬盘分区方法。这种方法中,分区表指定了硬
盘中的分区个数、各分区类型、起始位置等信息。
2. 主分区、扩展分区和逻辑分区
Linux 在 i386 平台上所遵循的分区方法将分区划分为两种类型:主分区和扩展分区。
每个硬盘可有四个主分区,但其中只有一个可作为引导分区,即活动分区。如果使用扩
展分区(每个盘上仅能有一个扩展分区),则主分区最多只能有三个。每个扩展分区可
以进一步划分为四个逻辑分区,逻辑分区不能作为引导分区。
下面列出的是某台计算机的分区情况:
$ fdisk -l /dev/hda
Disk /dev/hda: 128 heads, 63 sectors, 788 cylinders
Units = cylinders of 8064 * 512 bytes
Devie Boot Begin Start End Blocks Id System
/dev/hda1 * 1 1 261 1052320+ b Win95 FAT32
/dev/hda2 262 262 522 1052322 5 Extended
/dev/hda3 523 523 779 1036224 83 Linux native
/dev/hda4 780 780 788 36288 82 Linux swap
/dev/hda5 262 262 522 1052320+ 6 DOS 16-bit >=32M
$
图 12-9 表示了该硬盘的分区情况。
图 12-9 某硬盘的分区情况
上述硬盘中包含三个主分区,分别为 /dev/hda1、/dev/hda3 和 /dev/hda4;一个扩展
分区,为 /dev/hda2。扩展分区又划分为一个逻辑分区,/dev/hda5。主分区和扩展分
区中各有一个引导扇区。
分区类型
除了在主引导记录中有一个分区表之外,在扩展分区中也有一个分区表。前者定义主分
区和扩展分区的分区信息;而后者定义逻辑分区的分区信息。分区表中为每个分区包含
有一个字节的信息,用来说明该分区的类型。指定分区类型的目的只是为了让不同的操
作系统能够区别这些分区,以避免同时使用不同的分区。例如,图 12-9 所描述的硬盘
分区就为不同的操作系统所用。但是,操作系统可能并不判断分区类型。例如,Linux
在任何类型的分区中均可以建立任意类型的文件系统。相反,Microsoft 的操作系统
则根据分区类型判断是否可访问,因此,非 FAT、VFAT、FAT32或 NTFS 等分区是无法
识别的。
不同分区类型在分区表中的类型字节值不同,表 12-4 给出了部分分区类型的类型值。
表 12-4 常见的分区类型
类型
说明
类型
说明
类型
说明
0
空
40
Venix 80286
a5
BSD/386
1
DOS 12-bit FAT
51
Novell
b7
BSDI fs
2
XENIX root
52
Microport
b8
BSDI swap
3
XENIX usr
63
GNU HURD
c7
Syrinx
4
DOS 16-bit <32M
64
Novell
db
CP/M
5
Extended
75
PC/IX
e1
DOS access
6
DOS 16-bit 3 32M
80
Old MINIX
e3
DOS R/O
7
OS/2 HPFS
81
Linux/MINIX
f2
DOS secondary
8
AIX
82
Linux swap
ff
BBT
9
AIX bootable
83
Linux native
a
OS/2 Boot Manage
93
Amoeba
b
Win95 FAT32
94
Amoeba BBT
利用 fdisk 进行分区时,可以获得同样的分区类型表。
硬盘的分区
和 DOS 一样,Linux 中用来分区的程序也称为 fdisk。和 DOS 的 fdisk 不一样的是
,Linux 的 fdisk 不关心分区类型,从而能够对各种类型的分区进行操作。cfdisk 和
fdisk 类似,但 cfdisk 可在全屏幕方式下进行操作。只要掌握了上述概念,利用这
两个程序进行分区就不会太困难。
进行分区时,需要注意如下问题:
使用 IDE 硬盘时,因为 BIOS 的限制,引导分区(包含可引导内核文件的分区)只能
完全包含在前 1024 柱面内。 应当确保分区包含偶数个扇区,这是因为文件系统数据
块的大小一般为 2 个扇区。 在修改分区之前,应当备份重要数据。许多 MS-DOS 的实
用工具可简化分区过程,并能保证数据的安全,这些工具包括 fips 和 qpmagic 等。
分区的对应设备文件
每个主分区、扩展分区以及逻辑分区和相应的设备文件对应。这些文件的名称一般是在
表示整个硬盘的设备文件之后添加分区编号。主分区或扩展分区的编号按顺序从 1 到
4;逻辑分区的编号从 5 开始,依次编号,最大为 8。例如,/dev/hda2 指第一个 I
DE 硬盘的第二个主分区或扩展分区。
12.8.3 无文件系统的磁盘
并不是所有的磁盘或分区以文件系统的方式使用,例如,Linux 以原始方式使用交换分
区;许多软盘中的数据也是以原始方式组织的,例如,Linux 的引导软盘中就没有文件
系统。避免使用文件系统有如下好处:
可以充分利用磁盘空间,因为文件系统总是有一些额外的开销。
能够提高磁盘在不同系统之间的兼容性。例如,利用 tar 备份的数据,几乎可在任意
一个操作系统中读取。 方便数据的备份。
无文件系统磁盘的使用主要利用 dd 命令。如下所示,可将磁盘上的数据保存到文件系
统中的 floppy-image 文件中:
$ dd if=/dev/fd0H1440 of=floppy-image
2880+0 records in
2880+0 records out
$
利用如下的命令可将文件系统中的 floppy-image 文件以原始方式保存到磁盘上:
$ dd if=floppy-image of=/dev/fd0H1440
2880+0 records in
2880+0 records out
$
MS-DOS 中用来读取原始软盘的工具主要有 hd-copy 和 rawwrite 等。
12.9 其他存储设备
12.9.1 CD-ROM
由于其大容量和非易失性,CD-ROM 现在经常作为软件的发行介质,但和硬盘比较起来
,CD-ROM 的速度较低。
通常而言,CD-ROM 上的数据按国际标准 ISO9660 组织。这是一个非常小的文件系统,
类似 MS-DOS 的 FAT 文件系统。但正因为它小,所以几乎能被任何一种操作系统映射
为自己的文件系统。
PC 机上常见的 CD-ROM 驱动器接口为 EIDE 以及 SCSI,有些老式的还通过声卡连接。
一般而言,通过 IDE 连接时的设备文件命名方式和硬盘一样。通常,在 /dev 目录中
,有一个符号链接 /dev/cdrom 指向实际的 CD-ROM 设备:
12.9.2 磁带
和常见的录音磁带类似,磁带只能顺序存取,因此速度很低,但它也支持随机访问,也
就是说,可以从一处跳到另一处。因为磁带的高容量和低成本,所以经常用来进行数据
的归档和备份。
12.10 显示卡和监视器
如果仅在文本方式下使用 Linux,则不需要对显示卡和监视器进行特殊设置。一般而言
,常见的显示卡和监视器均支持标准的 80 列、25 行的 16 色文本显示模式。但是,
如果要在 Linux 上配置运行 X Window(简称 X),则必须了解自己的显示卡和监视器
。Linux 的多数商业发行版本均提供一个比较友好的界面,可用来设置显示卡和监视器
。例如,在 Red Hat 5.x 中,Xconfigurator 可帮助你完成大多数的设置工作。这一
程序可以检测出大多数常见的显示卡型号及其参数。但是,当你的显示卡无法自动检测
时,有时需要利用更高级的 xf86config 或 XFree86Setup 等程序进行设置。在利用
xf86config 程序进行设置之前,必须了解有关显示卡和监视器的参数及其意义。
一般而言,显示卡是控制监视器的电路板,插入 PC 主板的 ISA、PCI 或 AGP 插槽中
,有些主板则直接包含有图形芯片组。
12.10.1 光栅扫描监视器
所有图形卡的操作原理都是一样的。显示卡中的显示 RAM(VRAM)中存储着要显示的图
象,显示卡负责根据 VRAM 中的数据产生信号并在监视器上显示图形。
监视器是用于显示图形或文本的物理设备,对常见的 PC 机而言,显示屏幕一般是荧光
显象管,电子束来回扫描并让荧光发光而产生图象。笔记本电脑一般配备的是液晶显示
屏。
如图 12-10 所示,监视器中的图象由大量的水平扫描线形成,监视器中的电子束在荧
光屏上来回扫描而生成扫描线。
图 12-10 光栅扫描监视器的原理
荧光屏上的单个发光点称为一个“象素”。通过控制扫描电子束的强度就可以显示一条
图象线。荧光在显示屏上的显示时间很短,但是由于图象的重复绘制,加上人眼的视觉
暂留,可在人脑中形成稳定的图象。一般的监视器可在一秒内重绘 50 ~ 90 次。
参照图 12-10,电子束每扫描完一条光栅线之后,要折回到下一条光栅线的开头扫描,
电子束的这种运动称为“水平折回”。类似地,电子束扫描完一整屏之后,要重新从第
一条光栅线开始扫描,这种运动称为“垂直折回”。这两种运动分别对应监视器的两个
参数:“水平扫描频率”和“垂直扫描频率”。
12.10.2 彩色监视器
彩色监视器通过三原色,红、绿、蓝的组合显示颜色。彩色监视器荧光屏上的象素是呈
三角形分布的红绿蓝荧光点。红绿蓝电子束分别以不同的强度扫描红绿蓝荧光粉,就可
以显示出许多不同的颜色。
12.10.3 调色板和分辨率
我们知道,监视器能够显示的颜色可以上万种,而标准的 VGA 16色模式只能同时显示
16 种颜色。能够同时显示的颜色数实际是由图形卡的显示模式决定的,同时受到监视
器的限制。为了处理上的方便,图形卡预先定义一种调色板,例如包含 256 种颜色的
调色板,程序可通过指定调色板中的颜色索引号,即 0 到 255,来指定某象素的实际
颜色。通常,调色板中的颜色是可以通过编程改变的。
标准的 VGA 16 色模式定义了 16 种颜色,因此每个象素的颜色可由 4 位二进制数表
示;而 256 色模式下,需要用 8 位二进制数表示一个象素。
当前许多流行的显示卡都可以利用 2 个字节(16位)或 3 个字节(24 位)来表示象
素的颜色。这时,用来表示象素的字节直接包含红绿蓝三种颜色。因此,对于 24 位的
显示模式来说,它可以显示 256 ′ 256 ′ 256 =16777216 种颜色,通常称为“真彩
色”,而这种模式也需要更多的显示内存来存储整个图象。
分辨率指水平扫描线和垂直扫描线的数量。不同的显示卡模式对应不同的分辨率,但最
高分辨率一般受监视器的限制。常见的分辨率为 640 ′ 480,即水平可以有 640 个象
素,垂直可有 480 个象素。另外,800 ′ 600、1024 ′ 768 等也是常见的分辨率。
12.10.4 显示内存
显示卡在随机访问储存器中,也即显示内存中保存象素。显示内存的大小直接影响可显
示的分辨率和颜色数。对于 256 色、1024 ′ 768 的显示模式来讲,就需要 1024 ′
768 = 786432 字节的显示内存。
12.10.5 点时钟
在配置 X Window 的显示卡时,经常要遇到点时钟(dot clock)这一术语。点时钟指
显示卡控制整屏扫描线的速率。点时钟的值以每秒能够绘制的点的数量表示。
对于 640 ′ 480 的显示模式来说,可见点的数量有 640 ′ 480 = 307200个。为了获
得稳定的图象,至少要以每秒 72 次的速度绘制所有这些点,因此,显示卡要在一秒内
显示 307200 ′ 72 = 22118400 个点,因此,点时钟的值大约为 22 MHz。
但是,实际上点时钟的值要稍微大一些,这是因为扫描线的范围要稍微比 640 ′ 480
大一些。因此,对 640 ′ 480,刷新频率为 72 Hz 的模式,点时钟大约为 25.2 MH
z。
老的显示卡支持一组固定的点时钟,而新的显示卡则可以通过编程指定点时钟。如果显
示卡的点时钟是可编程的,则 X Server 可以以任意可接受的值操作显示卡,但需要指
定用来控制点时钟的芯片,即时钟芯片。
12.10.6 XFree86
我们知道,各种显示卡的内部构造不同,为了提高不同显示卡之间的兼容性,视频电子
学标准协会建立了 VESA 标准。VESA 提供了一组附加的 BIOS 功能,利用这组功能可
以访问大多数 Super VGA 的扩充模式和功能。在 MS-DOS 中,利用 VESA BIOS 访问
VESA 兼容的Super VGA 是非常方便的。但是,由于Linux 建立在 80386 的保护模式之
上,因此不能直接利用 VESA BIOS。实际上,Linux 中的 XFree86 通过对显示卡的直
接控制而进行操作。因此,某些显示卡可在 XFree86 中支持,而有些,尤其是多数 A
GP 显示卡还不能由 XFree86 支持,幸运的是,大多数 AGP 显示卡和某些 Super VGA
卡兼容,因此,也可以利用兼容显示卡对应的 X Server。
监视器对 XFree86 也同样重要,显示卡控制监视器,显示卡给出的点时钟如果和监视
器不兼容,也同样无法正常显示图象。显示分辨率不仅和显示内存有关,也和监视器支
持的刷新频率有关。
对 XFree86 来说,有关显示卡,以及鼠标、键盘的信息保存在 /etc 目录中的 XF86C
onfig 文件中。不同的 Linux 发行版本保存该文件的位置可能不同,Red Hat 5.x 在
/etc/X11/ 目录中保存该文件。
该配置文件本身由若干信息组成,这些信息以段(Section)的方式组织,分别说明不
同的硬件配置情况,见表 12-5。
表 12-5 XF86Config 文件中的主要配置信息
Files
指定 RGB 数据库路径,以及字体文件路径。
Server flags
指定 X Server 的选项。
Keyboard
指定键盘参数。
Pointer
指定鼠标参数。
Moniter
指定监视器参数。
Device
指定显示卡参数。
Screen
给出显示卡、监视器以及 X Server 的综合说明。
一般而言,段的格式如下所示:
Section “SectionName”
Parameter1
Parameter2
EndSection
对 Monitor 和 Device 段而言,可以定义多个不同段,每个段利用不同的字符串标识
,如下所示:
# 定义两个 Monitor 段
Section “Monitor”
Identifier “My monitor”
VendorName “Unknown”
ModelName “Unknown”
BandWidth 75.0
HorizSync 30-64
VertRefresh 55-90
Modeline “640x400” 25.175 640 664 760 800 400 409 411 450
...
EndSection
Section “Monitor”
Identifier “ViewSonic 15GS”
...
EndSection
# 定义两个 Device 段
Section “Device”
Identifier “Number Nine GXE64 with S3-Trio64”
...
EndSection
Section “Device”
Identifier “Generic VGA”
VendorName “Unknown”
Chipset “generic”
# VidoeRam 256
# Clocks 25.2 28.3
EndSection
然后在定义 Screen 段时,可利用标识字符串来引用不同的监视器和显示卡参数,这种
方法在一定程度上提高了配置的灵活性。XF86Config 中一般定义有多个 Screen 段,
不同的 Screen 段针对不同的 X Server 而设置。X Window 启动时,自动利用最佳(
即最能发挥显示卡和监视器性能的设置) Screen 段中的信息。典型的 Screen 段的定
义如下:
Section “Screen”
Driver “accel”
Device “Number Nine GXE64 with S3-Trio64”
Monitor “My monitor”
Subsection “Display”
Depth 8
Modes “640x480” “800x600” “1024x768”
ViewPort 0 0
Virtual 1024 768
EndSubSection
Subsection “Display”
Depth 16
Modes “640x480” “800x600”
ViewPort 0 0
Virtual 800 600
EndSubSection
Subsection “Display”
Depth 32
Modes “640x400”
ViewPort 0 0
Virtual 600 400
EndSubSection
其中,Screen 段中的 Driver 参数指定了所使用的 X Server。XFree86 所使用的 X
Server 分为 4 大类,见表 12-6。
表 12-6 X Server 的分类
vga2
VGA 单色模式。
vga16
标准 VGA 16 色模式。
svga
指 Super VGA 的 640x480 256 色模式。
accel
指各种加速 X Server,需指定明确的显示卡芯片组。
不同的 Display 子段一般用于不同的颜色模式,上述例子中指定了三种颜色模式。X
Window 启动时自动使用第一个 Display 子段的信息,但可通过指定 bpp(bytes per
pixels,每象素的字节数,和 Display 子段的 depth 参数一样)明确指定使用的 D
isplay 子段,例如:
startx -- -bpp 32
Display 子段中的 Modes 参数指定了一组显示卡和监视器能够支持的显示模式。”80
0x600” 等模式名称在 Monitor 段中定义。当某种模式定义有多个显示分辨率时,可
在 X Window 运行时利用 Ctrl+Alt+Plus 和 Ctrl+Alt+Minus 在不同的分辨率之间切
换,这里的 Plus 和 Minus 是数字键盘上的“+”和“-”键。如果指定了一个显示卡
或监视器无法支持的显示模式时,可利用 Ctrl+Alt+Backspace 按键强制关闭 X Wind
ow。
当显示内存的数量比指定模式所需的内存要多时,X Server 可利用多余的内存建立一
个比物理屏幕大的虚拟屏幕。这时,可利用 Virtul 指定虚拟桌面的大小,而利用 Vi
ewPort 可指定物理屏幕的左上角在虚拟屏幕中的位置。
参见上面的 Device 段,VendorName、BoardName 和 Chipset 分别指定显示卡的类型
和芯片组。对于标准 VGA 模式来说,这些参数是无关紧要的,也不需要指定显示内存
(VideoRam)的大小和点时钟(Clocks)。对于许多没有可编程点时钟的显示卡来说,
Clocks 参数指定了该显示卡支持的所有点时钟。
参见上面的 Monitor 段,其中指定了监视器的许多技术参数,包括带宽(BandWidth,
MHz)、水平同步频率(HorizSync,kHz)和垂直刷新速率(VertRefresh,Hz)。这些
参数一般由厂家公布在监视器手册中,并且不能随意设定,否则可能会损坏监视器。
Monitor 段中的 Modeline 是监视器最重要的参数,它可以用两种等价格式给出,一种
是单行格式,一种是多行格式,其中包含的数据是一致的。利用单行格式时,其语法如
下:
Modeline “name” CLK HRES HSS HSE HTOT VRES VSS VSE VTOT flags
表 12-7 解释了上述这些参数的含义。
表 12-7 Modeline 的参数含义
“name”
指定该模式的名称,在 Screen 段中用该名称引用此模式。
CLK
该模式的点时钟。对具有固定点时钟的显示卡来说,该点时钟必须和 Device 段中给
出的某个点时钟值相等。
HRES HSS HSE HTOT
水平时序参数。HRES 是光栅扫描线上以象素为单位的水平分辨率。从 图 12-10 可见
,实际分辨率要比可见分辨率高,HTOT 即指定实际的象素点数。HSS 是水平同步信号
的起始点,而 HSE 是水平同步信号的终止点。
VRES VSS VSE VTOT
垂直时序参数。VRES 是光栅扫描线上以象素为单位的垂直分辨率。从 图 12-10 可见
,实际分辨率要比可见分辨率高,VTOT 即指定实际的垂直象素点数。VSS 是垂直同步
信号的起始点,而 VSE 是垂直同步信号的终止点。
flags
指定模式标志。例如,对隔行扫描方式来说,值为 Interlace。利用该标志也可以指
定同步信号的极性,可取 +HSync、-HSync、+VSync 和 VSync 等值。这些标志可从监
视器手册中查到。
如果我们没有任何其他可用资料,却需要配置 modeline,则可从监视器手册中查到特
定模式下的垂直刷新速率(Hz)和水平同步频率(kHz)。有时监视器只提供这两个参
数的有效区间。一般而言,点时钟和这两个频率之间有如下等式关系:
CLK = RR * HTOT * VTOT
CLK = HSF * HTOT
其中 RR 指监视器的屏幕刷新频率(处于监视器的垂直刷新频率区间),而 HSF 是监
视器的水平扫描频率。例如,当屏幕刷新频率为 72 Hz 时,对于某给定的点时钟,从
第一个等式可计算得到 HTOT * VTOT,从第二个等式可计算得到 HTOT,最终可得到 V
TOT 以及 HTOT。
这时,所需参数只剩下 HSS、HSE、VSS 和 VSE(HRES 和 VRES 由显示模式的分辨率确
定)。但这几个参数只能通过试验才能得到,这些参数应满足如下条件:
HTOT > HSE > HSS > HRES
VTOT > VSE > VSS > VRES
12.11 键盘和鼠标
键盘和鼠标通常是操作系统的标准输入设备,Linux 也不例外。任何能够在 DOS 下正
常工作的键盘,也同样能够在 Linux 中正常工作。但是,Linux 的键盘有一些 DOS 所
没有的特殊属性。鼠标是另外一种输入设备,如果不使用鼠标,就无法在 X Window 系
统中进行高效操作。鼠标的接口类型有许多种,常见的如串行鼠标、PS/2 接口鼠标等
。本节重点讲述 Linux 中和键盘、鼠标相关的术语和概念,以及相应的设置工具。
12.11.1 键盘布局
“键盘布局”指键盘上各个键的布局。一般来说,一个键盘上的键可划分为几部分:打
字键、功能键、光标键和数字键等。不同的键盘布局一般具有不同的键个数,主要区别
在于功能键的个数、是否有光标键以及是否有数字键等。
Linux 内核一般以某个唯一的数值来表示不同的键,该数值称为“键码”。和 DOS BI
OS 中的扫描码概念一样。虽然有些键的名字是一样的,例如,打字键“1”和数字键“
1”,它们都表示数字“1”,但它们在 Linux 内核中由两个不同的数字表示。再比如
,打字键“#”和打字键“3”一般由同一个键代表,Linux 用同样的数值表示它们,用
户击键时这些键所代表的是数字还是符号,这取决于键盘上的修饰键。当用户按打字键
“3”时,同时按住了“Shift”键,则说明该键代表的是符号“#”,而不是数字“3”
。如果按打字键“a”时,按住了“Ctrl”键,则该键代表特殊的 ASCII 字符。因此,
Shift 键和 Ctrl 键以及 Alt 键等一般称为修饰键。键盘驱动程序根据用户按下的键
的键码,以及当前修饰键的按下状态等,将用户的输入翻译为相应的 ASCII 值。
和 Shift 等修饰键不同,Caps Lock 等键虽然也是修饰键,但它们的功能略微有些不
同。这些键称为“切换键”或“锁定键”,这种键有:Caps Lock、Num Lock 和 Scro
ll Lock 键。用户按一次切换键后,键盘上的某些键所代表的含义就会发生变化,再按
一次切换键,这些键的含义复原。常用的切换键为 Caps Lock,用来切换字母键的大小
写。键盘驱动程序实际为每种切换键保留有一个标志位或标志值,按照这些标志将用户
的输入翻译为正确的 ASCII 值或键值。用户按下不同的切换键后,键盘驱动程序还要
同时修改键盘右上角 LED 灯的点亮状态。
上述过程是键盘驱动程序在 Linux 虚拟控制台上的处理。因为 Linux 将键盘看成一种
字符设备,如果直接读取该设备,则可以获得键盘上所有键的按键状态,从而改变默认
的键盘处理逻辑。X Window 对键盘的处理实际就是这样的,它将键盘的键码直接翻译
为自己的键符号。
12.11.2 键盘的重复延迟和重复率
这两个概念和 Windows 95 的相应概念一样。用户按下某个键后,经过一定时间键盘会
自动重复该键,这一时间就是键盘的重复延迟时间。重复率则指键盘的重复速率。如果
重复速率太高,用户按某个键时就可能获得比意想的输入多的键输入。默认情况下,P
C 键盘的重复延迟设置为 250 ms,而重复延迟则设置为 10.9 次每秒(cps)。利用
kbdrate 命令可修改键盘的这两个物理参数,例如:
$ kbdrate r 12.0 d 500
将重复率设置为 12.0 cps,而重复延迟设置为 500 ms。不带任何参数时,kbdrate 命
令将这两个参数设置为默认参数。
在 X Window 下,也可以利用上述命令修改这两个参数。除此之外,X Window 还提供
了 xset 命令,可利用该命令取消键盘的重复功能,例如:
$ xset r off
会取消重复功能,而利用
$ xset r on
会打开重复功能。但是,xset 命令不能设置键盘的重复率。
12.11.3 Linux 中的键盘映射
对于英语来说,键盘上的字母键直接和英语字母表中的字母对应,但是对于非英语的语
种来说,情况就不太一样了。例如,德语中的“?”字母就没有直接的键和它对应,为
此,Linux 提供“键盘映射”或“键盘翻译”,利用键盘映射可将某些键转换为特殊键
。
前面提到,X Window 直接处理了键盘的输入输出端口,因此,在 Linux 虚拟控制台下
和 X Window 下使用不同的键盘映射方法。在 Linux 虚拟控制台上,可利用 loadkey
s 命令将特殊按键映射为特殊字符;而在 X Window 中,必须使用 xmodmap 命令完成
键盘映射。这些命令均按照字符映射表文件(文本文件)中的规定完成相应的转换。在
X Window 启动时,它会参考 Linux 文本模式下的字符映射表,因此可获得某些一致
的键映射。
字符映射表文件保存在 /usr/lib/kbd/keytables 目录下,defkeymap.map 是默认的字
符映射表文件。利用命令:
$ loadkeys fr.map
可装入 fr.map 所规定的字符映射表。这时,按下“.”会显示“:”。命令
$ loadkeys d
可装入默认字符映射表。对于非默认的键盘映射,可在启动时在 shell 脚本中装入特
殊的映射表。
对X Window 而言,它对键盘的处理过程分如下两个步骤:
1.X Server 首先将键码转换为键符号名(keysym)。文件 /usr/include/X11/keysy
mdef.h 中包含所有的符号名。X Server 能够区分修饰键带来的不同,因为 keysymde
f.h 中区分了两种不同的键,例如对“a”和“A”,分别用“KS_a”和“KS_A”定义。
2.X Server 将键符号翻译为 ASCII 字符串。对于大多数的键来说,该字符串只包含
一个字符,而对于功能键等特殊按键来说,则包含多个字符。例如,F5 键对应的默认
ASCII 字符串为 “5~”。
利用 xmodmap 工具可修改键盘和键符号名之间的对应关系。例如,X Window 中“A”
的键码为 30,而“Q”的键码为16。如果建立文件 maptest:
keycode 38 = A
keycode 24 = Q
在 xterm 中运行
$ xmodmap maptest
之后,将发现“A”键和“Q”键交换了过来。
上述的 maptest 文件实际就是一个简单的 X Window 映射文件。但需要注意的是,文
件中的 keycode 和 Linux 内核对键值的定义是不一样的,一般而言,X Window 中的
键码要比内核的键值大 8。利用 showkey 命令可以查看内核对键值的定义。例如,运
行 showkey 并前后按下“A”和“Q”后,程序的输出为:
$ showkey
kb mode was RAW
...
keycode 30 press
keycode 30 press
keycode 16 press
keycode 16 press
该程序给出的是“A”和“Q”的内核键值。
在 XF86Config 文件中,Keyboard 段用来指定键盘参数,一般而言,这些参数不需要
特殊设置:
Section “Keyboard”
Protocol “Standard”
AutoRepeat 500 5
EndSection
12.11.4 鼠标接口
当前 PC 中最常见的鼠标接口是串行接口、PS/2 辅助设备端口以及 Microsoft 总线鼠
标等。另外,还有一些不太常见的鼠标接口,它们有些是上面这些接口的变种,有些则
依赖于上面的接口。表 12-8 列出了这些鼠标接口。
表 12-8 常见鼠标接口
接口类型
说明
设备名称
串行接口
这种鼠标象调制解调器一样连接到 PC 的串行端口。Microsoft、Logitech 鼠标也具
备串行接口。 /dev/ttys0
/dev/ttys1
PS/2 辅助设备端口
这种鼠标通过键盘控制器上的辅助设备端口连接。
/dev/psaux
Microsoft 总线鼠标
这种鼠标连接插在 PC 主板的接口卡上。
/dev/inportbm
Logitech 总线鼠标
这种鼠标和 Microsoft 总线鼠标类似,但所遵循的协议不同。
/dev/logibm
ATI-XL 总线鼠标
这是 Microsoft 总线鼠标的变种,它直接连接到 ATI-XL 显示卡上。
/dev/atibm
其他
一些内置在笔记本电脑中的接口,一般而言,这种接口依赖于 PS/2 接口进行连接。
所有的鼠标均需要占用中断请求线 IRQ,某些还需要一些 I/O 端口地址。串行端口 C
OM1 和 COM2 默认分别使用 IRQ4 和 IRQ3;总线鼠标默认使用 IRQ5,有时可能会造成
和声卡、SCSI 控制器之间的中断冲突。PS/2 辅助端口总使用 IRQ12,该设置是无法改
变的。
12.11.5 鼠标设备名称
和键盘以及调制解调器一样,鼠标设备也是字符设备。对于不同的鼠标接口,Linux 使
用不同的特殊设备文件名称,见表 12-8。
为方便起见,利用 /dev/mouse 作为通用的鼠标设备,这一设备文件通过符号连接指向
实际的鼠标设备。例如,在某笔记本电脑中,利用如下命令可看到符号连接情况:
$ ls -l /dev/mouse
lrwxrwxrwx 1 root root 10 Sep 4 21:08 mouse -> /dev/psaux
利用这种约定,运行在使用不同鼠标接口的计算机中的程序均可以利用 /dev/mouse 设
备文件访问鼠标。
12.11.6 鼠标协议
鼠标协议指鼠标用来包装鼠标移动和按钮状态信息的约定。鼠标协议由鼠标数据的接受
者使用,用来解释鼠标的移动和按钮状态。鼠标协议对 XFree86 来说非常重要,因为
X Server 必须能够解释和使用鼠标数据,以便可以在屏幕上绘制鼠标的移动,并响应
鼠标的按钮事件。表 12-9 给出了常见的鼠标协议。
表 12-9 常见鼠标协议
协议名称
对应的鼠标类型
BusMouse
Microsoft 和 Logitech 总线鼠标。
Logitech
老的 Logitech 串行鼠标。新的 Logitech 鼠标使用 Microsoft 或 Mouseman 协议。
Microsoft
Microsoft 或其他串行鼠标。
MMSeries
MMSeries 串行鼠标。
Mouseman
Logitech Mouseman 鼠标。
MouseSystems
MouseSystems 鼠标。
PS/2
所有连接到 PS/2 辅助端口的鼠标。
MMHitTab
MouseMan HitTablet。
Xqueue
只有在 keyboard 协议也使用 Xqueue 时,才使用该协议。
12.11.7 鼠标和 XFree86
在 XFree86 中,鼠标数据的接受者是 X Server。X Server 至少需要了解如下信息:
鼠标的设备文件名称。可以指定为 /dev/mouse,也可以直接指定为相应的设备文件。
鼠标为发送移动和按钮状态信息而使用的协议。
这些鼠标参数,在 /etc/X11/XF86Config 文件的“Pointer”段中指定。除此之外,还
需要设置一些其他信息。例如,对 Logitech 串行鼠标,还需要指定 BaudRate 和 Sa
mpleRate 参数,分别代表波特率和采样频率。如果鼠标为两键鼠标,还可以指定模拟
三键鼠标,例如:
Emulate3Buttons
对于 MouseSystems 鼠标,需要在 Pointer 段中指定如下参数:
ClearDTR
ClearRTS
某些三键鼠标,当单击中间键时,会发送一个左右键的同时单击信息,可以利用如下参
数关闭这一功能:
ChordMiddle
典型的鼠标 Pointer 段如下所示:
Section “Pointer”
Protocol “Microsoft”
Device “/dev/mouse”
Emulate3Button
EndSection
12.12 打印机
11.12.1 打印机及其设备文件
典型的 PC 具有一个并行端口和两个串行端口,大多数打印机连接在计算机的并行端口
上。在 Linux 中,并行端口的设备名称和设备号如表 12-10 所示。
表 12-10 Linux 中的并行端口设备名称和设备号
I/O 端口
设备名称
主设备号
次设备号
0x3bc
/dev/lp0
6
0
0x378
/dev/lp1
6
1
0x278
/dev/lp2
6
2
在大多数 PC 机中,LPT1 端口使用的 I/O 地址为 0x378,因此,一般的并行设备名称
为 /dev/lp1。
12.12.2 假脱机和打印作业
假脱机指能够在后台进行打印的能力。Linux 中的打印环境由许多程序组成,它们也支
持假脱机。假脱机目录是包含打印文件的目录。
打印任务指利用单个打印命令要求打印的内容。Linux 中的打印程序在假脱机目录中排
列各个打印任务,然后由后台进程周期性地将打印作业从假脱机目录中按顺序发送到打
印机。
12.12.3 打印作业控制
在 Linux 中,可以利用命令 lpr 将打印作业放置在打印作业队列中等待打印。例如,
可用如下的命令打印文件 test.txt:
$ lpr test.txt
lpr 命令将 test.txt 文件复制到假脱机目录(一般处于 /var/spool 目录)中,然后
由 lpd 后台进程将文件发送到打印机。如果要打印的文件非常大,则可以利用 lpr 命
令的 -s 参数,建立一个指向欲打印文件的符号连接,这样,就不需要进行复制。
利用 lpr 的 -p 参数,可以指定打印机类型。例如:
$ lpr Phplj test.txt
指定打印机名称为 hplj,该名称实际定义在 /etc/printcap 文件中。也可以利用 PR
INTER 这一 shell 环境变量指定默认的打印机。
利用 lpq 命令可检验打印队列。例如:
$ lpq
lp is ready and printing
Rank Owner Job Files Total Size
active root 1 test.txt 14186 bytes
1st WeiYM 2 support.c 42644 bytes
Rank 列中的 active 表明该打印作业是正在打印的打印作业。
利用 lprm 命令可取消打印作业。利用该命令时,需要指定打印作业的编号。例如:
$ lprm 1
dfA001Aa00235 dequeued
cfA001Aa00235 dequeued
利用 lprm - 命令可取消所有的打印作业。
利用 lpc status 命令可查看打印机状态。例如:
$ lpc status
lp:
queuing is enabled
printing is enabled
no entries
no daemon present
如果打印机支持 PostScript,则可以直接输出 PostScript 文件。
12.12.4 Linux 的打印原理
在 MS-DOS 中,我们经常利用 copy 命令直接向打印机端口输出要打印的文件。在 Li
nux 中,如果登录为 root,并且保证打印机工作正常,也可以利用类似的命令直接输
出到打印机:
$ cat test.txt > /dev/lp1
但是,上述命令在多用户和多任务系统中是非常有害的。在多任务系统中,通常利用假
脱机方式打印。在 Linux 中,每个打印机对应有一个假脱机目录,每个要打印到该打
印机的打印作业保存在对应的假脱机目录中,每个文件对应一个打印作业。一个后台进
程,即打印守护进程 lpd,周期性地检验假脱机目录中的新文件,如果发现有新文件,
则负责发送到打印机。打印作业实际在假脱机目录中按队列排队,因此,多个打印作业
形成了一个打印队列。
如上所述,我们可以使用 lpd、lpr、lpq、lprm 以及 lpc 等命令操作或查看打印队列
。除此之外,在 Linux 的打印处理中,/etc/printcapp 文件也扮演着重要的角色。
如前所述,利用 lpc 命令可以查看打印机状态,实际上,该命令是一个交互式命令,
可以利用一些预先定义的命令控制打印机。例如:
$ lpc
lpc> help
Commands may be abbreviated. Commands are:
abort enable disable help restart status topq ?
clean exit down quit start stop up
lpc> stop hplj
...
lpc> q
$
表 12-11 列出了常用的 lpc 命令。
表 12-11 常用的 lpc 命令
命令
说明
使用许可
restart printer-name
重新启动打印机守护进程 (lpd)。可使用 all 指代所有的打印机。
任何人
status printer-name
显示指定打印机的状态。如果不指定打印机名称,则显示默认打印机(lp)的状态。
任何人
help command-name
显示帮助信息。
任何人
Exit
退出 lpc(仅能用于交互式方式)
任何人
Quit
退出 lpc(仅能用于交互式方式)
任何人
abort printer-name
和 stop 命令类似,但不等待当前作业完成。当打印重新开始时,当前作业继续。
root
clean printer-name
从打印机队列中清除所有的作业,包括活动作业。
root
disable printer-name
关闭指定打印机的打印作业假脱机。之后,用户无法利用 lpr 命令打印。
root
down printer-name message
关闭假脱机并停止打印机守护进程,效果等同于 disable 和 stop 命令的组合使用。
之后,用户运行 lpq 命令时,将显示 message。 root
enable printer-name
打开指定打印机的打印作业假脱机。
root
start printer-name
打开打印机守护进程。之后,守护进程就可以打印指定打印机的假脱机目录中的任何
作业。 root
stop printer-name
等待当前打印作业完成后,关闭打印机守护进程。之后,守护进程停止打印假脱机目
录中的作业。打印停止后,用户仍然可以使用 lpr 提交打印作业,但只有利用 start
命令打开打印机守护进程之后才能打印这些作业。 root
topq printer-name job-id
将指定的打印作业挪到打印机队列的前面。如果使用用户名指定 job-id,则所有该用
户的打印作业被提前。 root
up printer-name
down 命令的反操作,该命令打开假脱机并启动打印机守护进程,等同于 enable 和
start 命令的组合使用。 root
/etc/printcap 文件是 Linux 打印环境的核心。该文本文件描述了不同打印机的打印
能力。下面是 /etc/printcap 文件定义一个 HP LaserJet 打印机的例子:
# HP LaserJet printer
lp|hplj|Laserjet-ADDL|HP Laserjet 4M in Advanced Development Lab:\
:lp=/dev/lp1:\
:sd=/usr/spool/lp1:\
:mx#0:\
:if=/usr/spool/lp1/hplj-if.pl:\
:lf=/usr/spool/lp1/hplj-log:\
:sh:
上面的例子定义了如下内容:
将打印作业发送到设备 /dev/lp1(lp 域)。
在 /usr/spool/lp1 目录保存排队的打印作业(sd 域)。
不限制打印作业的大小(mx 域)。
通过 /usr/spool/lp1/hplj-if.pl 筛选器传递打印文件(if 域),筛选器等同于 Wi
ndows 95 中的打印机驱动程序。 在文件 /usr/spool/lp1/hplj-log 中保存错误日志
(lf 域)。 将打印作业发送到设备 /dev/lp1(lp 域)。
打印作业间的隔离页(sh 域)。
其他用来定义打印机的域可参见有关文档。
12.13 其他外设
Linux 能够支持的外设多种多样,除了上面的这些外设外,还有声卡、调制解调器、网
络设备、PCMCIA 卡等。和这些设备相关的安装和配置问题可参阅有关文档。
--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: bin@mtlab.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:608.963毫秒