韋東山嵌入式linux系列-驅動進化之路:總線設備驅動模型

1?驅動編寫的 3 種方法

以 LED 驅動為例

1.1?傳統寫法

使用哪個引腳,怎么操作引腳,都寫死在代碼中。
最簡單,不考慮擴展性,可以快速實現功能。
修改引腳時,需要重新編譯。

應用程序調用open等函數最簡單的方法是驅動層也提供對應的drv_open,應用程序調用read,驅動層也提供對應的drv_read等等。需要寫出驅動層的函數,為了便于管理,將這些函數放到file_operations結構體中,即第一步定義對應的file_operations結構體,并實現對應的open等程序(第一步);實現完成之后,將file_operations結構體通過register_chrdev注冊到內核(第二步);然后通過入口函數調用注冊函數(chrdev),安裝驅動程序的時候,內核會調用入口函數,完成file_operations結構體的注冊(第三步);有入口函數就有出口函數(第四步)。對于字符設備驅動程序而言,file_operations結構體是核心,每一個驅動程序都對應file_operations結構體,內核中有眾多file_operations結構體,怎么才能找到對應的結構體呢?

應用程序要訪問驅動程序,需要打開一個設備結點,里面有主設備號,根據設備結點的主設備號在內核中找到對應的file_operations結構體。注冊結構體時足以提供主設備號,可以讓內核分配;最后就是完善信息,創建類,創建設備。

之后有了面向對象/分層/分離

1.2?總線設備驅動模型

引入 platform_device/platform_driver,將“資源”與“驅動”分離開來。
代碼稍微復雜,但是易于擴展。
冗余代碼太多,修改引腳時設備端的代碼需要重新編譯。
更換引腳時 , 圖中的led_drv.c基本不用改,但是需要修改led_dev.c。

左邊是和具體硬件打交道,右邊對應是抽象。通過總線bus管理

1.3?設備樹

通過配置文件──設備樹來定義“資源”(內核之外),會被編譯成dtb文件,再傳給內核,內核解析dtb文件,構造出一系列的platform?device。
代碼稍微復雜,但是易于擴展。
無冗余代碼,修改引腳時只需要修改 dts 文件并編譯得到 dtb 文件,把它傳給內核。
無需重新編譯內核/驅動。

2?在 Linux 中實現“分離”: Bus/Dev/Drv 模型

實例

有一個platform?device,里面有resource,resource指向一個數組,里面定義了設備的資源(中斷),平臺設備指定資源;平臺platform driver有probe函數,這個函數用來做驅動相關的事情;platform?device和platform?driver通過name建立聯系。

找到platform_device.h(/include/linux)

有注冊和注銷函數

搜索,隨便找一個是全局變量的

有一個platform?device,里面有resource,resource指向一個數組,里面定義了設備的資源(中斷),平臺設備指定資源;平臺platform driver有probe函數,這個函數用來做驅動相關的事情;platform?device和platform?driver通過name建立聯系。

這里的resource需要遵守一定的規則

搜索platform?driver-serial8250

platform?device和platform?driver是怎么掛鉤的

搜索-serial8250_isa_driver

也是注冊進內核

內核中有虛擬的總線platform_bus_type,有兩個鏈表,左邊是設備鏈表,右邊是driver鏈表。當注冊平臺設備platform?device時,平臺設備就會放到左邊的鏈表,當注冊平臺驅動platform?driver時,平臺驅動就會放入到右邊的鏈表。放入之后就會和對方的成員比較,匹配成功就調用對應driver中的probe函數。

是否匹配成功

怎么匹配呢

參看源碼

 * Platform device IDs are assumed to be encoded like this:* "<name><instance>", where <name> is a short description of the type of* device, like "pci" or "floppy", and <instance> is the enumerated* instance of the device, like '0' or '42'.  Driver IDs are simply* "<name>".  So, extract the <name> from the platform_device structure,* and compare it against the name of the driver. Return whether they match* or not.*/
