遍歷PCI裝置

2021-05-31 23:45:43 字數 3449 閱讀 1865

原文:

(該文在2023年3月11日做過修改,其中**已為完整**)

pc機在啟動的時候,都會看到乙個pci裝置清單,可以看到機器中的所有pci裝置,其實搜尋pci裝置的程式並不難編,本文通過乙個例項說明如何遍歷pci裝置。

工作環境:ms-dos 6.22,djgpp+rhide

1、了解pci裝置

pci的含義是外設部件互連(peripheral component interconnect),pci區域性匯流排(local bus)是2023年由intel定義的,現在pci區域性匯流排已經成為了pc機中不可缺少的外圍裝置匯流排,幾乎所有的外部裝置都連線到pci區域性匯流排上,我們說的pci裝置,實際上就是指連線在pci區域性匯流排上的裝置。

2、你的bios是否支援pci bios服務

在我的另一篇部落格文章:32位bios說明(

)中,說明了如何判斷bios是否是32位的,以及是否支援pci bios服務,實際上,並沒有那麼麻煩,因為在絕大多數有pci插槽的pc機中,bios都是32位的,同時也是支援pci bios的,在我的另一篇部落格文章:呼叫pci bios(

)中,介紹了pci bios中常用的功能呼叫,其中的第乙個呼叫就是檢查「pci bios的存在性」,通常我們利用這個功能呼叫來作為pci bios的存在檢測已經足夠了,方法如下:

組合語言:

mov  ax, 0b01h

int 1ah

c語言(djgpp下):

long unsigned int    i;

__dpmi_regs           r;

r.x.ax = 0xb101;

__dpmi_int(0x1a, &r);

i = r.x.flags;

if ((i & 0x01) == 0) printf("\nsupport pci bios");

else printf("\nnot suport pci bios");

根據返回引數就可以判斷pci bios是否存在,具體方法請參閱:呼叫pci bios(

)這篇部落格文章,如果你的bios不支援pci bios,那麼本文介紹的方法可能不完全適用你。

3、了解pci配置空間

學習pci程式設計,不了解pci的配置空間是不可能的,配置空間是一塊容量為256位元組並具有特定記錄結構或模型的位址空間,通過配置空間,我們可以了解該pci裝置的一些配置情況,進而控制該裝置,除主匯流排橋以外的所有pci裝置都必須事先配置空間,本節僅就一些配置空間的共有的規定作一些說明,更加具體和詳細的資訊請參閱其他書籍及相應的晶元手冊。

配置空間的前64個位元組叫頭標區,頭標區又分成兩個部分,第一部分為前16個位元組,在各種型別的裝置中定義都是一樣的,其他位元組隨各裝置支援的功能不同而有所不同,位於偏移0eh的投標型別字段規定了是何種布局,目前有三種頭標型別,頭標型別1用於pci-pci橋,頭標型別2用於pci-cardbus橋,頭標型別0用於其他pci裝置,下圖為頭標型別0的頭標區布局。

頭標區中有5個字段涉及裝置的識別。

(1) **商識別字段(vendor id)

偏移:00h。該欄位用以標明裝置的製造者。乙個有效的**商標識由pci sig來分配,以保證它的唯一性。0ffffh是該字段的無效值。

(2) 裝置識別字段(device id)

偏移:02h。用以標明特定的裝置,具體**由**商來分配。

(3) 版本識別字段(revision id)

偏移:08h。用來指定乙個裝置特有的版本識別**,其值由**商提供,可以是0。

(4) 頭標型別字段(header type)

偏移:0eh。該字段有兩個作用,一是用來表示配置空間頭標區第二部分的布局型別;二是用以指定裝置是否包含多功能。位7用來標識乙個多功能裝置,位7為0表明是單功能裝置,位7為1表明是多功能裝置。位0-位6表明頭標區型別。

(5) 分類**字段(class code)

偏移:09h。標識裝置的總體功能和特定的暫存器級程式設計介面。該位元組分三部分,每部分佔乙個位元組,第一部分是基本分類**,位於偏移0bh,第二部分叫子分類**,位於偏移0ah處,第三部分用於標識乙個特定的暫存器級程式設計介面(如果有的話)。

