在驱动开发中如果可以使用设备树进行参数配置而不用频繁修改源码时间很方便的事情。
这里以I2C设备举例,记录一下。
由于要使用的设备挂载在I2C下,所以要先找到指定的I2C节点,然后添加。
设备树中定义:
&i2c1 {
modle1@15 {
compatible = "company name,modle";
reg = <0x15>;
marray = <1 2 3 4 5 6>;
mstring = "this is modle";
mint = <5866>;
};
};
解释:
&i2c1 {
节点名@地址 {
匹配属性名(必有不能改)compatible = "company name,modle";
地址属性名(必有不能改)reg = <0x15>;
数组属性名(自定义)marray = <1 2 3 4 5 6>;
字符串属性名(自定义)mstring = "this is modle";
数字属性名(自定义)mint = <5866>;
};
};
将设备树编译成**.dtb**文件然后进行替换,这里就不多说了。
正常获取属性都是在驱动通过 **compatible ** 这个属性匹配上之后,probe 函数被调用时获取设备树的节点。
int iic_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int i;
struct device dev; /* 设备对象 */
const char *mstr;
unsigned int mint;
unsigned int marray[10];
dev = client->dev;
memset(marray, 0, sizeof(marray));
of_property_read_u32_array(dev.of_node, "marray", marray, 6); /* 读取节点中属性名为 marray 的数组 */
of_property_read_string(dev.of_node, "mstring", &mstr); /* 读取节点中属性名为 mstring 的字符串 */
of_property_read_u32(dev.of_node, "mint", &mint); /* 读取节点中属性名为 mint 的数字 */
PRINT("%s ------ addr = %x\n", __FUNCTION__, client->addr); /* 打印设备地址,即 reg 属性的值 */
PRINT("%s ------ of_node->name = %s\n", __FUNCTION__, dev.of_node->name); /* 打印节点名称 */
for (i = 0; i < 10; i++) {
PRINT("%s ------ marray[%d] = %d\n", __FUNCTION__, i, marray[i]);
}
PRINT("%s ------ mstr = %s\n", __FUNCTION__, mstr);
PRINT("%s ------ mint = %d\n", __FUNCTION__, mint);
return 0;
}
这里就只记录三种,获取数字、获取字符串、获取数组,相似的函数使用起来都大同小异。
驱动中获取设备数文件属性的函数都在头文件 \kernel\include\linux\of.h 中有声明。
/* 原型 */
static inline int of_property_read_u32_array(const struct device_node *np,
const char *propname, u32 *out_values, size_t sz)
参数解释:
/* 原型 */
static inline int of_property_read_string(struct device_node *np,
const char *propname, const char **out_string)
参数解释:
/* 原型 */
static inline int of_property_read_u32(const struct device_node *np,
const char *propname, u32 *out_value)
参数解释:
#include
#include
#include
/*************************************************************************************************/
// 局部宏定义
/*************************************************************************************************/
#define EN_DEBUG 1 /* 调试信息开关 */
#if EN_DEBUG
#define PRINT(x...) printk(KERN_EMERG x) /* 设置为紧急信息等级 */
#else
#define PRINT(x...)
#endif
/*************************************************************************************************/
// 用来匹配设备的id
/*************************************************************************************************/
static const struct of_device_id of_device_match[] = {
{.compatible = "company name,modle"},
{}
};
/*************************************************************************************************/
// 设备类型id列表
/*************************************************************************************************/
const struct i2c_device_id i2c_device_table[] = {
{"modle", 0},
{},
};
/**************************************************************************************************
** 功能: 本驱动的探针函数,当驱动加载时被调用
** 参数: 无
** 返回: 无
**************************************************************************************************/
int iic_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int i;
struct device dev; /* 设备对象 */
const char *mstr;
unsigned int mint;
unsigned int marray[10];
dev = client->dev;
memset(marray, 0, sizeof(marray));
of_property_read_u32_array(dev.of_node, "marray", marray, 4); /* 读取节点中属性名为 marray 的数组 */
of_property_read_string(dev.of_node, "mstring", &mstr); /* 读取节点中属性名为 mstring 的字符串 */
of_property_read_u32(dev.of_node, "mint", &mint); /* 读取节点中属性名为 mint 的数字 */
PRINT("%s ------ addr = %x\n", __FUNCTION__, client->addr); /* 打印设备地址,即 reg 属性的值 */
PRINT("%s ------ of_node->name = %s\n", __FUNCTION__, dev.of_node->name); /* 打印节点名称 */
for (i = 0; i < 10; i++) {
PRINT("%s ------ marray[%d] = %d\n", __FUNCTION__, i, marray[i]);
}
PRINT("%s ------ mstr = %s\n", __FUNCTION__, mstr);
PRINT("%s ------ mint = %d\n", __FUNCTION__, mint);
return 0;
}
/**************************************************************************************************
** 功能: 本驱动的移除函数,当驱动卸载时被调用
** 参数: 无
** 返回: 无
**************************************************************************************************/
int iic_remove(struct i2c_client *client)
{
return 0;
}
/* i2c驱动对象 */
struct i2c_driver iic_driver = {
.probe = iic_probe,
.remove = iic_remove,
.driver = {
.name = "iic_dev_name",
.of_match_table = of_match_ptr(of_device_match),
},
.id_table = i2c_device_table,
};
/**************************************************************************************************
** 函数名称: drv_init
** 功能: 驱动初始化函数,在加载时被调用
** 参数: 无
** 返回: 无
**************************************************************************************************/
static int __init drv_init(void)
{
PRINT("%s ------ \n", __FUNCTION__);
i2c_register_driver(THIS_MODULE, &iic_driver); /* 注册i2c驱动 */
return 0;
}
/**************************************************************************************************
** 函数名称: drv_exit
** 功能描述: i2c驱动退出函数,在卸载时被调用
** 参数: 无
** 返回: 无
**************************************************************************************************/
static void __exit drv_exit(void)
{
PRINT("%s ------ \n", __FUNCTION__);
i2c_del_driver(&iic_driver); /* 移除i2c驱动 */
}
module_init(drv_init); /* 模块初始化 */
module_exit(drv_exit); /* 模块卸载 */
MODULE_AUTHOR("hrx"); /* 模块作者 */
MODULE_DESCRIPTION("Linux Driver"); /* 模块描述 */
MODULE_VERSION("1.0.0"); /* 模块版本 */
MODULE_LICENSE("GPL"); /* 模块遵守的License */
root@imx6qsabresd:/tmp# insmod devtree_demo.ko
[ 1073.108993] drv_init ------
[ 1073.112013] iic_probe ------ addr = 15
[ 1073.115819] iic_probe ------ of_node->name = modle1
[ 1073.120710] iic_probe ------ marray[0] = 1
[ 1073.124848] iic_probe ------ marray[1] = 2
[ 1073.128955] iic_probe ------ marray[2] = 3
[ 1073.133056] iic_probe ------ marray[3] = 4
[ 1073.137185] iic_probe ------ marray[4] = 0
[ 1073.141289] iic_probe ------ marray[5] = 0
[ 1073.145414] iic_probe ------ marray[6] = 0
[ 1073.149520] iic_probe ------ marray[7] = 0
[ 1073.153621] iic_probe ------ marray[8] = 0
[ 1073.157865] iic_probe ------ marray[9] = 0
[ 1073.161973] iic_probe ------ mstr = this is modle
[ 1073.166705] iic_probe ------ mint = 5866