2020年2月29日 星期六

Linux Kernel(17.2)- Common Device Tree API


properties的value可以是empty或是以下資料型態:
  • Text strings (null terminated) are represented with double quotes: string-property = "a string";
  • 'Cells' are 32 bit unsigned integers delimited by angle brackets: cell-property = <0xbeef 123 0xabcd1234>;
  • Binary data is delimited with square brackets: binary-property = [0x01 0x23 0x45 0x67];
  • Data of differing representations can be concatenated together using a comma: mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;
  • Commas are also used to create lists of strings: string-list = "red fish", "blue fish";

這章節介紹幾個API,用於存取這些常見的資料型態,會以下的DTS的內容進行parse
/ {
  node1 {
    compatible = "brook,dts-test";
    a-string-property = "A string";
    a-string-list-property = "first string", "second string";
    // hex is implied in byte arrays. no '0x' prefix is required
    a-byte-data-property = [01 23 34 56];
    child-node1 {
      first-child-property;
      second-child-property = <1>;
      a-string-property = "Hello, world";
    };
    child-node2 {
    };
  };
  
  node2 {
    compatible = "brook,dts-test";
    an-empty-property;
    a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */
    child-node@1 {
    };
    child-node@2 {
    };
  };
};


  • of_match_device(): Sanity check for device that device is matching with the node
  • of_property_read_string(): To read string property
  • of_property_count_strings(): Find and return the number of strings from a multiple strings property.
  • of_property_read_string_index(): Read a string with index from string-list property.
  • of_find_property(): Find and return the property pointer by giving named
  • of_property_for_each_u32(): A macro to iterate the property to get all values
  • of_property_read_bool(): Returns true if the property exist false otherwise
  • of_find_node_by_name(): Find a node by its "name" property
  • for_each_child_of_node(): Traverse all child device node for current device node

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>

static struct of_device_id brook_dt_id[] = {
    {
     .compatible = "brook,dts-test",
    },
    {}
};

MODULE_DEVICE_TABLE(of, brook_dt_id);

static int brook_dts_probe(struct platform_device *pdev)
{
    const struct of_device_id *of_id;
    struct device_node *node, *child;
    struct property *pp;
    int i, ret, of_cnt, len;
    const char *str;
    const __be32 *cur;
    u32 val;

    // sanity check of_match_device() allows to get the matching entry
    of_id = of_match_device(brook_dt_id, &pdev->dev);
    if (!of_id) {
        pr_err("%s: of_id is NULL\n", __func__);
        return -1;
    }

    node = pdev->dev.of_node;
    // To read string property
    ret = of_property_read_string(node, "a-string-property", &str);
    if (!ret) {
        printk("a-string-property: %s\n", str);
    } else {
        printk("no a-string-property\n");
    }

    // Find and return the number of strings from a multiple strings property.
    of_cnt = of_property_count_strings(node, "a-string-list-property");
    if (of_cnt) {
        for (i = 0; i < of_cnt; i++) {
            ret = of_property_read_string_index(node, "a-string-list-property", i, &str);
            if (!ret) {
                printk("a-string-list-property[%d]: %s\n", i, str);
            }
        }
    }

    // to find aproperty named if arg2
    pp = of_find_property(node, "a-byte-data-property", &len);
    if (pp) {
        u8 *u8p = pp->value;
        printk("a-byte-data-property: len:%d, pp->len:%d", len, pp->length);
        for (i = 0; i < len; i++) {
            printk("a-byte-data-property:[%d] = %02x\n", i, u8p[i]);
        }
    }

    // to find aproperty named if arg2
    of_property_for_each_u32(node, "a-cell-property", pp, cur, val) {
        printk("a-cell-property: %04x/%04x\n", *cur, val);
    }

    // Returns true if the property exist false otherwise
    if (of_property_read_bool(node, "an-empty-property")) {
        printk("has an-empty-property\n");
    } else {
        printk("no an-empty-property\n");
    }

    // Traverse all child device node for current device node
    for_each_child_of_node(node, child) {
        printk("child name: %s\n", child->name);
    }

    // Find a node by its "name" property
    child = of_find_node_by_name(node, "child-node1");
    if (child) {
        printk("%s has a child %s\n", node->name, child->name);
    }

    return 0;
}

