blogger wordpressseo人員招聘
第六十八章 設(shè)備樹(shù)插件介紹
????????Linux 4.4之后引入了動(dòng)態(tài)設(shè)備樹(shù),其中的設(shè)備樹(shù)插件(Device Tree Overlay)是一種擴(kuò)展機(jī)制,允許在運(yùn)行時(shí)動(dòng)態(tài)添加、修改或刪除設(shè)備節(jié)點(diǎn)和屬性。
? ? ? ? 設(shè)備樹(shù)插件機(jī)制通過(guò)DTS(設(shè)備樹(shù)源文件)定義,提供了一種靈活配置硬件設(shè)備的方式,無(wú)需重新編譯整個(gè)設(shè)備樹(shù),也無(wú)需重啟系統(tǒng)即可進(jìn)行硬件配置更改。
????????在 linux 源碼中 linux_sdk/kernel/Documentation/filesystems/configfs 目錄下的 configfs.txt。是設(shè)備樹(shù)插件的幫助文檔。
第六十九章 設(shè)備樹(shù)插件語(yǔ)法和編譯實(shí)驗(yàn)
69.1 設(shè)備樹(shù)插件語(yǔ)法
????????設(shè)備樹(shù)插件的語(yǔ)法格式基于設(shè)備樹(shù)源文件的語(yǔ)法,但是有一些特定的語(yǔ)法和指令用于描述插件的行為。
????????我們新建 overlay.dts,
1 首先添加插件頭部聲明,它指定了插件的名稱(chēng)和版本等信息,并指定了要修改的設(shè)備樹(shù)的路徑,
/dts-v1/;
/plugin/;
// 插件頭部聲明(示例,實(shí)際內(nèi)容根據(jù)需求填寫(xiě))
/plugin/name: "my_overlay";
/plugin/version: "1.0";
/plugin/target-path: "/"; // 目標(biāo)設(shè)備樹(shù)路徑
2 插件節(jié)點(diǎn)名稱(chēng)用于指定要操作的設(shè)備節(jié)點(diǎn)及其屬性。
? ? ? ? 假設(shè)需要編寫(xiě)插件的設(shè)備樹(shù)節(jié)點(diǎn)如下:
rk_485_ctl:rk-485-ctl{compatible = "topeet,rs485_ctl";gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;pinctrl-names = "default";pinctrl-0 = <&rk_485_gpio>;
}
? ? ? ? 設(shè)備樹(shù)插件有以下四種寫(xiě)法。?了解即可。
/dts-v1/;
/plugin/;&{/rk-485-ctl}{ 或者 &rk_485_ctl{overlay_node{status = "okay";};
};/{fragment@0{target-path = "rk-485-cl"; 或者 target= <rk-485-cl>;__overlay__{overlay_node{status = "okay";}}}
}
69.2 設(shè)備樹(shù)插件編譯
? ? ? ? 使用方法一,然后編譯設(shè)備樹(shù)插件 overlay.dts,輸入以下命令:
/home/topeet/Linux/linux_sdk/kernel/scripts/dtc/dtc-I dts //輸入文件的格式-O dtb //輸出文件的格式overlay.dts //輸入的源文件-o overlay.dtbo //輸出文件的名稱(chēng)和路徑
????????反編譯設(shè)備樹(shù),輸入以下命令:
/home/topeet/Linux/linux_sdk/kernel/scripts/dtc/dtc -I dtb -O dts overlay.dtbo -o 1.dts
第七十章 設(shè)備樹(shù)插件使用
70.1 準(zhǔn)備實(shí)驗(yàn)環(huán)境
? ? ? ? 要求內(nèi)核鏡像支持設(shè)備樹(shù)插件,一般要求內(nèi)核版本4.4以上。
????????使用“insmod xxx.ko”命令加載設(shè)備樹(shù)插件驅(qū)動(dòng)。
? ? ? ? 使用 cat /proc/filesystems 查看當(dāng)前內(nèi)核支持的文件系統(tǒng)類(lèi)型的列表。

????????在Linux系統(tǒng)中,/proc/filesystems文件是一個(gè)虛擬文件,它提供了當(dāng)前內(nèi)核支持的文件系統(tǒng)類(lèi)型的列表。這個(gè)文件是由內(nèi)核動(dòng)態(tài)生成的,并且只存在于內(nèi)存中,不占用磁盤(pán)空間。
????????輸出中的每一行都代表一個(gè)文件系統(tǒng)類(lèi)型,前面的 nodev表示該文件系統(tǒng)類(lèi)型不支持在磁盤(pán)上作為設(shè)備掛載(即它不是基于塊設(shè)備的文件系統(tǒng))。沒(méi)有nodev前綴的文件系統(tǒng)類(lèi)型則通??梢?huà)燧d在磁盤(pán)設(shè)備或其他類(lèi)型的文件系統(tǒng)之上。
70.2 設(shè)備樹(shù)插件的使用
????????在上一章節(jié)中,我們編寫(xiě)了 overlay.dts。
????????在 overlay.dts 中,rk-485-ctl 節(jié)點(diǎn)下添加新的節(jié)點(diǎn)overlay_node 節(jié)點(diǎn),如下所示:
/dts-v1/;
/plugin/;&{/rk-485-ctl}{ overlay_node{status = "okay";};
};
????????使用 dtc 編譯器編譯得到 dtbo 文件,并將 dtbo 拷貝到開(kāi)發(fā)板上。
/home/topeet/Linux/linux_sdk/kernel/scripts/dtc/dtc
-I dts
-O dtb
overlay.dts
-o overlay.dtbo
????????我們進(jìn)到系統(tǒng)?/sys/kernel/config/device-tree/overlays/(這個(gè)目錄需要加載設(shè)備樹(shù)插件才會(huì)生成)目錄下。
????????在這個(gè)目錄下使用以下命令創(chuàng)建一個(gè)內(nèi)核對(duì)象,
mkdir test
?????????使用命令 cd test 進(jìn)到 test 文件夾,在文件夾下創(chuàng)建 status和 dtbo兩個(gè)文件
cd test
? ? ? ? ?使用 cat /overlay.dtbo > dtbo 將 插件.dtbo文件 寫(xiě)入 dtbo文件。
? ? ? ? ?在狀態(tài)文件status中寫(xiě)入 1,來(lái)使能插件。echo 1 > status。
????????此時(shí)查看 proc文件系統(tǒng)的devicetree可以看到加載的 插件節(jié)點(diǎn)。
ls /proc/device-tree/rk-485-ctl/overlay_node/

