嵌入式驅動學習第一周——linux設備管理模型

前言

?? 現在來聊點原理性的東西——linux設備管理模型

?? 嵌入式驅動學習專欄將詳細記錄博主學習驅動的詳細過程,未來預計四個月將高強度更新本專欄,喜歡的可以關注本博主并訂閱本專欄,一起討論一起學習。現在關注就是老粉啦!

行文目錄

  • 前言
  • 1. LDM數據結構
    • 1.1 總線、設備、驅動關系
      • 1.1.1 類
      • 1.1.2 設備
      • 1.1.3 驅動
  • 2. kobject sysfs
    • 2.1 kobjects
    • 2.2 ktype
    • 2.3 kset
  • 參考資料

1. LDM數據結構

?? linux 設備模型LDM的上層依賴于總線、設備驅動程序、設備和類。

1.1 總線、設備、驅動關系

?? 在LINUX驅動的世界里,所有的設備和驅動都是掛在總線上的,也就是總線來管理設備和驅動的,總線知道掛在它上邊的所有驅動和設備的情況,由總線完成驅動和設備的匹配和探測。

?? 總線上掛著驅動和設備,一個驅動可以管理多個設備,一個設備保存一個對應驅動的信息,一般在初始化的時候,總線先初始化,然后設備先注冊,最后驅動去找設備,完成他們之間的銜接。

?? 系統已經給我們準備好了我們所學要的總線。對于我們來說,就是去學好怎么在系統中添加設備以及相關的驅動就行了。

1.1.1 類

?? 相關結構體:struct classstruct class_device

?? 類發明來就是來管理設備的,是對設備的高級抽象,本質也是一個結構體,但是按照類的思想來組織成員的。運用class,可以讓用戶空間的程序根據自己要處理的事情來調用設備,而不是根據設備被接入到系統的方式或設備的工作原來調用。

?? 一個struct class結構體類型變量對應一個類,內核提供了class_create() 函數,可以用它來創建一個類,這個類存放于 sysfs 下面, 一旦創建了類,再調用 device_create() 函數在 /dev 目錄下創建相應的設備節點。

1.1.2 設備

?? 驅動中常寫的struct device是硬件設備在內核驅動框架中的抽象
?? 使用device_register函數向內核驅動框架注冊一個設備,也可使用device_create來創建,device_create函數是對device_register的封裝。
?? 通常device不會單獨使用,而是被包含在一個具體的設備結構體中

?? 使用案例如下所示:

struct gpioled_dev {dev_t devid;struct cdev cdev;struct class *class;			// 定義一個classstruct device *device;			// 定義一個deviceint major;int minor;struct device_node *nd;int led_gpio;
};static int __init led_init(void)
{......newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);		// 先創建classif (IS_ERR(newchrled.class)) {return PTR_ERR(newchrled.class);}newchrled.device = device_create(newchrled.class, NULL, newchrled.devid, NULL, NEWCHRLED_NAME);		// 再用class創建deviceif (IS_ERR(newchrled.device)) {return PTR_ERR(newchrled.device);}......
}static void __exit led_exit(void)
{......device_destroy(newchrled.class, newchrled.devid);		// 先釋放deviceclass_destroy(newchrled.class);							// 再釋放class
}

1.1.3 驅動

?? struct device_driver是驅動程序在內核驅動框架中的抽象
?? 關鍵元素1:name,驅動程序的名字,很重要,經常被用來作為驅動和設備的匹配依據
?? 關鍵元素2:probe,驅動程序的探測函數,用來檢測一個設備是否可以被該驅動所管理

?? 使用方式:

/** @description: 驅動程序的探測函數,檢測設備是否被該驅動所管理,當驅動與設備匹配后此函數會執行* @param-dev  : platform設備* @return     : 0,成功;其他負值,失敗*/
static int led_probe(struct platform_device *dev)
{int i = 0;int ressize[5];u32 val = 0;struct resource *ledsource[5];printk("led driver and device has matched!\r\n");for (i = 0; i < 5; i++) {ledsource[i] = platform_get_resource(dev, IORESOURCE_MEM, i);if (!ledsource[i]) {dev_err(&dev->dev, "No MEM resource for always on\n");return -ENXIO;}ressize[i] = resource_size(ledsource[i]);}IMX6U_CCM_CCGR1  = ioremap(ledsource[0]->start, ressize[0]);SW_MUX_GPIO1_IO3 = ioremap(ledsource[1]->start, ressize[1]);SW_PAD_GPIO1_IO3 = ioremap(ledsource[2]->start, ressize[2]);GPIO1_DR         = ioremap(ledsource[3]->start, ressize[3]);GPIO1_GDIR       = ioremap(ledsource[4]->start, ressize[4]);val = readl(IMX6U_CCM_CCGR1);val &= ~(3 << 26);val |= (3 << 26);writel(val, IMX6U_CCM_CCGR1);writel(5, SW_MUX_GPIO1_IO3);writel(0x10b0, SW_PAD_GPIO1_IO3);val = readl(GPIO1_GDIR);val &= ~(1 << 3);val |= (1 << 3);writel(val, GPIO1_GDIR);val = readl(GPIO1_DR);val |= (1 << 3);writel(val, GPIO1_DR);if (leddev.major) {leddev.devid = MKDEV(leddev.major, 0);register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);} else {alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);leddev.major = MAJOR(leddev.devid);leddev.minor = MINOR(leddev.devid);}leddev.cdev.owner = THIS_MODULE;cdev_init(&leddev.cdev, &led_fops);cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);if (IS_ERR(leddev.class)){return PTR_ERR(leddev.class);}leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);if (IS_ERR(leddev.device)) {return PTR_ERR(leddev.device);}return 0;
}/** @description: remove函數,移除platform驅動的時候此函數會執行* @param-dev  : platfrom 設備* @return     : 0,成功;其他負值,失敗*/
static int led_remove(struct platform_device *dev)
{iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO3);iounmap(SW_PAD_GPIO1_IO3);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);cdev_del(&leddev.cdev);unregister_chrdev_region(leddev.devid, LEDDEV_CNT);device_destroy(leddev.class, leddev.devid);class_destroy(leddev.class);return 0;
}static struct platform_driver led_driver = {.driver = {.name  = "imx6ul-led2",},.probe  = led_probe,.remove = led_remove
};

2. kobject sysfs

2.1 kobjects

?? 設備模型的核心部分是kobjects,類似于java中object對象類,提供了諸如計數、名稱、父指針等字段,可以創建對象的層次結構。其定義如下:

struct kobject {char			* k_name;				// 指向kobject名稱,如果名稱長度小于KOBJ_NAME_LEN,則存入name數組中,如果超過,則動態分配一個緩沖區存放,KOBJ_NAME_LEN是20個字節char			name[KOBJ_NAME_LEN];struct kref		kref;					// 實現kobject的引用計數struct list_head	entry;struct kobject		* parent;			// 父對象,在內核中構造一個對象層次結構,并可以將多個對象間的關系表現出來struct kset		* kset;struct kobj_type	* ktype;struct dentry		* dentry;			// 指向dentry結構體,在sysfs中該結構體就表示這個kobject
};

?? kobject通常是嵌入到其他結構體中的,其單獨意義其實并不大。當kobject被嵌入到其他結構體中時,該結構體便擁有了kobject提供的標準功能。

2.2 ktype

?? ktype是為了描述一族kobject所具有的普遍特性。因此,不在需要每個kobject都分別定義自己的特性,而是將這些特性在ktype結構體中一次定義,然后所有“同類”的kobject都能共享一樣的特性。

struct kobj_type {void (*release)(struct kobject *);struct sysfs_ops	* sysfs_ops;struct attribute	** default_attrs;
};

?? release指針指向在kobject引用計數減為零時要被調用的析構函數。該函數負責釋放所有的kobject使用的內存和其他相關清理工作。

?? sysfs_ops變量指向sysfs_ops結構體。該結構體表述了sysfs文件讀寫是的特性。

?? default_attrs指向一個attribute結構體數組。這些結構體定義了該kobject相關的默認屬性。屬性描述了給定對象的特征,如果該kobject被導出到sysfs中,那么這些屬性都將相應地作為文件而導出。數組中的最后一項必須為NULL。

2.3 kset

