EISA 匯流排支援¶
- 作者:
Marc Zyngier <maz@wild-wind.fr.eu.org>
本文件對將 EISA 驅動程式移植到新的 EISA/sysfs API 進行了一些隨機註釋。
從 2.5.59 版本開始,EISA 匯流排幾乎獲得了與 PCI 或 USB 等更多主流匯流排相同的地位。 這透過 sysfs 實現,sysfs 定義了一組不錯的抽象來管理匯流排、裝置和驅動程式。
雖然新的 API 使用起來非常簡單,但將現有驅動程式轉換為新的基礎設施並非易事(主要是因為檢測程式碼通常也用於探測 ISA 卡)。 此外,大多數 EISA 驅動程式都是最舊的 Linux 驅動程式之一,因此可以想象,多年來這裡已經積累了一些灰塵。
EISA 基礎設施由三部分組成
匯流排程式碼實現了大部分通用程式碼。 它在 EISA 程式碼執行的所有架構之間共享。 它實現匯流排探測(檢測總線上可用的 EISA 卡)、分配 I/O 資源、允許透過 sysfs 進行花哨的命名,併為驅動程式註冊提供介面。
匯流排根驅動程式實現了匯流排硬體和通用匯流排程式碼之間的粘合。 它負責發現實現匯流排的裝置,並設定它以便以後被匯流排程式碼探測。 這可以簡單到在 x86 上保留一個 I/O 區域,也可以更復雜,例如 hppa EISA 程式碼。 這是為了在“新”平臺上執行 EISA 而需要實現的部分。
驅動程式為匯流排提供它管理的裝置列表,並實現必要的回撥來探測和釋放裝置(如果被告知)。
下面的每個函式/結構都位於 <linux/eisa.h> 中,該檔案嚴重依賴於 <linux/device.h>。
匯流排根驅動程式¶
int eisa_root_register (struct eisa_root_device *root);
eisa_root_register 函式用於將裝置宣告為 EISA 匯流排的根。 eisa_root_device 結構儲存對該裝置的引用,以及一些用於探測目的的引數
struct eisa_root_device {
struct device *dev; /* Pointer to bridge device */
struct resource *res;
unsigned long bus_base_addr;
int slots; /* Max slot number */
int force_probe; /* Probe even when no slot 0 */
u64 dma_mask; /* from bridge device */
int bus_nr; /* Set by eisa_root_register */
struct resource eisa_root_res; /* ditto */
};
node |
用於 eisa_root_register 內部目的 |
dev |
指向根裝置的指標 |
res |
根裝置 I/O 資源 |
bus_base_addr |
此總線上插槽 0 的地址 |
slots |
要探測的最大插槽號 |
force_probe |
即使插槽 0 為空(沒有 EISA 主機板)也進行探測 |
dma_mask |
預設 DMA 掩碼。 通常是橋接裝置的 dma_mask。 |
bus_nr |
唯一的匯流排 ID,由 eisa_root_register 設定 |
驅動¶
int eisa_driver_register (struct eisa_driver *edrv);
void eisa_driver_unregister (struct eisa_driver *edrv);
足夠清楚嗎?
struct eisa_device_id {
char sig[EISA_SIG_LEN];
unsigned long driver_data;
};
struct eisa_driver {
const struct eisa_device_id *id_table;
struct device_driver driver;
};
id_table |
以 NULL 結尾的 EISA ID 字串的陣列,後跟一個空字串。 每個字串都可以選擇與驅動程式相關的值(driver_data)配對。 |
driver |
通用驅動程式,如裝置驅動程式中所述。 只有 .name、.probe 和 .remove 成員是必需的。 |
一個例子是 3c59x 驅動程式
static struct eisa_device_id vortex_eisa_ids[] = {
{ "TCM5920", EISA_3C592_OFFSET },
{ "TCM5970", EISA_3C597_OFFSET },
{ "" }
};
static struct eisa_driver vortex_eisa_driver = {
.id_table = vortex_eisa_ids,
.driver = {
.name = "3c59x",
.probe = vortex_eisa_probe,
.remove = vortex_eisa_remove
}
};
裝置¶
sysfs 框架在裝置發現和移除時呼叫 .probe 和 .remove 函式(請注意,.remove 函式僅在驅動程式作為模組構建時才會被呼叫)。
這兩個函式都傳遞一個指向“struct device”的指標,該指標封裝在如下所述的“struct eisa_device”中
struct eisa_device {
struct eisa_device_id id;
int slot;
int state;
unsigned long base_addr;
struct resource res[EISA_MAX_RESOURCES];
u64 dma_mask;
struct device dev; /* generic device */
};
id |
EISA ID,從裝置讀取。 id.driver_data 是從匹配的驅動程式 EISA ID 設定的。 |
slot |
檢測到裝置的插槽號 |
state |
指示裝置狀態的標誌集。 當前標誌為 EISA_CONFIG_ENABLED 和 EISA_CONFIG_FORCED。 |
res |
分配給此裝置的四個 256 位元組 I/O 區域的集合 |
dma_mask |
從父裝置設定的 DMA 掩碼。 |
dev |
通用裝置(參見基本裝置結構) |
您可以使用 'to_eisa_device' 宏從 'struct device' 獲取 'struct eisa_device'。
其他東西¶
void eisa_set_drvdata (struct eisa_device *edev, void *data);
將資料儲存到裝置的 driver_data 區域中。
void *eisa_get_drvdata (struct eisa_device *edev):
獲取先前儲存到裝置的 driver_data 區域中的指標。
int eisa_get_region_index (void *addr);
返回給定地址的區域號 (0 <= x < EISA_MAX_RESOURCES)。
核心引數¶
- eisa_bus.enable_dev
要啟用的插槽的逗號分隔列表,即使韌體將卡設定為停用。 驅動程式必須能夠在這些條件下正確初始化裝置。
- eisa_bus.disable_dev
要停用的插槽的逗號分隔列表,即使韌體將卡設定為啟用。 不會呼叫驅動程式來處理此裝置。
- virtual_root.force_probe
強制探測程式碼探測 EISA 插槽,即使它找不到符合 EISA 標準的主機板(插槽 0 上沒有任何顯示)。 預設為 0(不強制),當設定 CONFIG_EISA_VLB_PRIMING 時設定為 1(強制探測)。
隨機註釋¶
將 EISA 驅動程式轉換為新的 API 主要涉及刪除程式碼(因為探測現在位於核心 EISA 程式碼中)。 不幸的是,大多數驅動程式在 ISA 和 EISA 之間共享它們的探測例程。 拆除 EISA 程式碼時必須特別小心,因此其他匯流排不會受到這些外科手術打擊...
您不得期望在從 eisa_driver_register 返回時檢測到任何 EISA 裝置,因為匯流排很可能尚未被探測。 事實上,這正是大多數時候發生的情況(匯流排根驅動程式通常在啟動過程中較晚才啟動)。 不幸的是,大多數驅動程式都在自行探測,並期望在退出其探測例程時已經探索了整臺機器。
例如,將您最喜歡的 EISA SCSI 卡切換到“熱插拔”模型是“正確的事情”(tm)。
感謝¶
我想感謝以下人員的幫助
Xavier Benigni 借給我一臺很棒的 Alpha Jensen,
James Bottomley, Jeff Garzik 將這些東西放入核心,
Andries Brouwer 貢獻了大量的 EISA ID,
Catrin Jones 在家裡處理了太多的機器。