要?jiǎng)h掉插件節(jié)點(diǎn),直接把?/sys/kernel/config/device-tree/overlays/ 下的 test文件刪掉就可。
????????要加載多個(gè)插件,多寫(xiě)幾個(gè)文件夾,把 dtc編譯后的插件內(nèi)容用 cat xxx > bbb 寫(xiě)到 dtbo 文件就行。?
第七十一章 虛擬文件系統(tǒng) ConfigFS
????????虛擬文件系統(tǒng) ConfigFS 是一個(gè)特殊的文件系統(tǒng),旨在提供一種動(dòng)態(tài)配置 Linux 內(nèi)核和設(shè)備的機(jī)制。
71.1 常用的虛擬文件系統(tǒng)
????????在Linux內(nèi)核中,虛擬文件系統(tǒng)為應(yīng)用程序提供了統(tǒng)一的文件訪(fǎng)問(wèn)接口,簡(jiǎn)化了開(kāi)發(fā)、維護(hù),提高了可移植性和靈活性。以下是幾個(gè)常用的虛擬文件系統(tǒng)及其功能簡(jiǎn)述:
Procfs:? ? 主要用于進(jìn)程、設(shè)備、驅(qū)動(dòng)等系統(tǒng)信息,表示運(yùn)行時(shí)狀態(tài)。
Sysfs:? ? ?主要用于設(shè)備、驅(qū)動(dòng)等內(nèi)核對(duì)象的屬性和狀態(tài)。
Configfs:主要用于動(dòng)態(tài)管理內(nèi)核對(duì)象。允許運(yùn)行時(shí)添加、修改和刪除內(nèi)核對(duì)象
Procfs:
????????功能:訪(fǎng)問(wèn)內(nèi)核運(yùn)行時(shí)狀態(tài),包括進(jìn)程、設(shè)備、驅(qū)動(dòng)程序等系統(tǒng)信息。
????????路徑:通常在 /proc 目錄下。
# 訪(fǎng)問(wèn)CPU信息
/proc/cpuinfo
Sysfs:
????????功能:表示系統(tǒng)中的設(shè)備、驅(qū)動(dòng)程序等內(nèi)核對(duì)象,為這些對(duì)象的屬性和狀態(tài)提供統(tǒng)一的訪(fǎng)問(wèn)接口。
路徑:通常在 /sys 目錄下。
# 查看設(shè)備信息
/sys/class/tty/ttyS0/device/idVendor
Configfs:
????????功能:動(dòng)態(tài)配置和管理內(nèi)核對(duì)象,允許在運(yùn)行時(shí)添加、修改和刪除內(nèi)核對(duì)象。
????????路徑:通常在 /sys/kernel/config 目錄下。
# 動(dòng)態(tài)配置內(nèi)核對(duì)象
/sys/kernel/config
????????設(shè)備樹(shù)插件選擇 ConfigFS 原因在于,
????????configfs允許用戶(hù)空間動(dòng)態(tài)配置內(nèi)核對(duì)象,無(wú)需改內(nèi)核代碼,適合設(shè)備樹(shù)插件技術(shù)。
第七十二章 ConfigFS 核心數(shù)據(jù)結(jié)構(gòu)
72.1 關(guān)鍵數(shù)據(jù)結(jié)構(gòu)
ConfigFS核心數(shù)據(jù)結(jié)構(gòu):
configfs_subsystem:頂層結(jié)構(gòu),代表整個(gè)ConfigFS系統(tǒng),含根配置項(xiàng)組和系統(tǒng)狀態(tài)。
config_group:配置項(xiàng)組,可含多個(gè)相關(guān)配置項(xiàng),成層次結(jié)構(gòu),含父子配置項(xiàng)指針。
config_item:基本配置項(xiàng),表示內(nèi)核對(duì)象,含類(lèi)型、名稱(chēng)、屬性和狀態(tài)、父子關(guān)系指針。
????????這些結(jié)構(gòu)形成樹(shù)形,subsystem為根,group為組,item為項(xiàng),通過(guò)指針連接成父子關(guān)系。

