)
接前一篇文章嵌入式Linux驱动开发 —— 从DTS到代码的桥梁与简单OF系列API3属性读取 API如何从节点中提取信息找到了节点下一步就是读取它的属性。这是OF API的核心部分也是驱动开发者用得最多的部分。of_find_property查找属性结构体这是最底层的属性查找函数struct property *of_find_property(const struct device_node *np, const char *name, int *lenp);参数说明np设备节点name属性名lenp输出参数返回属性值的字节长度返回值是找到的property结构体指针如果没找到就返回NULL。这个函数返回的是原始的property结构体你可以直接访问它的value字段。但value是void *类型你需要自己解释它的内容。我们的LED 驱动里用这个函数读取了compatible属性struct property* proper; proper of_find_property(led.device_tree_node, compatible, NULL); if (proper NULL) { pr_err(compatible property find failed\n); } else { pr_info(compatible %s\n, (char*)proper-value); }这里我们知道compatible属性的值是个字符串所以直接把value强转成char *来打印。但这种方法并不安全因为compatible实际上是个字符串数组可能包含多个以null结尾的字符串。更好的做法是用专门的字符串读取函数我们稍后讲。of_property_read_string读取字符串属性int of_property_read_string(struct device_node *np, const char *propname, const char **out_string);这个函数用于读取字符串类型的属性比如status、device_type等。参数说明np设备节点propname属性名out_string输出参数返回字符串指针返回值是0表示成功负值表示失败-EINVAL属性不存在-ENODATA属性值为空。我们的LED驱动用它来读取status属性const char* str; int ret; ret of_property_read_string(led.device_tree_node, status, str); if (ret 0) { pr_err(status read failed!\n); } else { pr_info(status %s\n, str); }这里需要注意一个细节如果属性里包含多个字符串字符串数组这个函数只会返回第一个。如果你想读取第N个字符串可以用of_property_read_string_index()。of_property_read_u32读取32位整数int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value);这个函数用于读取单个32位整数属性。设备树里的0x12345678会被解析成一个u32值。参数说明np设备节点propname属性名out_value输出参数返回读取的值返回值是0表示成功负值表示失败。类似的还有读取8位、16位、64位整数的版本of_property_read_u8()of_property_read_u16()of_property_read_u64()of_property_read_u32_array读取整数数组这个函数用于读取包含多个整数的属性比如reg属性int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz);参数说明np设备节点propname属性名out_values接收数据的数组指针sz要读取的元素个数返回值是0表示成功负值表示失败。我们的LED驱动用它来读取reg属性u32 regdata[10]; int ret; ret of_property_read_u32_array(led.device_tree_node, reg, regdata, 10); if (ret 0) { pr_err(reg property read failed!\n); of_node_put(led.device_tree_node); return -EINVAL; } pr_info(reg data:\n); for (int i 0; i 10; i) { pr_cont(%#X , regdata[i]); } pr_cont(\n);这里我们预先知道reg属性有10个整数5组地址-长度对所以直接读10个。在实际驱动里你可能需要先用of_property_count_elems_of_size()来获取元素个数动态分配内存。of_property_count_elems_of_size计算数组元素个数int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size);这个函数返回指定属性里有多少个指定大小的元素。比如你想知道reg属性里有多少个u32可以这样做int count of_property_count_elems_of_size(np, reg, sizeof(u32));返回值是元素个数负值表示出错。更多内容请看下回。