RM新时代网站-首页

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

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

3天內(nèi)不再提示

萬千設(shè)備,linux內(nèi)核如何知道?

嵌入式小生 ? 來源:嵌入式小生 ? 2023-07-12 08:52 ? 次閱讀

1、簡介

本文基于內(nèi)核源碼4.19.4分析。

linux內(nèi)核設(shè)備的注冊由device_register()函數(shù)完成,這個函數(shù)是linux設(shè)備驅(qū)動模型的核心函數(shù),實現(xiàn)在/drivers/base/core.c中:

199d7ba0-204a-11ee-962d-dac502259ad0.png

在device_register()函數(shù)中,分為兩個步驟:

(1)調(diào)用device_initialize():該步驟用于初始化一個device。

(2)調(diào)用device_add():該函數(shù)用于將device添加到linux內(nèi)核的device樹中。

2、device_initialize分析

該函數(shù)接收一個struct device *dev參數(shù),在該函數(shù)中初始化struct device結(jié)構(gòu)中的幾個重要成員:

19b23cac-204a-11ee-962d-dac502259ad0.png

設(shè)置dev->kobj.kset為device_kset。device_kset是一個struct kset類型的全局變量,用于向sysfs文件系統(tǒng)中導(dǎo)出目錄:/sys/device/* 。

初始化dev中的kobject,并指定與這個對象相關(guān)聯(lián)的ktype為device_type。

初始化dma_pools鏈表。

初始化struct device中的各種鎖:

19d1e322-204a-11ee-962d-dac502259ad0.png

初始化device的電源管理

19f41bf4-204a-11ee-962d-dac502259ad0.png

如果在NUMA下,還會初始化設(shè)置device的numa_node為-1。

接著初始化device下的links中的鏈表:

1a0a4da2-204a-11ee-962d-dac502259ad0.png

在struct device 中的links表示鏈接到該設(shè)備的suppliers和consumers,由struct dev_links_info表示:

1a1af6f2-204a-11ee-962d-dac502259ad0.png

設(shè)置device下的links.status值為DL_DEV_NO_DRIVER,表示此時還沒有對應(yīng)驅(qū)動attach到這個設(shè)備。

以上步驟則是device_initialize()初始化設(shè)備時完成的操作。

3、device_add分析

(1)調(diào)用get_device(dev)增加device的引用計數(shù)。

(2)如果dev->p為NULL,則調(diào)用device_private_init()設(shè)置device的私有數(shù)據(jù):

1a376102-204a-11ee-962d-dac502259ad0.png

(3)設(shè)置device的name:

1a53a498-204a-11ee-962d-dac502259ad0.png

如果開啟支持pr_debug()函數(shù),則會打印出對應(yīng)的設(shè)備名稱。

(4)尋找父設(shè)備和父設(shè)備對應(yīng)的kobj,并調(diào)用kobject_add()將dev->kobj添加到dev->kobj.parent:

1a6f4130-204a-11ee-962d-dac502259ad0.png

(5)使用device_create_file為device創(chuàng)建sysfs屬性文件:

error=device_create_file(dev,&dev_attr_uevent);

dev_attr_uevent是一個struct device_attribute類型的數(shù)據(jù),該結(jié)構(gòu)用于描述導(dǎo)出設(shè)備屬性的接口,定義如下:

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()的功能是將設(shè)備添加到指定的設(shè)備類中,并在/sys/class目錄下為設(shè)備創(chuàng)建符號鏈接,以便用戶空間程序能夠方便地訪問和管理設(shè)備。

(7)調(diào)用device_add_attrs()為設(shè)備添加屬性:

error=device_add_attrs(dev);

device_add_attrs()的功能是為設(shè)備添加屬性,并在/sys/devices目錄下創(chuàng)建相應(yīng)的屬性文件。這樣,用戶空間程序可以通過訪問設(shè)備的屬性文件來讀取和修改設(shè)備的屬性值。這個函數(shù)在設(shè)備驅(qū)動的初始化過程中常常被調(diào)用,以確保設(shè)備的屬性能夠正確地顯示和訪問。

(8)調(diào)用bus_add_device()添加設(shè)備到bus:

1a8d5b0c-204a-11ee-962d-dac502259ad0.png

bus_add_device用于將設(shè)備添加到總線上。它的功能是將一個設(shè)備(struct device結(jié)構(gòu)體)添加到指定總線(struct bus_type結(jié)構(gòu)體)上,并進行相應(yīng)的初始化和注冊操作。

bus_add_device的執(zhí)行邏輯:

(1)從dev->bus中取得bus_type*類型的指針bus,如果獲取bus不成功,則函數(shù)直接返回;如果bus獲取成功,則會繼續(xù)后續(xù)的第(2)步操作。

(2)調(diào)用device_add_attrs接口,將由bus->dev_attrs指針定義的默認attribute添加到內(nèi)核中,這個操作會體現(xiàn)在sysfs文件系統(tǒng)中的/sys/devices/xxx/xxx_device/目錄中。

(3)調(diào)用device_add_groups將bus_dev_groups添加到內(nèi)核中。

(4)調(diào)用sysfs_create_link將該設(shè)備在sysfs中的目錄,鏈接到該bus的devices目錄下

(5)接著依然調(diào)用sysfs_create_link,在該設(shè)備的sysfs目錄中,創(chuàng)建一個指向該設(shè)備所在bus目錄的鏈接,命名為subsystem。

(6)前面幾個操作實則是向sysfs文件系統(tǒng)注冊關(guān)于設(shè)備的信息,向用戶空間拋出接口。最后步驟則是調(diào)用klist_add_tail()將該設(shè)備指針保存到bus->p->klist_devices中。

(9)調(diào)用device_pm_add()將一個設(shè)備添加到PM核心的active設(shè)備鏈表中。

(10)創(chuàng)建設(shè)備節(jié)點:

1aa8bb0e-204a-11ee-962d-dac502259ad0.png

(11)通過bus_notifier告知系統(tǒng)設(shè)備已經(jīng)添加:

1ac739f8-204a-11ee-962d-dac502259ad0.png

(12)調(diào)用bus_probe_device()為該設(shè)備probe一個驅(qū)動。該函數(shù)實現(xiàn)如下:

1ae151bc-204a-11ee-962d-dac502259ad0.png

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

(1)從dev中解析出該dev所在而bus,如果bus不存在,則退出該函數(shù)。

(2)如果設(shè)置了driver_autoprobe,則調(diào)用device_initial_probe(dev)。該函數(shù)本質(zhì)調(diào)用到device_attach(),嘗試將設(shè)備連接到驅(qū)動程序。

(3)遍歷bus上的子系統(tǒng)接口鏈表interfaces,如果add_dev函數(shù)指針存在,則調(diào)用對應(yīng)的函數(shù)。(從源碼來看有些驅(qū)動程序,會使用struct subsys_interface來實現(xiàn),在此處實現(xiàn)對注冊的subsys_interface下的add_dev的調(diào)用執(zhí)行)

(13)如果父設(shè)備存在,則會將該設(shè)備添加到父設(shè)備的klist_children鏈表中(klist_children是包含此設(shè)備的所有子節(jié)點的鏈表):

1afa2ff2-204a-11ee-962d-dac502259ad0.png

(14)如果設(shè)備的class不為NULL,則會將class綁定到device:

klist_add_tail(&dev->p->knode_class,&dev->class->p->klist_devices);

(15)通知所有的interface接口:

1b0936aa-204a-11ee-962d-dac502259ad0.png

在內(nèi)核中,struct class_interface是用于表示設(shè)備類和設(shè)備驅(qū)動之間的接口的結(jié)構(gòu)體。它定義了設(shè)備類與設(shè)備驅(qū)動之間的關(guān)聯(lián)關(guān)系,允許設(shè)備驅(qū)動在注冊時與相應(yīng)的設(shè)備類進行關(guān)聯(lián),并提供了一組函數(shù)指針,用于設(shè)備類調(diào)用設(shè)備驅(qū)動中的操作。

struct class_interface結(jié)構(gòu)體定義如下:

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鏈接到設(shè)備類的接口鏈表中。

class: 指向與該接口相關(guān)聯(lián)的設(shè)備類。

add: 指向設(shè)備類調(diào)用設(shè)備驅(qū)動的添加操作的函數(shù)指針。當設(shè)備添加到設(shè)備類時,會調(diào)用此函數(shù)。

remove: 指向設(shè)備類調(diào)用設(shè)備驅(qū)動的移除操作的函數(shù)指針。當設(shè)備從設(shè)備類中移除時,會調(diào)用此函數(shù)。

通過使用struct class_interface,設(shè)備驅(qū)動可以與設(shè)備類進行交互,以便在設(shè)備添加或移除時執(zhí)行相應(yīng)的操作。這種機制允許設(shè)備驅(qū)動與設(shè)備類解耦,使得設(shè)備驅(qū)動可以在設(shè)備類的上下文中執(zhí)行一些操作,而無需直接操作設(shè)備類。

回到device_add()中,使用了list_for_each_entry()遍歷interfaces鏈表,如果設(shè)置了class_intf->add_dev,則調(diào)用該回調(diào)函數(shù)指針指向的函數(shù)。

4、總結(jié)

結(jié)合本文內(nèi)容和linux內(nèi)核源碼,得出以下結(jié)論:

(1)在設(shè)備驅(qū)動模型中,所有的設(shè)備注冊操作最后都會調(diào)用device_register()函數(shù)實現(xiàn)。

(2)在筆者分析的linux版本下的device_register()中,存在兩個數(shù)據(jù)結(jié)構(gòu):struct class_interface 和struct subsys_interface。從內(nèi)核源碼來看,這兩個結(jié)構(gòu)只在為數(shù)不多的幾個特定驅(qū)動程序中使用,那么可證明這可能是歷史發(fā)展遺留下來的代碼,在device_register中仍然保留了對這部分代碼的支持。

(3)在device_register()中調(diào)用了bus_probe_device(),從而證明在注冊設(shè)備的時候發(fā)生了『設(shè)備與驅(qū)動匹配』的過程。





審核編輯:劉清

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

    關(guān)注

    115

    文章

    6177

    瀏覽量

    144443
  • Linux系統(tǒng)
    +關(guān)注

    關(guān)注

    4

    文章

    593

    瀏覽量

    27392
  • dma
    dma
    +關(guān)注

    關(guān)注

    3

    文章

    560

    瀏覽量

    100546
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    316

    瀏覽量

    21644
  • numa
    +關(guān)注

    關(guān)注

    0

    文章

    7

    瀏覽量

    3837

原文標題:一臉懵,萬千設(shè)備,linux內(nèi)核如何知道?

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

收藏 人收藏

    評論

    相關(guān)推薦

    Linux設(shè)備驅(qū)動開發(fā)詳解:基于最新的Linux 4.0內(nèi)核

    Linux設(shè)備驅(qū)動開發(fā)詳解:基于最新的Linux 4.0內(nèi)核
    發(fā)表于 08-31 12:29

    什么是linux設(shè)備驅(qū)動看了就知道

    想要深入理解linux設(shè)備驅(qū)動,你必須明確以下幾個問題:· 應(yīng)用程序、庫、內(nèi)核、驅(qū)動程序的關(guān)系· 設(shè)備類型· 設(shè)備文件、主
    發(fā)表于 04-06 06:50

    如何編譯設(shè)備樹和Linux內(nèi)核鏡像文件

    實驗任務(wù):編譯設(shè)備樹和Linux內(nèi)核鏡像文件,拷貝到sd卡中,再從sd卡中拷貝到nand閃存對應(yīng)的分區(qū)中,最后nand啟動,進入linux系統(tǒng)本篇博客內(nèi)容:1.實驗流程2.注意事項1.
    發(fā)表于 12-20 07:11

    Linux內(nèi)核教程

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

    linux內(nèi)核kernel-api

    linux內(nèi)核kernel-api,不知道從哪兒找的了,但是你如果想要做內(nèi)核編程,這是一部api函數(shù)詳盡的工具書!??!五星推薦
    發(fā)表于 10-30 17:16 ?19次下載

    Linux設(shè)備驅(qū)動開發(fā)詳解》第4章、Linux內(nèi)核模塊

    Linux設(shè)備驅(qū)動開發(fā)詳解》第4章、Linux內(nèi)核模塊
    發(fā)表于 10-27 14:15 ?0次下載
    《<b class='flag-5'>Linux</b><b class='flag-5'>設(shè)備</b>驅(qū)動開發(fā)詳解》第4章、<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>模塊

    知道linux常用查看硬件設(shè)備信息命令的方法是什么?

    知道linux常用查看硬件設(shè)備信息命令的方法是什么?
    發(fā)表于 05-13 11:04 ?3149次閱讀

    谷歌Android設(shè)備內(nèi)核引入主線Linux內(nèi)核難嗎?

    Android是基于Linux內(nèi)核的操作系統(tǒng),但是,運行在Android設(shè)備上的內(nèi)核其實與Google選擇的LTS版本Linux
    的頭像 發(fā)表于 11-22 10:41 ?3054次閱讀
    谷歌Android<b class='flag-5'>設(shè)備</b><b class='flag-5'>內(nèi)核</b>引入主線<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>難嗎?

    linux內(nèi)核是什么_linux內(nèi)核學(xué)習(xí)路線

    Linux內(nèi)核是一個操作系統(tǒng)(OS)內(nèi)核,本質(zhì)上定義為類Unix。它用于不同的操作系統(tǒng),主要是以不同的Linux發(fā)行版的形式。Linux
    發(fā)表于 09-16 15:49 ?2637次閱讀

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

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

    最硬核的Linux內(nèi)核文章

    來源 :頭條號@Linux學(xué)習(xí)教程,冰凌塊兒 01 前言 本文主要講解什么是Linux內(nèi)核,以及通過多張圖片展示Linux內(nèi)核的作用與功能,
    的頭像 發(fā)表于 10-19 17:46 ?2114次閱讀
    最硬核的<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>文章

    快速理解什么是Linux內(nèi)核以及Linux內(nèi)核的內(nèi)容

    01 前言 本文主要講解什么是Linux內(nèi)核,以及通過多張圖片展示Linux內(nèi)核的作用與功能,以便于讀者能快速理解什么是Linux
    的頭像 發(fā)表于 10-21 12:02 ?4286次閱讀
    快速理解什么是<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>以及<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>的內(nèi)容

    如何才能編譯Linux內(nèi)核

    內(nèi)核,是一個操作系統(tǒng)的核心。它負責(zé)管理系統(tǒng)的進程、內(nèi)存、設(shè)備驅(qū)動程序、文件和網(wǎng)絡(luò)系統(tǒng),決定著系統(tǒng)的性能和穩(wěn)定性。Linux 作為一個自由軟件,在廣大愛好者的支持下,內(nèi)核版本不斷更新。新
    發(fā)表于 11-04 18:04 ?8次下載

    如何使用Linux內(nèi)核實現(xiàn)USB驅(qū)動程序框架

    Linux內(nèi)核提供了完整的USB驅(qū)動程序框架。USB總線采用樹形結(jié)構(gòu),在一條總線上只能有唯一的主機設(shè)備Linux內(nèi)核從主機和
    發(fā)表于 11-06 17:59 ?20次下載
    如何使用<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>實現(xiàn)USB驅(qū)動程序框架

    linux驅(qū)動程序如何加載進內(nèi)核

    Linux系統(tǒng)中,驅(qū)動程序是內(nèi)核與硬件設(shè)備之間的橋梁。它們允許內(nèi)核與硬件設(shè)備進行通信,從而實現(xiàn)對硬件設(shè)
    的頭像 發(fā)表于 08-30 15:02 ?440次閱讀
    RM新时代网站-首页