过Linux的人都知道在Linux上硬件的配置过程是非常繁杂的。比如说,对于一块普通的pci网卡,您可能先要知道它的芯片类型,网卡生产厂商,然后猜出它对应的硬件驱动模块,然后再使用modprobe(insmod)插入这个模块,再然后还要生成一系列的配置脚本,最后才能使其正常工作。这还只是一块网卡的配置过程,但是对于不胜枚举的其他硬件,如显卡、声卡、modem、isdn设备、usb设备、pcmcia设备,而它们的配置方法和生成的配置脚本都不尽相同,因此对于一个普通用户要想全部掌握这些配置过程是相当困难的。硬件的自动检测是进行Linux下设备自动配置过程的前提。本文的内容是先从硬件在Linux下的内核描述信息开始,着重介绍如何实现硬件的自动检测。
1:设备检测的一般介绍
一般而言,在Linux下进行设备自动检测是根据设备的总线类型进行的。现在的微机系统上最常见的总线类型有PCI、SERIAL、USB、PCMCIA、PARPORT、ISA、SCSI等。对于检测过程,一般不是通过c语言的库函数直接对设备进行访问,并读取设备的信息,而是通过内核的/proc文件系统进行。这种检测方式,充分利用了内核中关于硬件的多种检测函数,具有高效、稳定的特点,并且在内核版本升级之后,使程序的变化也为最小。对于大多数现在流行的系统硬件,在插入适当的模块之后,内核会在/proc文件系统中生成相应的描述文件。检测过程就是读取这样的文件,并将其信息进行相应的处理,从中提取出设备标识、设备描述、设备工作状态等信息。
由于涉及到对/proc文件系统的访问,并可能在检测过程开始时插入需要的设备模块,所以需要用户以root用户方式执行下面所说的操作。
在检测过程结束的时候,用户一般能够得到设备的唯一标识(制造商标识和设备标识)和设备的当前的状态信息。这时就需要一个设备数据库,这个数据库将设备的唯一标识和对应的设备驱动程序对应起来,然后由此生成/etc/modules.conf中的对应表项及其他配置脚本,完成整个的硬件配置过程。
2 PCI设备的自动检测
2.1 PCI设备简介
对于每个pci设备都由一个总线号、一个设备号和一个功能号确定。PCI设备可以访问三类地址空间:PCI的I/O空间、PCI的存储空间和PCI的配置空间。前两者可由PCI总线上的所有设备共享。PCI的配置空间由256个字节构成,其布局是标准化的。下表显示的是配置空间中前64字节的每个配置寄存器的分布情况:
Vendor ID Device ID
Command Reg Status Reg
Revision ID Class Code
Cache Line Latency Timer Header Type BIST
Base Address 0
Base Address 1
Base Address 2
Base Address 3
Base Address 4
Base Address 5
CardBus CIS pointer
Subsystem Vendor ID Subsystem Device ID
Expansion ROM Base Add
Reserved(PCI Capability List)
Reserved
IRQ Line IRQ Pin Min_Gnt Max_Lat
class code
设备的类型标识,类寄存器是16位的值。它的高八位确定基类,如SCSI设备的分类码位0x0100。Linux系统的定义见中的声明。现在摘录如下:
#define PCI_CLASS_NOT_DEFINED
0x0000
#define PCI_CLASS_NOT_DEFINED_VGA
0x0001
#define PCI_BASE_CLASS_STORAGE
0x01
#define PCI_CLASS_STORAGE_SCSI
0x0100
#define PCI_CLASS_STORAGE_IDE
0x0101
#define PCI_CLASS_STORAGE_FLOPPY
0x0102
#define PCI_CLASS_STORAGE_IPI
0x0103
#define PCI_CLASS_STORAGE_RAID
0x0104
#define PCI_CLASS_STORAGE_OTHER
0x0180
#define PCI_BASE_CLASS_NETWORK
0x02
#define PCI_CLASS_NETWORK_ETHERNET
0x0200
#define PCI_CLASS_NETWORK_TOKEN_RING
0x0201
#define PCI_CLASS_NETWORK_FDDI
0x0202
#define PCI_CLASS_NETWORK_ATM
0x0203
#define PCI_CLASS_NETWORK_OTHER
0x0280
#define PCI_BASE_CLASS_DISPLAY
0x03
#define PCI_CLASS_DISPLAY_VGA
0x0300
#define PCI_CLASS_DISPLAY_XGA
0x0301
#define PCI_CLASS_DISPLAY_OTHER
0x0380
#define PCI_BASE_CLASS_MULTIMEDIA
0x04
#define PCI_CLASS_MULTIMEDIA_VIDEO
0x0400
#define PCI_CLASS_MULTIMEDIA_AUDIO
0x0401
#define PCI_CLASS_MULTIMEDIA_OTHER
0x0480
#define PCI_BASE_CLASS_MEMORY
0x05
#define
PCI_CLASS_MEMORY_RAM
0x0500
#define
PCI_CLASS_MEMORY_FLASH
0x0501
#define
PCI_CLASS_MEMORY_OTHER
0x0580
#define PCI_BASE_CLASS_BRIDGE
0x06
#define
PCI_CLASS_BRIDGE_HOST
0x0600
#define
PCI_CLASS_BRIDGE_ISA
0x0601
#define
PCI_CLASS_BRIDGE_EISA
0x0602
#define
PCI_CLASS_BRIDGE_MC
0x0603
#define
PCI_CLASS_BRIDGE_PCI
0x0604
#define
PCI_CLASS_BRIDGE_PCMCIA
0x0605
#define
PCI_CLASS_BRIDGE_NUBUS
0x0606
#define
PCI_CLASS_BRIDGE_CARDBUS
0x0607
#define
PCI_CLASS_BRIDGE_OTHER
0x0680
#define PCI_BASE_CLASS_COMMUNICATION
0x07
#define PCI_CLASS_COMMUNICATION_SERIAL
0x0700
#define PCI_CLASS_COMMUNICATION_PARALLEL
0x0701
#define PCI_CLASS_COMMUNICATION_OTHER
0x0780
#define PCI_BASE_CLASS_SYSTEM
0x08
#define PCI_CLASS_SYSTEM_PIC
0x0800
#define PCI_CLASS_SYSTEM_DMA
0x0801
#define PCI_CLASS_SYSTEM_TIMER
0x0802
#define PCI_CLASS_SYSTEM_RTC
0x0803
#define PCI_CLASS_SYSTEM_OTHER
0x0880
#define PCI_BASE_CLASS_INPUT
0x09
#define PCI_CLASS_INPUT_KEYBOARD
0x0900
#define PCI_CLASS_INPUT_PEN
0x0901
#define PCI_CLASS_INPUT_MOUSE
0x0902
#define PCI_CLASS_INPUT_OTHER
0x0980
#define PCI_BASE_CLASS_DOCKING
0x0a
#define PCI_CLASS_DOCKING_GENERIC
0x0a00
#define PCI_CLASS_DOCKING_OTHER
0x0a01
#define PCI_BASE_CLASS_PROCESSOR
0x0b
#define PCI_CLASS_PROCESSOR_386
0x0b00
#define PCI_CLASS_PROCESSOR_486
0x0b01
#define PCI_CLASS_PROCESSOR_PENTIUM
0x0b02
#define PCI_CLASS_PROCESSOR_ALPHA
0x0b10
#define PCI_CLASS_PROCESSOR_POWERPC
0x0b20
#define PCI_CLASS_PROCESSOR_CO
0x0b40
#define PCI_BASE_CLASS_SERIAL
0x0c
#define PCI_CLASS_SERIAL_FIREWIRE
0x0c00
#define PCI_CLASS_SERIAL_ACCESS
0x0c01
#define PCI_CLASS_SERIAL_SSA
0x0c02
#define PCI_CLASS_SERIAL_USB
0x0c03
#define PCI_CLASS_SERIAL_FIBER
0x0c04
#define PCI_CLASS_SERIAL_SMBUS
0x0c05
#define PCI_BASE_CLASS_INTELLIGENT
0x0e
#define PCI_CLASS_INTELLIGENT_I2O
0x0e00
#define PCI_CLASS_HOT_SWAP_CONTROLLER
0xff00
#define PCI_CLASS_OTHERS
0xff
Base Address 0- Base Address 5
表示此卡占用的内存范围。
IRQ Line
指定的设备所使用的中断号,它在系统启动时由固件复制。
IRQ Pin
PCI卡有4个物理引脚,用于把中断从卡上发送到PCI总线上。为0表示设备不支持中断,非0表示使用哪一个终端引脚。此信息可让中断处理子系统处理来自该设备的中断。
关于pci设备的其他信息,您可以参考PCI Local Bus Specification。
2.2 Linux下PCI设备的检测过程
一个pci设备可映射到最多六个地址区段。每个区段由内存或I/O位置组成。区段的大小和当前位置由配置寄存器报告。
检测pci设备先要打开文件/proc/bus/pci/devices,例如存在下列数据:
003980867111
0000000000000000000000000000000000000f0010000000000000000
上面的数据表示一个pci设备,对于第一个数字0039(十六进制表示),高八位表示总线号(bus),对于低三位表示功能号(function),剩余的五位表示设备号(device)。也就是说,0039表示,总线0,设备号为7,功能号为1。由此,内核生成设备对应的文件/proc/bus/pci/bus/device.function。此文件为256个字节,对应读出的设备配置信息,第十字节开始的双字节表示设备的类型。第二个数字80867111表示,设备的vendorid为8086,deviceid为7111。通过查询设备配置数据库可知设备标识80867111表示Intel Corporation|82371AB PIIX4 IDE控制器。第三个数字表示占用的irq。
用户可以