如何在LINUX 下实现硬件的自动检测



如何在LINUX 下实现硬件的自动检测?用过 Linux 的人都知道在Linux 上硬件的配置过程是非常繁杂的。比如说,对于一块普通的pci 网卡,您可能先要知道它的芯片类型,网卡生产厂商,然后猜出它对应的硬件驱动模块,然后再使用modprobe

(insmod)插入这个模块,再然后还要生成一系列的配置脚本,最后才能使其正常工作。这还只是一块网
卡的配置过程,但是对于不胜枚举的其他硬件,如显卡、声卡、modem、isdn 设备、usb 设备、pcmcia
设备,而它们的配置方法和生成的配置脚本都不尽相同,因此对于一个普通用户要想全部掌握这些配置过
程是相当困难的。硬件的自动检测是进行Linux 下设备自动配置过程的前提。本文的内容是先从硬件在
Linux 下的内核描述信息开始,着重介绍如何实现硬件的自动检测。
设备检测的一般介绍
一般而言,在 Linux 下进行设备自动检测是根据设备的总线类型进行的。现在的微机系统上最常见的总线
类型有PCI、SERIAL、USB、PCMCIA、PARPORT、ISA、SCSI 等。对于检测过程,一般不是通过c 语
言的库函数直接对设备进行访问,并读取设备的信息,而是通过内核的/proc 文件系统进行。这种检测方式,
充分利用了内核中关于硬件的多种检测函数,具有高效、稳定的特点,并且在内核版本升级之后,使程序
的变化也为最小。对于大多数现在流行的系统硬件,在插入适当的模块之后,内核会在/proc 文件系统中生
成相应的描述文件。检测过程就是读取这样的文件,并将其信息进行相应的处理,从中提取出设备标识、
设备描述、设备工作状态等信息。
由于涉及到对/proc 文件系统的访问,并可能在检测过程开始时插入需要的设备模块,所以需要用户以root
用户方式执行下面所说的操作。
在检测过程结束的时候,用户一般能够得到设备的唯一标识(制造商标识和设备标识)和设备的当前的状
态信息。这时就需要一个设备数据库,这个数据库将设备的唯一标识和对应的设备驱动程序对应起来,然
后由此生成/etc/modules.conf 中的对应表项及其他配置脚本,完成整个的硬件配置过程。
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 设备的分类码位0×0100。Linux
系统的定义见<linux/pci.h>中的声明。现在摘录如下:
#define PCI_CLASS_NOT_DEFINED 0×0000
#define PCI_CLASS_NOT_DEFINED_VGA 0×0001
#define PCI_BASE_CLASS_STORAGE 0×01
#define PCI_CLASS_STORAGE_SCSI 0×0100
#define PCI_CLASS_STORAGE_IDE 0×0101
#define PCI_CLASS_STORAGE_FLOPPY 0×0102
#define PCI_CLASS_STORAGE_IPI 0×0103
#define PCI_CLASS_STORAGE_RAID 0×0104
#define PCI_CLASS_STORAGE_OTHER 0×0180
#define PCI_BASE_CLASS_NETWORK 0×02
#define PCI_CLASS_NETWORK_ETHERNET 0×0200
#define PCI_CLASS_NETWORK_TOKEN_RING 0×0201
#define PCI_CLASS_NETWORK_FDDI 0×0202
#define PCI_CLASS_NETWORK_ATM 0×0203
#define PCI_CLASS_NETWORK_OTHER 0×0280
#define PCI_BASE_CLASS_DISPLAY 0×03
#define PCI_CLASS_DISPLAY_VGA 0×0300
#define PCI_CLASS_DISPLAY_XGA 0×0301
#define PCI_CLASS_DISPLAY_OTHER 0×0380
#define PCI_BASE_CLASS_MULTIMEDIA 0×04
#define PCI_CLASS_MULTIMEDIA_VIDEO 0×0400
#define PCI_CLASS_MULTIMEDIA_AUDIO 0×0401
#define PCI_CLASS_MULTIMEDIA_OTHER 0×0480
#define PCI_BASE_CLASS_MEMORY 0×05
#define PCI_CLASS_MEMORY_RAM 0×0500
#define PCI_CLASS_MEMORY_FLASH 0×0501
#define PCI_CLASS_MEMORY_OTHER 0×0580
#define PCI_BASE_CLASS_BRIDGE 0×06
#define PCI_CLASS_BRIDGE_HOST 0×0600
#define PCI_CLASS_BRIDGE_ISA 0×0601
#define PCI_CLASS_BRIDGE_EISA 0×0602
#define PCI_CLASS_BRIDGE_MC 0×0603
#define PCI_CLASS_BRIDGE_PCI 0×0604
#define PCI_CLASS_BRIDGE_PCMCIA 0×0605
#define PCI_CLASS_BRIDGE_NUBUS 0×0606
#define PCI_CLASS_BRIDGE_CARDBUS 0×0607
#define PCI_CLASS_BRIDGE_OTHER 0×0680
#define PCI_BASE_CLASS_COMMUNICATION 0×07
#define PCI_CLASS_COMMUNICATION_SERIAL 0×0700
#define PCI_CLASS_COMMUNICATION_PARALLEL 0×0701
#define PCI_CLASS_COMMUNICATION_OTHER 0×0780
#define PCI_BASE_CLASS_SYSTEM 0×08
#define PCI_CLASS_SYSTEM_PIC 0×0800
#define PCI_CLASS_SYSTEM_DMA 0×0801
#define PCI_CLASS_SYSTEM_TIMER 0×0802
#define PCI_CLASS_SYSTEM_RTC 0×0803
#define PCI_CLASS_SYSTEM_OTHER 0×0880
#define PCI_BASE_CLASS_INPUT 0×09
#define PCI_CLASS_INPUT_KEYBOARD 0×0900
#define PCI_CLASS_INPUT_PEN 0×0901
#define PCI_CLASS_INPUT_MOUSE 0×0902
#define PCI_CLASS_INPUT_OTHER 0×0980
#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。
用户可以通过察看/proc/pci 文件,可以获得系统连接的pci 设备的基本信息描述,或者用户也可以使用命
令lspci(需要安装包pciutils)来察看PCI 设备较为详细的描述信息。但是为了使内核显示上述信息,必
须要在编译内核时加入PCI 设备名数据库,这会使内核增大约80KB。
关于 Linux 系统PCI 设备的进一步信息您可以阅读http://www.linuxdoc.org/HOWTO/PCI-HOWTO.html
ISAPNP 设备的自动检测
3.1 ISAPNP 设备简介
在每个 ISAPNP 设备加电启动之后,都会进行一个自动配置过程,它的主要步骤如下:
• 设置所有的 isapnp 卡为配置模式
• 每次隔离一个 isapnp 卡
• 指定一个句柄并读取卡的资源数据结构
• 在所有的卡的资源需求和兼容性被决定之后,使用句柄指派每个卡无冲突的资源
• 激活所有的 isapnp 卡并使其离开配置模式
pnp 软件使用一系列规范定义的命令标识和配置设备,这些命令由三个8 位端口发出(不支持16
位的配置端口)。写到这些端口中任何一个的打开系统中pnp 逻辑的数据序列对所有卡生效。这
个数据序列被称作初始键。
所有卡响应同样的 I/O 端口寻址,因此为了一次只寻址一个卡pnp 软件需要一种隔离机制。隔离
协议使用独一无二的标号一次区别一个卡。在隔离之后,pnp 软件对每个卡指定一个句柄,由它
对应确定的pnp 卡。
每个卡上支持可读的资源数据结构,用以描述卡上支持的和功能请求的资源。此结构允许每个ISA
卡有多个功能,每个功能作为一个逻辑设备来定义。每个逻辑设备提供pnp 资源信息,pnp 标准
寄存器独立配置每个逻辑设备。
隔离操作之后,pnp 软件读取每个卡的资源数据结构。在所有的资源的能力和需求已知之后,系
统发出一个资源仲裁来裁决每个卡的资源分配并使用命令寄存器指定每个资源类型。
在资源被指派之后,I/O 冲突检测机制执行。命令集也包括激活/禁止卡的功能的命令集。在配置
之后,pnp 卡离开配置模式。如果向卡重新发出初始化键值,则可以重新使能配置模式(防止配
置信息被故意删除)。
对于isa pnp 设备有三个八位端口被用于存取isapnp 卡的配置空间。配置空间由一系列8 位寄存
器组成。这些寄存器被用于发送命令,检测状态,存取资源数据信息和配置pnp 硬件。
Port Name Location Type
ADDRESS 0×0279 (Printer status port) Write-only
WRITE_DATA 0x0A79 (Printer status port + 0×0800) Write-only
READ_DATA Relocatable in range 0×0203 to 0x03FF Read-only
Table 1. 自动配置端口
• 地址端口(ADDRESS Port)
在访问 pnp 寄存器之前,首先写寄存器地址到地址端口,紧接着从READ_DATA 端口读或者从
WRITE_DATA 端口写。地址端口也是初始键的写目标。
隔离机制的关键是每个卡都有一个独一无二的编号(serial identifier)。serial identifier 是一个72
位独一无二、非0 的数字,由两个32 位域和一个8 位校验位组成。头32 位是制造商标识,另32
位可以是任何值。只要不存在任何两块编号相同的卡。
Figure 1. Shifting of Serial Identifier
在隔离过程结束时,当前控制的卡被指定一个句柄,称为Card Select Number(CSN),用于以后检索此
卡。在卡响应其他的命令之前,此卡必须被指定一个CSN。
CSN 是一个8 位寄存器,加电使所有卡的此寄存器置为0×0。一旦卡的隔离操作结束,此卡的CSN 寄存
器被指定一个独一无二的值,以使pnp 软件能区别所用的卡。isapnp 状态如下:
• Wait for Key
在加电重设之后或在响应重设与等待命令之后所有卡进入此状态。在此状态下没有命令被激活直
到初始键被检测。Wait for Key 在正常系统操作过程中是pnp 卡的缺省状态。在配置和激活操
作之后,软件应设置所有的卡到此状态。
• Sleep
在此状态,pnp 卡等待Wake[CSN]命令。此命令会由CSN 值设置一个或多个卡进入Isolation 或
Config 状态。在Wake[CSN]命令的写数据位[7:0]的值与卡的CSN 匹配时,卡离开Sleep 状态。
若Wake[CSN]命令写数据为0,所有的没有指定CSN 的卡会进入Isolation 状态。若Wake[CSN]
命令写数据为非0,Wake[CSN]命令的CSN 参数与卡上分派的CSN 匹配的卡会进入Config 状态。
• Isolation
在此状态,pnp 卡响应对隔离寄存器的读请求。一旦卡被隔离,独一无二的CSN 被指定,CSN
作为卡的唯一标识用于在Wake[CSN]命令中选择此卡。一旦写入CSN,卡过渡到Config 状态。
• Config
在此状态的卡会响应所有的配置命令,包括读卡的资源配置信息以及编程卡的资源选择。
关于 ISAPNP 设备的详细的硬件信息,您可以参考ISAPNP Specification
3.2 Linux 系统下ISAPNP 设备的自动检测
ISA 设备的自动检测是指对支持Plug and Play ISA 规范1.0 的ISA 设备的检测,对不支持此规范的ISA 设
备,此检测过程是无法工作的。这时的硬件检测和配置是完全要根据用户的个人经验进行。在进行下述检
测过程之前,对于基于2.2.X 内核的Linux 系统,需要用户安装包isapnptools。对于2.4.x 内核,则用户
只需在编译内核时加入ISA Plug and Play support 即可。在检测开始之前,必须由用户手动插入模块
(modprobe)isapnp.o 或者isa-pnp.o(由内核版本决定)。在用户插入上述模块之后,内核会自动生成
/proc 下对应的描述文件。这些描述文件包括/proc/isapnp,/proc/bus/isapnp/devices,/proc/bus/isapnp/
csn。
例如,在系统中存在 OPL3-SA3 类型的声卡时,未挂接设备驱动程序的情况下,/proc/isapnp 文件内容如
下:
Card 1 ‘YMH0020:OPL3-SA3 Sound Board’ PnP version 1.0
Logical device 0 ‘YMH0021:Unknown’
Device is not active
Active DMA 0,0
Resources 0
Priority preferred
Port 0×220-0×220, align 0xf, size 0×10, 16-bit address
decoding
Port 0×530-0×530, align 0×7, size 0×8, 16-bit address decoding
Port 0×388-0×388, align 0×7, size 0×8, 16-bit address decoding
Port 0×330-0×330, align 0×1, size 0×2, 16-bit address decoding
Port 0×370-0×370, align 0×1, size 0×2, 16-bit address decoding
IRQ 5 High-Edge
DMA 0 8-bit byte-count type-A
DMA 1 8-bit byte-count type-A
Alternate resources 0:1
Priority acceptable
Port 0×240-0×240, align 0xf, size 0×10, 16-bit address
decoding
Port 0xe80-0xe80, align 0×7, size 0×8, 16-bit address
decoding
Port 0×388-0×388, align 0×7, size 0×8, 16-bit address
decoding
Port 0×300-0×300, align 0×1, size 0×2, 16-bit address
decoding
Port 0×100-0xffe, align 0×1, size 0×2, 16-bit address
decoding
IRQ 5,7,2/9,10,11 High-Edge
DMA 0,1,3 8-bit byte-count type-A
DMA 0,1,3 8-bit byte-count type-A
Alternate resources 0:2
Priority functional
Port 0×220-0×280, align 0xf, size 0×10, 16-bit address
decoding
Port 0×530-0xf48, align 0×7, size 0×8, 16-bit address
decoding
Port 0×388-0x3f8, align 0×7, size 0×8, 16-bit address
decoding
Port 0×300-0×334, align 0×1, size 0×2, 16-bit address
decoding
Port 0×100-0xffe, align 0×1, size 0×2, 16-bit address
decoding
IRQ 3,5,7,2/9,10,11 High-Edge
DMA 0,1,3 8-bit byte-count type-A
DMA 0,1,3 8-bit byte-count type-A
Logical device 1 ‘YMH0022:Unknown’
Compatible device PNPb02f
Device is not active
Active DMA 0,0
Resources 0
Priority preferred
Port 0×201-0×201, align 0×0, size 0×1, 16-bit address decoding
Alternate resources 0:1
Priority functional
Port 0×201-0×211, align 0xf, size 0×1, 16-bit address
decoding
上述信息的第一行表示此ISA 设备的板卡数,其后的YMH0020 表示板卡标识。以” Logical Device”为行首
的小节代表不同的逻辑设备(一块isapnp 卡上可以存在多个逻辑设备)。” Device is not active “表示此设
备的驱动程序未加载,在设备的驱动程序加载后此处显示” Device is active “。在装入设备对应的驱动程序
后,其后的字段以”Active”开始表示设备所占用的资源。例如
Active port 0×240,0xe80,0×388,0×300,0×100(占用的端口号)
Active IRQ 5 [0x2] (占用的中断号)
Active DMA 1,3 (占用的DMA)
此文件再往下的部分列出的是此卡可以占用的地址空间,一般是一组资源配置方案,上面的例子就包含三
组可选的资源配置方案,分别是缺省方案、可选配置方案1(Alternate resources 0:1)和可选配置方案2
(Alternate resources 0:2)。
存储设备的自动检测
存储设备主要是指硬盘,光驱等能够进行告诉数据存取的设备。我们最常见的存储设备按照总线类型分类
主要包括ide,scsi 这两种。对于ide 设备,Linux 系统一般是使用hd*来表示,*是按照连接的总线位置顺
序编号。一般而言,我们现在所使用的微机有两个ide 接口,并且每个接口上只能连接两个设备,一个为
主设备而另一个为从设备。对于连接在ide0 上的主设备它的设备名为hda,而对于在ide0 上的从设备它
的设备名为hdb。以此类推,连接在ide1 上的主、从设备的设备名分别为hdc 和hdd。
一般而言,现有的linux 发行版都将对ide 设备的支持加入内核,所以在系统启动之后,相应的设备模块已
经在内核中了,所以检测过程只需对/proc/ide 下相应的文件进行访问就行了。对于scsi 设备,对它们的支
持一般都不打入内核,所以要想使scsi 设备在Linux 下生效必须先插入对应的设备驱动模块。这就要求用
户在创建lilo 时必须在/etc/lilo.conf 中加入一行”initrd=”,它连接的由命令mkinitrd 生成系统启动映像。例
如,在使用Adaptec,AIC-7850 的scsi 芯片组时,使用模块aic7xxx,此时需要进行如下步骤:
mkinitrd –ifneeded /boot/initrd-2.4.3.img 2.4.3 –with=aic7xxx
然后编辑/etc/lilo.conf,加入行: initrd=/boot/initrd-2.4.3.img
重新运行 lilo,启动后,这时就会在目录/proc/scsi 下出现设备的对应描述文件。只要检索这些文件就可以
完成对设备的检测。
• ide 设备的检测过程
1. 查找/proc/ide/下名为的hd*(*为通配符,可为a,b,…)的目录(目录名为设备名)。
2. 打开文件/proc/ide/hd*/media,此文件的只由一行构成,其内容为cdrom、disk、tape
或floppy,此文件的内容表示此IDE 设备的类型。
3. 打开文件/proc/ide/hd*/model,由此文件得到详细的设备描述信息。例如:ST313021A,
表示希捷硬盘,型号为ST313021A。
4. 打开文件/proc/ide/hd*/geometry,这个文件描述的是硬盘的几何信息。例如
physical 16383/16/63
logical 1583/255/63(cylinders/heads/sectors)
表示这块 ide 硬盘的柱面数,头数和扇区数
5. 由命令mknod path, b, major, minor,创建设备结点。对于从/dev/hda 到/dev/hdh 的设
备结点的主次设备号为:
/dev/hda major = 3, minor = 0
/dev/hdb major = 3, minor = 64
/dev/hdc major = 22, minor = 0
/dev/hdd major = 22, minor = 64
/dev/hde major = 33, minor = 0
/dev/hdf major = 33, minor = 64
/dev/hdg major = 34, minor = 0
/dev/hdh major = 34, minor = 64
• scsi 设备的检测过程
1. 读入/proc/scsi/scsi 文件,其文件结构:
Attached devices:
Host: scsi**** Channel: **** Id: **** Lun: ****
Vendor: XXXXXXX Model:xxxxxx Rev:
Type: Direct-Access(类型为hd,设备名为sd*)
Sequential-Access(类型为tape,设备名为st*)
CD-ROM (类型为cdrom,设备名为scd*)
Scanner (类型为scanner,设备名为sg*)
Printer (类型为printer,设备名为sg*)
其他设备(设备名为sg*)
USB 设备的自动检测
5.1 USB 设备检测的一般过程
USB 设备检测也是通过/proc 目录下的USB 文件系统进行的。为了使一个USB 设备能够正常工作,必须
要现在系统中插入USB 桥接器模块。在检测开始时,一般要先检测是否存在/proc/bus/usb 目录,若不存
在则尝试插入USB 桥接模块。
现在一般的 USB 桥接器模块有两种类型,UHCI 和OHCI。在决定插入那一个桥接器模块时,可以察看
/proc/pci 文件来决定。打开此文件,您若发现USB 节为I/O at 0xHHHH 格式(例如出现 I/O at 0xe000
[0xe01f]),HHHH 为16 进制数,则桥接器类型为UHCI。若是它为32 bit memory at 0xHH000000 形
式(例如出现32 bit memory at 0xee000000),HH 为16 进制数,则桥接器类型为OHCI。但是若您的桥
接器类型不满足上述任何一种情况,唯一的解决办法就是您尝试插入这两种模块,直到成功为止。一般而
言,UHCI 类型的桥接器它的插入模块是uhci 或usb-uhci(由内核版本决定);而对于OHCI 类型的桥接
器它的插入模块是ohci 或usb-ohci。
您在正确的插入了桥接器模块之后,这时/proc 文件系统下就会出现USB 设备目录,不过这时这个目录是
空的,没有任何文件。这时您就必须挂接usbdevfs 文件系统,然后通过此文件系统检测连接的设备。在成
功挂接usb 文件系统之后,就会生成文件/proc/bus/usb/devices,/proc/bus/usb/drivers 和目录
/proc/bus/usb/busNo。挂接usbdevfs 文件您可以通过如下操作实现:
mount -t usbdevfs none /proc/bus/usb
或在/etc/fstab 上加入
none /proc/bus/usb usbdevfs defaults 0 0
然后通过/proc/bus/usb/devices 文件的内容,您就可以获得连接的设备信息,包括设备标识和制造商标是
等信息。
usb 设备类型描述:
表 5-1 usb 设备类码
设备规范 设备类码 接口类码
应用程序特定 – 0xFE
声音接口0×00 0×01
通信设备0×02 -
CDC 控制接口e – 0×02
CDC 数据接口- 0x0A
HID 0×00 0×03
HUB 0×09 0×09
批量存储设备0×00 0×08
监视器same as HID same as HID
电源设备same as HID same as HID
物理设备- 0×05
打印机- 0×07
供应商特定- 0xFF
5.2 usb 文件系统简介
T = 总线拓扑结构(Lev, Prnt, Port, Cnt,
等),是指USB 设备和主机之间的连接方式
B = 带宽 (仅用于USB 主控制器)
D = 设备描述信息
P = 产品标识信息
S = 串描述符
C = 配置描述信息 (* 表示活动配置)
I = 接口描述信息
E = 终端点描述信息
一般格式:
d = 十进制数
x = 十六进制数
s = 字符串
拓扑信息
T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
| | | | | | | | |__最
大子设备
| | | | | | | |__设备速度
(Mbps)
| | | | | | |__设备编号
| | | | | |__这层的设备数
| | | | |__此设备的父连接器/端口
| | | |__父设备号
| | |__此总线在拓扑结构中的层次
| |__总线编号
|__拓扑信息标志
带宽信息
B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
| | | |__同步请求编号
| | |__中断请求号
| |__分配给此总线的总带宽
|__带宽信息标志
设备描述信息和产品标识信息
D: Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
D: Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
| | | | | | |__配置编号
| | | | | |______缺省终端点的最大
包尺寸
| | | | |
| | | | |__设备协议
| | | |__设备子类型
| | |__设备类型
| |__设备USB 版本
|__设备信息标志编号#1
P: Vendor=xxxx ProdID=xxxx Rev=xx.xx
| | | |__产品修订号
| | |__产品标识编码
| |__制造商标识编码
|__设备信息标志编号#2
串描述信息
S: Manufacturer=ssss
| |__设备上读出的制造商信息
|__串描述信息
S: Product=ssss
| |__设备上读出的产品描述信息,对于USB 主控制器此字段为”USB *HCI Root
Hub”
|__串描述信息
S: SerialNumber=ssss
| |__设备上读出的序列号,对于USB 主控制器它是一个生成的字符串,表示设备标

