博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设备树API
阅读量:5839 次
发布时间:2019-06-18

本文共 7919 字,大约阅读时间需要 26 分钟。

引子

首先看一个例子,也可参考中的gpio示例。该示例选自openwrt的gpio-button-hotblug驱动。

设备树code:

gpio-keys-polled {        compatible = "gpio-keys-polled";        #address-cells = <1>;        #size-cells = <0>;        poll-interval = <20>;        bat {            label = "bat";            gpios = <&gpio0 9 1>;            linux,code = <0x211>;        };        reset {            label = "reset";            gpios = <&gpio0 10 1>;            linux,code = <0x198>;        };        mode {            label = "mode";            gpios = <&gpio0 14 1>;            linux,code = <0x100>;            linux,input-type = <5>;        };    };

驱动相关code:

#ifdef CONFIG_OFstatic struct gpio_keys_platform_data *gpio_keys_get_devtree_pdata(struct device *dev){    struct device_node *node, *pp;    struct gpio_keys_platform_data *pdata;    struct gpio_keys_button *button;    int error;    int nbuttons;    int i = 0;    node = dev->of_node;    if (!node)        return NULL;    nbuttons = of_get_child_count(node);    if (nbuttons == 0)        return NULL;    pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * (sizeof *button),        GFP_KERNEL);    if (!pdata) {        error = -ENOMEM;        goto err_out;    }    pdata->buttons = (struct gpio_keys_button *)(pdata + 1);    pdata->nbuttons = nbuttons;    pdata->rep = !!of_get_property(node, "autorepeat", NULL);    of_property_read_u32(node, "poll-interval", &pdata->poll_interval);    for_each_child_of_node(node, pp) {        enum of_gpio_flags flags;        if (!of_find_property(pp, "gpios", NULL)) {            pdata->nbuttons--;            dev_warn(dev, "Found button without gpios\n");            continue;        }        button = &pdata->buttons[i++];        button->gpio = of_get_gpio_flags(pp, 0, &flags);        button->active_low = flags & OF_GPIO_ACTIVE_LOW;        if (of_property_read_u32(pp, "linux,code", &button->code)) {            dev_err(dev, "Button without keycode: 0x%x\n",                button->gpio);            error = -EINVAL;            goto err_out;        }        button->desc = of_get_property(pp, "label", NULL);        if (of_property_read_u32(pp, "linux,input-type", &button->type))            button->type = EV_KEY;        button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);        if (of_property_read_u32(pp, "debounce-interval",                    &button->debounce_interval))            button->debounce_interval = 5;    }    if (pdata->nbuttons == 0) {        error = -EINVAL;        goto err_out;    }    return pdata;err_out:    return ERR_PTR(error);}static struct of_device_id gpio_keys_of_match[] = {    { .compatible = "gpio-keys", },    { },};MODULE_DEVICE_TABLE(of, gpio_keys_of_match);static struct of_device_id gpio_keys_polled_of_match[] = {    { .compatible = "gpio-keys-polled", },    { },};MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);#elsestatic inline struct gpio_keys_platform_data *gpio_keys_get_devtree_pdata(struct device *dev){    return NULL;}#endif
static struct platform_driver gpio_keys_driver = {    .probe  = gpio_keys_probe,    .remove = gpio_keys_remove,    .driver = {        .name   = "gpio-keys",        .owner  = THIS_MODULE,        .of_match_table = of_match_ptr(gpio_keys_of_match),    },};static struct platform_driver gpio_keys_polled_driver = {    .probe  = gpio_keys_polled_probe,    .remove = gpio_keys_remove,    .driver = {        .name   = "gpio-keys-polled",        .owner  = THIS_MODULE,        .of_match_table = of_match_ptr(gpio_keys_polled_of_match),    },};
static int __init gpio_button_init(void){    int ret;    ret = platform_driver_register(&gpio_keys_driver);    if (ret)        return ret;    ret = platform_driver_register(&gpio_keys_polled_driver);    if (ret)        platform_driver_unregister(&gpio_keys_driver);    return ret;}static void __exit gpio_button_exit(void){    platform_driver_unregister(&gpio_keys_driver);    platform_driver_unregister(&gpio_keys_polled_driver);}module_init(gpio_button_init);module_exit(gpio_button_exit);

该驱动同时注册了两种设备驱动:gpio_keys_driver和gpio_keys_polled_driver,前者采用中断方式检测按键状态,后者通过轮询方式检测案件状态。

OF API

设备树API通常以of_开头,实现代码位于drivers/of目录下,drivers/of目录下文件如下:

address.c  fdt.c      of_mtd.c  of_pci_irq.c       pdt.cbase.c     irq.c      of_net.c  of_private.h       platform.cdevice.c   of_mdio.c  of_pci.c  of_reserved_mem.c  selftest.c

include/linux/目录下头文件:

of_address.h       of_gpio.h          of_mdio.h          of_pdt.hof_device.h        of.h               of_mtd.h           of_platform.hof_dma.h           of_iommu.h         of_net.h           of_reserved_mem.hof_fdt.h           of_irq.h           of_pci.h

0. 数据结构

of.h为基础头文件,包含相关数据结构的定义。

typedef u32 phandle;typedef u32 ihandle;struct property {    char    *name;    int length;    void    *value;    struct property *next;    unsigned long _flags;    unsigned int unique_id;};struct device_node {    const char *name;    const char *type;    phandle phandle;    const char *full_name;    struct  property *properties;    struct  property *deadprops;    /* removed properties */    struct  device_node *parent;    struct  device_node *child;    struct  device_node *sibling;    struct  device_node *next;  /* next device of same type */    struct  device_node *allnext;   /* next in list of all nodes */    struct  proc_dir_entry *pde;    /* this node's proc directory */    struct  kref kref;    unsigned long _flags;    void    *data;#if defined(CONFIG_SPARC)    const char *path_component_name;    unsigned int unique_id;    struct of_irq_controller *irq_trans;#endif};#define MAX_PHANDLE_ARGS 8struct of_phandle_args {    struct device_node *np;    int args_count;    uint32_t args[MAX_PHANDLE_ARGS];};#define of_match_ptr(_ptr)  (_ptr)

1. 寻找节点

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

判断设备结点的compatible 属性是否包含compat指定的字符串。当一个驱动支持2个或多个设备的时候,这些不同.dts文件中设备的compatible 属性都会进入驱动 OF匹配表。因此驱动可以透过Bootloader传递给内核的Device Tree中的真正结点的compatible 属性以确定究竟是哪一种设备,从而根据不同的设备类型进行不同的处理。

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

根据compatible属性,获得设备结点。遍历Device Tree中所有的设备结点,看看哪个结点的类型、compatible属性与本函数的输入参数匹配,大多数情况下,from、type为NULL,则表示遍历所有节点。

2. 读取属性

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);

int of_property_read_u64(const struct device_node *np, const char

*propname, u64 *out_value);

读取设备结点np的属性名为propname,类型为8、16、32、64位整型数组的属性。对于32位处理器来讲,最常用的是of_property_read_u32_array()。

of_property_read_u32_array(np, "arm,data-latency", data, ARRAY_SIZE(data)); of_property_read_u32_array(np, propname, out_value, 1);

int of_property_read_string(struct device_node *np, const char

*propname, const char **out_string);

int of_property_read_string_index(struct device_node *np, const char

    *propname, int index, const char **output);

前者读取字符串属性,后者读取字符串数组属性中的第index个字符串。

static inline bool of_property_read_bool(const struct device_node *np,

                                         const char *propname);

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

3. 内存映射

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

通过设备结点直接进行设备内存区间的 ioremap(),index是内存段的索引。若设备结点的reg属性有多段,可通过index标示要ioremap的是哪一段,只有1段的情 况,index为0。采用Device Tree后,大量的设备驱动通过of_iomap()进行映射,而不再通过传统的ioremap。

4. 解析中断

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

透过Device Tree或者设备的中断号,实际上是从.dts中的interrupts属性解析出中断号。若设备使用了多个中断,index指定中断的索引号。

5. 获取与节点对应的platform_device

struct platform_device *of_find_device_by_node(struct device_node *np);

在拿到device_node的情况下,反向获取对应的platform_device。

在已知platform_device的情况下,想获取device_node,如下:

static int imx_gpio_probe (struct platform_device *op){     struct device_node *dn = op->dev.of_node;     ...               }

 

参考:

1.

2.

转载地址:http://uyjcx.baihongyu.com/

你可能感兴趣的文章
索引 - 唯一索引设计指南
查看>>
一种快速订票方法
查看>>
分享:When.js 1.8.0 发布,Promises/A 的实现
查看>>
hdu 2084(数塔-经典dp)
查看>>
eclipse.ini内存设置【转】
查看>>
WPF布局——面板优先使用顺序
查看>>
(转)利用AIR的ServerSocket类让 AIR 做socket服务器
查看>>
注释下载GhostDoc使用与原始注释
查看>>
字符串编码(Encoding) - ACM
查看>>
《精通ASP.NET MVC 3框架》勘误表
查看>>
Android程序的安装和卸载
查看>>
wmi查询——vbs
查看>>
MFC字体(一)(控件文字字体)
查看>>
文件初始化简单高效的分块记录的实现
查看>>
对svn分支合并类型和深度的理解
查看>>
程序员们都是不被世人所理解的真正天才吗?-请大家看这个数独的解法
查看>>
类方法熬之滴水穿石:JAVA的世界(4)
查看>>
ORACLE_RESETLOGS浅析
查看>>
基于Predictive Parsing的ABNF语法分析器(六)——AbnfParser文法解析器之多个符号连接的情形(如rule和CRLF)...
查看>>
spring事务管理
查看>>