這部分的**定義很多,請自行查閱pci規範相關文件。我們在實際應用中會對一些用到的**加以說明。

4、配置暫存器的讀寫

x86的cpu只有記憶體和i/o兩種空間,沒有專用的配置空間,pci協議規定利用特定的i/o空間操作驅動pci橋路轉換成配置空間的操作。目前存在兩種轉換機制,即配置機制1#和配置機制2#。配置機制2#在新的設計中將不再被採用,新的設計應使用配置機制1#來產生配置空間的物理操作。這種機制使用了兩個特定的32位i/o空間,即cf8h和cfch。這兩個空間對應於pci橋路的兩個暫存器,當橋路看到cpu在區域性匯流排對這兩個i/o空間進行雙字操作時,就將該i/o操作轉變為pci匯流排的配置操作。暫存器cf8h用於產生配置空間的位址(config-address),暫存器cfch用於儲存配置空間的讀寫資料(config-data)。

將要訪問配置空間暫存器的匯流排號、裝置號、功能號和暫存器號以乙個雙字的格式寫到配置位址埠 (cf8h-cfbh),接著執行配置資料埠 (cfch)的讀和寫,向配置資料口寫資料即向配置空間寫資料,從配置資料口讀資料即從配置空間讀資料。

bit  31  30...24 23......16 15......11 10......8 7..........2   1  0

|    保留     匯流排號     裝置號    功能號      暫存器號     0  0

+----使能位,1有效,0無效

暫存器號:選擇配置空間中的乙個雙字(32位)

功能號:選擇多功能裝置中的某乙個功能,有八種功能,0--7

裝置號:在一條給定的匯流排上選擇32個裝置中的乙個。0--31

匯流排號:從系統中的256條匯流排中選擇一條,0--255

儘管理論上可以有256條匯流排,但實際上pc機上pci插槽的匯流排號都是1,有些工控機的匯流排號是2或者3,所以我們只需要查詢0--4號匯流排就足夠了。

pci規範規定,功能0是必須實現的,所以,如果功能0的頭標型別欄位的位7為0,表明這是乙個單功能裝置,則沒有必要再去查其他功能,否則要查詢所有其他功能。

5、遍歷pci裝置

至此,我們掌握的有關pci的知識已經足夠我們遍歷pci裝置了,其實便利方法非常簡單就是按照匯流排號、裝置號、功能號的順序依次羅列所有的可能性,讀取配置空間頭標區的**商**、及裝置**,進而找到所有pci裝置。

#include

#include

typedef unsigned long      udword;

typedef unsigned short int uword;

int main() }}

}}}   // end of main

兩部分程式加起來基本構成了乙個完整的遍歷pci裝置的程式,本**可以djgpp下編譯通過並正常執行(測試環境:dos 6.22 djgpp2.2+rhide1.5)。

遍歷PCI裝置

pc機在啟動的時候,都會看到乙個pci裝置清單,可以看到機器中的所有pci裝置,其實搜尋pci裝置的程式並不難編,本文通過乙個例項說明如何遍歷pci裝置。工作環境 ms dos 6.22,djgpp rhide 1 了解pci裝置 pci的含義是外設部件互連 peripheral component...

linux下遍歷所有pci裝置

在linux中,每乙個pci裝置都有乙個相應的結構體叫pci dev,它用來記錄pci裝置的一些匯流排,配置資訊等等。所以要遍歷所有的pci裝置就相當於遍歷pci dev結構體,程式只是遍歷pci的一種手段,而pci在計算機中是如何架構的,pci和pci之間有什麼關聯,才是遍歷所有pci裝置的精髓。...

PCI裝置驅動

pci匯流排 一種將系統外部裝置連線起來的匯流排標準。如isa usb匯流排都掛載在pci匯流排上。開發pci裝置驅動,需要獲取pci配置空間的各個資料。基礎pci區域性匯流排與主處理器相連線的host pci稱為北橋 基礎pci匯流排與中斷控制器 ide控制器 usb控制器 dma控制器和isa匯...