RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

linux內核中的driver_register介紹

嵌入式小生 ? 來源:嵌入式小生 ? 2023-07-14 09:17 ? 次閱讀

1、簡介

linux內核注冊驅動由driver_register()完成。它將驅動程序的信息添加到內核的驅動程序列表中,使得內核能夠在需要時與該驅動程序進行交互。

當調用driver_register()函數(shù)時,內核會將驅動程序添加到內核驅動程序列表中,并在需要時使用該驅動程序來匹配和初始化設備。驅動程序的探測函數(shù)(probe)將在設備與驅動程序匹配時調用,以便進行設備的初始化。移除函數(shù)(remove)將在設備從系統(tǒng)中移除時調用,以進行相關的清理操作。

通過調用driver_register()函數(shù),驅動程序可以將自身注冊到內核中,從而使得內核能夠管理和與驅動程序進行交互。這為設備的探測、初始化、配置和移除提供了必要的框架和支持。

內核中,幾乎所有的驅動子系統(tǒng)都會以該函數(shù)進行封裝,開放出對應驅動的注冊函數(shù),例如PCI驅動框架,在/drivers/pic/pci-driver.c文件中會調用該函數(shù):

78dbf582-21db-11ee-962d-dac502259ad0.png

再比如對應i2c設備驅動,在i2c驅動框架下的/driver/i2c/i2c-core.c文件中有如下代碼:

793a14b4-21db-11ee-962d-dac502259ad0.png

綜上可知,driver_register()在幾乎所有的驅動子系統(tǒng)中都會使用到。兜兜轉轉,最后都會調用到該函數(shù)。

2、driver_register分析

在linux內核中,struct device_driver結構體用于表示一個設備驅動程序。它包含了驅動程序的相關信息,如名稱、總線類型、探測函數(shù)、移除函數(shù)等,用于與設備進行匹配、初始化和清理操作。struct device_driver結構體提供了設備驅動程序的基本信息和回調函數(shù),用于與設備進行匹配、初始化、清理和管理。

通過使用該結構體,驅動程序能夠在設備與驅動程序匹配時進行初始化操作,并在設備移除或系統(tǒng)關機時進行相應的清理操作。此外,還可以通過屬性組和電源管理操作等擴展功能來增強驅動程序的功能和靈活性。該結構定義如下:

structdevice_driver{
constchar*name;//
structbus_type*bus;//驅動程序所屬的總線類型。

structmodule*owner;//模塊擁有者
constchar*mod_name;//在構建內建模塊時使用

boolsuppress_bind_attrs;//是否禁用通過sysfsbound/unbound操作

conststructof_device_id*of_match_table;//設備樹匹配表
conststructacpi_device_id*acpi_match_table;//ACPI匹配表。

int(*probe)(structdevice*dev);//驅動程序的探測函數(shù),用于在設備與驅動程序匹配時進行初始化。
int(*remove)(structdevice*dev);//驅動程序的移除函數(shù),用于在設備從系統(tǒng)中移除時進行清理。
void(*shutdown)(structdevice*dev);//驅動程序的關機函數(shù),用于在系統(tǒng)關機時進行相關的清理操作。
int(*suspend)(structdevice*dev,pm_message_tstate);//驅動程序的掛起函數(shù),用于在設備進入掛起狀態(tài)時進行相關的操作。
int(*resume)(structdevice*dev);//驅動程序的恢復函數(shù),用于在設備從掛起狀態(tài)恢復時進行相關的操作。
conststructattribute_group**groups;//驅動程序的屬性組,用于提供設備的特定屬性。

conststructdev_pm_ops*pm;//驅動程序的電源管理操作,用于控制設備的電源管理。

structdriver_private*p;//驅動核心的私有數(shù)據(jù)。驅動核心能訪問。
};

driver_register函數(shù)用于向設備驅動模型注冊一個設備驅動,實現(xiàn)在/drivers/base/driver.c文件中:

intdriver_register(structdevice_driver*drv)
{
intret;
structdevice_driver*other;

BUG_ON(!drv->bus->p);

if((drv->bus->probe&&drv->probe)||
(drv->bus->remove&&drv->remove)||
(drv->bus->shutdown&&drv->shutdown))
printk(KERN_WARNING"Driver'%s'needsupdating-pleaseuse"
"bus_typemethods
",drv->name);

other=driver_find(drv->name,drv->bus);
if(other){
printk(KERN_ERR"Error:Driver'%s'isalreadyregistered,"
"aborting...
",drv->name);
return-EBUSY;
}

ret=bus_add_driver(drv);
if(ret)
returnret;
ret=driver_add_groups(drv,drv->groups);
if(ret){
bus_remove_driver(drv);
returnret;
}
kobject_uevent(&drv->p->kobj,KOBJ_ADD);

returnret;
}

driver_register()具體執(zhí)行流程如下:

(1)調用driver_find()通過名字找到bus上的driver。

(2)調用bus_add_driver()添加一個driver到bus。

(3)調用driver_add_groups()將屬性組(attribute_group)添加到驅動程序中。

(4)調用kobject_uevent()觸發(fā)內核KOBJ_ADD事件,用于向用戶空間發(fā)送KOBJ_ADD事件通知。

下文將展開driver_find()和bus_add_driver()進行分析。

(2-1)driver_find分析

該函數(shù)接收兩個參數(shù)

(1)name:驅動程序的名稱。

(2)bus:待被掃描的bus。

函數(shù)實現(xiàn)如下:

79690530-21db-11ee-962d-dac502259ad0.png

調用kset_find_obj()根據(jù)name尋找是否有kobject,如果找到了,則使用to_driver()返解出struct driver_private,然后將driver_private->driver作為參數(shù)返回;否則返回NULL。

該行代碼中:

structkobject*k=kset_find_obj(bus->p->drivers_kset,name);

bus->p->drivers_kset本質是struct kset,struct kset是linux內核對象的集合,添加的設備驅動將作為內核對象添加到對應的kset集合中。kset_find_obj()則用于在kset中搜索出對應name的內核對象,該函數(shù)實現(xiàn)如下:

79855bcc-21db-11ee-962d-dac502259ad0.png

回到driver_register()中,如果driver_find()找到了對應的device_driver,則證明該設備驅動已經(jīng)注冊過了,這時候則返回退出driver_register();否則繼續(xù)執(zhí)行后續(xù)的bus_add_driver()操作。

(2-2)bus_add_driver分析

bus_add_driver()實現(xiàn)在/drivers/base/bus.c中,將執(zhí)行下列具體的邏輯:

(1)從drv->bus中解析出bus,如果bus為NULL,則返回退出bus_add_driver:

bus=bus_get(drv->bus);
if(!bus)
return-EINVAL;

(2)調用kzalloc()分配一個struct driver_private內存空間:

79c2e424-21db-11ee-962d-dac502259ad0.png

(3)調用klist_init()初始化設備鏈表klist_devices:

klist_init(&priv->klist_devices,NULL,NULL);

(4)設置驅動私有數(shù)據(jù)的driver和kobj.kset字段,并將驅動私有數(shù)據(jù)設置到驅動程序的->p字段:

priv->driver=drv;
drv->p=priv;
priv->kobj.kset=bus->p->drivers_kset;

(5)調用kobject_init_and_add()初始化設備私有數(shù)據(jù)中的內核對象,并指定驅動類型driver_ktype:

error=kobject_init_and_add(&priv->kobj,&driver_ktype,NULL,
"%s",drv->name);
if(error)
gotoout_unregister;

driver_ktype定義如下:

staticstructkobj_typedriver_ktype={
.sysfs_ops=&driver_sysfs_ops,
.release=driver_release,
};

(6)使用klist_add_tail()將priv->knode_bus節(jié)點添加到bus->p->klist_drivers總線的驅動鏈表中。

(7)如果設置了驅動所屬的bus的drivers_autoprobe,則調用drvier_attach()嘗試將驅動程序綁定到設備:

79ec2f28-21db-11ee-962d-dac502259ad0.png

(8)使用moudle_add_drvier將設備驅動程序添加到內核模塊系統(tǒng)中,使之可以與設備進行關聯(lián)。通過調用這個函數(shù),可以將設備驅動程序注冊到內核的設備驅動程序列表中,以便在設備被發(fā)現(xiàn)時自動加載并與之匹配。

(9)調用driver_create_file()為設備驅動創(chuàng)建sysfs中的屬性文件。該文件將顯示在/sys/bus//drivers//目錄下,其中是設備所屬的總線類型,是設備驅動程序的名稱。

(10)調用driver_add_groups()將設備驅動程序的bus的屬性組添加到sysfs中,這些屬性組將顯示在/sys/bus//drivers//目錄下,其中是設備所屬的總線類型,是設備驅動程序的名稱。

3、總結

driver_register()是linux 內核中用于注冊設備驅動程序的函數(shù)。它屬于linux設備驅動模型的一部分,用于將驅動程序添加到內核的設備驅動程序列表中,以便內核可以與相應的硬件設備進行交互。在內核中的大部分驅動都會形成自己的驅動框架核心,例如:USB、i2c、spi等,這些驅動框架核心也一般都會封裝出自己的注冊函數(shù),但是這些注冊函數(shù)本質上都是調用driver_register()實現(xiàn)驅動的注冊。例如下圖所示:

7a21d18c-21db-11ee-962d-dac502259ad0.png





審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • USB接口
    +關注

    關注

    9

    文章

    701

    瀏覽量

    55634
  • 電源管理
    +關注

    關注

    115

    文章

    6177

    瀏覽量

    144443
  • LINUX內核
    +關注

    關注

    1

    文章

    316

    瀏覽量

    21644
  • I2C驅動
    +關注

    關注

    0

    文章

    9

    瀏覽量

    7046
  • ADD
    ADD
    +關注

    關注

    1

    文章

    20

    瀏覽量

    9422

原文標題:linux內核中竟有如此“高冷”的driver_register

文章出處:【微信號:嵌入式小生,微信公眾號:嵌入式小生】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Linux內核開發(fā)工具介紹

    進行嵌入式Linux產(chǎn)品開發(fā),往往需要對內核進行裁剪和定制,以滿足嵌入式產(chǎn)品的功能和性能需求。本文介紹幾種閱讀Linux內核源碼的工具和方法
    發(fā)表于 12-29 15:20 ?4708次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b>開發(fā)工具<b class='flag-5'>介紹</b>

    Linux內核開發(fā)工具介紹

    進行嵌入式Linux產(chǎn)品開發(fā),往往需要對內核進行裁剪和定制,以滿足嵌入式產(chǎn)品的功能和性能需求。本文介紹幾種閱讀Linux內核源碼的工具和方法
    發(fā)表于 01-06 17:20

    總線設備驅動模型淺析

    時,最終都會調用到:int driver_register(structdevice_driver *drv){ // 將驅動綁定在對應的總線上,主要工作把驅動(device_driver)添加到總線
    發(fā)表于 08-22 16:19

    iMX6Q開發(fā)板設備樹內核-注冊驅動例程介紹

    `文檔主要講解在 iMX6Q/D/PLUS 開發(fā)板的設備樹內核(4.1.15)源碼,設備樹注冊驅動和非設備樹的類似。 1 注冊驅動源碼分析 設備樹的內核驅動,platform_
    發(fā)表于 07-18 15:42

    Linux內核教程

    本章學習目標掌握LINUX內核版本的含義理解并掌握進程的概念掌握管道的概念及實現(xiàn)了解內核的數(shù)據(jù)結構了解LINUX內核的算法掌握
    發(fā)表于 04-10 16:59 ?0次下載

    Linux內核學習起步課件

    Linux內核學習起步介紹
    發(fā)表于 04-10 17:22 ?0次下載

    Linux內核配置系統(tǒng)詳解

    隨著 Linux 操作系統(tǒng)的廣泛應用,特別是 Linux 在嵌入式領域的發(fā)展,越來越多的人開始投身到 Linux 內核級的開發(fā)。面對日益龐
    發(fā)表于 11-01 15:45 ?4次下載

    Linux設備模型:device和device driver

    device和device driverLinux驅動開發(fā)的基本概念。Linux kernel的思路很簡單:驅動開發(fā),就是要開發(fā)指定的軟件(driver)以驅動指定的設備,所以ker
    發(fā)表于 05-10 11:21 ?2454次閱讀

    你了解Embeded linux的probe

    所謂的"probe”,是指在Linux內核,如果存在相同名稱的device和device_driver內核就會執(zhí)行device_
    發(fā)表于 05-14 16:18 ?3954次閱讀
    你了解Embeded <b class='flag-5'>linux</b><b class='flag-5'>中</b>的probe

    linux內核參數(shù)設置_linux內核的功能有哪些

    本文主要闡述了linux內核參數(shù)設置及linux內核的功能。
    發(fā)表于 09-17 14:40 ?1371次閱讀
    <b class='flag-5'>linux</b><b class='flag-5'>內核</b>參數(shù)設置_<b class='flag-5'>linux</b><b class='flag-5'>內核</b>的功能有哪些

    Linux內核的編譯與運行

    本文檔的主要內容詳細介紹的是Linux內核的編譯與運行免費下載。
    發(fā)表于 03-25 13:48 ?11次下載

    Linux內核結構介紹

    通常情況下,Linux內核的結構被認為包含以下11個主要層次。
    的頭像 發(fā)表于 04-14 11:59 ?1262次閱讀

    萬千設備,linux內核如何知道?

    linux內核設備的注冊由device_register()函數(shù)完成,這個函數(shù)是linux設備驅動模型的核心函數(shù)
    的頭像 發(fā)表于 07-12 08:52 ?839次閱讀
    萬千設備,<b class='flag-5'>linux</b><b class='flag-5'>內核</b>如何知道?

    使用 PREEMPT_RT 在 Ubuntu 構建實時 Linux 內核

    的實時內核補丁來完成。簡介我們曾介紹過在Ubuntu22.04啟用實時Linux內核有多簡單,因為Canonical已將該
    的頭像 發(fā)表于 04-12 08:36 ?2414次閱讀
    使用 PREEMPT_RT 在 Ubuntu <b class='flag-5'>中</b>構建實時 <b class='flag-5'>Linux</b> <b class='flag-5'>內核</b>

    linux內核通用HID觸摸驅動

    linux內核,為HID觸摸面板實現(xiàn)了一個通用的驅動程序,位于/drivers/hid/hid-multitouch.c文件。hid觸摸驅動是以struct hid_
    的頭像 發(fā)表于 10-29 10:55 ?541次閱讀
    <b class='flag-5'>linux</b><b class='flag-5'>內核</b><b class='flag-5'>中</b>通用HID觸摸驅動
    RM新时代网站-首页