ISA 驅動程式¶
以下文字改編自 Rene Herman 編寫的 ISA 匯流排驅動程式初始提交的提交訊息。
在最近關於“使用平臺裝置的 ISA 驅動程式”的討論中,有人指出 (ALSA) ISA 驅動程式遇到了一個問題,即由於 probe() 錯誤未透過驅動模型傳遞上來,導致無法在未找到其硬體時選擇使驅動程式載入(更確切地說是設備註冊)失敗。在此過程中,我建議單獨的 ISA 匯流排可能是最佳選擇;Russell King 同意並建議該匯流排可以使用 .match() 方法進行實際的裝置發現。
附件完成了這一點。對於這種舊的非(通用)可發現的 ISA 硬體,只有驅動程式本身可以進行發現,因此與 platform_bus 不同的是,這個 isa_bus 也將 match() 分配給驅動程式。
另一個區別是:這些裝置僅在驅動模型中存在,因為驅動程式建立它們是為了驅動它們,這意味著所有裝置建立也已內部化。
這種用法模型很好,並已獲得 Takashi Iwai 和 Jaroslav Kysela 在 ALSA 方面的認可。現在 ALSA 驅動程式的 module_init(僅適用於舊版 ISA 驅動程式)變為
static int __init alsa_card_foo_init(void)
{
return isa_register_driver(&snd_foo_isa_driver, SNDRV_CARDS);
}
static void __exit alsa_card_foo_exit(void)
{
isa_unregister_driver(&snd_foo_isa_driver);
}
因此,它與其他匯流排模型非常相似。這消除了 ALSA ISA 驅動程式中大量的重複初始化程式碼。
傳入的 isa_driver 結構體是一個常規的驅動程式結構體,它嵌入了一個 struct device_driver,包含正常的 probe/remove/shutdown/suspend/resume 回撥,以及前面提到的 .match 回撥。
您看到的傳入的“SNDRV_CARDS”是一個“unsigned int ndev”引數,指示要建立多少個裝置並呼叫我們的方法。
platform_driver 回撥以 platform_device 引數呼叫;而 isa_driver 回撥直接以 struct device *dev, unsigned int id 對呼叫 —— 考慮到裝置建立完全在匯流排內部,不透過傳入 isa_dev 來洩露它們會更簡潔。反正除了 struct device 之外,id 是我們唯一需要的東西,這也有助於在回撥中編寫更優雅的程式碼。
有了這個額外的 .match() 回撥,ISA 驅動程式就擁有了所有選項。如果 ALSA 想保留舊的非載入行為,它可以將舊的 .probe 全部放在 .match 中,這樣只有在一切都被發現存在並被確認後,它們才會保持註冊。如果它想保留在轉換為平臺裝置後無意中保持了一段時間的始終載入行為,它就可以不提供 .match(),而像以前一樣在 .probe() 中完成所有操作。
如果它,正如 Takashi Iwai 之前所建議的,為了更緊密地遵循更合理的匯流排模型,希望在後續繫結可能成功時進行載入,那麼它可以使用 .match() 來處理先決條件(例如檢查使用者是否希望啟用該卡以及是否已傳入埠/中斷/DMA 值),並使用 .probe() 來處理其他所有事情。這是最好的模型。
關於程式碼...
這隻匯出了兩個函式:isa_{,un}register_driver()。
isa_register_driver() 註冊 struct device_driver,然後迴圈遍歷傳入的 ndev,建立並註冊裝置。這會導致匯流排匹配方法對這些裝置被呼叫,即
int isa_bus_match(struct device *dev, struct device_driver *driver)
{
struct isa_driver *isa_driver = to_isa_driver(driver);
if (dev->platform_data == isa_driver) {
if (!isa_driver->match ||
isa_driver->match(dev, to_isa_dev(dev)->id))
return 1;
dev->platform_data = NULL;
}
return 0;
}
它做的第一件事是檢查這個裝置是否確實是該驅動程式的一個裝置,透過檢視裝置的 platform_data 指標是否設定為該驅動程式。平臺裝置比較字串,但由於所有內容都是內部的,我們不需要這樣做,因此 isa_register_driver() 濫用 dev->platform_data 作為 isa_driver 指標,我們可以在這裡檢查它。我相信 platform_data 可用於此目的,但如果不行,將 isa_driver 指標移動到私有結構體 isa_dev 中當然也可以。
然後,如果驅動程式沒有提供 .match 方法,它就會匹配。如果提供了,則呼叫驅動程式的 match() 方法來確定匹配。
如果它**不**匹配,dev->platform_data 會被重置,以向 isa_register_driver 指示這一點,然後 isa_register_driver 可以再次登出該裝置。
如果在所有這些過程中,有任何錯誤發生,或者根本沒有裝置匹配,則所有操作都會被回滾,並返回錯誤或 -ENODEV。
isa_unregister_driver() 只是登出匹配的裝置和驅動程式本身。
module_isa_driver 是一個輔助宏,用於在模組初始化/退出時不執行任何特殊操作的 ISA 驅動程式。這消除了大量的樣板程式碼。每個模組只能使用此宏一次,並且呼叫它會替換 module_init 和 module_exit。
max_num_isa_dev 是一個宏,用於根據 ISA 裝置的地址範圍,確定可以在 I/O 埠地址空間中註冊的最大 ISA 裝置數量。