网站开发使用什么技术,地图网站怎么做的,百度搜索搜不到网站,北京seo外包# 前置知识 在图中#xff0c;树的主干就是系统总线#xff0c; IIC 控制器、 SPI 控制器等都是接到系统主线上的分支。其中 IIC1 上接了 AT24C02这个 IIC 设备#xff0c; DTS 文件的主要功能就是按照图所示的结构来描述板子上的设备信息。
1. Device格式
DTS文件格式
…# 前置知识 在图中树的主干就是系统总线 IIC 控制器、 SPI 控制器等都是接到系统主线上的分支。其中 IIC1 上接了 AT24C02这个 IIC 设备 DTS 文件的主要功能就是按照图所示的结构来描述板子上的设备信息。
1. Device格式
DTS文件格式
/dts-v1/; // 表示版本
[memory reservations] // 格式为: /memreserve/ address length;
/ {[property definitions][child nodes]
};
node格式
[label:] node-name[unit-address] {[properties definitions][child nodes]
}; label标号可以省略可以使用label来引用node node-name节点的名称长度应该为 1-31 个字符命名应该以小写或者大写字母开头 unit-address表示设备地址或者寄存器首地址 properties 简单地说 properties 就是“namevalue” value 有多种取值方式 Property 格式 1: [label:] property-name value; Property 格式 2(没有值): [label:] property-name; Property 取值只有 3 种: arrays of cells(1 个或多个 32 位数据, 64 位数据使用 2 个 32 位数据表示 eginterrupts 17 0xc;), string(字符串egcompatible simple-bus), bytestring(1 个或多个字节eglocal-mac-address [00 00 12 34 56 78]; // 每个 byte 使用 2 个 16 进制数来表示) 2. 标准属性
2.1 compatible
compatible 属性值由 string list 组成定义了设备的兼容性推荐格式为manufacturer,modelmanufacturer 描述了生产商model 描述了型号
compatible fsl,imx6ull-14x14-evk, fsl,imx6ull; 根节点下 compatible 属性用来选择哪一个“ machine desc”一个内核可以支持 machine A也支持 machine B内核启动后会根据根节点的compatible 属性找到对应的 machine desc 结构体执行其中的初始化函数
compatible fsl,imx6ul-evk-wm8960,fsl,imx-audio-wm8960 设备节点下的compatible属性是用来匹配驱动程序的一般驱动程序文件都会有一个 OF 匹配表此 OF 匹配表保存着一些 compatible 值如果设备节点的 compatible 属性值核 OF 匹配表中的任何一个值相等那么就表示这个设备可以使用这个驱动。如下
static const struct of_device_id imx_wm8960_dt_ids[] {{ .compatible fsl,imx-audio-wm8960, },{ /* sentinel */ }
};
2.2 model
model 属性值是一个 string指明了设备的厂商和型号推荐格式为manufacturer,model。
model Freescale i.MX6 ULL 14x14 EVK Board;
2.3 phandle
phandle 属性值是一个 u32为设备树中唯一的节点指定一个数字标识符用于其它节点指明关系。
2.4 status
status 属性值是一个 string表示设备的运行状态可用值如下表 2.5 #address-cells 和 #size-cells #address-cells and #size-cells 属性值是一个 u32可以用在任何拥有子节点的设备中并描述子设备节点应该如何寻址。 #address-cells属性定义子节点 reg 属性中地址字段所占用的字长也就是占用 u32 单元格的数量。 #size-cells属性定义子节点 reg 属性值的长度所占用的 u32 单元格的数量。
2.6 reg
reg 属性值是一个 prop-encoded-array用来描述设备地址空间资源信息一般是某个外设的寄存器地址范围信息包括起始地址和地址长度。
reg address1 length1 address2 length2 address3 length3……
2.7 name(过时了建议不用) 它的值是字符串用来表示节点的名字。在跟 platform_driver 匹配时优先级最低。 compatible 属性在匹配过程中优先级最高
3. 常用节点
3.1 根节点 树是由树根开始的在设备树中称之为根节点路径为/根节点不需要节点名称所有子节点都是挂在根节点上的可以看到最简单的根节点如下
/ {};
根节点的属性有 3.2 aliases aliases 节点用来定义别名为了内核方便访问节点。
aliases {can0 flexcan1;can1 flexcan2;ethernet0 fec1;ethernet1 fec2;gpio0 gpio1;gpio1 gpio2;gpio2 gpio3;gpio3 gpio4;gpio4 gpio5;i2c0 i2c1;i2c1 i2c2;i2c2 i2c3;i2c3 i2c4;mmc0 usdhc1;mmc1 usdhc2;serial0 uart1;serial1 uart2;serial2 uart3;serial3 uart4;serial4 uart5;serial5 uart6;serial6 uart7;serial7 uart8;spi0 ecspi1;spi1 ecspi2;spi2 ecspi3;spi3 ecspi4;usbphy0 usbphy1;usbphy1 usbphy2;}; 3.3 chosen chosen 节点是为了uboot 向 Linux 内核传递数据重点是 bootargs 参数一般.dts 文件中 chosen 节点通常为空或者内容很少。
chosen {stdout-path uart1;};
3.4 CPU 一般不需要我们设置在 dtsi 文件中都定义好了
cpus {#address-cells 1;#size-cells 0;cpu0: cpu0 {.......}
};
3.5 memory 芯片厂家不可能事先确定你的板子使用多大的内存所以 memory 节点需要板厂设置比如
memory {reg 0x80000000 0x20000000;};
4. OF 操作函数
of.h // 提供设备树的一般处理函数,
// 比如 of_property_read_u32(读取某个属性的 u32 值),
// of_get_child_count(获取某个 device_node 的子节点数)
of_address.h // 地址相关的函数,
// 比如 of_get_address(获得 reg 属性中的 addr, size 值)
// of_match_device (从 matches 数组中取出与当前设备最匹配的一项)
of_dma.h // 设备树中 DMA 相关属性的函数
of_gpio.h // GPIO 相关的函数
of_graph.h // GPU 相关驱动中用到的函数, 从设备树中获得 GPU 信息
of_iommu.h // 很少用到
of_irq.h // 中断相关的函数
of_mdio.h // MDIO (Ethernet PHY) API
of_net.h // OF helpers for network devices.
of_pci.h // PCI 相关函数
of_pdt.h // 很少用到
of_reserved_mem.h // reserved_mem 的相关函数
4.1 查找节点
通过节点名字查找节点
extern struct device_node *of_find_node_by_name(struct device_node *from,const char *name);
参数意义如下
from开始查找的节点NULL 表示根节点name要查找的节点名称
返回值为找到的节点NULL 为查找失败。
通过节点类型查找节点
extern struct device_node *of_find_node_by_type(struct device_node *from,const char *type); type 参数指定要查看节点对应的 type 字符串也就是 device_type 属性值。
通过 device_type 和 compatible 查找节点
extern struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compat); 通过 of_device_id 匹配表来查找节点
extern 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); 通过路径来查找节点
static inline struct device_node *of_find_node_by_path(const char *path)
{return of_find_node_opts_by_path(path, NULL);
}
4.2 获取父子节点
获取父节点
extern struct device_node *of_get_parent(const struct device_node *node);
迭代查找子节点
extern struct device_node *of_get_next_child(const struct device_node *node,struct device_node *prev);
4.3 提取属性值
查找指定节点的属性
extern struct property *of_find_property(const struct device_node *np,const char *name,int *lenp);
参数 name 指属性名字lenp 指属性值的字节数。
获取属性中元素的数量
extern int of_property_count_elems_of_size(const struct device_node *np,const char *propname, int elem_size); 参数 propname 是需要统计元素数量的属性名字参数 elem_size 是元素的长度。 返回值是获取到的属性元素数量。 eg. reg 属性的值通常是一个数组使用此函数可以获取的数组的大小。 从属性中获取指定索引的 u32 类型数据值
extern int of_property_read_u32_index(const struct device_node *np,const char *propname,u32 index, u32 *out_value); 参数 out_value 用来返回获取到的值。 返回值用来表示是否获取成功。 从属性中获取数组值
extern int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz);
extern int of_property_read_u16_array(const struct device_node *np,const char *propname, u16 *out_values, size_t sz);
extern int of_property_read_u32_array(const struct device_node *np,const char *propname,u32 *out_values,size_t sz);
extern int of_property_read_u64_array(const struct device_node *np,const char *propname,u64 *out_values,size_t sz); eg. reg 属性的值通常是一个数组使用这个函数可以一次读取出一个数组也就是 reg 属性的全部值。
从属性中获取布尔值/整形值
/*** of_property_read_bool - Findfrom a property* np: device node from which the property value is to be read.* propname: name of the property to be searched.** Search for a property in a device node.* Returns true if the property exist false otherwise.*/
static inline bool of_property_read_bool(const struct device_node *np,const char *propname)
{struct property *prop of_find_property(np, propname, NULL);return prop ? true : false;
}static inline int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value)
{return of_property_read_u8_array(np, propname, out_value, 1);
}static inline int of_property_read_u16(const struct device_node *np,const char *propname,u16 *out_value)
{return of_property_read_u16_array(np, propname, out_value, 1);
}static inline int of_property_read_u32(const struct device_node *np,const char *propname,u32 *out_value)
{return of_property_read_u32_array(np, propname, out_value, 1);
}static inline int of_property_read_s32(const struct device_node *np,const char *propname,s32 *out_value)
{return of_property_read_u32(np, propname, (u32*) out_value);
} 从属性中获取字符串
extern int of_property_read_string(struct device_node *np,const char *propname,const char **out_string);
获取#address-cells 和#size-cells 属性值
extern int of_n_addr_cells(struct device_node *np);
extern int of_n_size_cells(struct device_node *np);
# 驱动示例 atk-led{#address-cells 1;#size-cells 1;compatible atk,led;status okay;reg 0x20C406C 40x20E0068 4 0x20E02F4 4 0x209C000 4;};
#include linux/console.h
#include linux/dma-mapping.h
#include linux/init.h
#include linux/ipu-v3.h
#include linux/module.h
#include linux/mxcfb.h
#include linux/mxc_v4l2.h
#include linux/platform_device.h
#include linux/sched.h
#include linux/types.h
#include linux/videodev2.h
#include linux/vmalloc.h
#include linux/of.h
#include linux/io.h
#include linux/fs.h
#include linux/of_platform.h
#include linux/uaccess.htypedef struct
{volatile uint32_t GPIO_DR;volatile uint32_t GPIO_GDIR;volatile uint32_t GPIO_PSR;volatile uint32_t GPIO_ICR1;volatile uint32_t GPIO_ICR2;volatile uint32_t GPIO_IMR;volatile uint32_t GPIO_ISR;volatile uint32_t GPIO_EDGE_SEL;
}GPIO_TypeDef;static GPIO_TypeDef *GPIO;static volatile uint32_t *CCM_CCGR;
static volatile uint32_t *IOMUXC_SW_MUX_CTL_PAD;
static volatile uint32_t *IOMUXC_SW_PAD_CTL_PAD;typedef struct
{struct device_node *devNode; /* 设备节点 */int reg_num; /* reg长度 */u32 *reg_value;char drv_name[50]; /* 驱动名称 */int major; /* 主设备号 */int minor; /* 次设备号 */dev_t devt; /* 设备号 */struct device *device; /* 设备 */char device_name[50]; /* 设备名称 */struct class *class; /* 类 */char class_name[50]; /* 类名称 */
}atk_led_private;atk_led_private led_pri {.devNode NULL,.drv_name led_drv,.reg_value NULL,.major 0,.minor 0,.devt 0,.device NULL,.device_name led_dev,.class NULL,.class_name led_class,
};static int led_open(struct inode *inode, struct file *file)
{uint32_t val;/* 使能GPIO1时钟 */*CCM_CCGR | (3 26);/* 设置IO复用 */val *IOMUXC_SW_MUX_CTL_PAD;val ~(0x0F);val | 5;*IOMUXC_SW_MUX_CTL_PAD val;/* 设置IO属性 *//* 设置IO方向,设置GPIO1_IO03为输出 */GPIO-GPIO_GDIR | (1 3);return 0;
}static int led_release(struct inode *inode, struct file *file)
{return 0;
}static ssize_t led_write(struct file *file, const char __user *buff, size_t size, loff_t *ppos)
{uint8_t status;int err;err copy_from_user(status, buff, 1);if(status 1){GPIO-GPIO_DR ~(13);}else{GPIO-GPIO_DR | (13);}return 1;
}static const struct file_operations led_op {.owner THIS_MODULE,.open led_open,.release led_release,.write led_write,
};static int atk_led_probe(struct platform_device *device)
{int err;int i;printk(atk_led_probe\r\n);/* 获取节点 */led_pri.devNode of_find_node_by_path(/atk-led);if(led_pri.devNode NULL){printk(of_find_node_by_path fail\r\n);return -1;}/* 获取数字属性的长度 */led_pri.reg_num of_property_count_elems_of_size(led_pri.devNode, reg, sizeof(uint32_t));if(led_pri.reg_num 0) {printk(of_property_count_elems_of_size error\r\n);return -1;}/* 读取数字属性 */led_pri.reg_value (u32*)kmalloc(sizeof(u32)*led_pri.reg_num, GFP_KERNEL);err of_property_read_u32_array(led_pri.devNode, reg, led_pri.reg_value, led_pri.reg_num);if(err ! 0) {printk(of_property_read_u32_array fail\r\n);return -1;}/* 打印属性值 */for(i0; iled_pri.reg_num; i2) {printk(reg %x %x \r\n, led_pri.reg_value[i], led_pri.reg_value[i1]);}CCM_CCGR ioremap(led_pri.reg_value[0], led_pri.reg_value[1]);IOMUXC_SW_MUX_CTL_PAD ioremap(led_pri.reg_value[2], led_pri.reg_value[3]);IOMUXC_SW_PAD_CTL_PAD ioremap(led_pri.reg_value[4], led_pri.reg_value[5]);GPIO ioremap(led_pri.reg_value[6], led_pri.reg_value[7]);led_pri.major register_chrdev(0, led_pri.drv_name, led_op);led_pri.devt MKDEV(led_pri.major, led_pri.minor);led_pri.class class_create(THIS_MODULE, led_pri.class_name);if(IS_ERR(led_pri.class)){printk(class_create error\r\n);err PTR_ERR(led_pri.class);goto err_class_create_out;}led_pri.device device_create(led_pri.class, NULL, led_pri.devt, NULL, led_pri.device_name);if(IS_ERR(led_pri.device)){printk(device_create error\r\n);err PTR_ERR(led_pri.device);goto err_device_create_out;}return 0;err_device_create_out:class_destroy(led_pri.class);
err_class_create_out:unregister_chrdev(led_pri.major, led_pri.drv_name);return err;
}static int atk_led_remove(struct platform_device *device)
{printk(atk_led_drv_remove\r\n);device_destroy(led_pri.class, led_pri.devt);class_destroy(led_pri.class);unregister_chrdev(led_pri.major, led_pri.drv_name);return 0;
}static struct of_device_id atk_led_id[] {{.compatible atk,led},{}
};static struct platform_driver atk_led_driver
{.probe atk_led_probe,.remove atk_led_remove,.driver {.owner THIS_MODULE,.name atk,led,.of_match_table atk_led_id,},
};static int __init atk_led_init(void)
{int err;printk(atk_led_init);err platform_driver_register(atk_led_driver);return 0;
}static void __exit atk_led_exit(void)
{platform_driver_unregister(atk_led_driver);
}module_init(atk_led_init);
module_exit(atk_led_exit);MODULE_LICENSE(GPL);
# 补充信息
1. 查看设备树信息
cd /sys/firmware/devicetree/base/节点是目录属性是文件比如当前设备树下既有个atk-led的设备节点这个就是书写的LED的设备树 还可以使用 cat 指令查看属性值 2. 查看 platform_device 的信息
cd /sys/devices/platform 20c406c.atk-led就是编写的led的platform_device进去看一下 其中driver就是和atk-led驱动设备匹配的驱动程序了
3. 查看 platform_driver 的信息
cd /sys/bus/platform/drivers/ 这个就是和atk-led平台设备匹配的驱动程序啦