USB 熱插拔¶
Linux 熱插拔¶
在像 USB (和 Cardbus PCI) 這樣的熱插拔匯流排中,終端使用者在通電狀態下將裝置插入匯流排。 在大多數情況下,使用者希望這些裝置可以立即使用。 這意味著系統必須做很多事情,包括
找到可以處理該裝置的驅動程式。 這可能涉及載入核心模組;較新的驅動程式可以使用 module-init-tools 將其裝置(和類)支援釋出到使用者實用程式。
將驅動程式繫結到該裝置。 匯流排框架使用裝置驅動程式的 probe() 例程來完成此操作。
告訴其他子系統配置新裝置。 可能需要啟用列印佇列、啟動網路、安裝磁碟分割槽等等。 在某些情況下,這些將是特定於驅動程式的操作。
這涉及核心模式和使用者模式操作的混合。 使裝置可以立即使用意味著任何使用者模式操作都不能等待管理員來完成它們:核心必須被動地觸發它們(觸發一些監控守護程式來呼叫幫助程式),或者主動地(直接呼叫這樣的使用者模式幫助程式)。
那些觸發的操作必須支援系統的管理策略; 這些程式在這裡被稱為“策略代理”。 通常,它們涉及分派到更熟悉的管理工具的 shell 指令碼。
因為其中一些操作依賴於驅動程式的資訊(元資料),而這些資訊目前僅在動態連結驅動程式時可用,所以當您配置高度模組化的系統時,您會獲得最佳的熱插拔效果。
核心熱插拔助手 (/sbin/hotplug)¶
有一個核心引數:/proc/sys/kernel/hotplug,它通常儲存路徑名 /sbin/hotplug。 該引數命名了一個核心可以在不同時間呼叫的程式。
/sbin/hotplug 程式可以由任何子系統呼叫,作為其對配置更改的反應的一部分,來自該子系統中的執行緒。 只需要一個引數:被通知某些核心事件的子系統的名稱。 該名稱用作進一步事件分派的第一個鍵;任何其他引數和環境變數引數都由進行呼叫的子系統指定。
熱插拔軟體和其他資源可在以下網址獲得
郵件列表資訊也可在該站點獲得。
USB 策略代理¶
當 USB 裝置從系統中新增或刪除時,USB 子系統當前會呼叫 /sbin/hotplug。 呼叫由核心 hub 工作佇列 [hub_wq] 完成,或者作為 root hub 初始化的一部分(由 init、modprobe、kapmd 等完成)。 它的單個命令列引數是字串“usb”,並且它傳遞以下環境變數
ACTION |
|
PRODUCT |
USB 供應商、產品和版本程式碼(十六進位制) |
TYPE |
裝置類程式碼(十進位制) |
INTERFACE |
介面 0 類程式碼(十進位制) |
如果配置了 “usbdevfs”,則還會傳遞 DEVICE 和 DEVFS。 DEVICE 是裝置的路徑名,對於具有多個和/或備用介面而使驅動程式選擇複雜化的裝置非常有用。 按照設計,USB 熱插拔獨立於 usbdevfs:您可以執行 USB 裝置設定的大部分基本部分,而無需使用該檔案系統,也無需執行使用者模式守護程式來檢測系統配置中的更改。
當前可用的策略代理實現可以載入模組的驅動程式,並且可以呼叫特定於驅動程式的設定指令碼。 最新的實現利用了 USB module-init-tools 支援。 後來的代理可能會解除安裝驅動程式。
USB Modutils 支援¶
當前版本的 module-init-tools 將建立一個 modules.usbmap 檔案,該檔案包含來自每個驅動程式的 MODULE_DEVICE_TABLE 的條目。 各種使用者模式策略代理可以使用此類檔案來確保在啟動時或稍後載入所有正確的驅動程式模組。
有關此類表條目的完整資訊,請參閱 linux/usb.h; 或檢視現有驅動程式。 每個表條目描述了一個或多個標準,用於將驅動程式與裝置或裝置類別進行匹配。 特定標準由 “match_flags” 中設定的位以及欄位值標識。 您可以直接構造標準,也可以使用如下宏,並使用 driver_info 來儲存更多資訊
USB_DEVICE (vendorId, productId)
... matching devices with specified vendor and product ids
USB_DEVICE_VER (vendorId, productId, lo, hi)
... like USB_DEVICE with lo <= productversion <= hi
USB_INTERFACE_INFO (class, subclass, protocol)
... matching specified interface class info
USB_DEVICE_INFO (class, subclass, protocol)
... matching specified device class info
一個簡短的示例,對於支援多個特定 USB 裝置及其怪癖的驅動程式,可能具有如下的 MODULE_DEVICE_TABLE
static const struct usb_device_id mydriver_id_table[] = {
{ USB_DEVICE (0x9999, 0xaaaa), driver_info: QUIRK_X },
{ USB_DEVICE (0xbbbb, 0x8888), driver_info: QUIRK_Y|QUIRK_Z },
...
{ } /* end with an all-zeroes entry */
};
MODULE_DEVICE_TABLE(usb, mydriver_id_table);
大多數 USB 裝置驅動程式應將這些表傳遞給 USB 子系統以及模組管理子系統。 但並非全部:某些驅動程式框架使用分層在 USB 上的介面連線,因此它們不需要這樣的 struct usb_driver。
直接連線到 USB 子系統的驅動程式應宣告如下
static struct usb_driver mydriver = {
.name = "mydriver",
.id_table = mydriver_id_table,
.probe = my_probe,
.disconnect = my_disconnect,
/*
if using the usb chardev framework:
.minor = MY_USB_MINOR_START,
.fops = my_file_ops,
if exposing any operations through usbdevfs:
.ioctl = my_ioctl,
*/
};
當 USB 子系統知道驅動程式的裝置 ID 表時,它會在選擇要 probe() 的驅動程式時使用。 執行新裝置處理的執行緒會根據裝置的介面和裝置描述符檢查驅動程式的裝置 ID 條目 MODULE_DEVICE_TABLE。 只有在匹配時才會呼叫 probe(),並且 probe() 的第三個引數將是匹配的條目。
如果您沒有為您的驅動程式提供 id_table,那麼可能會為每個新裝置 probe 您的驅動程式;probe() 的第三個引數將為 NULL。