72.2 子系統(tǒng)、配置組和?配置項(xiàng)
????????configfs_subsystem 結(jié)構(gòu)體:成員有config_group 結(jié)構(gòu)體: 和互斥鎖,
????????config_group 結(jié)構(gòu)體:成員有config_item結(jié)構(gòu)體,和多個(gè)鏈表頭,
? ? ? ? config_item結(jié)構(gòu)體,成員有 config_item_type結(jié)構(gòu)體和引用計(jì)數(shù)等。
? ? ? ? config_item_type結(jié)構(gòu)體有
????????????????configfs_item_operations配置項(xiàng)操作集、
????????????????configfs_group_operations配置組操作集。
? ? ? ? ? ? ? ? configfs_attribute屬性文件操作集。
config_item_operations操作集有release方法。
config_group_operations操作集make_item、drop_item、make_group等方法。
configfs_attribute屬性文件操作集有 myread_show和 mywrite_store方法,在 只讀屬性文件、只寫(xiě)屬性文件分別被 讀出、寫(xiě)入時(shí)執(zhí)行。?
????????configfs_subsystem 結(jié)構(gòu)體:
/*configfs子系統(tǒng)結(jié)構(gòu)體*/
struct configfs_subsystem {struct config_group su_group;//配置項(xiàng)組結(jié)構(gòu)體struct mutex su_mutex; //互斥鎖
};
? ? ? ? config_group 結(jié)構(gòu)體:?
/*config_group配置組*/
struct config_group {struct config_item cg_item; //配置項(xiàng)struct list_head cg_children; //雙向鏈表頭,鏈接配置組下所有子配置組和配置項(xiàng)struct configfs_subsystem *cg_subsys;//配置組所屬子系統(tǒng)struct list_head default_groups; //雙向鏈表頭,鏈接配置組的默認(rèn)子組struct list_head group_entry; //雙向鏈表頭,鏈接配置組所屬子系統(tǒng)的條目
};
?????????config_item 結(jié)構(gòu)體:
/*config_item配置項(xiàng)*/
struct config_item {char *ci_name; //配置項(xiàng)名稱(chēng)指針char ci_namebuf[CONFIGFS_ITEM_NAME_LEN]; //配置項(xiàng)名稱(chēng)緩沖區(qū).一個(gè)配置項(xiàng)就是一個(gè)目錄struct kref ci_kref; //配置項(xiàng)引用計(jì)數(shù) struct list_head ci_entry; //配置項(xiàng)的鏈表?xiàng)l目struct config_item *ci_parent; //父配置項(xiàng)struct config_group *ci_group; //配置項(xiàng)組const struct config_item_type *ci_type; //目錄下屬性文件和屬性操作struct dentry *ci_dentry; //指向與配置項(xiàng)關(guān)聯(lián)的目錄項(xiàng)(dentry)的指針。
};//每個(gè)配置項(xiàng)都對(duì)應(yīng)一個(gè)文件系統(tǒng)目錄項(xiàng),
//config_item_type用于描述配置項(xiàng)類(lèi)型和操作,包括用于讀寫(xiě)目錄項(xiàng)屬性的回調(diào)函數(shù)//在ConfigFS中,每個(gè)配置項(xiàng)都對(duì)應(yīng)一個(gè)文件系統(tǒng)目錄項(xiàng),
//該目錄項(xiàng)用于與用戶(hù)空間進(jìn)行交互
//(如通過(guò)mount命令掛載ConfigFS后,可以通過(guò)文件操作來(lái)訪(fǎng)問(wèn)這些配置項(xiàng))。
? ? ? ? 接下來(lái)我們分析一下設(shè)備樹(shù)插件驅(qū)動(dòng)代碼,
????????設(shè)備樹(shù)插件驅(qū)動(dòng)代碼定義了ConfigFS子系統(tǒng)和配置項(xiàng)組。
????????dtbocfg_root_subsys是子系統(tǒng)實(shí)例,其根配置項(xiàng)組由 config_group表示,命名為"device-tree",并指定了自定義類(lèi)型 dtbocfg_root_type。子系統(tǒng)使用互斥鎖保護(hù)操作。
????????首先,在這里,該結(jié)構(gòu)體的.cg_item 字段表示根配置項(xiàng)組的基本配置項(xiàng)。
/*創(chuàng)建configfs子系統(tǒng)實(shí)例的定義和初始化*/
static struct configfs_subsystem dtbocfg_root_subsys = { //dtbocfg_root_subsys.su_group 是一個(gè) config_group 結(jié)構(gòu)體,它表示子系統(tǒng)的根配置項(xiàng)組。//.cg_item 字段表示根配置項(xiàng)組的基本配置項(xiàng).su_group.cg_item.ci_namebuf = "device-tree", /*根配置項(xiàng)名稱(chēng)*///注冊(cè)子文件系統(tǒng)時(shí),會(huì)在sys/kernel/configs目錄下,用根配置項(xiàng)名稱(chēng)創(chuàng)建子文件系統(tǒng)//配置項(xiàng)的類(lèi)型=一個(gè)自定義config_item_type.su_group.cg_item.ci_type = &dtbocfg_root_type,//初始化互斥鎖.su_mutex = __MUTEX_INITIALIZER(dtbocfg_root_subsys.su_mutex),
};
? ? ? ? 注意,子文件系統(tǒng)有 配置項(xiàng)組成員,配置項(xiàng)組成員有根配置項(xiàng),注冊(cè)子文件系統(tǒng)時(shí),用的是根配置項(xiàng)的名字。?
? ? ? ? 注冊(cè) 配置項(xiàng)組的時(shí)候,用的是注冊(cè)函數(shù)給的名字參數(shù)?
????????通過(guò)這段代碼,創(chuàng)建了一個(gè)名為"device-tree"的子系統(tǒng),它的根配置項(xiàng)組為空。
????????可在該子系統(tǒng)下添加更多配置項(xiàng)和配置項(xiàng)組,用于動(dòng)態(tài)配置和管理設(shè)備樹(shù)相關(guān)的內(nèi)核對(duì)象。
?????????Linux 系統(tǒng)下創(chuàng)建了 device-tree 這個(gè)子系統(tǒng),

?????????接下來(lái)是設(shè)備樹(shù)插件驅(qū)動(dòng)代碼中注冊(cè)配置項(xiàng)組的部分,
/*創(chuàng)建配置項(xiàng)組實(shí)例*/
static struct config_group dtbocfg_overlay_group = { .cg_item.ci_type = &dtbocfg_overlays_type,
}; /**/
static int dtbocfg_module_init(void) { int retval; /*初始化Configfs子系統(tǒng)的根配置項(xiàng)組*/config_group_init(&dtbocfg_root_subsys.su_group); /*初始化Confifs子系統(tǒng)的名為 overlays的配置項(xiàng)組*/ config_group_init_type_name(&dtbocfg_overlay_group,"overlays", &dtbocfg_overlays_type);/*注冊(cè)子系統(tǒng)*/retval = configfs_register_subsystem(&dtbocfg_root_subsys); if (retval) goto register_subsystem_failed; /*注冊(cè)配置項(xiàng)組*/retval = configfs_register_group(&dtbocfg_root_subsys.su_group, &dtbocfg_overlay_group); if (retval) goto register_group_failed; pr_info("OK\n"); return 0; register_group_failed: /*注銷(xiāo)子系統(tǒng)*/configfs_unregister_subsystem(&dtbocfg_root_subsys);
register_subsystem_failed: return retval;
}
初始化函數(shù) dtbocfg_module_init()執(zhí)行以下步驟:
????????初始化子系統(tǒng)的根配置項(xiàng)組和名為"overlays"的配置項(xiàng)組,指定類(lèi)型dtbocfg_overlays_type。
????????configfs_register_subsystem()注冊(cè)子系統(tǒng)。
????????將"overlays"配置項(xiàng)組添加到子系統(tǒng)的根配置項(xiàng)組下。
????????configfs_register_group()在子系統(tǒng)中注冊(cè)配置項(xiàng)組。
????????如注冊(cè)失敗,注銷(xiāo)子系統(tǒng)并返回錯(cuò)誤碼;成功則打印"OK"。
????????結(jié)果是在/sys/kernel/config下創(chuàng)建了名為"device-tree"的子系統(tǒng),并在其下創(chuàng)建了名為"overlays"的容器。

