Linux驅動開發筆記(五)——設備樹(下)——OF函數

一、OF函數定義

第6.8講 Linux設備樹詳解-綁定文檔以及OF函數_嗶哩嗶哩_bilibili

《指南》43.9部分

? ? ? ? 設備樹的功能就是描述設備信息,幫助驅動開發。那么驅動如何獲取設備信息?獲取這些信息的函數linux直接提供,都定義在linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/include/linux/of.h文件中。這些函數統一以of開頭,也稱為OF函數。

1.1?查找節點

? ? ? ? 設備樹上的設備都是一個個節點。要獲取某個設備信息,需要先找到這個設備節點。Linux內核使用device_node結構體來描述一個節點:

// 定義在linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/include/linux/of.h
struct device_node {const char *name;    // 節點名const char *type;    // 設備類型phandle phandle;const char *full_name;    // 節點全名struct fwnode_handle fwnode;struct	property *properties;    // 屬性struct	property *deadprops;     // removed屬性struct	device_node *parent;     // 父節點struct	device_node *child;      // 子節點struct	device_node *sibling;struct	kobject kobj;unsigned long _flags;void	*data;
#if defined(CONFIG_SPARC)const char *path_component_name;unsigned int unique_id;struct of_irq_controller *irq_trans;
#endif
};

1.1.1 of_find_node_by_name

????????通過名字查找節點。名字是完整的node-name@unit-address,不是只有前半部分node-name,也不是label。

struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
// from:   從哪個節點開始查找。為NULL表示從根節點開始查找整個設備樹
// name:   要查找節點的名字。名字不要包含label!   
// return: 找到的節點。返回NULL表示未找到

1.1.2 of_find_node_by_type

????????通過device_type類型查找。不過現在device_type已經棄用,這個函數也很少再用。

struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
// from:   從哪個節點開始查找。為NULL表示從根節點開始查找整個設備樹
// type:   要查找節點的device_type字符串
// return: 找到的節點。返回NULL表示未找到

1.1.3?of_find_compatible_node

????????通過兼容性列表compatible查找

struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compat);
// from:   從哪個節點開始查找。為NULL表示從根節點開始查找整個設備樹
// type:   要查找節點的device_type字符串。可以為NULL,表示忽略device_type屬性
// compat: 要查找節點的compatible屬性列表
// return: 找到的節點。返回NULL表示未找到
// eg: struct device_node *node;node = of_find_compatible_node(NULL, NULL, "arm,cortex-a7"); // 查找整個設備樹上兼容arm,cortex-a7的設備節點

1.1.4?of_find_matching_node_and_match

????????通過匹配列表查找

struct device_node *of_find_matching_node_and_match(struct device_node *from,const struct of_device_id *matches,const struct of_device_id **match);
// from:    從哪個節點開始查找。為NULL表示從根節點開始查找整個設備樹
// matches: of_device_id匹配列表,也就是在此匹配表里面查找節點。
// match:   找到的匹配的of_device_id
// return:  找到的節點。返回NULL表示未找到

1.1.5?of_find_node_by_path

????????通過路徑查找。這個路徑指的是設備節點在設備樹中的路徑,不是文件路徑。

static inline struct device_node *of_find_node_by_path(const char *path)
// path:   帶有全路徑的節點名,可以使用節點的別名,比如“/backlight”就是根節點下backlight節點的全路徑。 
// return: 找到的節點。返回NULL表示未找到
//eg:
struct device_node *np;
np = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000");

1.2 查找父/子節點

1.2.1?of_get_parent

獲取指定節點的父節點

struct device_node *of_get_parent(const struct device_node *node)
// node  : 要查找父節點的節點
// return: 找到的父節點。NULL表示未找到

1.2.2?of_get_next_child

獲取指定節點的子節點

struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)
// node  : 要查找子節點的節點
// prev  : 前一個子節點。一個節點下有很多子節點,可以設置從哪一個子節點開始查找
//         可以設置為NULL,表示從第一個子節點開始
// return: 找到的子節點

1.3?提取屬性值

? ? ? ? 通過前面兩類函數找到了目標節點,現在可以開始獲得指定節點的具體屬性了。

1.3.1 of_find_property

????????查找指定的屬性。

static inline struct property *of_find_property(const struct device_node *np,const char *name, int *lenp)
// np    : 節點
// name  : 屬性名
// lenp  : 屬性值的字節長度,一般寫NULL即可
// return: 找到的屬性

