設備樹下的 platform 驅動編寫

設備樹下的 platform 驅動編寫

設備樹下的 platform 驅動簡介

platform 驅動框架分為總線、設備和驅動,其中總線不需要我們這些驅動程序員去管理,這個是 Linux 內核提供的,我們在編寫驅動的時候只要關注于設備和驅動的具體實現即可。在沒有設備樹的 Linux 內核下,我們需要分別編寫并注冊 platform_device 和 platform_driver,分別代表設備和驅動。在使用設備樹的時候,設備的描述被放到了設備樹中,因此 platform_device 就不需要我們去編寫了。

1、在設備樹中創建設備節點

肯定要先在設備樹中創建設備節點來描述設備信息,重點是要設置好 compatible屬性的值,因為 platform 總線需要通過設備節點的 compatible 屬性值來匹配驅動!這點要切記。

示例代碼 55.1.1 gpioled 設備節點
1 gpioled {
2 #address-cells = <1>;
3 #size-cells = <1>;
4 compatible = "atkalpha-gpioled";
5 pinctrl-names = "default";
6 pinctrl-0 = <&pinctrl_led>;
7 led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
8 status = "okay";
9 };

注意第 4 行的 compatible 屬性值為“atkalpha-gpioled”,因此一會在編寫 platform驅動的時候of_match_
table 屬性表中要有“atkalpha-gpioled”。

2、編寫 platform 驅動的時候要注意兼容屬性
示例代碼 55.1.2 of_match_table 匹配表的設置
1 static const struct of_device_id leds_of_match[] = {
2 { .compatible = "atkalpha-gpioled" }, /* 兼容屬性 */
3 { /* Sentinel */ }
4 };
5 6
MODULE_DEVICE_TABLE(of, leds_of_match);
7 8
static struct platform_driver leds_platform_driver = {
9 .driver = {
10 .name = "imx6ul-led",
11 .of_match_table = leds_of_match,
12 },
13 .probe = leds_probe,
14 .remove = leds_remove,
15 };

第 1~4 行, of_device_id 表,也就是驅動的兼容表,是一個數組,每個數組元素為 of_device_id類型。每個數組元素都是一個兼容屬性,表示兼容的設備,一個驅動可以跟多個設備匹配。這里我們僅僅匹配了一個設備,那就是 55.1.1 中創建的 gpioled 這個設備。第 2 行的 compatible 值為“atkalpha-gpioled”,驅動中的 compatible 屬性和設備中的 compatible 屬性相匹配,因此驅動中對應的 probe 函數就會執行。注意第 3 行是一個空元素,在編寫 of_device_id 的時候最后一個元素一定要為空!
原因如下:使用一個結構數組來定義一系列的數據時,通常需要一個方法來標識數組的結束。在of_device_id數組中,這種標識是必要的,因為內核需要知道何時停止搜索這個數組。這就是為什么在of_device_id數組的最后一個元素通常是一個空元素的原因。
標記數組結束:Linux內核在處理設備匹配表時,會遍歷of_device_id數組直到遇到一個完全為空的結構體。這個空結構體(所有字段為零)作為哨兵值,告訴內核已經到達數組的末尾。如果沒有這個哨兵條目,內核在處理數組時可能會超出其邊界,導致未定義行為或內存訪問錯誤。
確保安全:在內核編程中,安全非常重要,因為任何小錯誤都可能導致系統崩潰或安全漏洞。使用哨兵條目是一種安全措施,防止內核代碼在數組遍歷時越界。
第 6 行, 通過 MODULE_DEVICE_TABLE 聲明一下 leds_of_match 這個設備匹配表。
第 11 行,設置 platform_driver 中的 of_match_table 匹配表為上面創建的 leds_of_match,至此我們就設置好了 platform 驅動的匹配表了。

3、編寫 platform 驅動

