驱动——platform驱动总线三种匹配方式

2023-05-16

三种platform驱动匹配方式代码案例以及现象

方式一:通过设置名字进行匹配

相关API简介:

1、platform_device的API

①分配对象

struct platform_device {

        const  char *name;//用于进行匹配的名字

        int  id;//总线号 PLATFORM_DEVID_AUTO(自动分配总线号)

        struct  devicedev;//父类

        u32     num_resources;//表示设备信息的个数

        struct resource*resource;//描述硬件设备信息的结构体

};

struct device {

        void    (*release)(struct device *dev); //释放device的资源

}

struct resource {

        resource_size_t start;//资源的起始数值 

        resource_size_t end;//资源的结束值

        unsigned long flags;//资源的类型 // IORESOURCE_IO|IORESOURCE_MEM|IORESOURCE_IRQ };

②对象初始化

1>定义一个relese函数

void pdev_release(struct device *dev) { }

2>对设备信息进行填充

struct resource res[]={

                [0]={

                        .start=0x12345678,

                        .end=0x12345678+49,

                        .flags= IORESOURCE_MEM,

                },

                [1]={

                        .start=71,

                        .end=71,

                        .flags= IORESOURCE_IRQ,

                },

};

3>给对象赋值

struct platform_device pdev={

                        .name="aaaaa",

                        .id=PLATFORM_DEVID_AUTO,

                        .dev={

                                .release=pdev_release,

                        },

                        .resource=res,

                        .num_resources=ARRAY_SIZE(res),

};

③将对象注册进内核

int platform_device_register(struct platform_device *pdev)

参数:platform_device对象指针

④注销对象

 int platform_device_unregister(struct platform_device *pdev)

 2、platform_driver的API

①对象结构体

struct platform_driver {
                //匹配成功后执行probe函数
                int (*probe)(struct platform_device *);
                 //设备和驱动分离的时候执行remove函数
                int (*remove)(struct platform_device *);
                 //父类,进行匹配选项的设置
                struct device_driver driver;
                 //通过id_table的方式匹配设备文件
                const struct platform_device_id *id_table;
};

struct device_driver {
                const char  *name;//设置名字匹配
                struct of_device_id*of_match_table;//通过设备树进行匹配
        };

②对象的初始化

//定义一个probe函数
    int pdrv_probe(struct platform_device *pdev)
    {      
    }
    int pdrv_remove(struct platform_device *pdev)
    {      
    }
    //对象初始化
    struct platform_driver pdrv={
        .probe=pdrv_probe,
        .remove=pdrv_remove,  
        .driver={
            .name="aaaaa",        
        },  
    };

③对象的注册

 #define platform_driver_register(drv)   __platform_driver_register(drv, THIS_MODULE)

④对象的注销

void platform_driver_unregister(struct platform_driver *drv)

3、代码实现

——device

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>

//对设备信息进行填充
  struct resource res[]={
      [0]={
         .start=0x12345678,
         .end=0x12345678+49,
         .flags= IORESOURCE_MEM,     
      },
      [1]={
          .start=71,
         .end=71,
         .flags= IORESOURCE_IRQ,      
      },
  };
  
//定义一个relese函数
void pdev_release(struct device *dev)
{
    printk("%s:%d\n",__func__,__LINE__);
}