static int brook_dts_remove(struct platform_device *pdev)
{
    return 0;
}

static struct platform_driver brook_dts_platform_driver = {
    .probe = brook_dts_probe,
    .remove = brook_dts_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "brook-dts",
        .of_match_table = brook_dt_id,
    },
};


static int __init brook_init_module(void)
{
    return platform_driver_register(&brook_dts_platform_driver);
}

static void __exit brook_exit_module(void)
{
    platform_driver_unregister(&brook_dts_platform_driver);
}

module_init(brook_init_module);
module_exit(brook_exit_module);
MODULE_LICENSE("GPL");

執行結果如下:
/ # insmod dts.ko
a-string-property: A string
a-string-list-property[0]: first string
a-string-list-property[1]: second string
a-byte-data-property: len:4, pp->len:4
a-byte-data-property:[0] = 01
a-byte-data-property:[1] = 23
a-byte-data-property:[2] = 34
a-byte-data-property:[3] = 56
no an-empty-property
child name: child-node1
child name: child-node2
node1 has a child child-node1
no a-string-property
a-cell-property: 1000000/0001
a-cell-property: 2000000/0002
a-cell-property: 3000000/0003
a-cell-property: 4000000/0004
has an-empty-property
child name: child-node
child name: child-node


以下摘錄http://www.myexception.cn/linux-unix/1910031.html, linux下devicetree中常用的of函數
linux下devicetree中常用的of函数
从device_node中获取信息:

int of_property_read_u8_array(const struct device_node *np, const char *propname,u8 *out_values, size_t sz);

int of_property_read_u16_array(const struct device_node *np, const char *propname,u16 *out_values, size_t sz);

int of_property_read_u32_array(const struct device_node *np, const char *propname,u32 *out_values, size_t sz);

从设备结点np中读取属性名为propname,类型为8、16、32、位整型数组的属性值,并放入out_values,sz指明了要读取的个数。


static inline int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value) 

static inline int of_property_read_u16(const struct device_node *np,const char *propname,u8 *out_value) 

static inline int of_property_read_u32(const struct device_node *np,const char *propname,u8 *out_value) 

从设备结点np中读取属性名为propname,类型为8、16、32位的属性值,并放入out_values。实际上这里调用的就是sz为1的XXX_array函数。

 

int of_property_read_u32_index(const struct device_node *np,const char*propname,u32 index, u32 *out_value)

从设备结点np中读取属性名为propname的属性值中第index个u32数值给out_value

 

int of_property_read_u64(conststruct device_node *np, const char *propname,u64 *out_value)

从设备结点np中读取属性名为propname,类型为64位的属性值,并放入out_values

 

int of_property_read_string(struct device_node *np, const char *propname,const char**out_string)

从设备结点np中读取属性名为propname的字符串型属性值

 

int of_property_read_string_index(struct device_node *np, const char *propname,intindex, const char **output)

从设备结点np中读取属性名为propname的字符串型属性值数组中的第index个字符串

 

int of_property_count_strings(struct device_node *np, const char *propname)

从设备结点np中读取属性名为propname的字符串型属性值的个数

 

unsigned int irq_of_parse_and_map(struct device_node *dev, int index)

从设备节点dev中读取第index个irq号

 

int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)

从设备节点dev中读取第index个irq号,并填充一个irq资源结构体

 

int of_irq_count(struct device_node *dev)

获取设备节点dev的irq个数


static inline bool of_property_read_bool(const struct device_node *np,const char *propname);

如果设备结点np含有propname属性,则返回true,否则返回false。一般用于检查空属性是否存在。

 

