驱动——platform驱动总线三种匹配方式
创始人
2024-02-29 19:48:34

三种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 
#include 
#include //对设备信息进行填充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)
{//注册devicereturn platform_device_register(&pdev);
}
static void __exit mycdev_exit(void)
{//注销deviceplatform_device_unregister(&pdev);}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

——driver

#include
#include
#include
#include
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
struct platform_device_id {
    char name[PLATFORM_NAME_SIZE];//匹配的名字
    kernel_ulong_t driver_data;//设备驱动的私有数据
};

 代码实现—

——device

#include 
#include 
#include //对设备信息进行填充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)
{//注册devicereturn platform_device_register(&pdev);
}
static void __exit mycdev_exit(void)
{//注销deviceplatform_device_unregister(&pdev);}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

——driver

#include
#include
#include
#include
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
#include
#include
#include
#include
#include
/*   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、 测试现象

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...