Linux內核中使用結構體property表示屬性,其中property結構為:

struct property {char	*name;    // 屬性名int	length;       // 長度void	*value;   // 值struct property *next;    // 下一個屬性unsigned long _flags;unsigned int unique_id;struct bin_attribute attr;
};

?1.3.2 of_property_count_elems_of_size

????????獲取屬性中元素的數量。比如reg屬性值(如reg = <0x80000000 0x20000000>;)是一個數組,那么使用此函數可以獲取到這個數組的大小(2)。

int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size)
// np       : 節點
// proname  : 需要統計元素數量的屬性名字
// elem_size:每一個元素的size
// return   : 得到的屬性元素數量

1.3.3 of_property_read_u32_index

????????用于從屬性中獲取指定索引的u32類型數據值。

????????比如某個屬性有多個u32類型的值,那么就可以使用此函數來獲取指定索引的數據值。

static inline int of_property_read_u32_index(const struct device_node *np,const char *propname, u32 index, u32 *out_value)
// np       : 節點
// proname  : 要讀取的屬性名
// index    : 要讀取的值的索引
// out_value: 讀取到的值
// return   : 0成功。負值失敗:-EINVAL屬性不存在,-ENODATA表示要讀取的數據,-EOVERFLOW屬性值列表太小

1.3.4?of_property_read_u8_array

? ? ? ? 用于讀取一個u8類型數組屬性的所有數據。

????????類似的函數還有of_property_read_u16_array、of_property_read_u32_array、of_property_read_u64_array,表示不同的數組類型。

int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)
// np        : 節點
// propname  : 要讀取的屬性名
// out_values: 讀取到的數組
// sz        : 要讀取的數組元素數量
// return    : 0成功。負值失敗:-EINVAL屬性不存在,-ENODATA沒有要讀取的數據,-EOVERFLOW屬性值列表太小。

1.3.5?of_property_read_u8

? ? ? ? 除了數組屬性以外,很多屬性只有一個整形值。該函數用于讀取這種只有一個u8整形值的屬性。

????????類似的函數還有of_property_read_u16、of_property_read_u32、of_property_read_u64。

int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)
// np        : 節點
// propname  : 要讀取的屬性名
// out_values: 讀取到的值
// return    : 0成功。負值失敗:-EINVAL屬性不存在,-ENODATA沒有要讀取的數據,-EOVERFLOW屬性值列表太小。

1.3.6 of_property_read_string

? ? ? ? 用于讀取字符串類型屬性的值

int of_property_read_string(struct device_node *np,const char *propname, const char **out_string)
// np        : 節點
// propname  : 要讀取的屬性名
// out_string: 讀取到的字符串
// return    : 0成功。負值失敗

1.3.7?of_n_addr_cells

? ? ? ? 獲取#size-cells的值

int of_n_addr_cells(struct device_node *np);
// np    : 節點
// return: 獲取到的#size-cells的值

1.3.8?of_n_size_cells

? ? ? ? 獲取#size-cells的值

int of_n_size_cells(struct device_node *np)、
// np    : 節點
// return: 獲取到的#size-cells的值

二、OF函數實際使用

第6.9講 Linux設備樹詳解-OF函數操作實驗_嗶哩嗶哩_bilibili

2.1 文件結構

? ? ? ? 新建實驗4文件夾4_dtsof,直接將之前實驗3文件夾3_newchrled里的Makefile、newchrled.c、.vscode復制到新的文件夾里。將newchrled.c改名為dtsof.c。

? ? ? ? 用vscode打開4_dtsof,將工作區另存為。

4_DTSOF (工作區)
├── .vscode
│   ├── c_cpp_properties.json
│   └── settings.json
├── 4_dtsof.code-workspace
├── Makefile
└── dtsof.c

? ? ? ? 將Makefile中的obj-m修改為obj-m := dtsof.o

2.2?dtsof.c

2.2.1獲取backlight的compatible屬性值

imx6ull-alientek-emmc.dts中backlight的定義如下:

	backlight {compatible = "pwm-backlight";pwms = <&pwm1 0 5000000>;brightness-levels = <0 4 8 16 32 64 128 255>;default-brightness-level = <6>;status = "okay";};