?? kset是kobject對象的集合體。把它看成是一個容器,可將所有相關的kobject對象,比如“全部的塊設備”置于一個位置。kset把kobject集中到一個集合中。

struct kset {struct subsystem	* subsys;struct kobj_type	* ktype;struct list_head	list;struct kobject		kobj;struct kset_hotplug_ops	* hotplug_ops;
};

?? 其中ktype指向kset集合中kobject對象的類型。
?? list連接該集合中所有的kobject對象。
?? kobj指向的kobject對象代表了該集合的基類。
?? hotplug_ops指向一個用于處理集合中kobject對象的熱插拔操作的結構體。
?? subsys指針指向該結構體相關的struct subsystem結構體。

參考資料

[1] linux設備模型

[2] Linux設備模型

[3] Linux設備驅動模型

[4] device_create()、device_register()、deivce_add()區別

[5] Linux內核設計與實現—kobject sysfs

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

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

相關文章

編寫dockerfile掛載卷

編寫dockerfile文件 [rootwq docker-test-volume]# vim dockerfile1 [rootwq docker-test-volume]# cat dockerfile1 FROM centosVOLUME ["volume01","volume02"]CMD echo "------end------" CMD /bin/bash [rootwq docker-test-volume]#使用do…

leetcode:51.N皇后(復習)

題目理解&#xff1a;&#xff08;回溯算法&#xff09; 樹形結構——層數代表行數&#xff0c;遞歸的深度就是總行數。 代碼實現&#xff1a;

解釋Android中的Activity生命周期,以及在哪個生命周期方法中可以進行布局的初始化?

在Android中&#xff0c;Activity的生命周期是指Activity從創建到銷毀的整個過程&#xff0c;這個過程中會經歷一系列的回調方法。了解Activity的生命周期對于管理資源、處理用戶交互和確保應用的穩定性非常重要。下面是Activity生命周期的主要階段及其對應的回調方法&#xff…

手寫 Attention 迷你LLaMa2——LLM實戰

https://github.com/Yuezhengrong/Implement-Attention-TinyLLaMa-from-scratch 1. Attention 1.1 Attention 靈魂10問 你怎么理解Attention&#xff1f; Scaled Dot-Product Attention中的Scaled&#xff1a; 1 d k \frac{1}{\sqrt{d_k}} dk? ?1? 的目的是調節內積&…

分布式ID選型對比(4)