|__串描述信息
配置描述信息
C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
| | | | |__最大电流(mA)
| | | |__属性
| | |__配置编号
| |__接口数
|__配置信息标志
接口描述信息(可为多个)
I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
| | | | | | | |__驱动名
| | | | | | |__接口协议
| | | | | |__接口子类
| | | | |__接口类
| | | |__中断点数
| | |__可变设置编号
| |__接口编号
|__接口信息标志
终端点描述信息
E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
| | | | |__间隔
| | | |__终端点最大包尺寸
| | |__属性(终端点类型)
| |__终端点地址(I=In,O=Out)
|__终端点信息标志
举个例子,这是在连接了一个USB 键盘时的配置情况。
T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh=
2
B: Alloc= 41/900 us ( 5%), #Int= 3, #Iso= 0
D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0000 ProdID=0000 Rev= 0.00
S: Product=USB UHCI Root Hub
S: SerialNumber=e000
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00
Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms
T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh=
3
D: Ver= 1.10 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=07e4 ProdID=a961 Rev= 0.01
S: Manufacturer=ALCOR
S: Product=Movado USB Keyboard
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00
Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 1 Ivl=255ms
T: Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=12 MxCh=
0
D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=07e4 ProdID=a961 Rev= 0.01
S: Manufacturer=ALCOR
S: Product=Movado USB Keyboard
C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr= 0mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=01
Driver=hid
E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl= 10ms
I: If#= 1 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=00
Driver=hid
E: Ad=82(I) Atr=03(Int.) MxPS= 4 Ivl=255ms
它的物理拓扑可用下图来表示:
对于 Linux 下的usb 设备而言,T:(总线拓扑)行用于生成连接在hub 上的设备的描述信息,I:(接口信息)
行可用于决定每个设备所用的驱动程序,C:(配置信息)可用于列出设备使用最大电流。
对于 Linux 下的usb 设备,您可以访问http://www.linux-usb.org 获取更详细的信息。
并行设备的自动检测
6.1 并行设备检测的一般过程
在 Linux 下要实现连接在并口上的设备检测,要求设备必须是支持IEEE 1284 协议的。对于不支持IEEE
1284 通讯协议的并行设备,是无法完成自动检测的。同样在定制系统内核时,也必须在并行端口支持
(Parallel port support)选项中选中IEEE 1284 transfer mode 这一项。在并口检测开始时,检测程序应
检查是否存在/proc/sys/dev/parport 目录(针对2.4.x 内核),若不存在则尝试插入模块parport。加载parport
模块一般有三种方式:
• 静态插入模块
insmod parport.o
或 insmod parport_pc.o io=0x3bc,0×378,0×278 irq=none,7,auto
废除系统缺省的检测值
• kmod(/etc/modules.conf)加载
alias parport_lowlevel parport_pc
options parport_pc io=0×378,0×278 irq=7,auto
内核的并口探测程序用于获得IEEE 1284 设备标识信息。在并口被检测时,连接到其上的设备被
分析。探测的信息在/proc/sys/dev/parport/。
• 在编译并口代码进入内核之后,使用内核加在参数
如:加入 LILO 命令行
parport=0x3bc parport=0×378,7 parport=0×278,auto,nofifo
parport=0
禁止内核parport 支持
parport=auto
内核自动检测
在成功的插入了此模块之后,这时/proc 文件系统下就会存在目录/proc/sys/dev/parport,但是此时此目录
下的文件大部分为空,没有任何内容。这时您就可以根据并口连接的设备,尝试插入相应的内核驱动模块。
例如,当连接并口打印机时,您可以插入模块lp。使用如下命令:
insmod lp parport=0 (对于打印机连接在并口0(LPT1))
在成功插入此模块之后,而且在连接的并口设备支持IEEE 1284协议时,这时此目录下的autoprobe,modes
等文件会出现设备上读出的设备描述以及设备配置信息。由此信息,您可以在CUPS 中选择对应的打印机
驱动程序,完成打印机的配置。
6.2 /proc/sys/dev/parport/文件结构
目录树:
parport
|– default
| |– spintime
| `– timeslice
|– parport0
| |– autoprobe
| |– autoprobe0
| |– autoprobe1
| |– autoprobe2
| |– autoprobe3
| |– devices
| | |– active
| | `– lp
| | `– timeslice
| |– base-addr
| |– irq
| |– dma
| |– modes
| `– spintime
`– parport1
|– autoprobe
|– autoprobe0
|– autoprobe1
|– autoprobe2
|– autoprobe3
|– devices
| |– active
| `– ppa
| `– timeslice
|– base-addr
|– irq
|– dma
|– modes
`– spintime
文件 文件内容
devices/active
使用那个端口的设备驱动程序列表。在当前使用端口的设备前会出现一个”+”号。串”none”
意味着没有设备驱动程序使用这个端口。
base-addr 并行端口的基地址或再不只一个端口时由tab 分隔的多个基地址。
irq 并行端口的IRQ,若不使用时则用-1
dma 并行端口的dma 通道,若没有使则用-1
modes
并行端口的硬件模式PCSPP PC 风格的SPP 寄存器可用(标准并行端口)TRISTATE 端
口是双向的COMPAT 打印机的硬件加速可用EPP EPP 协议的硬件加速可用(增强并行
端口)ECP ECP 协议的硬件加速可用DMA DMA 可用
autoprobe 已经获得的IEEE-1284 设备标识信息
autoprobe[0-3] 从遵循IEEE-1284.3 的雏菊链路设备取出的设备信息
spintime
忙循环等待外设响应的微秒数。调节此值可以改善外设的性能。这是端口级的设置。它应
用于此端口上的所有设备
timeslice 设备驱动程序允许保持端口声明的微秒数。这只是一个建议,驱动程序在必要时可以忽略。
defaultinfo
对于每个socket,描述socket 主控制器和它的性能,*为对应的socket 编号
/proc/bus/pccard{pci,cardbus}
对于cardbus 桥,桥的pci 配置空间的转储和桥的cardbus 配置寄存器的转储
7.2 pcmcia 配置文件
/etc/pcmcia/config 实际上是一个针对pcmcia 设备的配置数据库,它的内容主要是指定卡驱动程序加载时
所需的模块。例如
device “serial_cs”
class “serial” module “misc/serial”, “serial_cs”
表示在插入 serial_cs 时,需要先插入模块misc/serial 和serial_cs。
pcmcia 主机控制器的主要类型为
• Databook TCIC-2
• Intel i82365SL-compatible
当前pcmcia 设备包括5 种IO 设备类型包括network,SCSI,cdrom,fixed disk,和serial 以及2 种内存
设备类型memory 和FTL。对于每一种类型,在/etc/pcmcia/目录下存在两个配置脚本,例如,对于scsi
设备都存在一个主配置脚本(/etc/pcmcia/scsi)和选项配置脚本(/etc/pcmcia/scsi.opts)。
7.3 pcmcia 启动脚本(/etc/sysconfig/pcmcia)
PCMCIA
为 yes 表示启动PCMCIA 支持
PCIC
标识 PCCard 接口控制驱动模块。一般有两种类型:tcic 或i82365,缺省是i82365。
PCIC_OPTS
PCIC 模块的选项
例如:PCIC_OPTS=”irq_list=5,9,10″、”do_scan=0″ 完全禁止中断检测
CORE_OPTS
pcmcia_core 模块的选项。见man pcmcia_core。
CARDMGR_OPTS
cardmgr 守护程序的选项。见man cardmgr。
SCHEME
设置 pccard 的配置方案。
cardmgr 处理/etc/pcmcia/config.opts 中的io 端口范围。但在极少的情况下,从设备读可以阻碍系统功能而
导致死锁。在CORE_OPTS 中加入probe_io=0,可以禁止此操作。使用i82365 或tcic 驱动程序时,irq_list
选项可用于限制测试的中断。cs_irq 用于明确设置中断以检测卡状态改变。若不能使用中断,可以使用
poll_interval=100(100 表示轮询间隔为1 秒)设置轮询。这些选项应置入/etc/rc.d/rc.pcmcia 或
/etc/sysconfig/pcmcia 的”PCIC_OPTS=”行。
7.4 cardmgr 和cardctl 的使用
cardmgr 基于/etc/pcmcia/config 中的信息来配置卡。cardmgr 为每个socket 记录设备信息,此信息存于
/var/lib/pcmcia/stab 中。例如:
Socket 0: Adaptec APA-1460 SlimSCSI
0 scsi aha152x_cs 0 sda 8 0
0 scsi aha152x_cs 1 scd0 11 0
Socket 1: Serial or Modem Card
1 serial serial_cs 0 ttyS1 5 65
第一个域表示socket,第二个是设备类型,第三个是设备名,第四个用于关联多个设备和一个驱动程序时
的设备编号。第五个是设备名。最后两个域标是设备的主、次设备号。
cardctl 可用于监视和控制当前pcmcia socket 的状态。
cardctl config,显示socket 配置,包括电源,中断,I/O 配置。例如:
Socket 0:
not configured
Socket 1:
Vcc = 5.0, Vpp1 = 0.0, Vpp2 = 0.0
Card type is memory and I/O
IRQ 3 is dynamic shared, level mode, enabled
Speaker output is enabled
Function 0:
Config register base = 0×0800
Option = 0×63, status = 0×08
I/O window 1: 0×0280 to 0x02bf, auto sized
I/O window 2: 0x02f8 to 0x02ff, 8 bit
cardctl indent,得到卡的标识信息,包括产品标识信息,制造商标识代码,功能标识代码:
Socket 0:
no product info available
Socket 1:
product info: “LINKSYS”, “PCMLM336″, “A”, “0040052D6400″
manfid: 0×0143, 0xc0ab
function: 0 (multifunction)
cardctl suspend 和cardctl resume 用于无需卸载相关驱动程序的情况下关闭卡。cardctl reset 用于尝试重
设和重新配置卡。cardctl insert 和cardctl eject 用于仿真卡的物理的插入和删除动作。推荐在退出卡之前,
执行cardctl eject 命令。/etc/rc.d/rc.pcmcia stop 会卸载所有的pcmcia 包。
关于作者
于辰涛,联想(北京)电脑公司软件工程师。目前主要从事 Linux 系统安装程序的开发工作,主要研究兴
趣是操作系统的工作机制和开发底层系统程序。您可以通过电子邮件scu_yct@263.net 跟他联系。