Linux 裝置驅動模型中,按照層次的組織結構,抽象成總線(struct bus_type),裝置(struct device),驅動(struct device_driver)的層次組織形式,這是最原始的抽象結構,在此基礎之上,根據不同類型的總線/裝置/驅動,有形成了更高層次的組織結構,如virtio總線(struct bus_type virtio_bus),virtio裝置(struct virtio_device),virtio驅動(struct virtio_driver)等。
不同的抽象層次構成一顆網狀的樹,linux核心通過驅動模型:kobject,kset來組織樹的結構。
上圖說明了總線通過兩個資料結構:devices_ket和driver_kset來管理注冊在此總線上的所有的裝置和驅動,為了友善周遊,linux增加了klist_devices和klist_drivers用來實作裝置和驅動的周遊。
了解linux驅動模型,最重要的是了解裝置與驅動的比對過程,即在何時,驅動與裝置如何實作比對?
總結起來,裝置的注冊時機為調用device_register(),将devices注冊到總線的devices_kset上,同理,驅動的注冊為調用driver_register将驅動注冊到總線的drivers_kset上。
下圖對照說明了Device和Driver的注冊過程。
裝置與驅動的比對主要有以下幾個點:
(1)如果總線的match函數非空,調用總線的match函數
(2)如果總線的probe函數非空,調用總線的probe函數,然後會在總線的probe函數中調用驅動的probe函數
(3)如果總線的probe函數為空,則直接調用驅動的probe函數
另外,bus_for_each_drv()是對BUS上所有的Driver都進行__device_attach()操作;同樣的,bus_for_each_dev()是對BUS上所有的Device都進行__driver_attach()操作。
那麼,這些函數的執行時機在哪呢?
隻要有device或device_driver被注冊到總線上,都會執行上面的過程。