?編寫dtsof.c,獲取backlight的compatible屬性值:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>/* 模塊入口 */
static int __init dtsof_init(void){int ret = 0;struct device_node *backlight_nd; // 節點指針struct property *comppro;         // 屬性指針// 查找backlight節點 // 路徑為/backlight   定義在linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/boot/dts/imx6ull-alientek-emmc.dtsbacklight_nd = of_find_node_by_path("/backlight"); //路徑查找if(backlight_nd == NULL){ // 失敗ret = -EINVAL;goto fail_findnd; // 錯誤處理}// 查找backlight屬性comppro = of_find_property(backlight_nd, "compatible", NULL); // 屬性名查找if(comppro == NULL){ret = -EINVAL;goto fail_finpro; // 錯誤處理} else {printk("compatible = %s\r\n",(char*)comppro->value);}return 0;fail_finpro:   // 查找屬性失敗
fail_findnd:  // 查找節點失敗printk("failed\r\n");return ret;
}/* 模塊出口 */
static void __exit dtsof_exit(void){}/* 注冊入口出口*/
module_init(dtsof_init);
module_exit(dtsof_exit);
MODULE_LICENSE("GPL");

# VSCODE終端
make
sudo cp dtsof.ko /home/for/linux/nfs/rootfs/lib/modules/4.1.15/ -f# 串口
cd lib/modules/4.1.15/
modprobe dtsof.ko
depmod
modprobe dtsof.ko  # 可以看到輸出:compatible = pwm-backlight
rmmod dtsof.ko

2.2.2獲取backlight的所有屬性值

????????上面的代碼只簡單演示了一下使用OF函數獲取compatible屬性值。要獲取backlight的所有屬性值,完整代碼如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/slab.h>/* 模塊入口 */
static int __init dtsof_init(void){int ret = 0;struct device_node *backlight_nd;// 節點指針struct property *comppro;        // 保存compatible屬性const char* status;              // 保存status屬性u32 default_brightness_level;    // 保存default-brightness-level屬性u32 count = 0;                   // 保存brightness-levels屬性的元素數量u32 *brightness_levels;          // 保存brightness-levels屬性的數據u8 i = 0;                        // 給for循環用的// 1.查找backlight節點======================================================================// 路徑為/backlight   // 定義在linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/arch/arm/boot/dts/imx6ull-alientek-emmc.dtsbacklight_nd = of_find_node_by_path("/backlight"); //路徑查找if(backlight_nd == NULL){ // 失敗ret = -EINVAL;goto faile_findnd;}// 2.查找backlight屬性======================================================================// 獲取compatible屬性(屬性名查找)comppro = of_find_property(backlight_nd, "compatible", NULL);if(comppro == NULL){ret = -EINVAL;goto fail_finpro;} else {printk("compatible = %s\r\n",(char*)comppro->value);}// 獲取status屬性(讀取字符串)ret = of_property_read_string(backlight_nd, "status", &status);if(ret < 0){goto fail_finprs;} else {printk("status = %s\r\n", status);}// 獲取default-brightness-level屬性(讀取u32)ret = of_property_read_u32(backlight_nd, "default-brightness-level", &default_brightness_level);if(ret < 0){goto fail_read32;} else {printk("default-brightness-level = %d\r\n", default_brightness_level);}// 獲取brightness-levels的元素個數(讀取元素個數)count = of_property_count_elems_of_size(backlight_nd, "brightness-levels", sizeof(u32));if(count < 0){goto fail_readele;} else {printk("brightness-level elems size = %d\r\n", count);// 獲取brightness-levels的數據(讀取u32數組)brightness_levels = kmalloc(count * sizeof(u32), GFP_KERNEL); // 內存申請if(!brightness_levels){ goto fail_mem;}ret = of_property_read_u32_array(backlight_nd, "brightness-levels", brightness_levels, count);if(ret < 0){goto fail_readarr; // 錯誤處理統一放到goto里面去,因此這里不釋放內存,而是放到goto去處理} else {printk("brightness-level elems = ");for(i=0;i<count;i++){printk("%d ",brightness_levels[i]);}printk("\r\n");kfree(brightness_levels);}}return 0;/* 錯誤處理 */
// 這里goto只是演示一下格式,并不詳細處理fail_readarr:  // 讀取brightness-levels數據失敗kfree(brightness_levels); //釋放內存
fail_mem:          // 內存分配失敗
fail_readele:      // 讀取元素數量失敗
fail_read32:       // 讀取default-brightness-level失敗
fail_finprs:       // 讀取status失敗
fail_finpro:       // 查找compatible失敗
faile_findnd:      // 查找節點失敗printk("failed\r\n");return ret;
}/* 模塊出口 */
static void __exit dtsof_exit(void){}/* 注冊入口出口*/
module_init(dtsof_init);
module_exit(dtsof_exit);
MODULE_LICENSE("GPL");

