简介
Linux驱动内需要设备数组数据,可以在设备树(devicetree)使用"[1 2 3 4]"或则"<1 2 3 4>"的方式定义,这种方式和我们在C语言内定义数组颇为相似。
解析数组的函数在内核文件drivers/of/property.c中实现,内核实现了获取8/16/32/64位数组的方法。
本文以获取8/32位数组的方法举例。
解析函数定义:
int of_property_read_variable_u8_array(const struct device_node *np,
const char *propname, u8 *out_values,
size_t sz_min, size_t sz_max)
功能:从设备树获取数组,每个数组元素大小是8位。
参数:@np,设备树节点。
@propname,节点内的属性名称,如下面例子的"key-define"。
@out_values,存储的位置,需要自行申请
@sz_min/@sz_max,数组最小/最大长度。
返回:获取数组元素的个数
例子
linux内核版本:4.14
设备树描述:
定义一个节点,8位数组内容以十六进制表示,但不需要在数字前加0x表示十六进制,数组元素用"[]"方括号围起来,例如
key-define1 = [ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 ];
32位数组,需要在数字前加入0x表示16进制,数组元素用"<>"尖括号围起来,例如
key-define2 = <0x11 0x22 0x33>
mtest@43A00000{
compatible = "mtest";
reg = <0x43A00000 0x4>;
interrupt-parent = <&gpio0>;
interrupts = <160 1>;
keypad,num-rows = <5>;
keypad,num-columns=<21>;
key-define1 = [
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10
];
key-define2 = <0x11 0x22 0x33>;
key-define3 = <11 22 33>;
};
驱动文件:
在自定义的驱动文件,probe函数内调用test_get_dt解析数组内容。
static int test_get_dt(struct device * dev, struct icfc_self_node * self)
{
int ret;
int key_number = 0;
unsigned char def1[20];
unsigned int def23[16];
int i;
ret = of_property_read_variable_u8_array(dev->of_node,"key-define1", def1, 2, 20);
if (ret < 0)
{
printk("get define 1 fail\n");
return -1;
}
printk( "get defs 1 number:%d\n", ret);
for (i = 0; i < ret; i++)
{
printk( "%d,", def1[i]);
}
printk("\n");
printk( "--------------------------------------------------------\n");
ret = of_property_read_variable_u32_array(dev->of_node,"key-define2", def23, 2, 10);
if (ret < 0)
{
printk("get define2 fail\n");
return -1;
}
printk( "get defs 2 number:%d\n", ret);
for (i = 0; i < ret; i++)
{
printk( "%d,", def23[i]);
}
printk("\n");
printk( "--------------------------------------------------------\n");
ret = of_property_read_variable_u32_array(dev->of_node,"key-define3", def23, 2, 10);
if (ret < 0)
{
printk("define3\n");
return -1;
}
printk( "get defs 3 number:%d\n", ret);
for (i = 0; i < ret; i++)
{
printk( "%d,", def23[i]);
}
printk("\n");
printk( "--------------------------------------------------------\n");
return 0;
}
内核日志
get defs 1 number:17
0,1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,
--------------------------------------------------------
get defs 2 number:3
17,34,51,
--------------------------------------------------------
get defs 3 number:3
11,22,33,
--------------------------------------------------------
内核函数参考
参考drivers/of/property.c的函数of_property_read_variable_u8_array
/**
* of_property_read_variable_u8_array - Find and read an array of u8 from a
* property, with bounds on the minimum and maximum array size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz_min: minimum number of array elements to read
* @sz_max: maximum number of array elements to read, if zero there is no
* upper limit on the number of elements in the dts entry but only
* sz_min will be read.
*
* Search for a property in a device node and read 8-bit value(s) from
* it. Returns number of elements read on success, -EINVAL if the property
* does not exist, -ENODATA if property does not have a value, and -EOVERFLOW
* if the property data is smaller than sz_min or longer than sz_max.
*
* dts entry of array should be like:
* property = /bits/ 8 <0x50 0x60 0x70>;
*
* The out_values is modified only if a valid u8 value can be decoded.
*/
int of_property_read_variable_u8_array(const struct device_node *np,
const char *propname, u8 *out_values,
size_t sz_min, size_t sz_max)
{
size_t sz, count;
const u8 *val = of_find_property_value_of_size(np, propname,
(sz_min * sizeof(*out_values)),
(sz_max * sizeof(*out_values)),
&sz);
if (IS_ERR(val))
return PTR_ERR(val);
if (!sz_max)
sz = sz_min;
else
sz /= sizeof(*out_values);
count = sz;
while (count--)
*out_values++ = *val++;
return sz;
}