static int platform_match(struct device *dev, struct device_driver *drv)
{struct platform_device *pdev = to_platform_device(dev);struct platform_driver *pdrv = to_platform_driver(drv);/* When driver_override is set, only bind to the matching driver */// 1先用它if (pdev->driver_override)return !strcmp(pdev->driver_override, drv->name);/* Attempt an OF style match first */if (of_driver_match_device(dev, drv))return 1;/* Then try ACPI style match */if (acpi_driver_match_device(dev, drv))return 1;/* Then try to match against the id table */// 2再用它if (pdrv->id_table)return platform_match_id(pdrv->id_table, pdev) != NULL;/* fall-back to driver name match */// 3最后用它return (strcmp(pdev->name, drv->name) == 0);
}// 第2步
static const struct platform_device_id *platform_match_id(const struct platform_device_id *id,struct platform_device *pdev)
{while (id->name[0]) {if (strcmp(pdev->name, id->name) == 0) {pdev->id_entry = id;return id;}id++;}return NULL;
}

匹配過程是怎么啟動的呢

3?匹配規則

3.1?最先比較

platform_device.driver_override 和 platform_driver.driver.name,可以設置 platform_device 的 driver_override,強制選擇某個 platform_driver

3.2?然后比較

platform_device. name 和 platform_driver.id_table[i].name

Platform_driver.id_table 是“platform_device_id”指針,表示該 drv 支持若干個 device,它里面列出了各個 device 的{.name, .driver_data},其中的“ name”表示該 drv 支持的設備的名字, driver_data 是些提供給該 device 的私有數據。

3.3?最后比較

platform_device.name 和 platform_driver.driver.name
platform_driver.id_table 可能為空,
這時可以根據 platform_driver.driver.name 來尋找同名的 platform_device。

3.4?函數調用關系
platform_device_register
platform_device_adddevice_addbus_add_device // 放入鏈表bus_probe_device // probe 枚舉設備,即找到匹配的(dev, drv)device_initial_probe__device_attachbus_for_each_drv(...,__device_attach_driver,...)__device_attach_driverdriver_match_device(drv, dev) // 是否匹配driver_probe_device // 調用 drv 的 probeplatform_driver_register__platform_driver_registerdriver_registerbus_add_driver // 放入鏈表driver_attach(drv)bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);__driver_attachdriver_match_device(drv, dev) // 是否匹配driver_probe_device // 調用 drv 的 probe

4?常用函數

這些函數可查看內核源碼: drivers/base/platform.c,根據函數名即可知道其含義。下面摘取常用的幾個函數

4.1?注冊/反注冊
platform_device_register/ platform_device_unregister
platform_driver_register/ platform_driver_unregister
platform_add_devices // 注冊多個 device
4.2?獲得資源

返回該 dev 中某類型(type)資源中的第幾個(num)

struct resource *platform_get_resource(struct platform_device *dev,unsigned int type,unsigned int num)

返回該 dev 所用的第幾個(num)中斷:

int platform_get_irq(struct platform_device *dev, unsigned int num)

通過名字(name)返回該 dev 的某類型(type)資源:

struct resource *platform_get_resource_byname(struct platform_device *dev,unsigned int type,const char *name)

通過名字(name)返回該 dev 的中斷號

int platform_get_irq_byname(struct platform_device *dev, const char *name)

5?怎么寫程序

5.1?分配/設置/注冊 platform_device 結構體

在里面定義所用資源,指定設備名字。

5.2?分配/設置/注冊 platform_driver 結構體

在 其 中 的 probe 函 數里,分配/設置/注冊 file_operations 結構體 ,并從platform_device 中確實所用硬件資源, 指定 platform_driver 的名字。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/44732.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/44732.shtml
英文地址,請注明出處:http://en.pswp.cn/web/44732.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(深度估計學習)Depth Anything V2 復現

