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

news2024/12/29 11:49:21

三种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、 测试现象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/46220.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java基于springboot+vue的共享电动车管理系统 nodejs

随着在我国国民水平的提高&#xff0c;低碳环保的概念也深入人心&#xff0c;越来越多的人选择了绿色环保的出现方式&#xff0c;共享电动车更是为绿色出行提供了一个有利的保障。通过本人的调查研究发现&#xff0c;很多大学的共享电动车的管理还是用手工传统的方式在进行&…

谷歌翻译用不了的解决方案

1.上 https://ping.chinaz.com/ ping一下translate.google.cn 2.往下拉&#xff0c;根据自己所在地&#xff0c;例如广东深圳&#xff0c;则看看按照响应时间排序&#xff0c;找广东省内的。 3.把响应ip复制&#xff0c;并且本地ping一下看看响应时间 响应时间40ms还能接受 …

redis cluster如何添加和删除节点?

文章目录redis cluster如何增加和删除节点&#xff1f;背景说明添加节点添加 master 节点添加slave节点删除节点删除 master 节点删除slave节点redis cluster如何增加和删除节点&#xff1f; 背景说明 由于虚拟环境有限&#xff0c;目前所采用的集群方案是在 3 台机器去搭建 …

java项目_第166期ssm多人命题系统_java毕业设计_计算机毕业设计

java项目_第166期ssm多人命题系统_java毕业设计_计算机毕业设计 【源码请到资源专栏下载】 今天分享的项目是《ssm多人命题系统》 1、该项目分为3个角色&#xff0c;管理员和、用户、教师。 用户角色可以浏览前台,包含功能有&#xff1a; 首页、学校公告、试题信息、论坛信息 用…

Thread的基本用法

目录 1.创建线程 2.1 继承Thread类,重写run方法 2.2 实现Runnable,重写run方法 2.3 使用匿名内部类继承Thread类,重写run方法 2.4 使用匿名内部类实现Runnable接口,重写run方法 2.5 使用lambda表达式 3.Thread类的构造方法 4.Thread类的常见属性的获取方法 5.线程方法的…

游戏开发28课 cocoscreator 渲染排序说明

渲染排序说明 2D 渲染节点排序 2D 渲染节点可分为在 Canvas 下的节点和不在 Canvas 下的节点两种&#xff1a; 在 Canvas 下的节点可参考下文 UI 节点排序 部分的内容。 不在 Canvas 下的节点&#xff0c;用户可选择通过 自定义材质 来开启深度检测实现和 3D 物体的遮挡显示…

面试中经常被问到的几个回溯问题

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;本篇文章是对最近复刷的回溯相关的算法题进行记录&#xff0c;方便复习使用。 如果文章有什么需要改进的地方还请大佬不吝赐教&#x1f44f;&#x1f44f;。 小威在此先感谢各位大佬啦~~&#x1…

马尔可夫预测案例分析

根据已经有数据进行预测的研究方法有很多&#xff0c;包括arima模型、指数平滑法、灰色预测等&#xff0c;本文针对马尔可夫预测进行阐述。比如研究中国移动&#xff0c;中国联通和中国电信三家运营商&#xff0c;他们的用户可以互相携号转网&#xff0c;已经当前3家运营商的市…

开发者友好的Linux常见命令整理

系统本身 uname -a # 查看内核/操作系统/CPU信息 cat /etc/redhat-release 查看服务器版本 cat /proc/cpuinfo # 查看CPU信息 hostname # 查看计算机名 lspci -tv # 列出所有PCI设备 lsusb -tv # 列出所有USB设备 lsmod # 列出加载的内核模块 env # 查看环境变量 查看…

领域驱动设计-领域建模

领域建模 领域建模是针对问题空间的战术求解的过程&#xff1a;观察真实世界的业务需求&#xff0c;对业务知识进行提炼和转换&#xff0c;排除技术因素对建模产生的影响&#xff0c;一切围绕着业务需求而来。同时满足未来的需求变更与产品维护 快速建模法&#xff1a;名次动…