????????modprobe以后應當能看到以下內容:?

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

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

相關文章

8.2-使用字符串存儲 UTF-8 編碼文本

使用字符串存儲 UTF-8 編碼文本 我們在第4章討論過字符串&#xff0c;但現在將更深入地探討它們。新手 Rustacean 常常因為三個原因而卡在字符串上&#xff1a;Rust 傾向于暴露可能的錯誤、字符串比許多程序員想象的要復雜得多&#xff0c;以及 UTF-8。這些因素結合起來&#x…

以AI大模型重構教育新生態,打造“教-學-練-輔-評”一體化智能平臺

在《中國教育現代化2035》與“教育新基建”政策驅動下&#xff0c;教育數字化轉型已進入深水區。如何將AI技術深度融合于教學全流程&#xff0c;實現從“標準化”到“個性化”的跨越&#xff1f;文淵智閣推出的 AI教學大模型建設方案 &#xff0c;以“數據驅動AI潛能&#xff0…

AI在法律合同內容比對的應用實例

在商業世界的復雜交易中&#xff0c;合同是至關重要的法律保障。然而&#xff0c;隨著業務的擴展&#xff0c;合同數量呈指數級增長&#xff0c;合同條款也日趨復雜。對于法務和商務團隊來說&#xff0c;如何高效、準確地進行合同比對&#xff0c;成為一個亟待解決的難題。傳統…

【Maven】Maven多模塊拆分與依賴隔離 的終極深度解析,從 原子級配置 到 企業級架構設計,涵蓋 8大核心維度

Maven多模塊拆分與依賴隔離 的終極深度解析&#xff0c;從 原子級配置 到 企業級架構設計&#xff0c;涵蓋 8大核心維度一、模塊化工程結構設計&#xff08;黃金法則&#xff09;1. 分層架構模板2. 依賴流向控制矩陣二、依賴隔離的原子級配置1. 嚴格依賴管理&#xff08;父POM&…

大模型流式長鏈接場景下 k8s 優雅退出 JAVA

一、 java bootstrap.yml bootstrap.yml 啟動文件增加timeout-per-shutdown-phase spring:lifecycle:timeout-per-shutdown-phase: 30m# 這個值是故意設置這么大的&#xff0c;因為現在推理服務支持深度思考# 為了保證用戶側的連接不被斷開&#xff0c;因此我們需要設置超大 g…

uni-app用css編寫族譜樹家譜樹

需求背景&#xff1a;公司接到一個項目&#xff0c;是需要做一個族譜微信小程序&#xff0c;需要有族譜樹&#xff0c;且可以添加家族人員。 靈感來源&#xff1a;在插件市場中下載了作者 羊羊不想寫代碼 的插件tree-list族譜&#xff0c;樹形列表&#xff0c;可縮放滑動 - DC…

思途JSP學習 0731

繼0730&#xff0c;我們對項目做最后的升級一、刪除功能1、新增復選框輔助刪除條目的選擇修改我們的list.jsp和list.js在列表的第一列增加一列選擇框2、給復選框添加全選與行點擊選擇功能在行選擇功能中&#xff0c;因為此時的選擇框還未生成&#xff0c;所以我們將事件委托給他…

某訊視頻風控參數逆向分析

文章目錄1. 寫在前面2. 接口分析3. 加密分析4. 扣JS代碼【&#x1f3e0;作者主頁】&#xff1a;吳秋霖 【&#x1f4bc;作者介紹】&#xff1a;擅長爬蟲與JS加密逆向分析&#xff01;Python領域優質創作者、CSDN博客專家、阿里云博客專家、華為云享專家。一路走來長期堅守并致力…

[Broken IOS] 配置CLI | 終端用戶界面TUI

鏈接&#xff1a;https://palera.in/ docs&#xff1a;palera1n palera1n 是一款專為 Jailbroken蘋果設備 設計的強大工具&#xff0c;支持運行 iOS/iPadOS/tvOS 15.0 及更新系統 的 iPhone、iPad 和 Apple TV。 該工具通過 DFU 模式 下的底層 USB 通信引導設備&#xff0c;…

論文閱讀|ArxiV 2024|Mamba進一步研究|VSSD

