东营房地产网站建设,工厂erp管理系统软件,锡盟建设工程网站,深圳外企公司排名目录 一、设备树简介
二、设备树源码
三、获取设备树信息
1、增加设备节点
2、内核编译设备树
3、替换设备树文件
4、查看设备树节点
5、在驱动中获取节点的属性
6、编译驱动模块
7、加载模块 一、设备树简介
设备树的作用是描述一个硬件平台的硬件资源。这个“设备树…目录 一、设备树简介
二、设备树源码
三、获取设备树信息
1、增加设备节点
2、内核编译设备树
3、替换设备树文件
4、查看设备树节点
5、在驱动中获取节点的属性
6、编译驱动模块
7、加载模块 一、设备树简介
设备树的作用是描述一个硬件平台的硬件资源。这个“设备树”可以被bootloaderuboot传递到内核内核可以从设备树中获取硬件信息。
几个常见的文档缩写符号
DTS是指.dts格式的文件是一种ASII文本格式的设备树描述设备树源码一般一个.dts文件对应一个硬件平台。DTC是指编译设备树源码的工具一般情况下需要手动安装。DTB是设备树源码编译生成的文件类似于C语言中的“.bin”文件可以被硬件识别。
二、设备树源码 文件定位内核源码/arch/arm/boot/dts/imx6ull-mmc-npi.dts /*----------------------头文件--------------------------*/
#include dt-bindings/input/input.h
#include imx6ull.dtsi/*----------------------中间部分--------------------------*// {model Embedfire i.MX6ULL Board;compatible fsl,imx6ull-14x14-evk, fsl,imx6ull;aliases {pwm0 pwm1;pwm1 pwm2;pwm2 pwm3;pwm3 pwm4;};chosen {stdout-path uart1;};memory {reg 0x80000000 0x20000000;};reserved-memory {#address-cells 1;#size-cells 1;ranges;linux,cma {compatible shared-dma-pool;reusable;size 0x14000000;linux,cma-default;};};/*-------------以下内容省略--------------------*/
};
/*------------------追加部分--------------------------*/
cpu0 {/*dc-supply reg_gpio_dvfs;*/clock-frequency 800000000;
};clks {assigned-clocks clks IMX6UL_CLK_PLL4_AUDIO_DIV;assigned-clock-rates 786432000;
};/*------------------以下内容省略--------------------------*/
文件位置内核源码/arch/arm/boot/dts/imx6ull.dtsi
cpus {#address-cells 1;#size-cells 0;cpu0: cpu0 {compatible arm,cortex-a7;device_type cpu;/*----------以下内容省略-----------------*/}}
设备树源码分为3部分
第1-2行头文件。头文件的引用有两种一种为“.h”文件一种为“.dtsi文件”。imx6ull.dtsi由NXP官方提供是一个imx6ull平台“共用”的设备树文件。中间部分设备树节点。由{}组成每一个设备树都只有一个“/”节点。追加部分的意思是像原有的节点中追加内容。
三、获取设备树信息
1、增加设备节点 在ebf_linux_kernel/arch/arm/boot/dts/imx6ull-mmc-npi.dts这个设备树中尝试增加一个新的设备节点。
led_test{#address-cells 1;#size-cells 1;rgb_led_red0x0209C000{compatible fire,rgb_led_red;reg 0x0209C000 0x00000020;status okay;};
};
以上节点中#address-cells 1#size-cells 1意味着它的子节点的reg属性里的数据是“地址”、“长度”交替的。第二部分led的子节点定了三种属性分别为compatible、reg、status。由于在父节点设置了#address-cells 1#size-cells 1所以0x0209C000表示的是地址这里填写的GPIO1控制寄存器的首地址0x00000020表示的是地址长度。
2、内核编译设备树 编译内核时会自自动编译设备树到那时编译内核非常耗时所以可以用以下命令只编译设备树。
make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- npi_v7_defconfig
make ARCHarm -j4 CROSS_COMPILEarm-linux-gnueabihf- dtbs
执行结果如下 编译成功后生成的设备树文件.dtb位于源码目录下/arch/arm/boot/dts/,文件名为“imx6ull-mmc-npi.dtb”
3、替换设备树文件 将上位机上生成的.dtb文件替换掉开发板中的.dtb文件替换/usr/lib/linux-image-4.19.35-imx6/imx6ull-mmc-npi.dtb。
uboot在启动的时候负责将该目录的设备我呢见加载到内存供内核使用。
4、查看设备树节点 设备树的设备节点在文件系统中有与之相对应的文件位于/proc/device-tree目录进入目录查看如下 接着进入led_test文件夹可以发现led_test节点中定义的属性以及它的子节点如下所示。 在节点属性中多了一个name我们在led节点中并没有定义name属性这是自己生成的保存节点名。
这里的属性是一个文件而子系欸但是一个文件夹再次进入“rgb_led_red0x0209C000”文件夹。里面有compatible name regs status四个属性文件。我们可以使用“cat”命令查看这些属性文件如下所示 至此成功的在设备树中添加了一个名为“led_test”的节点。
5、在驱动中获取节点的属性 实验是一个简化的字符设备驱动在驱动中没有实际操作硬件仅在.open函数中调用of函数获取设备树节点中的属性获取成功后打印获取到的内容。 代码get_dts_info.c #include linux/init.h
#include linux/module.h
#include linux/fs.h
#include linux/cdev.h
#include linux/uaccess.h#include linux/types.h
#include linux/kernel.h
#include linux/delay.h
#include linux/ide.h
#include linux/errno.h
#include linux/gpio.h
#include asm/mach/map.h
#include asm/io.h#include linux/of.h
#include linux/of_address.h#define DEV_NAME get_dts_info
#define DEV_CNT (1)
//定义字符设备的设备号
static dev_t led_devno;
//定义字符设备结构体chr_dev
static struct cdev led_chr_dev;
//创建类
struct class *led_chrdev_class;struct device_node *led_device_node; //led的设备树节点
struct device_node *rgb_led_red_device_node; //rgb_led_red 红灯节点
struct property *rgb_led_red_property; //定义属性结构体指针
int size 0 ;
unsigned int out_values[18]; //保存读取得到的REG 属性值/*.open 函数*/
static int led_chr_dev_open(struct inode *inode, struct file *filp)
{int error_status -1;printk(\n open form device \n);/*获取DTS属性信息*/led_device_node of_find_node_by_path(/led_test);if(led_device_node NULL){printk(KERN_ALERT \n get led_device_node failed ! \n);return -1;}/*根据 led_device_node 设备节点结构体输出节点的基本信息*/printk(KERN_ALERT name: %s,led_device_node-name); //输出节点名printk(KERN_ALERT child name: %s,led_device_node-child-name); //输出子节点的节点名/*获取 rgb_led_red_device_node 的子节点*/ rgb_led_red_device_node of_get_next_child(led_device_node,NULL); if(rgb_led_red_device_node NULL){printk(KERN_ALERT \n get rgb_led_red_device_node failed ! \n);return -1;}printk(KERN_ALERT name: %s,rgb_led_red_device_node-name); //输出节点名printk(KERN_ALERT parent name: %s,rgb_led_red_device_node-parent-name); //输出父节点的节点名/*获取 rgb_led_red_device_node 节点 的compatible 属性 */ rgb_led_red_property of_find_property(rgb_led_red_device_node,compatible,size);if(rgb_led_red_property NULL){printk(KERN_ALERT \n get rgb_led_red_property failed ! \n);return -1;}printk(KERN_ALERT size : %d,size); //实际读取得到的长度printk(KERN_ALERT name: %s,rgb_led_red_property-name); //输出属性名printk(KERN_ALERT length: %d,rgb_led_red_property-length); //输出属性长度printk(KERN_ALERT value : %s,(char*)rgb_led_red_property-value); //属性值/*获取 reg 地址属性*/error_status of_property_read_u32_array(rgb_led_red_device_node,reg,out_values, 2);if(error_status ! 0){printk(KERN_ALERT \n get out_values failed ! \n);return -1;}printk(KERN_ALERT0x%08X , out_values[0]);printk(KERN_ALERT0x%08X , out_values[1]);return 0;
}/*.release 函数*/
static int led_chr_dev_release(struct inode *inode, struct file *filp)
{printk(\nrelease\n);return 0;
}/*字符设备操作函数集*/
static struct file_operations led_chr_dev_fops
{.owner THIS_MODULE,.open led_chr_dev_open,.release led_chr_dev_release,
};/*
*驱动初始化函数
*/
static int __init led_chrdev_init(void)
{int ret 0;printk(led chrdev init\n);//第一步//采用动态分配的方式获取设备编号次设备号为0//设备名称为EmbedCharDev可通过命令cat /proc/devices查看//DEV_CNT为1当前只申请一个设备编号ret alloc_chrdev_region(led_devno, 0, DEV_CNT, DEV_NAME);if(ret 0){printk(fail to alloc led_devno\n);goto alloc_err;}led_chrdev_class class_create(THIS_MODULE, led_chrdev);//第二步//关联字符设备结构体cdev与文件操作结构体file_operationscdev_init(led_chr_dev, led_chr_dev_fops);//第三步//添加设备至cdev_map散列表中ret cdev_add(led_chr_dev, led_devno, DEV_CNT);if(ret 0){printk(fail to add cdev\n);goto add_err;}//创建设备device_create(led_chrdev_class, NULL, led_devno, NULL,DEV_NAME);return 0;add_err://添加设备失败时需要注销设备号unregister_chrdev_region(led_devno, DEV_CNT);
alloc_err:return ret;
}/*
*驱动注销函数
*/
static void __exit led_chrdev_exit(void)
{printk(chrdev exit\n);device_destroy(led_chrdev_class, led_devno); //清除设备cdev_del(led_chr_dev); //清除设备号unregister_chrdev_region(led_devno, DEV_CNT); //取消注册字符设备class_destroy(led_chrdev_class); //清除类
}module_init(led_chrdev_init);
module_exit(led_chrdev_exit);MODULE_LICENSE(GPL); 使用“of_find_node_by_path”函数勋章“led_test”设备节点。参数是“led_test”的设备节点路径。获取成功后得到的是一个device_node类型的结构体指针然后就可以从这个结构体中获得想要的数据。获取完整的属性可能还需要使用其他of函数。获取rgb_led_red_device_node的子节点在上一部分中获取的“led”节点的“设备节点结构体”这里就可以使用“of_get_next_child”函数获取它的子节点。也可以从“led”节点的“设备节点结构体”中直接读取它的第一个子节点。使用“of_find_property”函数获取“rgb_led_red”节点的“compatiable”属性使用“of_property_read_u32_array”函数获取reg属性
6、编译驱动模块 命令make 生成get_dts_info.ko驱动模块
7、加载模块 将ko文件拷贝到开发板使用insmod安装模块然后可以在/dev/目录找到get_dts_info 向模块中随便输入一个字符 sudo sh -c echo 1 /dev/get_dts_info 可以看出已经成功打印出led节点属性和rgb_led_red字节点属性。