struct property* of_find_property(const struct device_node *np,const char *name,int *lenp)

根据name参数,在指定的设备结点np中查找匹配的property,并返回这个property

 

const void * of_get_property(const struct device_node *np, const char *name,int *lenp)

根据name参数,在指定的设备结点np中查找匹配的property,并返回这个property的属性值


struct device_node* of_get_parent(const struct device_node *node)

获得node节点的父节点的device node


int of_device_is_compatible(const struct device_node *device,const char *compat);

判断设备结点device的compatible属性是否包含compat指定的字符串


从of_allnodes中查找信息:

struct device_node* of_find_node_by_path(const char *path)
根据路径参数,在全局链表of_allnodes中,查找匹配的device_node


struct device_node* of_find_node_by_name(struct device_node *from,const char *name)
则根据name在全局链表of_allnodes中查找匹配的device_node,若from=NULL表示从头开始查找


struct device_node* of_find_node_by_type(struct device_node *from,const char *type)

根据设备类型在全局链表of_allnodes中查找匹配的device_node


struct device_node * of_find_compatible_node(struct device_node *from, const char*type, const char,*compatible);

根据compatible的属性值在全局链表of_allnodes中查找匹配的device_node,大多数情况下,from、type为NULL。

 

struct device_node* of_find_node_with_property(struct device_node *from,const char *prop_name)

根据节点属性的name在全局链表of_allnodes中查找匹配的device_node

 

struct device_node* of_find_node_by_phandle(phandle handle)

根据phandle在全局链表of_allnodes中查找匹配的device_node

 

杂:

void __iomem* of_iomap(struct device_node *node, int index);

通过设备结点直接进行设备内存区间的 ioremap(),index是内存段的索引。若设备结点的reg属性有多段,可通过index标示要ioremap的是哪一段,只有1段的情况,index为0

 

unsigned long __init of_get_flat_dt_root(void)

用来查找在dtb中的根节点,好像返回的都是0


int of_alias_get_id(struct device_node *np, const char *stem)

获取节点np对应的aliasid号

 

struct device_node* of_node_get(struct device_node *node)

void of_node_put(struct device_node *node)

device node计数增加/减少


const struct of_device_id* of_match_node(const struct of_device_id *matches,const struct device_node*node)

将matches数组中of_device_id结构的name和type与device node的compatible和type匹配,返回匹配度最高的of_device_id结构


platform_device和resource相关:

int of_address_to_resource(struct device_node *dev, int index,struct resource *r)

根据设备节点dev的reg属性值,填充资源结构体r。Index参数指明了使用reg属性中第几个属性值,一般设置为0,表示第一个。


struct platform_device* of_device_alloc(struct device_node *np,const char *bus_id,struct device *parent)

根据device node,bus_id以及父节点创建该设备的platform_device结构,同时会初始化它的resource成员。

 

int of_platform_bus_probe(struct device_node *root,const struct of_device_id *matches,struct device *parent)

遍历of_allnodes中的节点挂接到of_platform_bus_type总线上,由于此时of_platform_bus_type总线上还没有驱动,所以此时不进行匹配

 

int of_platform_populate(struct device_node *root,const struct of_device_id *matches,const struct of_dev_auxdata *lookup,struct device *parent)

遍历of_allnodes中的所有节点,生成并初始化所以节点的platform_device结构



struct platform_device* of_find_device_by_node(struct device_node *np)

根据device_node查找返回该设备对应的platform_device结构

    參考資料:
  • http://www.myexception.cn/linux-unix/1910031.html, linux下devicetree中常用的of函數
  • https://saurabhsengarblog.wordpress.com/2015/11/28/device-tree-tutorial-arm/, Device Tree Tutorial (ARM)
  • https://www.cnblogs.com/xiaojiang1025/p/6368260.html, Linux内核 设备树操作常用API





沒有留言:

張貼留言

熱門文章