通信原理技术复习重点知识

1.感知控制层通信的目的和特点&#xff1a; 目的&#xff1a;将各种传感设备&#xff08;数据采集设备以及相关的控制设备&#xff09;所感知的信息在较短的通信距离内传送到信息汇聚系统&#xff0c;并由该系统传送到网络传输层 特点&#xff1a;传输距离近&#xff0c;传输方…

使用 SAP WebIDE 将 SAP UI5 应用部署到 ABAP 系统时遇到的关于传输请求的错误

有朋友遇到一个在 webide 里部署 SAP UI5 应用到 ABAP Repository 里时出错的问题&#xff1a; 错误消息&#xff1a; Failed to get transports for the selected package. Request POST /webidedispatcher/destinations/LND500/sap/bc/adt/cts/transportchecks failed: Forbi…

【数学】仿射变换(续1)

在 这篇文章 中我介绍了椭圆中的圆幂定理。其中&#xff0c;椭圆中的“相交弦定理”为 PA⋅PBPC⋅PDrAB2rCD2\frac{PA\cdot PB}{PC \cdot PD}\frac{r_{AB}^2}{r_{CD}^2}PC⋅PDPA⋅PB​rCD2​rAB2​​ 本来以为它是从来见不到的东西 然而 请看此题&#xff1a; 以下给出两种常…

传奇登录器打不开的四种原因

最近很多传奇玩家或者GM都遇到了传奇登陆器打不开&#xff0c;没反应&#xff0c;提示无法访问指定设备等问题&#xff0c;导致很多游戏没有办法玩&#xff0c;让玩家心情沮丧&#xff0c;作为GM&#xff0c;那么就更伤心了&#xff0c;很多玩家进不来游戏&#xff0c;开服数千…

Vue3框架中路由的使用和局部刷新的功能(第十一课)

使用vue-router的步骤:p第一步&#xff1a;创建路由需要映射的组件&#xff08;打算显示的页面&#xff09;&#xff1b;p第二步&#xff1a;通过createRouter创建路由对象&#xff0c;并且传入routes和history模式&#xff1b;配置路由映射: 组件和路径映射关系的routes数组&a…

linux杀毒软件clamav安装

clamav 简介 ClamAV is an open source (GPLv2) anti-virus toolkit, designed especially for e-mail scanning on mail gateways. It provides a number of utilities including a flexible and scalable multi-threaded daemon, a command line scanner and advanced tool …

Git的基本使用

Git 1.Git基础知识 1.1Git简介 更新的历史保存在Gitee中不会丢失的。 1.简介&#xff1a;Git是一个分布式版本管理系统&#xff0c;是为了更好地管理Linux内核开发而创立的。 Git可以在任何时间点&#xff0c;把文档的状态作为更新记录保存起来。因此可以把编辑过的文档复…

AI强势入场,成就史上最快足球

众所周知&#xff0c;卡塔尔是全球最富裕的国度之一&#xff0c;是世界第一大液化天然气生成和出口国。丰富的石油资源&#xff0c;几乎让每一名原住民从出生之日起就实现财务自由&#xff0c;人均GDP高达6万多美元&#xff0c;钞能力毋庸置疑。 2022年世界杯正是在这片富饶的土…

图论 - 拓扑排序

有向图的拓扑序列 给定一个 nnn 个点 mmm 条边的有向图&#xff0c;点的编号是 111 到 nnn&#xff0c;图中可能存在重边和自环。 请输出任意一个该有向图的拓扑序列&#xff0c;如果拓扑序列不存在&#xff0c;则输出 −1。 若一个由图中所有点构成的序列 AAA 满足&#xf…

调试-一些奇怪的现象-以及const的作用

今天给大家看一些奇怪的例子&#xff0c;我们用调试来看看这到底是什么情况&#xff0c;本次选取环境为vs2019 话不多说&#xff0c;我们直接来看例子 #include <stdio.h>int main() {int i 0;int arr[10] { 0 };for (i 0; i < 12; i){arr[i] 0;printf("he…