linux驱动:(18)设备树下的platfrom总线

目录

匹配节点name

旧driver.c

新driver.c  (设备树)

验证方式

取资源

旧方法

新方法

第一个方法

第二个方法

注意

设备树of映射地址函数

例子

最后创建自己想要的设备,已经获取到了寄存器的值,可以回看前面章节


在以前的platfrom总线是通过两个文件,driver和device两个文件进行匹配成功送到probe函数的

现在有了设备树,通过设备树来替换device文件部分,那如何进行匹配呢,是通过设备树节点中的compatible属性来匹配相对应的name,但根节点中的compatible属性并不是,这个属性的作用是用来匹配内核与这个设备树匹不匹配

这章用到的节点也是16章中创建的自定义test节点

匹配节点name

旧driver.c

  • 找到我前面写的driver.c文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h> 
#include <linux/platform_device.h> 

int beep_probe(struct platform_device *pdev)
{
    printk("beep_probe\n");
    return 0;
}

int beep_remove(struct platform_device *pedv)
{
    printk("beep_remove\n");
    return 0;
};
const struct platform_device_id beep_id_table =
{
    .name = "123"
};

struct platform_driver beep_device =
{
    .probe = beep_probe,
    .remove = beep_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "beep_test"
    },
    .id_table = &beep_id_table
};

 
static int beep_driver_init(void)
{
    int ret = 0;
    ret = platform_driver_register(&beep_device);
    if (ret<0)
    {
        printk("platform_driver_register error\n");
        return ret;
    }
    
    printk("platform_driver_register ok\n");
    return 0;
}
 
static void beep_driver_exit(void)
{
    printk("beep goodbye");
    platform_driver_unregister(&beep_device);
}
 
module_init(beep_driver_init);
module_exit(beep_driver_exit);
MODULE_LICENSE("GPL");


在上面代码中,有两个name,但优先会匹配platform_device_id 结构体中的name

新driver.c  (设备树)

  • 下面我们更改为匹配设备树的代码
  • 添加一个of_device_id 结构体
    • 在其中添加compatible属性,这个属性等于要匹配的name,优先级最高,然后到platform_device_id 结构体中的name,最后才到platform_driver 结构体中的name
  • 在platform_driver 结构体中赋值of_device_id 结构体
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h> 
#include <linux/platform_device.h> 

int beep_probe(struct platform_device *pdev)
{
    printk("beep_probe\n");
    return 0;
}

int beep_remove(struct platform_device *pedv)
{
    printk("beep_remove\n");
    return 0;
};
const struct platform_device_id beep_id_table =
{
    .name = "123"
};
const struct of_device_id *of_match_table_test[] = 
{
    {.compatible = "test1234"},
    {}
};

struct platform_driver beep_device =
{
    .probe = beep_probe,
    .remove = beep_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "beep_test"
        .of_match_table= of_match_table_test;
    },
    .id_table = &beep_id_table
};

 
static int beep_driver_init(void)
{
    int ret = 0;
    ret = platform_driver_register(&beep_device);
    if (ret<0)
    {
        printk("platform_driver_register error\n");
        return ret;
    }
    
    printk("platform_driver_register ok\n");
    return 0;
}
 
static void beep_driver_exit(void)
{
    printk("beep goodbye");
    platform_driver_unregister(&beep_device);
}
 
module_init(beep_driver_init);
module_exit(beep_driver_exit);
MODULE_LICENSE("GPL");


验证方式

  • 保证已经在设备树中添加了节点,节点的compatible属性就是对应匹配的name,需要与上面代码中的一样
  • 编译成模块
  • 添加模块
  • 当匹配到设备树中的节点,并name中相同,就会输出beep_probe

取资源

旧方法

以前用driver.c时有两种方法,可以往回看,一个是直接通过结构体取,一个是通过函数

新方法

设备树也有两种方法

  • 一个是直接来拿
  • 一个是通过函数

第一个方法

比如在上面新代码中的beep_probe函数中的参数,设备树一识别到节点,节点就会转为函数中的参数

#include <linux/of.h>

int beep_probe(struct platform_device *pdev)
{
    printk("beep_probe\n");
    //第一种方法
    printk("node name is %s\n",pdev->dev.of_node->name);
    return 0;
}

 加载模块时就会直接打印出节点的名字

第二个方法

#include <linux/of.h>
int size;
u32 out_value[2]={0};
const char* str;

struct device_node *test_device_node;
struct property *test_node_property;
int beep_probe(struct platform_device *pdev)
{
    printk("beep_probe\n");
    //第二种方法
    //获取节点的名称
    test_device_node = of_find_node_by_path("/test");
    if (test_device_node==NULL)
    {
        printk("of_find_node_by_path error \n");
        return -1;
    }
    printk("test_device_node is %s\n",test_device_node->name);
    //读取节点的 reg 属性
    int ret;
    ret = of_property_read_u32_array(test_device_node,"reg",out_value,2);
    if (ret < 0)
    {
        printk("of_property_read_u32_array error \n");
        return -1;
    }
    printk("out_value[0] is 0x%08x\n",out_value[0]);
    printk("out_value[1] is 0x%08x\n",out_value[1]);
    return 0;
}

 加载模块就会打印出名字和reg属性

注意

  • 其实第二种方法中获取节点的名称test_device_node 等于 第一种方法中的pdev->dev.of_node
  • 在获取reg属性的时候,可以用pdev->dev.of_node替换test_device_node

设备树of映射地址函数

  • of_iomap
  • 作用:用于直接内存映射,以前是通过ioremap函数来完成的
  • 原型:
    void iomem *of_iomap(struct device_node *np,int index)
  • 参数:
    • np:设备节点,也就是上面的test_device_node
    • index:reg属性中要完成内存映射的段,也就是reg属性中的索引
      • 如果reg属性中只有一段的话,index设置为0(表示第一段)
      • 如果有多段,你想映射第x段,index 就是 x-1
  • 返回值:
    • 经过内存映射后的虚拟内存首地址,如果为 NULL 的话表示内存映射失败

例子

修改上面已经获取到reg的代码,将reg中的代码进行映射,reg中的指为<0x000000 0x000004>,前面表示地址,后面表示长度

#include <linux/of.h>
#include <linux/of_address.h>

int size;
u32 out_value[2]={0};
const char* str;

struct device_node *test_device_node;
struct property *test_node_property;
unsigned int *vir_addr;
int beep_probe(struct platform_device *pdev)
{
    printk("beep_probe\n");
    //第二种方法
    //获取节点的名称
    test_device_node = of_find_node_by_path("/test");
    if (test_device_node==NULL)
    {
        printk("of_find_node_by_path error \n");
        return -1;
    }
    printk("test_device_node is %s\n",test_device_node->name);
    //读取节点的 reg 属性
    int ret;
    ret = of_property_read_u32_array(test_device_node,"reg",out_value,2);
    if (ret < 0)
    {
        printk("of_property_read_u32_array error \n");
        return -1;
    }
    printk("out_value[0] is 0x%08x\n",out_value[0]);
    printk("out_value[1] is 0x%08x\n",out_value[1]);
    vir_addr = of_iomap(test_device_node,0);
    if (vir_addr == NULL)
    {
        printk("of_iomap error \n");
        return -1;
    }
    return 0;
}

最后创建自己想要的设备,已经获取到了寄存器的值,可以回看前面章节

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值