Depth Anything V2 復現 一、配置環境二、準備數據1. 權重文件2. 訓練數據 三、Test四、Train 代碼&#xff1a;https://github.com/DepthAnything/Depth-Anything-V2 一、配置環境 在本機電腦win跑之后依舊爆顯存&#xff0c;放到服務器跑&#xff1a;Ubuntu22.04&#xff0c…

使用Zabbix進行服務監控:構建高效穩定的IT服務管理平臺

使用Zabbix進行服務監控&#xff1a;構建高效穩定的IT服務管理平臺 在當今的數字化時代&#xff0c;IT服務管理&#xff08;ITSM&#xff09;對于確保企業IT系統的穩定性和性能至關重要。服務監控是ITSM的重要組成部分&#xff0c;可以幫助企業實時了解IT系統的運行狀況&#…

微調Qwen2大語言模型加入領域知識

目錄 試用Qwen2做推理安裝LLaMA-Factory使用自有數據集微調Qwen2驗證微調效果 試用Qwen2做推理 參考&#xff1a;https://qwen.readthedocs.io/en/latest/getting_started/quickstart.html from transformers import AutoModelForCausalLM, AutoTokenizer device "cuda…

極速構建的藝術:Kylin中Cube的并行構建實踐

極速構建的藝術&#xff1a;Kylin中Cube的并行構建實踐 引言 Apache Kylin是一款開源的分布式分析引擎&#xff0c;專為處理大規模數據集的即時查詢而設計。Kylin通過構建數據立方體&#xff08;Cube&#xff09;來優化查詢性能。隨著數據量的不斷增長&#xff0c;Cube的構建…

9.6 柵格圖層符號化唯一值著色渲染

文章目錄 前言多波段彩色渲染唯一值著色QGis設置為唯一值著色二次開發代碼實現唯一值著色 總結 前言 介紹柵格圖層數據渲染之唯一值著色渲染說明&#xff1a;文章中的示例代碼均來自開源項目qgis_cpp_api_apps 多波段彩色渲染唯一值著色 以“with_color_table.tif”數據為例…

硅谷甄選4(項目主體)

1.路由配置 1.1路由組件的雛形 src\views\home\index.vue&#xff08;以home組件為例&#xff09; 安裝插件&#xff1a; 1.2路由配置 1.2.1路由index文件 src\router\index.ts //通過vue-router插件實現模板路由配置 import { createRouter, createWebHashHistory } fro…

B站學習Java路線

Java 基礎 【零基礎 快速學Java】韓順平 零基礎30天學會Java JVM 尚硅谷宋紅康JVM全套教程&#xff08;詳解java虛擬機&#xff09; Java 并發 JUC

react-router實現路由攔截,useLocation,useNavigate鉤子

路由攔截 react-router中沒有直接給出攔截路由的方法&#xff0c;需要手動的去監聽路由的變化來攔截路由 路由攔截的要點&#xff1a; 能夠識別出目標路由和原始路由&#xff08;區分跳轉前和跳轉后&#xff09;能夠在跳轉時&#xff08;跳轉前或者跳轉后&#xff09;執行一些…

Python redis獲取的結果是字節不是字符串

Python redis獲取的結果是字節不是字符串 pool redis.ConnectionPool(hostlocalhost,port6379, passwordREDIS_PWD, decode_responsesTrue)需要指明給結果解碼decode_responsesTrue才能返回字符串

圖論基礎概念(詳細講解)

今天&#xff0c;我們講解一下圖論的概念&#xff0c;首先我們知道圖是一個什么東西。 圖你可以理解成一個網絡系統&#xff0c;兩個節點之間可能會有邊&#xff0c;邊鏈接兩個節點&#xff0c;可能是有向&#xff08;就比如說a只能往b,或者b只能往c)&#xff0c;可能是無向&a…

Vulnhub靶場 | DC系列 - DC1

https://www.vulnhub.com/series/dc,199/ 環境搭建 靶機鏡像下載地址&#xff1a;https://www.vulnhub.com/entry/dc-1,292/&#xff1b;需要將靶機和 kali 攻擊機放在同一個局域網里&#xff1b;本實驗kali 的 IP 地址&#xff1a;192.168.10.146。 滲透測試 1. 信息收集 …