基于設備樹的 platform 驅動和上一章無設備樹的 platform 驅動基本一樣,都是當驅動和設備匹配成功以后就會執行 probe 函數。我們需要在 probe 函數里面執行字符設備驅動那一套,當注銷驅動模塊的時候 remove 函數就會執行,都是大同小異的。
驅動程序如下:

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/***************************************************************
Copyright ? ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名		: leddriver.c
作者	  	: 左忠凱
版本	   	: V1.0
描述	   	: 設備樹下的platform驅動
其他	   	: 無
論壇 	   	: www.openedv.com
日志	   	: 初版V1.0 2019/8/13 左忠凱創建
***************************************************************/#define LEDDEV_CNT		1				/* 設備號長度 	*/
#define LEDDEV_NAME		"dtsplatled"	/* 設備名字 	*/
#define LEDOFF 			0
#define LEDON 			1/* leddev設備結構體 */
struct leddev_dev{dev_t devid;				/* 設備號	*/struct cdev cdev;			/* cdev		*/struct class *class;		/* 類 		*/struct device *device;		/* 設備		*/int major;					/* 主設備號	*/	struct device_node *node;	/* LED設備節點 */int led0;					/* LED燈GPIO標號 */
};struct leddev_dev leddev; 		/* led設備 *//** @description		: LED打開/關閉* @param - sta 	: LEDON(0) 打開LED,LEDOFF(1) 關閉LED* @return 			: 無*/
void led0_switch(u8 sta)
{if (sta == LEDON )gpio_set_value(leddev.led0, 0);else if (sta == LEDOFF)gpio_set_value(leddev.led0, 1);	
}/** @description		: 打開設備* @param - inode 	: 傳遞給驅動的inode* @param - filp 	: 設備文件,file結構體有個叫做private_data的成員變量* 					  一般在open的時候將private_data指向設備結構體。* @return 			: 0 成功;其他 失敗*/
static int led_open(struct inode *inode, struct file *filp)
{filp->private_data = &leddev; /* 設置私有數據  */return 0;
}/** @description		: 向設備寫數據 * @param - filp 	: 設備文件,表示打開的文件描述符* @param - buf 	: 要寫給設備寫入的數據* @param - cnt 	: 要寫入的數據長度* @param - offt 	: 相對于文件首地址的偏移* @return 			: 寫入的字節數,如果為負值,表示寫入失敗*/
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int retvalue;unsigned char databuf[2];unsigned char ledstat;retvalue = copy_from_user(databuf, buf, cnt);if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0];if (ledstat == LEDON) {led0_switch(LEDON);} else if (ledstat == LEDOFF) {led0_switch(LEDOFF);}return 0;
}/* 設備操作函數 */
static struct file_operations led_fops = {.owner = THIS_MODULE,.open = led_open,.write = led_write,
};/** @description		: flatform驅動的probe函數,當驅動與* 					  設備匹配以后此函數就會執行* @param - dev 	: platform設備* @return 			: 0,成功;其他負值,失敗*/
static int led_probe(struct platform_device *dev)
{	printk("led driver and device was matched!\r\n");/* 1、設置設備號 */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);}/* 2、注冊設備      */cdev_init(&leddev.cdev, &led_fops);cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);/* 3、創建類      */leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);if (IS_ERR(leddev.class)) {return PTR_ERR(leddev.class);}/* 4、創建設備 */leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);if (IS_ERR(leddev.device)) {return PTR_ERR(leddev.device);}/* 5、初始化IO */	leddev.node = of_find_node_by_path("/gpioled");if (leddev.node == NULL){printk("gpioled node nost find!\r\n");return -EINVAL;} leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);if (leddev.led0 < 0) {printk("can't get led-gpio\r\n");return -EINVAL;}gpio_request(leddev.led0, "led0");gpio_direction_output(leddev.led0, 1); /* led0 IO設置為輸出,默認高電平	*/return 0;
}/** @description		: platform驅動的remove函數,移除platform驅動的時候此函數會執行* @param - dev 	: platform設備* @return 			: 0,成功;其他負值,失敗*/
static int led_remove(struct platform_device *dev)
{gpio_set_value(leddev.led0, 1); 	/* 卸載驅動的時候關閉LED */gpio_free(leddev.led0);				/* 釋放IO 			*/cdev_del(&leddev.cdev);				/*  刪除cdev */unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注銷設備號 */device_destroy(leddev.class, leddev.devid);class_destroy(leddev.class);return 0;
}/* 匹配列表 */
static const struct of_device_id led_of_match[] = {{ .compatible = "atkalpha-gpioled" },{ /* Sentinel */ }
};/* platform驅動結構體 */
static struct platform_driver led_driver = {.driver		= {.name	= "imx6ul-led",			/* 驅動名字,用于和設備匹配 */.of_match_table	= led_of_match, /* 設備樹匹配表 		 */},.probe		= led_probe,.remove		= led_remove,
};/** @description	: 驅動模塊加載函數* @param 		: 無* @return 		: 無*/
static int __init leddriver_init(void)
{return platform_driver_register(&led_driver);
}/** @description	: 驅動模塊卸載函數* @param 		: 無* @return 		: 無*/
static void __exit leddriver_exit(void)
{platform_driver_unregister(&led_driver);
}module_init(leddriver_init);
module_exit(leddriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyw");

剩下操作過程都是一樣的。

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

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

相關文章

《昇思25天學習打卡營第6天 | 函數式自動微分》

《昇思25天學習打卡營第6天 | 函數式自動微分》 目錄 《昇思25天學習打卡營第6天 | 函數式自動微分》函數式自動微分簡單的單層線性變換模型函數與計算圖微分函數與梯度計算Stop Gradient 函數式自動微分 神經網絡的訓練主要使用反向傳播算法&#xff0c;模型預測值&#xff0…

建站小記:遷移域名DNS到CloudFlare

CloudFlare一直有賽博菩薩之稱&#xff0c;據說用它做DNS解析服務又快又好又免費&#xff0c;還能防DDOS攻擊&#xff0c;并且可以提供頁面訪問統計功能。 正好我博客網頁打開略卡頓&#xff0c;所以決定將自己的DNS解析遷移到CloudFlare。 1.登錄CF控制臺&#xff0c;添加自己…

LeetCode-刷題記錄-二分法合集(本篇blog會持續更新哦~)

一、二分查找概述 二分查找&#xff08;Binary Search&#xff09;是一種高效的查找算法&#xff0c;適用于有序數組或列表。&#xff08;但其實只要滿足二段性&#xff0c;就可以使用二分法&#xff0c;本篇博客后面博主會持續更新一些題&#xff0c;來破除一下人們對“只有有…

(已解決)Adobe Flash Player已不再受支持

文章目錄 前言解決方案 前言 一般來說&#xff0c;很少遇到官方網站使用Adobe Flash Player來進行錄用名單公示了。但是&#xff0c;今天就偏偏遇到一次&#xff0c; 用谷歌瀏覽器打不開&#xff0c; 點了沒有反應&#xff0c;用其他的瀏覽器&#xff0c;例如windows自帶的那…

Golang | Leetcode Golang題解之第207題課程表

題目&#xff1a; 題解&#xff1a; func canFinish(numCourses int, prerequisites [][]int) bool {var (edges make([][]int, numCourses)indeg make([]int, numCourses)result []int)for _, info : range prerequisites {edges[info[1]] append(edges[info[1]], info[0]…

數據結構:期末考 第六次測試(總復習)

一、 單選題 &#xff08;共50題&#xff0c;100分&#xff09; 1、表長為n的順序存儲的線性表&#xff0c;當在任何位置上插入或刪除一個元素的概率相等時&#xff0c;插入一個元素所需移動元素的平均個數為&#xff08; D &#xff09;.&#xff08;2.0&#xff09; A、 &am…

在node環境使用MySQL

什么是Sequelize? Sequelize是一個基于Promise的NodeJS ORM模塊 什么是ORM? ORM(Object-Relational-Mapping)是對象關系映射 對象關系映射可以把JS中的類和對象&#xff0c;和數據庫中的表和數據進行關系映射。映射之后我們就可以直接通過類和對象來操作數據表和數據了, 就…

join()方法——連接字符串、元組、列表和字典

自學python如何成為大佬(目錄):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 語法參考 join()方法用于連接字符串數組。將字符串、元組、列表中的元素以指定的字符&#xff08;分隔符&#xff09;連接生成一個新的字符串&#…

喜報 | 極限科技獲得北京市“創新型”中小企業資格認證

2024年6月20日&#xff0c;北京市經濟和信息化局正式發布《關于對2024年度4月份北京市創新型中小企業名單進行公告的通知》&#xff0c;極限數據&#xff08;北京&#xff09;科技有限公司憑借其出色的創新能力和卓越的企業實力&#xff0c;成功獲得“北京市創新型中小企業”的…

學會python——在excel中寫入數據(python實例十三)

目錄 1.認識Python 2.環境與工具 2.1 python環境 2.2 Visual Studio Code編譯 3 .想Excel中寫入數據 3.1 代碼構思 3.2 代碼實例 3.3 運行結果 4.總結 1.認識Python Python 是一個高層次的結合了解釋性、編譯性、互動性和面向對象的腳本語言。 Python 的設計具有很強的…

數據結構算法之B樹

一、緒論 1.1 數據結構的概念和作用 1.2 B樹的起源和應用領域 二、B樹的基本原理 2.1 B樹的定義和特點 2.2 B樹的結構和節點組成 2.3 B樹的插入 2.4 B樹的刪除操作 三、B樹的優勢和應用 3.1 B樹在數據庫系統中的應用 3.2 B樹在文件系統中的應用 3.3 B樹在內存管理中…

HTML5的多線程技術:Shared Worker的使用示例

Shared Worker 與普通的 Web Worker 類似&#xff0c;但不同之處在于它可以被多個瀏覽器窗口、標簽頁或者iframe共享&#xff0c;使得這些上下文之間能夠相互通信。下面是一個使用 Shared Worker 的完整示例。共享Worker腳本&#xff08;sharedWorker.js&#xff09; self.add…

isupper()方法——判斷字符串是否全由大寫字母組成

自學python如何成為大佬(目錄):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 語法參考 isupper()方法用于判斷字符串中所有的字母是否都是大寫。isupper()方法的語法格式如下&#xff1a; str.isupper() 如果字符串中包含至少…

我是如何在bytemd中實現自定義目錄的

介紹 接著上文說完&#xff0c;實現了在markdown編輯器中插入視頻的能力&#xff0c;接下來還需要繼續優化 markdown文檔的閱讀體驗&#xff0c;比如 再加個目錄 熟悉markdown語法的朋友可能會說&#xff0c;直接在編輯時添加 toc 標簽&#xff0c;可以在文章頂部自動生成目錄…

實驗三 時序邏輯電路實驗

仿真 鏈接&#xff1a;https://pan.baidu.com/s/1z9KFQANyNF5PvUPPYFQ9Ow 提取碼&#xff1a;e3md 一、實驗目的 1、通過實驗&#xff0c;理解觸發的概念&#xff0c;理解JK、D等常見觸發器的功能&#xff1b; 2、通過實驗&#xff0c;加深集成計數器功能的理解&#xff0c;掌…

?Ollama的本地安裝?

先來逛一下咱們的主角Ollama的官網地址&#xff1a; Ollama 大概長這個樣子&#x1f914; 因為本地系統的原因&#xff0c;文章只提供Widows的安裝方式&#xff0c;使用Linux和Mac的大佬&#xff0c;可以自行摸索&#x1f9d0; 下載完成后就是安裝了&#x1f355;&#xff0c…

一、Redis簡介

一、Redis介紹與一般應用 1.1 基本了解 Redis全稱Remote Dictionary Server(遠程字典服務)&#xff0c; 是一個開源的高性能鍵值存儲系統&#xff0c;通常用作數據庫、緩存和消息代理。使用ANSI C語言編寫遵守BSD協議&#xff0c;是一個高性能的Key-Value數據庫提供了豐富的數…

JVM性能監控與調優:生產環境的實踐指南

JVM性能監控與調優&#xff1a;生產環境的實踐指南 一、引言 在生產環境中&#xff0c;Java應用程序的性能監控和調優是確保系統穩定運行、提升用戶體驗的關鍵環節。JVM&#xff08;Java Virtual Machine&#xff09;作為Java應用程序的運行環境&#xff0c;其性能直接影響到…

Flink 本地任務添加配置參數

Flink 本地任務添加配置參數 配置一個Configuration&#xff0c;然后通過StreamExecutionEnvironment.getExecutionEnvironment(configuration)傳入。 例如&#xff1a; Configuration configuration new Configuration();configuration.set(RestartStrategyOptions.RESTART_…

蘋果筆記本能玩網頁游戲嗎 蘋果電腦玩steam游戲怎么樣 蘋果手機可以玩游戲嗎 mac電腦安裝windows

蘋果筆記本有著優雅的機身、強大的性能&#xff0c;每次更新迭代都備受用戶青睞。但是&#xff0c;當需要使用蘋果筆記本進行游戲時&#xff0c;很多人會有疑問&#xff1a;蘋果筆記本能玩網頁游戲嗎&#xff1f;蘋果筆記本適合打游戲嗎&#xff1f;本文將討論這兩個話題&#…