1、簡介
本文基于內核源碼4.19.4分析。
linux內核設備的注冊由device_register()函數完成,這個函數是linux設備驅動模型的核心函數,實現在/drivers/base/core.c中:
在device_register()函數中,分為兩個步驟:
(1)調用device_initialize():該步驟用于初始化一個device。
(2)調用device_add():該函數用于將device添加到linux內核的device樹中。
2、device_initialize分析
該函數接收一個struct device *dev參數,在該函數中初始化struct device結構中的幾個重要成員:
設置dev->kobj.kset為device_kset。device_kset是一個struct kset類型的全局變量,用于向sysfs文件系統中導出目錄:/sys/device/* 。
初始化dev中的kobject,并指定與這個對象相關聯的ktype為device_type。
初始化dma_pools鏈表。
初始化struct device中的各種鎖:
初始化device的電源管理:
如果在NUMA下,還會初始化設置device的numa_node為-1。
接著初始化device下的links中的鏈表:
在struct device 中的links表示鏈接到該設備的suppliers和consumers,由struct dev_links_info表示:
設置device下的links.status值為DL_DEV_NO_DRIVER,表示此時還沒有對應驅動attach到這個設備。
以上步驟則是device_initialize()初始化設備時完成的操作。
3、device_add分析
(1)調用get_device(dev)增加device的引用計數。
(2)如果dev->p為NULL,則調用device_private_init()設置device的私有數據:
(3)設置device的name:
如果開啟支持pr_debug()函數,則會打印出對應的設備名稱。
(4)尋找父設備和父設備對應的kobj,并調用kobject_add()將dev->kobj添加到dev->kobj.parent:
(5)使用device_create_file為device創建sysfs屬性文件:
error=device_create_file(dev,&dev_attr_uevent);
dev_attr_uevent是一個struct device_attribute類型的數據,該結構用于描述導出設備屬性的接口,定義如下:
structdevice_attribute{ structattributeattr; ssize_t(*show)(structdevice*dev,structdevice_attribute*attr, char*buf); ssize_t(*store)(structdevice*dev,structdevice_attribute*attr, constchar*buf,size_tcount); };
(6)添加類的符號鏈接:
error=device_add_class_symlinks(dev);
device_add_class_symlinks()的功能是將設備添加到指定的設備類中,并在/sys/class目錄下為設備創建符號鏈接,以便用戶空間程序能夠方便地訪問和管理設備。
(7)調用device_add_attrs()為設備添加屬性:
error=device_add_attrs(dev);
device_add_attrs()的功能是為設備添加屬性,并在/sys/devices目錄下創建相應的屬性文件。這樣,用戶空間程序可以通過訪問設備的屬性文件來讀取和修改設備的屬性值。這個函數在設備驅動的初始化過程中常常被調用,以確保設備的屬性能夠正確地顯示和訪問。
(8)調用bus_add_device()添加設備到bus:
bus_add_device用于將設備添加到總線上。它的功能是將一個設備(struct device結構體)添加到指定總線(struct bus_type結構體)上,并進行相應的初始化和注冊操作。
bus_add_device的執行邏輯:
(1)從dev->bus中取得bus_type*類型的指針bus,如果獲取bus不成功,則函數直接返回;如果bus獲取成功,則會繼續后續的第(2)步操作。
(2)調用device_add_attrs接口,將由bus->dev_attrs指針定義的默認attribute添加到內核中,這個操作會體現在sysfs文件系統中的/sys/devices/xxx/xxx_device/目錄中。
(3)調用device_add_groups將bus_dev_groups添加到內核中。
(4)調用sysfs_create_link將該設備在sysfs中的目錄,鏈接到該bus的devices目錄下
(5)接著依然調用sysfs_create_link,在該設備的sysfs目錄中,創建一個指向該設備所在bus目錄的鏈接,命名為subsystem。
(6)前面幾個操作實則是向sysfs文件系統注冊關于設備的信息,向用戶空間拋出接口。最后步驟則是調用klist_add_tail()將該設備指針保存到bus->p->klist_devices中。
(9)調用device_pm_add()將一個設備添加到PM核心的active設備鏈表中。
(10)創建設備節點:
(11)通過bus_notifier告知系統設備已經添加:
(12)調用bus_probe_device()為該設備probe一個驅動。該函數實現如下:
具體執行流程如下:
(1)從dev中解析出該dev所在而bus,如果bus不存在,則退出該函數。
(2)如果設置了driver_autoprobe,則調用device_initial_probe(dev)。該函數本質調用到device_attach(),嘗試將設備連接到驅動程序。
(3)遍歷bus上的子系統接口鏈表interfaces,如果add_dev函數指針存在,則調用對應的函數。(從源碼來看有些驅動程序,會使用struct subsys_interface來實現,在此處實現對注冊的subsys_interface下的add_dev的調用執行)
(13)如果父設備存在,則會將該設備添加到父設備的klist_children鏈表中(klist_children是包含此設備的所有子節點的鏈表):
(14)如果設備的class不為NULL,則會將class綁定到device:
klist_add_tail(&dev->p->knode_class,&dev->class->p->klist_devices);
(15)通知所有的interface接口:
在內核中,struct class_interface是用于表示設備類和設備驅動之間的接口的結構體。它定義了設備類與設備驅動之間的關聯關系,允許設備驅動在注冊時與相應的設備類進行關聯,并提供了一組函數指針,用于設備類調用設備驅動中的操作。
struct class_interface結構體定義如下:
structclass_interface{ structlist_headnode; structclass*class; int(*add)(structdevice*dev,structclass_interface*class_intf); void(*remove)(structdevice*dev,structclass_interface*class_intf); };
node: 用于將struct class_interface鏈接到設備類的接口鏈表中。
class: 指向與該接口相關聯的設備類。
add: 指向設備類調用設備驅動的添加操作的函數指針。當設備添加到設備類時,會調用此函數。
remove: 指向設備類調用設備驅動的移除操作的函數指針。當設備從設備類中移除時,會調用此函數。
通過使用struct class_interface,設備驅動可以與設備類進行交互,以便在設備添加或移除時執行相應的操作。這種機制允許設備驅動與設備類解耦,使得設備驅動可以在設備類的上下文中執行一些操作,而無需直接操作設備類。
回到device_add()中,使用了list_for_each_entry()遍歷interfaces鏈表,如果設置了class_intf->add_dev,則調用該回調函數指針指向的函數。
4、總結
結合本文內容和linux內核源碼,得出以下結論:
(1)在設備驅動模型中,所有的設備注冊操作最后都會調用device_register()函數實現。
(2)在筆者分析的linux版本下的device_register()中,存在兩個數據結構:struct class_interface 和struct subsys_interface。從內核源碼來看,這兩個結構只在為數不多的幾個特定驅動程序中使用,那么可證明這可能是歷史發展遺留下來的代碼,在device_register中仍然保留了對這部分代碼的支持。
(3)在device_register()中調用了bus_probe_device(),從而證明在注冊設備的時候發生了『設備與驅動匹配』的過程。
審核編輯:劉清
-
電源管理
+關注
關注
115文章
6154瀏覽量
144231 -
Linux系統
+關注
關注
4文章
591瀏覽量
27353 -
dma
+關注
關注
3文章
559瀏覽量
100421 -
LINUX內核
+關注
關注
1文章
316瀏覽量
21617 -
numa
+關注
關注
0文章
7瀏覽量
3832
原文標題:一臉懵,萬千設備,linux內核如何知道?
文章出處:【微信號:嵌入式小生,微信公眾號:嵌入式小生】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論