72.3 屬性和方法
????????我們要在容器下放目錄或?qū)傩晕募?#xff0c;所以我們看一下 config_item 結(jié)構(gòu)體,
struct config_item {char *ci_name;char ci_namebuf[CONFIGFS_ITEM_NAME_LEN]; //目錄的名字struct kref ci_kref;struct list_head ci_entry;struct config_item *ci_parent;struct config_group *ci_group;const struct config_item_type *ci_type; //目錄下屬性文件和屬性操作struct dentry *ci_dentry;
};
????????config_item 結(jié)構(gòu)體中包含了 config_item_type 結(jié)構(gòu)體,
/*配置項(xiàng)的屬性和操作*/
struct config_item_type { struct module *ct_owner; //所屬模塊struct configfs_item_operations *ct_item_ops; //item(目錄)的操作方法struct configfs_group_operations *ct_group_ops; //group(容器)的操作方法struct configfs_attribute **ct_attrs; //屬性文件的操作方法struct configfs_bin_attribute **ct_bin_attrs; //bin 屬性文件的操作方法
};
????????config_item_type 結(jié)構(gòu)體中包含了 struct configfs_item_operations 結(jié)構(gòu)體,
/*配置項(xiàng)組下,配置項(xiàng)刪除和鏈接的創(chuàng)建、刪除的鉤子函數(shù)*/
struct configfs_item_operations {//刪除 item 方法,在 group 下面使用 rmdir 命令會(huì)調(diào)用這個(gè)方法void (*release)(struct config_item *);//參數(shù)是指向被刪除的配置項(xiàng)的指針/*在嘗試創(chuàng)建一個(gè)從 src 到 target 的鏈接之前,這個(gè)函數(shù)會(huì)被調(diào)用。在 ConfigFS 中,配置項(xiàng)可以通過(guò)創(chuàng)建鏈接(link)來(lái)組織成樹(shù)狀結(jié)構(gòu)或形成關(guān)聯(lián)。*/int (*allow_link)(struct config_item *src, struct config_item *target);/*當(dāng)從 src 到 target 的鏈接被刪除時(shí),這個(gè)函數(shù)會(huì)被調(diào)用。*/void (*drop_link)(struct config_item *src, struct config_item *target);
};
????????config_item_type 結(jié)構(gòu)體中包含了 struct configfs_group_operations 結(jié)構(gòu)體,
/*配置項(xiàng)與配置項(xiàng)組關(guān)聯(lián)的相關(guān)鉤子函數(shù)*/
struct configfs_group_operations {//當(dāng)在配置組下使用 mkdir 命令創(chuàng)建一個(gè)新的子配置項(xiàng)時(shí),這個(gè)函數(shù)會(huì)被調(diào)用struct config_item *(*make_item)(struct config_group *group, const char *name);/*其實(shí)就是目錄下新建文件的時(shí)候,該函數(shù)調(diào)用*///當(dāng)在配置組下使用 mkdir 命令創(chuàng)建一個(gè)新的子配置組時(shí),這個(gè)函數(shù)會(huì)被調(diào)用。struct config_group *(*make_group)(struct config_group *group, const char *name);/*其實(shí)就是目錄下新建文件的時(shí)候,該函數(shù)調(diào)用.相較于make_item優(yōu)先級(jí)更高*///在配置項(xiàng)被完全設(shè)置或修改后,這個(gè)函數(shù)會(huì)被調(diào)用以確認(rèn)或提交這些更改。int (*commit_item)(struct config_item *item);//配置項(xiàng)與其父配置組之間的關(guān)聯(lián)被斷開(kāi)時(shí)(例如,當(dāng)配置項(xiàng)被刪除時(shí)),這個(gè)函數(shù)會(huì)被調(diào)用。void (*disconnect_notify)(struct config_group *group, struct config_item *item);//當(dāng)配置項(xiàng)從配置組中被刪除時(shí),這個(gè)函數(shù)會(huì)被調(diào)用。void (*drop_item)(struct config_group *group, struct config_item *item);
};
????????config_item_type 結(jié)構(gòu)體中包含了 struct configfs_attribute 結(jié)構(gòu)體,?
struct configfs_attribute {const char *ca_name; //屬性文件的名字struct module *ca_owner; //屬性文件文件的所屬模塊umode_t ca_mode; //屬性文件訪(fǎng)問(wèn)權(quán)限//讀寫(xiě)方法的函數(shù)指針,具體功能需要自行實(shí)現(xiàn)。ssize_t (*show)(struct config_item *, char *);ssize_t (*store)(struct config_item *, const char *, size_t);
};
struct configfs_bin_attribute { struct configfs_attribute cb_attr; /* 標(biāo)準(zhǔn)的屬性結(jié)構(gòu)體 */ void *cb_private; /* 私有數(shù)據(jù)指針,可用于用戶(hù)空間 */ size_t cb_max_size; /* 二進(jìn)制數(shù)據(jù)的最大大小 */ ssize_t (*read)(struct config_item *, void *, size_t); /* 讀取回調(diào)函數(shù) */ ssize_t (*write)(struct config_item *, const void *, size_t); /* 寫(xiě)入回調(diào)函數(shù) */
};
?
第七十三章 注冊(cè) configfs 子系統(tǒng)實(shí)驗(yàn)
????????我們編寫(xiě)驅(qū)動(dòng)代碼創(chuàng)建一個(gè)名為“myconfigfs”的 configfs 子系統(tǒng),并將其注冊(cè)到內(nèi)核中。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/configfs.h>//定義名為"myconfig_item_type"的配置項(xiàng)類(lèi)型結(jié)構(gòu)體
static const struct config_item_type myconfig_item_type ={.ct_owner = THIS_MODULE, .ct_item_ops = NULL, .ct_group_ops = NULL, .ct_attrs = NULL, };//定義一個(gè) configfs_subsystem 結(jié)構(gòu)體實(shí)例"myconfigfs_subsystem"
static struct configfs_subsystem myconfigfs_subsystem ={.su_group = {.cg_item = {.ci_namebuf = "myconfigfs", //配置項(xiàng)的名稱(chēng).ci_type = &myconfig_item_type, //配置項(xiàng)的操作},},
};//模塊的初始化函數(shù)
static int myconfigfs_init(void)
{//初始化配置組config_group_init(&myconfigfs_subsystem.su_group);//注冊(cè)子系統(tǒng)configfs_register_subsystem(&myconfigfs_subsystem);return 0;
}// 模塊退出函數(shù)
static void myconfigfs_exit(void)
{/*注銷(xiāo)子系統(tǒng)*/configfs_unregister_subsystem(&myconfigfs_subsystem);
}
module_init(myconfigfs_init); // 指定模塊的初始化函數(shù)
module_exit(myconfigfs_exit); // 指定模塊的退出函數(shù)
MODULE_LICENSE("GPL"); // 模塊使用的許可證
MODULE_AUTHOR("topeet"); // 模塊的作者
????????驅(qū)動(dòng)加載之后,進(jìn)入/sys/kernel/config 目錄下,可以看到注冊(cè)生成的 myconfigfs 子系統(tǒng),

第七十四章 注冊(cè) configs 配置項(xiàng)實(shí)驗(yàn)
? ? ? ? 由于 注冊(cè) config_group配置項(xiàng)組的過(guò)程和?注冊(cè) configfs子系統(tǒng)的過(guò)程相似,所以略過(guò),
????????而注冊(cè)配置項(xiàng)的過(guò)程包含了注冊(cè)配置項(xiàng)組的過(guò)程,且涉及config_item_type的配置過(guò)程,有著較多的鉤子函數(shù)需要配置。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/configfs.h>
// 定義一個(gè)名為"mygroup"的 config_group 結(jié)構(gòu)體
static struct config_group mygroup;
// 自定義的配置項(xiàng)結(jié)構(gòu)體
struct myitem
{struct config_item item;
};// 配置項(xiàng)釋放函數(shù)
void myitem_release(struct config_item *item)
{struct myitem *myitem = container_of(item, struct myitem, item);kfree(myitem);printk("%s\n", __func__);
}// 配置項(xiàng)操作結(jié)構(gòu)體
struct configfs_item_operations myitem_ops = {.release = myitem_release,
};// 配置項(xiàng)類(lèi)型結(jié)構(gòu)體
static struct config_item_type mygroup_item_type = {.ct_owner = THIS_MODULE, .ct_item_ops = &myitem_ops,
};// 新建配置項(xiàng)函數(shù)
struct config_item *mygroup_make_item(struct config_group *group, const char *name)
{struct myitem *myconfig_item;printk("%s\n", __func__);myconfig_item = kzalloc(sizeof(*myconfig_item), GFP_KERNEL);//創(chuàng)建一個(gè)配置項(xiàng),綁定 名稱(chēng) 和 屬性及操作config_item_init_type_name(&myconfig_item->item, name, &mygroup_item_type);return &myconfig_item->item;
}// 配置組操作結(jié)構(gòu)體
struct configfs_group_operations mygroup_ops = {/*綁定配置項(xiàng)的新建函數(shù)*/.make_item = mygroup_make_item,
};//config_item_type 結(jié)構(gòu)體,用于描述配置項(xiàng)類(lèi)型(但其實(shí)是傳給配置項(xiàng)組的成員)。
static const struct config_item_type mygroup_config_item_type = {.ct_owner = THIS_MODULE, .ct_group_ops = &mygroup_ops,
};// 定義名為"myconfig_item_type"的配置項(xiàng)類(lèi)型結(jié)構(gòu)體
static const struct config_item_type myconfig_item_type = {.ct_owner = THIS_MODULE, .ct_group_ops = NULL, //省略了配置項(xiàng)與配置項(xiàng)關(guān)聯(lián)的相關(guān)鉤子函數(shù)
};// 定義一個(gè) configfs_subsystem 結(jié)構(gòu)體實(shí)例"myconfigfs_subsystem"
static struct configfs_subsystem myconfigfs_subsystem = {//填充配置項(xiàng)組成員.su_group = {//填充配置項(xiàng)成員.cg_item = {.ci_namebuf = "myconfigfs", //填充配置項(xiàng)名稱(chēng).ci_type = &myconfig_item_type, //填充配置項(xiàng)操作}, },
};// 模塊的初始化函數(shù)
static int myconfig_group_init(void)
{// 初始化配置組config_group_init(&myconfigfs_subsystem.su_group);// 注冊(cè)子系統(tǒng)configfs_register_subsystem(&myconfigfs_subsystem);// 初始化配置組"mygroup" config_group_init_type_name(&mygroup, //配置項(xiàng)組實(shí)例"mygroup", //配置項(xiàng)組名字&mygroup_config_item_type); //配置項(xiàng)組操作// 在子系統(tǒng)中注冊(cè)配置組"mygroup" configfs_register_group(&myconfigfs_subsystem.su_group, &mygroup);return 0;
}// 模塊退出函數(shù)
static void myconfig_group_exit(void)
{// 注銷(xiāo)子系統(tǒng)configfs_unregister_subsystem(&myconfigfs_subsystem);
}
module_init(myconfig_group_init); // 指定模塊的初始化函數(shù)
module_exit(myconfig_group_exit); // 指定模塊的退出函數(shù)
MODULE_LICENSE("GPL"); // 模塊使用的許可
? ? ? ? ?加載模塊后,進(jìn)入 sys/kernel/config 目錄,發(fā)現(xiàn)注冊(cè)的文件系統(tǒng)目錄已經(jīng)生成,配置組目錄也已經(jīng)生成,

????????然后輸入“mkdir test”命令創(chuàng)建 config_item,如下圖所示,創(chuàng)建成功之后,打印
????????“mygroup_make_item”,說(shuō)明驅(qū)動(dòng)程序中 mygroup_make_item 函數(shù)成功執(zhí)行。

第七十五章 drop 和 release 函數(shù)
????????.release 是在 struct config_item_type 結(jié)構(gòu)體中定義的回調(diào)函數(shù)指針,用于在配置項(xiàng)被刪除時(shí)執(zhí)行資源釋放操作。
?????????每個(gè)配置項(xiàng)實(shí)例都有一個(gè)與之關(guān)聯(lián)的引用計(jì)數(shù)。
????????這個(gè)引用計(jì)數(shù)用于跟蹤有多少實(shí)體(如內(nèi)核模塊、進(jìn)程或其他內(nèi)核組件)正在使用該配置項(xiàng)。當(dāng)你創(chuàng)建一個(gè)新的配置項(xiàng)實(shí)例時(shí),通常會(huì)初始化其引用計(jì)數(shù)為 1,表示該配置項(xiàng)已經(jīng)被創(chuàng)建者所引用。隨著配置項(xiàng)被不同的實(shí)體所使用,其引用計(jì)數(shù)會(huì)增加;相應(yīng)地,當(dāng)這些實(shí)體不再需要該配置項(xiàng)時(shí),它們會(huì)通過(guò)調(diào)用 config_item_put 來(lái)減少其引用計(jì)數(shù)。當(dāng)引用計(jì)數(shù)減少到 0就會(huì)調(diào)用.release函數(shù)執(zhí)行清理工作。
?????????.drop_item 是在 struct configfs_group_operations 結(jié)構(gòu)體中定義的回調(diào)函數(shù)指針,用于在配置組被刪除時(shí)執(zhí)行相關(guān)的清理操作。
// 定義一個(gè)名為"mygroup"的 config_group 結(jié)構(gòu)體
static struct config_group mygroup;// 自定義的配置項(xiàng)結(jié)構(gòu)體
struct myitem
{struct config_item item;
};// 配置項(xiàng)釋放函數(shù),配置項(xiàng)的引用計(jì)數(shù)為0時(shí)執(zhí)行
void myitem_release(struct config_item *item)
{struct myitem *myitem = container_of(item, struct myitem, item);kfree(myitem);printk("%s\n", __func__);
}/* 配置項(xiàng)操作結(jié)構(gòu)體,填充配置項(xiàng)操作的release函數(shù) */
struct configfs_item_operations myitem_ops = {.release = myitem_release,
};// 配置項(xiàng)類(lèi)型結(jié)構(gòu)體
static struct config_item_type mygroup_item_type = {.ct_owner = THIS_MODULE, .ct_item_ops = &myitem_ops, //填充配置項(xiàng)操作
};// 創(chuàng)建配置項(xiàng)函數(shù)
struct config_item *mygroup_make_item(struct config_group *group, const char *name)
{struct myitem *myconfig_item;printk("%s\n", __func__);myconfig_item = kzalloc(sizeof(*myconfig_item), GFP_KERNEL);config_item_init_type_name(&myconfig_item->item, name, &mygroup_item_type);return &myconfig_item->item;
}// 刪除配置項(xiàng)函數(shù)
void mygroup_delete_item(struct config_group *group, struct config_item *item)
{struct myitem *myitem = container_of(item, struct myitem, item);config_item_put(&myitem->item); //減少傳入 config_item 實(shí)例的引用計(jì)數(shù)printk("%s\n", __func__);
}// 配置組操作結(jié)構(gòu)體
struct configfs_group_operations mygroup_ops = {.make_item = mygroup_make_item, //配置組創(chuàng)建配置項(xiàng)的鉤子函數(shù).drop_item = mygroup_delete_item,//配置組刪除配置項(xiàng)的鉤子函數(shù)
};// config_item_type 配置項(xiàng)類(lèi)型結(jié)構(gòu)體,用于描述配置項(xiàng)類(lèi)型。用于將配置組注冊(cè)進(jìn)子系統(tǒng)時(shí)初始化
static const struct config_item_type mygroup_config_item_type = {.ct_owner = THIS_MODULE, .ct_group_ops = &mygroup_ops, //填充配置組類(lèi)型的鉤子函數(shù)
};// 定義名為"myconfig_item_type"的配置項(xiàng)類(lèi)型結(jié)構(gòu)體,用于定義子系統(tǒng)時(shí)初始化
static const struct config_item_type myconfig_item_type = {.ct_owner = THIS_MODULE, .ct_group_ops = NULL,
};// 定義一個(gè) configfs_subsystem 結(jié)構(gòu)體實(shí)例
static struct configfs_subsystem myconfigfs_subsystem = {.su_group = {.cg_item = {.ci_namebuf = "myconfigfs", .ci_type = &myconfig_item_type, }, },
};// 模塊的初始化函數(shù)
static int myconfig_group_init(void)
{// 初始化配置組config_group_init(&myconfigfs_subsystem.su_group);// 注冊(cè)子系統(tǒng)configfs_register_subsystem(&myconfigfs_subsystem);// 初始化配置組"mygroup" config_group_init_type_name(&mygroup, "mygroup", &mygroup_config_item_type);// 在子系統(tǒng)中注冊(cè)配置組"mygroup" configfs_register_group(&myconfigfs_subsystem.su_group, &mygroup);return 0;
}//...省略模塊出口函數(shù)
? ? ? ? 在配置組目錄下,使用 mkdir創(chuàng)建配置項(xiàng),會(huì)執(zhí)行 make_item函數(shù),
? ? ? ? 使用 rmdir刪除配置項(xiàng),會(huì)先執(zhí)行 drop_item函數(shù),然后執(zhí)行release函數(shù)。
第七十六章 注冊(cè) attribute 實(shí)驗(yàn)
// 使用CONFIGFS_ATTR_RO和CONFIGFS_ATTR_WO宏定義只讀和只寫(xiě)屬性 ?
CONFIGFS_ATTR_RO(my, read); ?// 定義一個(gè)名為read的只讀屬性,關(guān)聯(lián)到myread_show函數(shù) ?
/*生成一個(gè) myattr_read只讀屬性*/ CONFIGFS_ATTR_WO(my, write); ?// 定義一個(gè)名為write的只寫(xiě)屬性,關(guān)聯(lián)到mywrite_store函數(shù) ?
/*生成一個(gè) myattr_write只寫(xiě)屬性*//*屬性文件和關(guān)聯(lián)的讀寫(xiě)方法是通過(guò)屬性名和函數(shù)名關(guān)聯(lián)的*/// 定義屬性數(shù)組,以NULL結(jié)尾,用于注冊(cè)到config_item_type中 ?
struct configfs_attribute *my_attrs[] = { ? ?&myattr_read, &myattr_write, NULL, ? ?
}; ?
?????????config_item_type 結(jié)構(gòu)體中包含了 struct configfs_attribute 結(jié)構(gòu)體,?
/*config_item_type結(jié)構(gòu)體下,包含了configfs_attribute結(jié)構(gòu)體*/
struct configfs_attribute {const char *ca_name; ? ? //屬性文件的名字struct module *ca_owner; //屬性文件文件的所屬模塊umode_t ca_mode; ? ? ? ? //屬性文件訪(fǎng)問(wèn)權(quán)限//讀寫(xiě)方法的函數(shù)指針,具體功能需要自行實(shí)現(xiàn)。ssize_t (*show)(struct config_item *, char *);ssize_t (*store)(struct config_item *, const char *, size_t);?
};
// 定義一個(gè)結(jié)構(gòu)體myitem,它包含一個(gè)config_item成員和其他自定義成員
struct myitem { struct config_item item; // 內(nèi)嵌的config_item,用于與配置文件系統(tǒng)交互 int size; // 用于存儲(chǔ)數(shù)據(jù)的大小 void *addr; // 指向數(shù)據(jù)的指針
}; // 釋放myitem資源的函數(shù),當(dāng)config_item被釋放時(shí)調(diào)用
void myitem_release(struct config_item *item) { struct myitem *myitem = container_of(item, struct myitem, item); // 將config_item指針轉(zhuǎn)換回myitem指針 kfree(myitem); // 釋放myitem占用的內(nèi)存
} // 讀取myitem數(shù)據(jù)的回調(diào)函數(shù),用于configfs的只讀屬性
ssize_t myread_show(struct config_item *item, char *page) { struct myitem *myitem = container_of(item, struct myitem, item); memcpy(page, myitem->addr, myitem->size); // 將數(shù)據(jù)復(fù)制到page中 return myitem->size; // 返回復(fù)制的字節(jié)數(shù)
} // 寫(xiě)入數(shù)據(jù)到myitem的回調(diào)函數(shù),用于configfs的只寫(xiě)屬性
ssize_t mywrite_store(struct config_item *item, const char *page, size_t size) { struct myitem *myitem = container_of(item, struct myitem, item); myitem->addr = kmemdup(page, size, GFP_KERNEL); // 分配新內(nèi)存并復(fù)制數(shù)據(jù) myitem->size = size; // 更新數(shù)據(jù)大小 return size; // 返回寫(xiě)入的字節(jié)數(shù)
} // 使用CONFIGFS_ATTR_RO和CONFIGFS_ATTR_WO宏定義只讀和只寫(xiě)屬性
CONFIGFS_ATTR_RO(my, read); // 定義一個(gè)名為myattr_read的只讀屬性,關(guān)聯(lián)到myread_show函數(shù)
CONFIGFS_ATTR_WO(my, write); // 定義一個(gè)名為myattr_write的只寫(xiě)屬性,關(guān)聯(lián)到mywrite_store函數(shù) // 定義屬性數(shù)組,以NULL結(jié)尾,用于注冊(cè)到config_item_type中
struct configfs_attribute *my_attrs[] = { &myattr_read, &myattr_write, NULL,
}; // 定義myitem的操作集,包括釋放函數(shù)
struct configfs_item_operations myitem_ops = { .release = myitem_release,
}; // 定義mygroup的config_item_type,包括所有者、操作集和屬性數(shù)組
struct config_item_type mygroup_item_type = { .ct_owner = THIS_MODULE, // 模塊所有者 .ct_item_ops = &myitem_ops, // 操作集 .ct_attrs = my_attrs, // 屬性數(shù)組
}; // 初始化函數(shù),用于注冊(cè)mygroup到配置文件系統(tǒng)
static int myconfig_group_init(void) { // 假設(shè)myconfigfs_subsystem已定義并初始化 configfs_register_subsystem(&myconfigfs_subsystem); // 注冊(cè)子系統(tǒng) config_group_init_type_name(&mygroup, "mygroup", &mygroup_item_type); // 初始化組并設(shè)置名稱(chēng)和類(lèi)型 configfs_register_group(&myconfigfs_subsystem.su_group, &mygroup); // 注冊(cè)組到子系統(tǒng)中 return 0;
} // 清理函數(shù),用于注銷(xiāo)mygroup和子系統(tǒng)
static void myconfig_group_exit(void) { configfs_unregister_subsystem(&myconfigfs_subsystem); // 注銷(xiāo)子系統(tǒng)
}
????????在使用CONFIGFS_ATTR_RO和CONFIGFS_ATTR_WO宏時(shí),
????????它們會(huì)生成名為 myattr_read和 myattr_write的 configfs_attribute結(jié)構(gòu)體實(shí)例。
/*生成只讀屬性 名為[_name]attr_read的configfs_attribute實(shí)例*/
#define CONFIGFS_ATTR_RO(_name, _show) struct configfs_attribute configfs_attr_##_name = { .ca_owner = THIS_MODULE,.ca_name = __stringify(_name), .ca_mode = S_IRUGO,.show = _show,} /*生成只寫(xiě)屬性 名為[_name]attr_write的configfs_attribute實(shí)例*/
#define CONFIGFS_ATTR_WO(_name, _store) struct configfs_attribute configfs_attr_##_name = { .ca_owner = THIS_MODULE, .ca_name = __stringify(_name), .ca_mode = S_IWUSR,.store = _store,}
? ? ? ? 模塊編譯、加載后,在名為 myconfigfs的子系統(tǒng)目錄下,有 配置組 mygroup目錄,使用mkdir創(chuàng)建配置項(xiàng) test,可以看到配置項(xiàng)目錄 test下有生成的 屬性文件 read 和 write。

? ? ? ? 可以使用 以下命令對(duì)屬性文件進(jìn)行操作:?
cat read //讀echo 1 > write //寫(xiě)入
????????分別對(duì)屬性文件 read 和 屬性文件 write 進(jìn)行讀寫(xiě)操作后,
????????會(huì)分別執(zhí)行 myread_show 和 mywrite_store 函數(shù)。
第七十七章 實(shí)現(xiàn)多級(jí)目錄
? ? ? ? 完成了 configfs_group_operations 結(jié)構(gòu)體下的,.make_group函數(shù),
? ? ? ? .make_group函數(shù)優(yōu)先級(jí)比 .make_item優(yōu)先級(jí)高,因此編譯好驅(qū)動(dòng)裝載好,使用mkdir創(chuàng)建目錄的時(shí)候會(huì)調(diào)用 .make_group視為新建了 配置組。
// 創(chuàng)建配置組函數(shù)
struct config_group *mygroup_make_group(struct config_group *group, const char *name)
{struct mygroup *mygroup;printk("%s\n", __func__);mygroup = kzalloc(sizeof(*mygroup), GFP_KERNEL);config_group_init_type_name(&mygroup->group, name, &mygroup_type);return &mygroup->group;
};// 配置組操作結(jié)構(gòu)體
struct configfs_group_operations mygroup_ops = {.make_item = mygroup_make_item, //新建配置項(xiàng)函數(shù).drop_item = mygroup_delete_item, //刪除配置項(xiàng)函數(shù).make_group = mygroup_make_group, //新建配置組函數(shù)
};
第七十八章 移植設(shè)備樹(shù)插件驅(qū)動(dòng)
????????移植設(shè)備樹(shù)插件到 iTOP-RK3568 開(kāi)發(fā)板上。移植設(shè)備樹(shù)插件主要包括以下幾個(gè)步驟
????????1 配置內(nèi)核支持掛載 configfs 虛擬文件系統(tǒng)。
????????2 配置內(nèi)核支持設(shè)備樹(shù)插件(kernel 4.4及以上)
????????3 移植設(shè)備樹(shù)插件驅(qū)動(dòng)
78.1 掛載 configfs 虛擬文件系統(tǒng)
? ? ? ? 內(nèi)核源碼的menuconfig頁(yè)面,選擇支持configfs文件系統(tǒng)。

????????將編譯之后的內(nèi)核鏡像燒寫(xiě)到開(kāi)發(fā)板上,接著使用 mount 命令檢查 configfs 虛擬文件系是否掛載成功。
如果系統(tǒng)沒(méi)有自動(dòng)掛載 configfs 虛擬文件系統(tǒng),需要輸入以下命令掛載:
mount -t //掛載的類(lèi)型
configfs //configfs虛擬文件系統(tǒng)
none //不需要具體的設(shè)備與掛載點(diǎn)關(guān)聯(lián)
/sys/kernel/config //掛載的文件目錄,掛載好后可通過(guò)該目錄與configfs交互,來(lái)動(dòng)態(tài)配置內(nèi)核對(duì)象
78.2 配置內(nèi)核支持設(shè)備樹(shù)插件
? ? ? ? 源碼,menuconfig頁(yè)面,勾選支持 device tree overlays。


? ? ? ? 內(nèi)核編譯成功后,就可以開(kāi)始移植設(shè)備樹(shù)。
78.3 移植驅(qū)動(dòng)
????????我們沒(méi)有必要重復(fù)造輪子,github 上有大神編寫(xiě)好的設(shè)備樹(shù)插件驅(qū)動(dòng)。
? ? ? ? 假設(shè) dtbocfg.c 是設(shè)備樹(shù)插件驅(qū)動(dòng)源碼,我們將此驅(qū)動(dòng)編譯成驅(qū)動(dòng)模塊或編譯進(jìn)內(nèi)核即可。
????????好了,設(shè)備樹(shù)插件驅(qū)動(dòng)移植完畢,設(shè)備樹(shù)插件的使用參考前面的章節(jié)即可。
第七十九章 設(shè)備樹(shù)插件驅(qū)動(dòng)分析
????????dtbocfg.c 為設(shè)備樹(shù)插件驅(qū)動(dòng)文件。
????????在 dtbocfg_overlays_type 中實(shí)現(xiàn)了 ct_group_ops 下的 make_item 和 drop_item。
// 初始化dtbocfg模塊的函數(shù)
static int __init dtbocfg_module_init(void)
{ int retval = 0; // 打印初始化開(kāi)始信息,注意這里應(yīng)該使用__func__來(lái)獲取當(dāng)前函數(shù)名 pr_info("%s: Initialization started\n", __func__); // 初始化configfs的group config_group_init(&dtbocfg_root_subsys.su_group); config_group_init_type_name(&dtbocfg_overlay_group, "overlays", &dtbocfg_overlays_type); // 注冊(cè)子系統(tǒng)到configfs retval = configfs_register_subsystem(&dtbocfg_root_subsys); if (retval != 0) { pr_err("%s: Couldn't register subsystem\n", __func__); } // 注冊(cè)group到已注冊(cè)的子系統(tǒng) retval = configfs_register_group(&dtbocfg_root_subsys.su_group, &dtbocfg_overlay_group); if (retval != 0) { pr_err("%s: Couldn't register group\n", __func__); } // 打印初始化成功信息 pr_info("%s: Initialization OK\n", __func__); return 0;
}

? ? ? ? 在配置組下,命令行輸入 mkdir時(shí),如果沒(méi)有實(shí)現(xiàn) make_group,則會(huì)去執(zhí)行 make_item。
? ? ? ? make_item負(fù)責(zé)開(kāi)辟空間,并調(diào)用初始化函數(shù)去初始化 config_item。
? ? ? ? config_item有 config_item_type成員,
? ? ? ? config_item_type成員 有
????????config_item_operations結(jié)構(gòu)體、config_group_operations結(jié)構(gòu)體。
????????attribute結(jié)構(gòu)體。bin_attribute結(jié)構(gòu)體。

? ? ? ? attribute結(jié)構(gòu)體有 read_show,和 write_store函數(shù)可以綁定。
? ? ? ? bin_attribute結(jié)構(gòu)體有read 和write ?可以綁定。
// 定義一個(gè)二進(jìn)制屬性,用于dtbo(設(shè)備樹(shù)二進(jìn)制對(duì)象)的覆蓋
CONFIGFS_BIN_ATTR(dtbocfg_overlay_item, dtbo, NULL, 1024*1024); // 1MiB足夠大 // 定義一個(gè)普通屬性,用于顯示或設(shè)置狀態(tài)
CONFIGFS_ATTR(dtbocfg_overlay_item, status);
//定義一個(gè)status屬性,該屬性屬于 dtbocfg_overlay_item配置項(xiàng)/* dtbocfg_overlay_item_attr_dtbo 和 dtbocfg_overlay_item_attr_status 是宏展開(kāi)后生成的變量名。*/// 定義一個(gè)屬性結(jié)構(gòu)體數(shù)組,包含所有與dtbocfg_overlay_item相關(guān)的普通屬性
static struct configfs_attribute *dtbocfg_overlay_attrs[] = { &dtbocfg_overlay_item_attr_status, //將屬性,通過(guò)屬性數(shù)組,填充給 配置項(xiàng)NULL, // 數(shù)組結(jié)束標(biāo)志
}; // 定義一個(gè)結(jié)構(gòu)體數(shù)組,包含所有與dtbocfg_overlay_item相關(guān)的二進(jìn)制屬性
static struct configfs_bin_attribute *dtbocfg_overlay_bin_attrs[] = { &dtbocfg_overlay_item_attr_dtbo, //將屬性,通過(guò)屬性數(shù)組,填充給 配置項(xiàng)NULL, // 數(shù)組結(jié)束標(biāo)志
};
????????CONFIGFS_BIN_ATTR 用于定義二進(jìn)制屬性。
/*定義一個(gè)二進(jìn)制屬性*/
#define CONFIGFS_BIN_ATTR(_name, _mode, _read,_write,_size) //二進(jìn)制屬性可存儲(chǔ)的最大字節(jié)數(shù)
????????CONFIGFS_ATTR 宏用于定義普通屬性。
/*定義一個(gè)普通屬性*/
#define CONFIGFS_ATTR(_name, //名稱(chēng)_mode, //權(quán)限_show, //讀操作函數(shù)_store) //寫(xiě)操作函數(shù)
????????當(dāng) status 寫(xiě)入 1 的時(shí),會(huì)執(zhí)行 dtbocfg_overlay_item_create 函數(shù)。在這個(gè)函數(shù)中又去執(zhí)行了 of_overlay_fdt_apply 函數(shù)。
????????完善dtbocfg_overlay_item_create 函數(shù),可以執(zhí)行我們需要的邏輯。
static ssize_t dtbocfg_overlay_item_status_store(struct config_item *item, const char *buf, size_t count)
{ struct dtbocfg_overlay_item *overlay = container_of(item, struct dtbocfg_overlay_item, item); ssize_t status; unsigned long value; // 嘗試將字符串緩沖區(qū)轉(zhuǎn)換為無(wú)符號(hào)長(zhǎng)整型值 if (0 != (status = kstrtoul(buf, 10, &value))) { goto failed; // 轉(zhuǎn)換失敗,跳轉(zhuǎn)到錯(cuò)誤處理 } // 根據(jù)值決定是釋放還是創(chuàng)建覆蓋項(xiàng) if (value == 0) { if (overlay->id >= 0) { // 如果id有效,則釋放覆蓋項(xiàng) dtbocfg_overlay_item_release(overlay); } } else { if (overlay->id < 0) { dtbocfg_overlay_item_create(overlay); } } return count; // 假設(shè)成功寫(xiě)入全部數(shù)據(jù)
failed: return -EPERM; // 權(quán)限錯(cuò)誤或轉(zhuǎn)換失敗
}
????????設(shè)備樹(shù)插件(dtbo)里面的節(jié)點(diǎn)也要被轉(zhuǎn)換成 device_node,有的 device_node 也要被轉(zhuǎn)換成 platform_device。
????????不過(guò)在進(jìn)行轉(zhuǎn)換之前,of_overlay_fdt_apply 函數(shù)會(huì)先創(chuàng)建一個(gè)改變集。然后根據(jù)這個(gè)改變集去進(jìn)行修改。
????????改變集是為了方便修改和復(fù)原設(shè)備樹(shù)而設(shè)計(jì)的。
????????設(shè)備樹(shù)是靜態(tài)的,編譯加載后不易直接更改。改變集記錄了設(shè)備樹(shù)的修改操作,如增刪改節(jié)點(diǎn),允許運(yùn)行時(shí)動(dòng)態(tài)調(diào)整,無(wú)需改動(dòng)源文件。它提供了高層次抽象,簡(jiǎn)化描述變化,且可保存、傳遞、應(yīng)用于不同設(shè)備樹(shù)。同時(shí),改變集支持撤銷(xiāo)修改,恢復(fù)原始狀態(tài)。