  //给对象赋值
  struct platform_device pdev={
      .name="aaaaa",
      .id=PLATFORM_DEVID_AUTO,
      .dev={
          .release=pdev_release,      
      },
      .resource=res,
      .num_resources=ARRAY_SIZE(res),        
  };

static int __init mycdev_init(void)
{
    //注册device
    return platform_device_register(&pdev);
}
static void __exit mycdev_exit(void)
{
    //注销device
    platform_device_unregister(&pdev);

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

——driver

#include<linux/init.h>
#include<linux/module.h>
#include<linux/platform_device.h>
#include<linux/mod_devicetable.h>
struct resource *res;
int irqno;
//对象的初始化
int pdrv_probe(struct platform_device *pdev)
{
    printk("%s:%d\n",__func__,__LINE__); 
    res=platform_get_resource(pdev,IORESOURCE_MEM,0);
        if(res==NULL)
        {
            printk("获取MEM资源失败\n");
            return ENODATA;
        }
    //获取中断类型的资源
    irqno=platform_get_irq(pdev,0);
        if(irqno<0)
        {
            printk("获取中断资源失败\n");
            return ENODATA;
        }

        printk("addr:%#llx ,irqno:%d\n",res->start,irqno);
    return 0;
}

int pdrv_remove(struct platform_device *pdev)
{
    printk("%s:%d\n",__func__,__LINE__);
    return 0;
} 
struct platform_driver pdrv={
    .probe=pdrv_probe,
    .remove=pdrv_remove,
    .driver={
        .name="aaaaa",
    },
};

module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

4、测试现象

 方式二:通过id_table方式匹配

        在驱动编写的时候,有时候需要一个驱动适配多款硬件,任何一个硬件的设备信息和这个驱动匹配成功后都可以执行这个驱动里的probe函数,所以为了解决这个情景,linux内核设计了id_table存取设备的名字列表,驱动端选择id_table方式通过platform_device_id来实现:

#include<linux/mod_devicetable.h>
struct platform_device_id {
    char name[PLATFORM_NAME_SIZE];//匹配的名字
    kernel_ulong_t driver_data;//设备驱动的私有数据
};

 代码实现—

——device

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>

//对设备信息进行填充
  struct resource res[]={
      [0]={
         .start=0x12345678,
         .end=0x12345678+49,
         .flags= IORESOURCE_MEM,     
      },
      [1]={
          .start=71,
         .end=71,
         .flags= IORESOURCE_IRQ,      
      },
  };
  
//定义一个relese函数
void pdev_release(struct device *dev)
{
    printk("%s:%d\n",__func__,__LINE__);
}

  //给对象赋值
  struct platform_device pdev={
      .name="hello1",
      .id=PLATFORM_DEVID_AUTO,
      .dev={
          .release=pdev_release,      
      },
      .resource=res,
      .num_resources=ARRAY_SIZE(res),        
  };

static int __init mycdev_init(void)
{
    //注册device
    return platform_device_register(&pdev);
}
static void __exit mycdev_exit(void)
{
    //注销device
    platform_device_unregister(&pdev);

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

——driver

#include<linux/init.h>
#include<linux/module.h>
#include<linux/platform_device.h>
#include<linux/mod_devicetable.h>
struct resource *res;
int irqno;
//对象的初始化
int pdrv_probe(struct platform_device *pdev)
{
    printk("%s:%d\n",__func__,__LINE__); 
    res=platform_get_resource(pdev,IORESOURCE_MEM,0);
        if(res==NULL)
        {
            printk("获取MEM资源失败\n");
            return ENODATA;
        }
    //获取中断类型的资源
    irqno=platform_get_irq(pdev,0);
        if(irqno<0)
        {
            printk("获取中断资源失败\n");
            return ENODATA;
        }

        printk("addr:%#llx ,irqno:%d\n",res->start,irqno);
    return 0;
}

int pdrv_remove(struct platform_device *pdev)
{
    printk("%s:%d\n",__func__,__LINE__);
    return 0;
} 
struct platform_device_id idtable[]={
    {"hello1",0},
    {"hello2",1},
    {"hello3",2},
    {},
};
//热插拔宏
MODULE_DEVICE_TABLE(platform,idtable);
struct platform_driver pdrv={
    .probe=pdrv_probe,
    .remove=pdrv_remove,
    .driver={
        .name="aaaaa",
    },
};

module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

测试现象 

 

方式三:通过设备树进行匹配

        在linux内核版本3.10之后,要求所有的设备信息都放在设备树中,所以在platform驱动被使用的时候不再写platform_device了。而是将platform_device中的设备信息直接放在设备树中即可

 1、添加设备节点信息

   myplatform{
       compatible="hqyj,platform";
       reg=<0x12345678 0x14>;
       interrupt-parent = <&gpiof>;
       interrupts = <9 0>;
       myled1 = <&gpioe 10 0>;
   };                              

2、将匹配方式设置为设备树匹配 

 //构建compatible表
    struct of_device_id oftable[]=
    {
        {.compatible="hqyj,platform",},
        {}
    };
    //热插拔宏
    MODULE_DEVICE_TABLE(of,oftable);  
    //对象初始化
    struct platform_driver pdrv={       
        .probe=pdrv_probe,
        .remove=pdrv_remove,  
        .driver={
            .name="aaaaa", //设置名字匹配
            .of_match_table=oftable,//设备树匹配
        }, 

3、解析设备树节点信息获取GPIO编号

4、代码实现

#include<linux/init.h>
#include<linux/module.h>
#include<linux/platform_device.h>
#include<linux/mod_devicetable.h>
#include<linux/of.h>
#include<linux/of_gpio.h>
/*   myplatform{
       compatible="hqyj,platform";
       reg=<0x12345678 0x14>;
       interrupt-parent = <&gpiof>;
       interrupts = <9 0>;
       myled1 = <&gpioe 10 0>;
   };                              
*/
struct resource *res;
int irqno;
struct gpio_desc *gpiono;
//对象的初始化
int pdrv_probe(struct platform_device *pdev)
{
    printk("%s:%d\n",__func__,__LINE__);
    res = platform_get_resource(pdev,IORESOURCE_MEM,0);
    if(res==NULL)
    {
        printk("paltform get resource error\n");
        return ENODATA;
    }
    irqno = platform_get_irq(pdev,0);
    if(irqno<0)
    {
        printk("paltform get irq error\n");
        return ENODATA;
    }
    printk("addr:%#x,irqno:%d\n",res->start,irqno);
    //解析设备树节点信息获取GPIO编号
    gpiono=gpiod_get_from_of_node(pdev->dev.of_node,"myled1",0,GPIOD_OUT_HIGH,NULL);
    if(IS_ERR(gpiono))
    {
        printk("gpiod get from of node error\n");
        return PTR_ERR(gpiono);
    }
    printk("gpiod get from of node success\n");
    //点灯
    gpiod_set_value(gpiono,1);
    return 0;
}

int pdrv_remove(struct platform_device *pdev)
{
    printk("%s:%d\n",__func__,__LINE__);
    gpiod_set_value(gpiono, 0);
    gpiod_put(gpiono);
    return 0;
} 
//构建compatible表
struct of_device_id oftable[]=
{
    {.compatible="hqyj,platform",},
    {}
};
//热插拔宏
MODULE_DEVICE_TABLE(of,oftable);
struct platform_driver pdrv={
    .probe=pdrv_probe,
    .remove=pdrv_remove,
    .driver={
        .name="aaaaa",
        .of_match_table=oftable,//设备树匹配
    },
    
};

module_platform_driver(pdrv);
MODULE_LICENSE("GPL");

5、 测试现象

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

驱动——platform驱动总线三种匹配方式 的相关文章

随机推荐

  • 12、TX2(ARM架构)平台换源

    关于换源的教程可参考一下其他博主的两篇文章 ARM架构换源 Ubuntu 国内源介绍 针对本机的换源操作如下 xff1a 进入配置目录 span class token function cd span etc apt 备份sources
  • VirtualBox 每天自动创建快照

    需求很简单 每天自动对虚拟机创建一个快照 避免忘记备份 同时给自己减少一点工作量 主要思路就是通过VBoxManage的命令行操作和windows的任务计划程序来完成定时备份的工作 VBoxManage 使用帮助如下 C Program F
  • c51单片机学习笔记-动态数码管实验(un)

    目的 xff1a 控制动态数码管从左至右显示数字 0 7 编译软件 xff1a keil5 过程 1 xff09 首先将 51 单片机的头文件包含进来 xff0c 然后定义 38 译码器的控制引脚 xff0c 并将共阴数码管 0 F 断码数
  • 在py-faster-rcnn/lib里make时报错: unrecognized command line option ‘-Wdate-time’

    在py faster rcnn lib里make时报错 xff1a c 43 43 pthread shared Wl O1 Wl Bsymbolic functions Wl Bsymbolic functions Wl z relro
  • C/C++ 日常学习总结(第十九篇)多线程详解

    这些讲解多线程文章都是非常好的 xff0c 我这边就归结出一个 lt 多线程详解 gt 出来 xff0c 感谢各位原创作者的辛苦劳动 xff0c 这些收藏起来方便自己消化 1 多线程笔试面试题汇总 解答地址 xff1a 概念问答 2 深入分
  • python3 算法题:七进制加法

    题目 xff1a 要求键盘输入两个七进制 0 6 数 xff0c 以空格分开 xff0c 计算两者之和输出 xff0c 例如 xff1a 输入 xff1a 16 1 输出 xff1a 20 思路 xff1a 这个题目跟十进制加法一样 xff
  • python3 实现麻将胡牌问题

    题目描述 xff1a 清一色是麻将番种之一 xff0c 指由一种花色的序数牌组成的和牌 数字1 9 xff0c 每个数字最多有4张牌 我们不考虑具体花色 xff0c 我们只看数字组合 刻子 xff1a 三张一样的牌 xff1b 如 111
  • python3爬虫简单介绍

    本文是为了防止自己以后忘了 xff0c 小白可以参考 xff0c 大神请绕道 先来扫盲 xff0c 什么是爬虫 xff1a 爬虫就是一系列按照某种规则自动从网上爬取信息的代码或者脚本 本文代码功能 xff1a 从百度百科里面爬取20个和py
  • python3 使用urllib.request.urlopen及re.findall爬取网页图片并保持本地

    本例使用urllib及re正则表达式 xff0c 爬取网页上 xff08 王俊凯百度百科 xff09 所有以jpg结尾的图片 xff0c 并保存本地 import re from urllib span class token punctu
  • python3 爬取网页内容解析并存入MySQL数据库

    爬取网页内容解析并存入MySQL数据库 用到的第三方库 xff1a BeautifulSoup xff1a 解析网页内容 xff0c 建议安装方法 xff1a pip install beautifulsoup4 pymysql xff1a
  • python二维列表按照某列(字符串列)排序;忽略大小写+区分大小写

    python二维列表按照某列 xff08 字符串列 xff09 排序 xff1b 忽略大小写 43 区分大小写 使用list自带的sorted 方法 xff0c data 61 sorted data key 61 lambda x x 1
  • tkinter 出现两个窗口 tk(未响应) 解决方法

    问题 xff1a tkinter界面开发 xff0c 莫名出现一个叫 tk 未响应 的小窗口 xff0c 最后发现是因为自定义了窗口图标导致产生多余窗口 解决方法 xff1a 将设置窗口图标代码放到设置窗口大小代码之后即可 xff08 该方
  • python3适配pykml教程

    pykml是用python2写的 xff0c 由于python3和python2语法及函数名有所不同 xff0c python3使用的时候需要手动修改几个地方 xff0c 如下 xff1a 1 出现 xff1a ModuleNotFound
  • c51单片机学习笔记-独立按键实验

    目的 xff1a 通过开发板上的独立按键 K1 控制 D1 指示灯亮灭 编译软件 xff1a keil5 过程 xff1a xff08 1 xff09 定义独立按键控制脚 sbit KEY1 61 P3 1 sbit KEY2 61 P3
  • openpyxl为指定区域设置边框为粗匣框线

    前言 xff1a 最近在用openpyxl分析Excel数据 xff0c 为了让表格层次更分明 xff0c 想给制定区域添加粗匣框线 xff0c 网上没有找到现成的方法 xff0c 自己摸索了一下 xff0c 终于解决了 xff0c 现在记
  • ubuntu上网问题以及ping通网络设备

    问题一 xff1a ubuntu上网问题 如何ping www baidu com Ubuntu上网模式有两种 xff1a 桥接和NAT 1 桥接模式 xff1a 前提是 xff1a 主机是连接的无线网 xff0c 主机有线网卡的IP设置的
  • Python脚本调用C++动态库,C++调用Python脚本实操

    一 Python调用C 43 43 动态库 实现方法 xff1a 使用python 的ctypes 模块加载dll 首先 xff0c 需要用VS创建一个dll动态库 xff0c 网上方法很多 xff0c 就不细说了 xff0c 代码如下 x
  • 利用GPU训练时的常见错误

    1 CUDA VIDIBLE DEVICES 61 4 5 python3 main py 我想在集群条件下利用4 5号GPU xff0c 由于模型较小 xff0c 并不清楚是都可以指定4 5号GPU xff08 内存占用情况看不出来 后续
  • Jetson TX1底板的接口调试

    1 I2C总线上外设查询 I2C Tools的安装和使用 在控制台输入 sudo apt get install i2c tools 安装完成后可以使用命令验证安装成功 sudo i2cdetect l I2C设备查询使用 sudo i2c
  • 驱动——platform驱动总线三种匹配方式

    三种platform驱动匹配方式代码案例以及现象 方式一 xff1a 通过设置名字进行匹配 相关API简介 xff1a 1 platform device的API 分配对象 struct platform device const char