百度UID generator 一, 創建表: worker_node(在項目啟動時初始化生成workId) CREATE TABLE worker_node (ID bigint NOT NULL AUTO_INCREMENT COMMENT auto increment id,HOST_NAME varchar(64) NOT NULL COMMENT host name,PORT varchar(64) NOT NULL COMMENT port,TYPE int…

金屬3D打印新材料嶄露頭角,性能卓越引領行業新潮流

在3D打印模具制造領域&#xff0c;材料的選擇對最終產品的性能有著至關重要的影響。隨著技術的不斷進步&#xff0c;金屬3D打印材料正迅速發展&#xff0c;展現出強大的競爭力和創新潛力。其中&#xff0c;3D打印企業毅速推出的多款不銹鋼粉末材料&#xff0c;如EM191、EM191S、…

字符串函數 strncpy() 詳解

什么是 strncpy() 函數&#xff1f; strncpy() 函數是 C 語言中的一個標準庫函數&#xff0c;它的作用是從一個字符串中按照指定的長度復制字符到另一個字符串中。它的原型如下&#xff1a; char *strncpy(char *dest, const char *src, size_t n);其中&#xff0c;dest 是目…

VMware Workstation Pro 17 虛擬機軟件安裝教程

VMware軟件介紹 VMware Workstation是一款功能強大的桌面虛擬計算機軟件&#xff0c;提供用戶可在宿主機操作系統上同時運行不同的操作系統(虛擬化技術)&#xff0c;所運行的操作系統可方便的進行復制和移動&#xff0c;突破傳統架構的限制。本文將以VMware Workstation Pro 1…

使用lnmp環境部署laravel框架需要注意的點

1&#xff0c;上傳項目文件后&#xff0c;需要chmod -R 777 storage授予文件權限&#xff0c;不然會報錯file_put_contents(/): failed to open stream: Permission denied。 如果后面還是報錯沒有權限的話&#xff0c;就執行ps -ef |grep php查詢php運行用戶。然后執行chown …

2024真正有效的蘋果mac電腦清理工具CleanMyMac X

一、前言 對于Mac用戶來說&#xff0c;電腦卡頓、運行緩慢無疑是一件令人頭疼的事情。而市面上的清理軟件又五花八門&#xff0c;效果參差不齊&#xff0c;如何才能找到一款真正有效的清理工具呢&#xff1f;今天&#xff0c;我們為大家推薦一款實力派電腦清理軟件——CleanMy…

【雙指針】刪除有序數組中重復元素,雙指針原地修改數組

刪除有序數組中重復元素 鏈接 . - 力扣&#xff08;LeetCode&#xff09;. - 備戰技術面試&#xff1f;力扣提供海量技術面試資源&#xff0c;幫助你高效提升編程技能,輕松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/remove-duplicates-from-sorted-array/…

宏定義中#與##的注意事項

1. #是字符串化操作符。它的作用是將宏參數轉換成字符串 2. ##是標記粘貼操作符。它的作用是將兩個標記連接起來形成一個新的標記 #define TEST1(a) #a #define TEST2(a) b##a/***********************************************************/ 舉例&#xff1a;TEST1(hello) 會…

python virtualenv創建虛擬環境

文章目錄 安裝virtualenv在當前目錄創建虛擬環境命令進入虛擬環境激活虛擬環境查看python版本退出虛擬環境 安裝virtualenv pip install virtualenv在當前目錄創建虛擬環境命令 python -m virtualenv venvPS E:\coding\bertopic> python -m virtualenv venv created virtu…

Linux:Nginx服務重寫功能

目錄 一、重寫功能 1.重寫功能作用 2.rewrite指令 if指令 return指令 set指令 break指令 3.rewrite標志 redirect標志 permanent標志 break標志 last標志 rewrite標志實驗 一、重寫功能 1.重寫功能作用 重寫功能(rewrite)用于實現URL的重寫&#xff0c;URL的重寫是非常有用…

LC打怪錄 283. moving zero

題目鏈接 力扣 class Solution:def moveZeroes(self, nums: List[int]) -> None:l0for r in range(len(nums)):if nums[r]:nums[l], nums[r] nums[r], nums[l]l 1return nums 方法一&#xff1a; 思路 雙指針 1. def moveZeroes(self, nums: List[int]) -> None: …

Stable Diffusion 3正式發布,旨在鞏固其在AI圖像領域相對于Sora和Gemini的領先地位

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…

vue3 + vite 項目可以使用純Js開發嗎?

答案&#xff1a;可以 創建項目&#xff1a; 按照鏈接參考或者按官方&#xff1a; webstorm 創建vue3 vite 項目-CSDN博客 項目目錄 tsconfig.json 配置允許js allowJs指定是否編譯js文件&#xff0c;在任意文件當中,如果我們模塊使用js寫的&#xff0c;那么我們需要 將all…

地理空間分析15——Python在應急響應與地理空間分析中的創新應用

目錄 寫在開頭1.Python及其在地理空間分析中的應用地理空間數據處理庫地理空間數據可視化工具 2.應急響應中的Python應用實例2.1 災害風險評估2.2 實時數據分析與響應2.3資源優化分配 3 地震應急響應案例&#xff1a;利用Python進行數據分析3.1 背景介紹3.2 數據收集與處理3.3 …

鏈式插補 (MICE):彌合不完整數據分析的差距

導 讀 數據缺失可能會扭曲結果&#xff0c;降低統計功效&#xff0c;并且在某些情況下&#xff0c;導致估計有偏差&#xff0c;從而破壞從數據中得出的結論的可靠性。 處理缺失數據的傳統方法&#xff08;例如剔除或均值插補&#xff09;通常會引入自己的偏差或無法充分利用數…

機器學習:模型選擇和模型優化

進行數據處理之后&#xff0c;我們得到了x_train和y_train&#xff0c;我們就可以用來進行回歸或分類模型訓練啦~ 一、模型選擇 我們這里可能使用的是回歸模型&#xff08;Regression&#xff09;&#xff0c;值得注意的是&#xff0c;回歸和分類不分家。分類是預測離散值&…