論文地址&#xff1a;pdf 代碼地址&#xff1a;code 文章目錄1.研究背景與動機2. 核心方法2.1 預備知識:mamba-ssm2.2 非因果狀態空間對偶性2.3 視覺狀態空間對偶性模型3. 實驗結果3.1 圖像分類任務3.2 目標檢測任務3.3 語義分割任務3.4 消融實驗4.局限性與結論4.1 局限性4.2 結…

Flutter中 Provider 的基礎用法超詳細講解(二)之ChangeNotifierProvider

目錄 前言 一、什么是ChangeNotifierProvider? 二、ChangeNotifier的簡單用法 1.定義狀態類 2.使用ChangeNotifierProvider提供狀態 3.獲取狀態并監聽更新 1.Consumer 2.通過API方式獲取 1.Provider.of (context) 2.context.watch () 3.context.read () 4.各種獲…

2025電商CPS分銷與推客系統小程序開發:趨勢、架構與實戰解析

一、行業趨勢&#xff1a;CPS模式與社交電商的深度融合1.1 電商行業新趨勢根據《2025年電子商務行業發展趨勢預測報告》&#xff0c;社交電商與內容營銷已成為核心增長點。消費者行為呈現三大特征&#xff1a;消費習慣轉變&#xff1a;線上購物占比超70%&#xff0c;Z世代用戶更…

Conda環境下配置的基本命令

功能命令創建環境conda create -n myenv python3.11激活環境conda activate myenv刪除環境conda env remove -n myenv復制環境conda create -n newenv --clone myenv列出所有環境conda env list列出環境所有包conda list徹底清除某個 Conda 環境中的所有已安裝包&#xff08;但…

Ps2025

快捷鍵CShs保存CSw存儲為S選取疊加選取,A選取減去選區C回車保存路徑內容識別 SF5 ADel填充前景色CDel填充背景色A上下 上下行間距A左右 左右字間距C左鍵絲滑放大縮小CASE蓋印圖層C}上移一格CG新建組sF6羽化像素鋼筆工具打上抹點&#xff0c;按住shift水平拉調增弧度左右兩個手柄…

ceph sc 設置文件系統格式化參數

前言 默認的 sc 文件系統 inode 太少,對于小文件場景,往往會出現容量沒滿,inode 已經用盡的情況,本文說明如何設置 inode。 說明 本文使用的是 rook-ceph 部署的 ceph 作為存儲后端。 xfs 文件系統 sc 創建帶格式化參數的 xfs 文件系統的 sc allowVolumeExpansion: t…

【LY88】ubuntu下的常用操作

vscode 下載安裝包 在安裝包所處文件夾空白區域右鍵調出終端 輸入下行命令安裝 c后接tab自動補全安裝包名稱&#xff08;前提是該文件夾中僅這一個c開頭文件&#xff0c;否則得再輸點字母&#xff0c;保證其可唯一索引到&#xff09; sudo dpkg -i ctab安裝完畢后輸入code&…

web應用從服務器主動推動數據到客戶端的方式

html5 websocket 全雙工交互 全雙工通信&#xff1a;建立持久連接&#xff0c;服務端和客戶端可隨時互相發送消息 低延遲&#xff1a;適合實時應用&#xff08;聊天、游戲、股票行情等&#xff09; socket協議是與HTTP協議平級的&#xff0c;websocket協議是建立在TCP協議之上的…

基于Spring Boot實現中醫醫學處方管理實踐

基于Spring Boot實現中醫醫學處方管理 以下是基于Spring Boot實現中醫醫學處方管理的相關示例和資源整理,涵蓋基礎架構、功能模塊及實際應用案例: 基礎項目結構 Spring Boot中醫處方系統通常采用MVC分層設計: 實體類:定義處方、藥材、患者等JPA實體 @Entity public clas…

從“人工核驗”到“智能鑒防”:護照鑒偽設備的科技革命

“一本偽造護照的查獲成本從72小時降至3秒&#xff0c;背后是光學傳感、量子加密與多模態AI的十年協同進化。”2025年全球邊檢口岸查獲偽假護照近500份&#xff0c;其中芯片偽造占比首超40%。當造假技術逼近分子級仿制&#xff0c;傳統肉眼鑒別徹底失效&#xff0c;多光譜成像、…

無人機飛控系統3D (C++)實踐

大疆無人機飛控系統3D模型開發 大疆無人機飛控系統3D模型開發(C++) 核心架構設計 大疆無人機的飛控系統通常采用分層架構,分為硬件抽象層(HAL)、中間件層和應用層。HAL負責與傳感器/執行器直接交互,中間件處理數據融合和通信協議,應用層實現核心控制算法。 典型代碼結…