首先任何Linux 驅(qū)動的加載入口都是xxx_init() 接口藤抡,卸載入口是xxx_exit(). 對于nvme驅(qū)動同樣,它的驅(qū)動加載入口是nvme_init()接口硝枉。
其內(nèi)部實現(xiàn)的一個關(guān)鍵的地方在于使用pci_register_driver()接口和它的接口參數(shù)來注冊其支持的設(shè)備的pcie設(shè)備廉丽。
其參數(shù)是nvme_driver,其取值如下:
static struct pci_driver nvme_driver = {
.name = "nvme",
.id_table = nvme_id_table,
.probe = nvme_probe,
.remove = nvme_remove,
.shutdown = nvme_shutdown,
.driver = {
.pm = &nvme_dev_pm_ops,
},
};
其中nvme_driver中的id_table 取值如下
static const struct pci_device_id nvme_id_table[] = {
{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) },
{ 0, }
};
其中PCI_DEVICE_CLASS宏用于創(chuàng)建一個struct pci_device_id類型的實例,這個實例只需要匹配指定的pci class妻味,這個指定的匹配PCI_CLASS_STORAGE_EXPRESS的類型正压,想vendor id, device id, subvendor id, subdevice id 都不care,只要匹配上PCI_CLASS_STORAGE_EXPRESS,就可以责球。
需要說明幾點
(1)每個pci設(shè)備都通過struct pci_device_id中的vender id, device id 和class node的一個實例唯一標志.
(2)每一個pci設(shè)備通過struct pci_device類型的實例表示焦履。
(3)每個pci驅(qū)動通過struct pci_driver類型的實例標識,它包含該支持該驅(qū)動的pci設(shè)備pci_device_id表棕诵,device driver設(shè)備驅(qū)動,和probe, remove 等函數(shù)指針裁良。
搞清楚了關(guān)鍵的參數(shù)含義,我們就可以開始pci device 和pci driver的綁定過程
(1)第一步校套,首先系統(tǒng)啟動的時候价脾,pci bus 會scan 所有在這條總線的所有設(shè)備,為每一個pci設(shè)備創(chuàng)建一個struct pci_device 類型的實例笛匙,而struct pci_device類型包含device的成員侨把,正是通過這個成員,pci bus 將所有在總線上得所有設(shè)備連接起來妹孙,通過pci bus的總線描述符的設(shè)備鏈表可以遍歷所有的設(shè)備秋柄。
(2)第二步,當pci driver加載的時候蠢正,pci driver 會初始化骇笔,并且會調(diào)用driver_register()來pci driver加到總線的驅(qū)動鏈表上.這樣支持該驅(qū)動設(shè)備插上去的時候,該通過什么pci driver 來驅(qū)動這個設(shè)備。在pci driver 注冊的過程中笨触,系統(tǒng)會檢查pci 驅(qū)動的id_table 懦傍,看在總線的device list 里面設(shè)備有沒有該pci driver 支持的,如果支持芦劣,就把這個設(shè)備加到這個pci driver的device list 里面粗俱,并開始probe 過程。