第五十五讲 插件设备树
第五十五講 插件設備樹
文章目錄
- 第五十五講 插件設備樹
- 一、概述
- 1、概述
- 2、使用前提
- 3、編譯工具
 
- 二、插件設備樹實驗
- 1、環(huán)境準備
- 2、實驗
- 3、驗證實驗
 
- 附錄
- 驅動代碼
- led.c
- led.h
- makefile
 
 
 
一、概述
1、概述
插件設備樹是在Linux4.4后引入的。
傳統(tǒng)的設備樹是批量管理硬件資源,如果需要添加或者刪除硬件資源,需要找出已經在設備中使用的的設備樹源文件然后在源文件上修改。這樣當硬件很多的時候會造成不便。
設備樹插件可以理解為主設備樹的“補丁”它動態(tài)的加載到系統(tǒng)中,并被內核識別。設備樹插件擁有相對固定的格式,甚至可以認為它只是把設備節(jié)點加了一個“殼”編譯后內核能夠動態(tài)加載它。 我們只需要根據(jù)格式編寫即可,格式如下:
/dts-v1/; /plugin/;/{fragment@0 {target-path = "/";__overlay__ {/*在此添加要插入的節(jié)點*/};}; };| /plugin/; | 表示允許使用未定義的引用并記錄它們,設備樹插件中可以引用主設備樹中的節(jié)點, 而這些“引用的節(jié)點”對于設備樹插件來說就是未定義的,所以設備樹插件應該加上“/plugin/”。 | 
| target-path = “/”; | 指定設備樹插件的加載位置,默認我們加載到根節(jié)點下,既“target-path =“/”。 | 
| overlay { /在此添加要插入的節(jié)點/ }; | 我們要插入的設備及節(jié)點或者要引用(追加)的設備樹節(jié)點放在__overlay__ {…};內。 | 
2、使用前提
編譯內核需要打開的配置
- CONFIG_OF_OVERLAY = y
- CONFIG_OF_CONFIGFS = y
掛載ConfigFS
mount x /sys/kernel/config -t configfs
3、編譯工具
安裝:sudo apt install device-tree-compiler
編譯示例:dtc -I dts -O dtb -o overlay.dtbo overlay.dts
二、插件設備樹實驗
1、環(huán)境準備
-  安裝設備樹編譯工具 sudo apt install device-tree-compiler 軟件使用方法查詢man dtc 
2、實驗
-  編寫 overlay 代碼 /dts-v1/;/plugin/;/ {fragment@0{target-path = "/";__overlay__{gunzai_led{#address-cells = <1>;#size-cells = <1>;compatible = "fire,rgb_led";ranges;rgb_led_red@0x020C406C{reg = <0x020C406C 0x000000040x020E006C 0x000000040x020E02F8 0x000000040x0209C000 0x000000040x0209C004 0x00000004>;status = "okay";};rgb_led_green@0x020C4074{reg = <0x020C4074 0x000000040x020E01E0 0x000000040x020E046C 0x000000040x020A8000 0x000000040x020A8004 0x00000004>;status = "okay";};rgb_led_blue@0x020C4074{reg = <0x020C4074 0x000000040x020E01DC 0x000000040x020E0468 0x000000040x020A8000 0x000000040x020A8004 0x00000004>;status = "okay";};};};};};
-  編譯 overlay 設備樹 dtc -I dts -O dtb -o overlay.dtbo overlay.dts overlay.dtbo: Warning (ranges_format): /fragment@0/__overlay__/gunzai_led has empty "ranges" property but its #address-cells (1) differs from /fragment@0/__overlay__ (2) overlay.dtbo: Warning (unit_address_vs_reg): Node /fragment@0 has a unit name, but no reg property overlay.dtbo: Warning (unit_address_format): Node /fragment@0/__overlay__/gunzai_led/rgb_led_red@0x020C406C unit name should not have leading "0x" overlay.dtbo: Warning (unit_address_format): Node /fragment@0/__overlay__/gunzai_led/rgb_led_red@0x020C406C unit name should not have leading 0s overlay.dtbo: Warning (unit_address_format): Node /fragment@0/__overlay__/gunzai_led/rgb_led_green@0x020C4074 unit name should not have leading "0x" overlay.dtbo: Warning (unit_address_format): Node /fragment@0/__overlay__/gunzai_led/rgb_led_green@0x020C4074 unit name should not have leading 0s overlay.dtbo: Warning (unit_address_format): Node /fragment@0/__overlay__/gunzai_led/rgb_led_blue@0x020C4074 unit name should not have leading "0x" overlay.dtbo: Warning (unit_address_format): Node /fragment@0/__overlay__/gunzai_led/rgb_led_blue@0x020C4074 unit name should not have leading 0s overlay.dtbo: Warning (avoid_default_addr_size): Relying on default #address-cells value for /fragment@0/__overlay__/gunzai_led overlay.dtbo: Warning (avoid_default_addr_size): Relying on default #size-cells value for /fragment@0/__overlay__/gunzai_led
-  將 dtbo 復制到開發(fā)板上 通過連接虛擬機 sftp 用戶名@IP地址 示例:sftp dragon@192.168.3.41 進入代碼目錄cd 編譯好的 dtbo 目錄 下載 overlay.dtbo 到開發(fā)板 get overlay.dtbo 退出ftp exit 
-  進入開發(fā)板,找到剛才傳輸過來的文件 
-  將 dtbo 文件移到目錄 設備樹目錄下sudo cp overlay.dtbo /usr/lib/linux-image-4.19.35-imx6/overlays/ 
-  修改 uEnv.txt 文件 新增dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/overlay.dtbo #Docs: https://embed-linux-tutorial.readthedocs.io/zh_CN/latest/README.htmluname_r=4.19.35-imx6 #uuid= mmc_dtb=imx6ull-mmc-npi.dtb nand_dtb=imx6ull-nand-npi.dtb###U-Boot Overlays### ###Documentation: https://embed-linux-tutorial.readthedocs.io/zh_CN/latest/linux_driver/device_tree_rgb_led.html ###Master Enable enable_uboot_overlays=1 #overlay_startdtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-i2c1.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-i2c2.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-74hc595.dtbo #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-485r1.dtbo #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-485r2.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-adc1.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-hdmi.dtbo #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-cam.dtbo #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-btwifi.dtbo #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-can1.dtbo #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-can2.dtbo #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-dht11.dtbo #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-ecspi3.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-key.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-lcd.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-touch-capacitive-goodix.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-led.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-sound.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-uart2.dtbo #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-uart3.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-mpu6050.dtbo dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/overlay.dtbo#overlay_endcmdline=coherent_pool=1M net.ifnames=0 vt.global_cursor_default=0#In the event of edid real failures, uncomment this next line: #cmdline=coherent_pool=1M net.ifnames=0 vt.global_cursor_default=0 video=HDMI-A-1:1024x768@60e#Use an overlayfs on top of a read-only root filesystem: #cmdline=coherent_pool=1M net.ifnames=0 vt.global_cursor_default=0 overlayroot=tmpfs##flash_firmware=continued #flash_firmware=once
-  重啟開發(fā)板 sudo reboot 
-  登錄開發(fā)板 
-  查看設備 ls /proc/device-tree[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eAqmIQd4-1665421762193)(C:\Users\Dragon\Desktop\學習\學習筆記\野火linux學習筆記\第四期\第五十五講 插件設備樹.assets\image-20221011001922804.png)] 
-  試驗成功 
3、驗證實驗
將之前的 led 驅動程序拷貝到開發(fā)板(這里就不具體說明了)
加載驅動程序 sudo insmod rgb_led.ko
debian@npi:~/ftp$ sudo insmod rgb_led.ko [sudo] password for debian: Sorry, try again. [sudo] password for debian: [ 81.163173] rgb_led: loading out-of-tree module taints kernel. [ 81.175548] <1> path is shadowrain_led [ 81.179411] DriverState is 0查看 dev 設備加載是否成功
ls /dev/
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LOQ6aTjD-1665421762200)(C:\Users\Dragon\Desktop\學習\學習筆記\野火linux學習筆記\第四期\第五十五講 插件設備樹.assets\image-20221011010527408.png)]
點燈
綠燈
sudo sh -c "echo 'green on'>/dev/shadowrain_led"
其他的燈自己點哈,就不演示了
附錄
驅動代碼
led.c
/** @LastEditors: 夜雨* @Date: 2022-03-17 20:56:32* @LastEditTime: 2022-03-19 13:15:37* @FilePath: \code\kernel\012rgb_led\rgb_led.c*/#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/platform_device.h>#include "rgb_led.h"int rgbLedOpen (struct inode *node, struct file *file){printk("\n open form driver \n");return 0;}ssize_t rgbLedWrite (struct file *file, const char __user *usr, size_t size, loff_t *loff){char lRecvBuf[10] = {0};int lRegData = 0;printk("<1> Led write");if(size >= 10){printk("<1> size error!");return -1;}if(copy_from_user(lRecvBuf, usr, size) < 0){printk("<1> copy error!");return -1;}printk("<1> recv is %s", lRecvBuf);if(strstr(lRecvBuf, "red on") != NULL){printk("red on");lRegData = ioread32(gRGBLedStr[0].virtual_DR);lRegData &= ~(0x01 << 4);iowrite32(lRegData, gRGBLedStr[0].virtual_DR);}else if(strstr(lRecvBuf, "red off") != NULL){lRegData = ioread32(gRGBLedStr[0].virtual_DR);lRegData |= (0x01 << 4);iowrite32(lRegData, gRGBLedStr[0].virtual_DR);}else if(strstr(lRecvBuf, "green on") != NULL){lRegData = ioread32(gRGBLedStr[1].virtual_DR);lRegData &= ~(0x01 << 20);iowrite32(lRegData, gRGBLedStr[1].virtual_DR);}else if(strstr(lRecvBuf, "green off") != NULL){lRegData = ioread32(gRGBLedStr[1].virtual_DR);lRegData |= (0x01 << 20);iowrite32(lRegData, gRGBLedStr[1].virtual_DR);}else if(strstr(lRecvBuf, "blue on") != NULL){lRegData = ioread32(gRGBLedStr[2].virtual_DR);lRegData &= ~(0x01 << 19);iowrite32(lRegData, gRGBLedStr[2].virtual_DR);}else if(strstr(lRecvBuf, "blue off") != NULL){lRegData = ioread32(gRGBLedStr[2].virtual_DR);lRegData |= (0x01 << 19);iowrite32(lRegData, gRGBLedStr[2].virtual_DR);}else{printk("error data %s", lRecvBuf);lRegData = ioread32(gRGBLedStr[0].virtual_DR);lRegData |= (0x01 << 4);iowrite32(lRegData, gRGBLedStr[0].virtual_DR);lRegData = ioread32(gRGBLedStr[1].virtual_DR);lRegData |= (0x01 << 20);iowrite32(lRegData, gRGBLedStr[1].virtual_DR);lRegData = ioread32(gRGBLedStr[2].virtual_DR);lRegData |= (0x01 << 19);iowrite32(lRegData, gRGBLedStr[2].virtual_DR);}return size;}struct cdev gRGBLedCdev = {.owner = THIS_MODULE,};struct file_operations gRGBLedFp = {.open = rgbLedOpen,.write = rgbLedWrite,};static int rgbProbe(struct platform_device *pdv){struct device_node *lRGBLedDeviceNode;int lRegData = 0;/*查找設備樹節(jié)點*/printk("<1> path is "DEVICE_NAME"");lRGBLedDeviceNode = of_find_node_by_path("/"DEVICE_NAME"");if(lRGBLedDeviceNode == NULL){printk("<1> Find node by path failed! \n");return -1;}/*獲取rgb_led節(jié)點的燈子節(jié)點*/gRGBLedStr[0].device_node = of_find_node_by_name(lRGBLedDeviceNode, "rgb_led_red");if(gRGBLedStr[0].device_node == NULL){return -1;}/*獲取 reg 屬性并轉化為虛擬地址*/gRGBLedStr[0].virtual_CCM_CCGR = of_iomap(gRGBLedStr[0].device_node, 0);gRGBLedStr[0].virtual_IOMUXC_SW_MUX_CTL_PAD = of_iomap(gRGBLedStr[0].device_node, 1);gRGBLedStr[0].virtual_IOMUXC_SW_PAD_CTL_PAD = of_iomap(gRGBLedStr[0].device_node, 2);gRGBLedStr[0].virtual_DR = of_iomap(gRGBLedStr[0].device_node, 3);gRGBLedStr[0].virtual_GDIR = of_iomap(gRGBLedStr[0].device_node, 4);// 初始化rgb端口/*---------------------------------------------------------------------------------*/lRegData = ioread32(gRGBLedStr[0].virtual_CCM_CCGR);iowrite32(lRegData | (3 << 26), gRGBLedStr[0].virtual_CCM_CCGR);lRegData = ioread32(gRGBLedStr[0].virtual_IOMUXC_SW_MUX_CTL_PAD);lRegData &= ~(0xf << 0);lRegData |= (0x05 << 0);iowrite32(lRegData, gRGBLedStr[0].virtual_IOMUXC_SW_MUX_CTL_PAD);lRegData = ioread32(gRGBLedStr[0].virtual_IOMUXC_SW_PAD_CTL_PAD);lRegData = (0x10B0);iowrite32(lRegData, gRGBLedStr[0].virtual_IOMUXC_SW_PAD_CTL_PAD);lRegData = ioread32(gRGBLedStr[0].virtual_GDIR);lRegData |= (0x01 << 4);iowrite32(lRegData, gRGBLedStr[0].virtual_GDIR);lRegData = ioread32(gRGBLedStr[0].virtual_DR);lRegData |= (0x01 << 4);iowrite32(lRegData, gRGBLedStr[0].virtual_DR);/*---------------------------------------------------------------------------------*/gRGBLedStr[1].device_node = of_find_node_by_name(lRGBLedDeviceNode, "rgb_led_green");if(gRGBLedStr[1].device_node == NULL){return -1;}/*獲取 reg 屬性并轉化為虛擬地址*/gRGBLedStr[1].virtual_CCM_CCGR = of_iomap(gRGBLedStr[1].device_node, 0);gRGBLedStr[1].virtual_IOMUXC_SW_MUX_CTL_PAD = of_iomap(gRGBLedStr[1].device_node, 1);gRGBLedStr[1].virtual_IOMUXC_SW_PAD_CTL_PAD = of_iomap(gRGBLedStr[1].device_node, 2);gRGBLedStr[1].virtual_DR = of_iomap(gRGBLedStr[1].device_node, 3);gRGBLedStr[1].virtual_GDIR = of_iomap(gRGBLedStr[1].device_node, 4);lRegData = ioread32(gRGBLedStr[1].virtual_CCM_CCGR);lRegData |= (0x03 << 12);iowrite32(lRegData, gRGBLedStr[1].virtual_CCM_CCGR);lRegData = ioread32(gRGBLedStr[1].virtual_IOMUXC_SW_MUX_CTL_PAD);lRegData &= ~(0xf << 0);lRegData |= (0x05 << 0);iowrite32(lRegData, gRGBLedStr[1].virtual_IOMUXC_SW_MUX_CTL_PAD);lRegData = ioread32(gRGBLedStr[1].virtual_IOMUXC_SW_PAD_CTL_PAD);lRegData = (0x10B0);iowrite32(lRegData, gRGBLedStr[1].virtual_IOMUXC_SW_PAD_CTL_PAD);lRegData = ioread32(gRGBLedStr[1].virtual_GDIR);lRegData |= (0x01 << 20);iowrite32(lRegData, gRGBLedStr[1].virtual_GDIR);lRegData = ioread32(gRGBLedStr[1].virtual_DR);lRegData |= (0x01 << 20);iowrite32(lRegData, gRGBLedStr[1].virtual_DR);/*---------------------------------------------------------------------------------*/gRGBLedStr[2].device_node = of_find_node_by_name(lRGBLedDeviceNode,"rgb_led_blue");if (gRGBLedStr[2].device_node == NULL){printk(KERN_ERR "\n get rgb_led_blue_device_node failed ! \n");return -1;}/*獲取 reg 屬性并轉化為虛擬地址*/gRGBLedStr[2].virtual_CCM_CCGR = of_iomap(gRGBLedStr[2].device_node, 0);gRGBLedStr[2].virtual_IOMUXC_SW_MUX_CTL_PAD = of_iomap(gRGBLedStr[2].device_node, 1);gRGBLedStr[2].virtual_IOMUXC_SW_PAD_CTL_PAD = of_iomap(gRGBLedStr[2].device_node, 2);gRGBLedStr[2].virtual_DR = of_iomap(gRGBLedStr[2].device_node, 3);gRGBLedStr[2].virtual_GDIR = of_iomap(gRGBLedStr[2].device_node, 4);/*初始化藍燈*/lRegData = ioread32(gRGBLedStr[2].virtual_CCM_CCGR);lRegData |= (0x03 << 12);iowrite32(lRegData, gRGBLedStr[2].virtual_CCM_CCGR); //開啟時鐘lRegData = ioread32(gRGBLedStr[2].virtual_IOMUXC_SW_MUX_CTL_PAD);lRegData &= ~(0xf << 0);lRegData |= (0x05 << 0);iowrite32(lRegData, gRGBLedStr[2].virtual_IOMUXC_SW_MUX_CTL_PAD); //設置復用功能lRegData = ioread32(gRGBLedStr[2].virtual_IOMUXC_SW_PAD_CTL_PAD);lRegData = (0x10B0);iowrite32(lRegData, gRGBLedStr[2].virtual_IOMUXC_SW_PAD_CTL_PAD); //設置PAD 屬性lRegData = ioread32(gRGBLedStr[2].virtual_GDIR);lRegData |= (0x01 << 19);iowrite32(lRegData, gRGBLedStr[2].virtual_GDIR); //設置GPIO4_IO19 為輸出模式lRegData = ioread32(gRGBLedStr[2].virtual_DR);lRegData |= (0x01 << 19);iowrite32(lRegData, gRGBLedStr[2].virtual_DR); //設置 GPIO4_IO19 默認輸出高電平if( alloc_chrdev_region(&rgbDev, 0, 1, DEVICE_NAME) < 0){printk("<1> alloc_chrdev_region failed \n");return -1;} cdev_init(&gRGBLedCdev, &gRGBLedFp);cdev_add(&gRGBLedCdev, rgbDev, 1);rgbClass = class_create(THIS_MODULE, DEVICE_NAME);device_create(rgbClass, NULL, rgbDev, NULL, DEVICE_NAME);return 0;}static const struct of_device_id rgbLed[] = {{.compatible = "fire,rgb_led"},{/* sentinel */}};struct platform_driver rgbPlatformDriver = {.probe = rgbProbe,.driver = {.name = "rgb_led_platform",.owner = THIS_MODULE,.of_match_table = rgbLed,},};static __init int RGBInit(void){int driverState;driverState = platform_driver_register(&rgbPlatformDriver);printk(KERN_ALERT "\tDriverState is %d\n", driverState);return 0;}static __exit void RGBExit(void){}module_init(RGBInit);module_exit(RGBExit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Yeyu");MODULE_DESCRIPTION("RGBModule");MODULE_ALIAS("RGBModule");led.h
/** @LastEditors: 夜雨* @Date: 2022-03-17 22:41:17* @LastEditTime: 2022-03-19 12:23:54* @FilePath: \code\kernel\012rgb_led\rgb_led.h*/#include <linux/of.h>#include <asm/io.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/kernel.h>#include <linux/uaccess.h>#include <linux/string.h>#include <linux/of_gpio.h>#include <linux/io.h>#include <linux/of_address.h>#define DEVICE_NAME "shadowrain_led"typedef struct {struct device_node *device_node;void __iomem *virtual_CCM_CCGR;void __iomem *virtual_IOMUXC_SW_MUX_CTL_PAD;void __iomem *virtual_IOMUXC_SW_PAD_CTL_PAD;void __iomem *virtual_DR;void __iomem *virtual_GDIR;}rgbLedStr;dev_t rgbDev;struct class * rgbClass;rgbLedStr gRGBLedStr[3];makefile
KERNEL_DIR=../../ebf_linux_kernel/build_image/build/ARCH=armCROSS_COMPILE=arm-linux-gnueabihf-export ARCH CROSS_COMPILEobj-m := rgb_led.oall:$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules.PHONE:clean copyclean:$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean copy:sudo cp *.ko /home/dragon/nfsshare參考資料
EBF_6ULL開發(fā)板快速使用手冊
設備樹
總結
以上是生活随笔為你收集整理的第五十五讲 插件设备树的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: English-国内三大翻译证书比较
- 下一篇: 微信新功能,拍一拍的背后,暗藏着商机
