歡迎您光臨本站 註冊首頁

如何在LINUX下實現硬體的自動檢測(上)

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  
內容:

設備檢測的一般介紹
PCI設備的自動檢測
ISAPNP設備的自動檢測
存儲設備的自動檢測
關於作者




於辰濤 (scu_yct@263.net)
聯想(北京)電腦公司軟體工程師
2001 年 7 月

用過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。
用戶可以通過察看/proc/pci文件,可以獲得系統連接的pci設備的基本信息描述,或者用戶也可以使用命令lspci(需要安裝包pciutils)來察看PCI設備較為詳細的描述信息。但是為了使內核顯示上述信息,必須要在編譯內核時加入PCI設備名資料庫,這會使內核增大約80KB。

關於Linux系統PCI設備的進一步信息您可以閱讀http://www.linuxdoc.org/HOWTO/PCI-HOWTO.html

3 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 0x0279 (Printer status port) Write-only
WRITE_DATA 0x0A79 (Printer status port + 0x0800) Write-only
READ_DATA Relocatable in range 0x0203 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位寄存器,加電使所有卡的此寄存器置為0x0。一旦卡的隔離操作結束,此卡的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 0x220-0x220, align 0xf, size 0x10, 16-bit address decoding
Port 0x530-0x530, align 0x7, size 0x8, 16-bit address decoding
Port 0x388-0x388, align 0x7, size 0x8, 16-bit address decoding
Port 0x330-0x330, align 0x1, size 0x2, 16-bit address decoding
Port 0x370-0x370, align 0x1, size 0x2, 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 0x240-0x240, align 0xf, size 0x10, 16-bit address decoding
Port 0xe80-0xe80, align 0x7, size 0x8, 16-bit address decoding
Port 0x388-0x388, align 0x7, size 0x8, 16-bit address decoding
Port 0x300-0x300, align 0x1, size 0x2, 16-bit address decoding
Port 0x100-0xffe, align 0x1, size 0x2, 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 0x220-0x280, align 0xf, size 0x10, 16-bit address decoding
Port 0x530-0xf48, align 0x7, size 0x8, 16-bit address decoding
Port 0x388-0x3f8, align 0x7, size 0x8, 16-bit address decoding
Port 0x300-0x334, align 0x1, size 0x2, 16-bit address decoding
Port 0x100-0xffe, align 0x1, size 0x2, 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 0x201-0x201, align 0x0, size 0x1, 16-bit address decoding
Alternate resources 0:1
Priority functional
Port 0x201-0x211, align 0xf, size 0x1, 16-bit address decoding




上述信息的第一行表示此ISA設備的板卡數,其後的YMH0020表示板卡標識。以" Logical Device"為行首的小節代表不同的邏輯設備(一塊isapnp卡上可以存在多個邏輯設備)。" Device is not active "表示此設備的驅動程序未載入,在設備的驅動程序載入后此處顯示" Device is active "。在裝入設備對應的驅動程序后,其後的欄位以"Active"開始表示設備所佔用的資源。例如
Active port 0x240,0xe80,0x388,0x300,0x100(佔用的埠號)
Active IRQ 5 [0x2] (佔用的中斷號)
Active DMA 1,3 (佔用的DMA)




此文件再往下的部分列出的是此卡可以佔用的地址空間,一般是一組資源配置方案,上面的例子就包含三組可選的資源配置方案,分別是預設方案、可選配置方案1(Alternate resources 0:1)和可選配置方案2(Alternate resources 0:2)。

4 存儲設備的自動檢測
存儲設備主要是指硬碟,光碟機等能夠進行告訴數據存取的設備。我們最常見的存儲設備按照匯流排類型分類主要包括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設備的檢測過程
查找/proc/ide/下名為的hd*(*為通配符,可為a,b,…)的目錄(目錄名為設備名)。
打開文件/proc/ide/hd*/media,此文件的只由一行構成,其內容為cdrom、disk、tape或floppy,此文件的內容表示此IDE設備的類型。
打開文件/proc/ide/hd*/model,由此文件得到詳細的設備描述信息。例如:ST313021A,表示希捷硬碟,型號為ST313021A。
打開文件/proc/ide/hd*/geometry,這個文件描述的是硬碟的幾何信息。例如
physical 16383/16/63
logical 1583/255/63(cylinders/heads/sectors)
表示這塊ide硬碟的柱面數,頭數和扇區數

由命令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設備的檢測過程
讀入/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*)



(待續)

作者簡介
於辰濤,聯想(北京)電腦公司軟體工程師。目前主要從事Linux系統安裝程序的開發工作,主要研究興趣是操作系統的工作機制和開發底層系統程序。您可以通過電子郵件 scu_yct@263.net 跟他聯繫。


[火星人 ] 如何在LINUX下實現硬體的自動檢測(上)已經有769次圍觀

http://coctec.com/docs/service/show-post-73821.html