CH16-DOM元素增刪改

CH16-DOM元素增刪改 本章目標 掌握如何使用DOM獲取節點時使用的屬性熟練使用DOM節點進行創建、添加、刪除、替換 一、使用DOM獲取節點時使用的屬性 1.1 首尾子節點 firstChild&#xff1a;獲取當前節點的首個子節點&#xff0c;注意&#xff1a;換行符、空格等也是節點。 …

【逆向】-異或-分組異或2

IDA查看源代碼 src長度32&#xff0c;encrypt函數加密&#xff0c;工4個參數&#xff0c;_FFFC雙擊&#xff0c;可以看到是個長度為7的固定值FnTest! 加密函數將4個參數又重新命名&#xff0c;混淆視聽&#xff0c;但是還是可以看到是嵌套循環&#xff0c;動態調試直接看結果可…

ArcGIS Pro SDK (八)地理數據庫 8 拓撲

ArcGIS Pro SDK &#xff08;八&#xff09;地理數據庫 8 拓撲 文章目錄 ArcGIS Pro SDK &#xff08;八&#xff09;地理數據庫 8 拓撲1 開放拓撲和進程定義2 獲取拓撲規則3 驗證拓撲4 獲取拓撲錯誤5 標記和不標記為錯誤6 探索拓撲圖7 找到最近的元素 環境&#xff1a;Visual …

C++11中重要的新特性之 lambda表達式 Part two

序言 在上一篇文章中&#xff0c;我們主要介紹了 C11 中的新增的關鍵詞&#xff0c;以及 范圍for循環 這類語法糖的使用和背后的邏輯。在這篇文章中我們會繼續介紹一個特別重要的新特性分別是 lambda表達式 。 1. lambda表達式 1.1 lambda的定義 C11 中的 lambda表達式 是一種…

昇思25天學習打卡營第19天 | ResNet50遷移學習再續

訓練模型部分代碼解析 構建Resnet50網絡 兩行初始化代碼 weight_init Normal(mean0, sigma0.02)這行代碼定義了一個初始化器weight_init&#xff0c;它將使用均值為0&#xff0c;標準差為0.02的正態分布來初始化網絡中的權重。這種初始化策略有助于在網絡的初始階段避免梯度…

Java基礎之集合

集合和數組的類比 數組: 長度固定可以存基本數據類型和引用數據類型 集合: 長度可變只能存引用數據類型存儲基本數據類型要把他轉化為對應的包裝類 ArrayList集合 ArrayList成員方法 添加元素 刪除元素 索引刪除 查詢 遍歷數組

day30【LeetCode力扣】18.四數之和

day30【LeetCode力扣】18.四數之和 1.題目描述 給你一個由 n 個整數組成的數組 nums &#xff0c;和一個目標值 target 。請你找出并返回滿足下述全部條件且不重復的四元組 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若兩個四元組元素一一對應&#xff0c;則認為兩個…

Linux: Mysql環境安裝

Mysql環境安裝&#xff08;Centos&#xff09; 前言一、卸載多余環境1.1 卸載mariadb1.2 查看并卸載系統mysql和mariadb安裝包 二、換取mysql官方yum源三、安裝并啟動mysql服務3.1 yum源加載3.2 安裝yum源3.3 安裝mysql服務3.3.1 安裝指令3.3.2 GPG密鑰問題解決方法3.3.3 查看是…

循環結構(一)——for語句【互三互三】

文章目錄 &#x1f341; 引言 &#x1f341; 一、語句格式 &#x1f341; 二、語句執行過程 &#x1f341; 三、語句格式舉例 &#x1f341;四、例題 &#x1f449;【例1】 &#x1f680;示例代碼: &#x1f449;【例2】 【方法1】 &#x1f680;示例代碼: 【方法2】…