• 探究linux设备驱动模型之——platform虚拟总线(二)


      上回说到,platform_match是驱动和设备之间的媒人婆,那么platform_match是如何匹配驱动和设备的呢?platform总线定义的匹配条件很简单,主要就是查看驱动结构体和设备结构体的name成员变量是否相同,不同总线定义的匹配条件都不同的,例如USB总线的匹配条件就异常复杂,USB总线我们迟点会具体分析的。

      现在我们把驱动和设备分开来讲,首先会讲驱动,在最后我们会以一个实际的例子来说明,当然这个例子是没有任何的实际意义的,主要是拿来学习。在后面我们还会回过头来完善这个例子的。

      我们先看看platform总线定义的驱动结构,如下所示

      struct platform_driver {
         int (*probe)(struct platform_device *);
         int (*remove)(struct platform_device *);
         void (*shutdown)(struct platform_device *);
         int (*suspend)(struct platform_device *, pm_message_t state);
         int (*resume)(struct platform_device *);
         struct device_driver driver;
         struct platform_device_id *id_table;
      };

      当platform_match帮驱动找到匹配的设备的时候会在某个时候调用该结构体的probe函数,remove方法是在设备被移除前会被调用的(驱动移除时并不会调用该remove方法)。下面给出一个很简单的驱动模块,

     1 #include <linux/module.h>
     2 #include <linux/kernel.h>
     3 #include <linux/fs.h>
     4 #include <linux/init.h>
     5 #include <linux/platform_device.h>
     6 #include <linux/types.h>
     7 #include <asm/system.h>
     8 struct haoge_data
     9 {
    10     char a[1024];
    11 };
    12 
    13 
    14 static int haoge_probe(struct platform_device *dev)
    15 {
    16     struct haoge_data * p =(dev->dev).platform_data;
    17     
    18     
    19 
    20     printk(KERN_ALERT "%s",p->a);
    21     
    22     return 0;
    23 }
    24 
    25 
    26 static struct platform_driver haoge_driver = {
    27     .probe        = haoge_probe,
    28 
    29     .driver        = {
    30         .name        = "haoge",
    31         .owner        = THIS_MODULE,
    32     },
    33 };
    34 
    35 static int __init haoge_init(void)
    36 {
    37 
    38     return platform_driver_register(&haoge_driver);
    39 }
    40 
    41 static void __exit haoge_exit(void)
    42 {
    43     
    44 
    45     platform_driver_unregister(&haoge_driver);
    46 }
    47 
    48 module_init(haoge_init);
    49 module_exit(haoge_exit);
    50 MODULE_LICENSE("GPL");
    51 MODULE_AUTHOR("HaoGe");

      大家可以编译这个驱动模块,然后把他加载,一加载这个驱动platform总线就会把他挂接到该总线的驱动链表上。这个模块唯一值得一提的便是haoge_probe函数,这函数是我们定义的该驱动的probe方法。这个函数只有一个参数,便是struct platform_device *dev。从名字可以看出,这个参数便是指向设备结构体的一个指针。这个结构体如下所示

      

    struct platform_device {

       const char * name;  

       int  id;  

       struct device dev;  

       u32  num_resources;  

       struct resource * resource;

       struct platform_device_id *id_entry;

           struct pdev_archdata archdata;

    };

      我们提一下这个结构体的name成员变量,我们之前说过platform总线是以名字来匹配驱动和设备的,所以如果我们另外写一个设备模块,把设备结构体的的name成员赋值为"haoge",那么该设备就会匹配上面我们所写的那个驱动模块。

      我们再来看一下platform_device结构体的dev成员变量:struct device dev。其实device结构体才是总线、设备、驱动这三者中真正的设备一员,相应的device_driver是真正的驱动一员。platform_device和platform_driver是platform总线对device和device_driver这两个最底层结构体的封装。在device结构体中有个成员platform_data,他是专门用于驱动和设备之间传输数据的。在我们定义的haoge_probe函数中,我们便是通过platform_data把设备传输过来的数据用printk函数打印出来。

      下面我们给出设备模块的代码。

     

     1 #include <linux/module.h>
     2 #include <linux/kernel.h>
     3 #include <linux/fs.h>
     4 #include <linux/init.h>
     5 #include <linux/platform_device.h>
     6 #include <linux/types.h>
     7 #include <asm/system.h>
     8 
     9 struct haoge_data
    10 {
    11     char a[1024];
    12 }s;
    13 
    14 struct platform_device haoge_device ={
    15     .name= "haoge",
    16     .id=1,
    17     .dev = {
    18             .platform_data = &s, 
    19      },
    20 };
    21 
    22 static int __init haoge_init(void)
    23 {
    24     sprintf(s.a,"haogeverygood!");
    25 
    26     platform_device_register(&haoge_device);
    27     
    28     return 0;
    29 }
    30 
    31 static void __exit haoge_exit(void)
    32 {
    33     
    34     platform_device_unregister(&haoge_device);
    35 }
    36 
    37 module_init(haoge_init);
    38 module_exit(haoge_exit);
    39 MODULE_LICENSE("GPL");
    40 MODULE_AUTHOR("HaoGe");

     一加载这个设备模块,platform总线就会把这个设备模块与驱动模块绑定起来,然后我们就会看到字符界面输出"haogeverygood!"的字样了。一般驱动和设备都是一对多的,一个驱动可以满足多个设备。所以我们可以加载另外一个设备,把上面的代码修改一下,如下:

     

     1 #include <linux/module.h>
     2 #include <linux/kernel.h>
     3 #include <linux/fs.h>
     4 #include <linux/init.h>
     5 #include <linux/platform_device.h>
     6 #include <linux/types.h>
     7 #include <asm/system.h>
     8 
     9 struct haoge_data
    10 {
    11     char a[1024];
    12 }s2;
    13 
    14 struct platform_device haoge2_device ={
    15     .name= "haoge",
    16     .id = 2,
    17     .dev = {
    18             .platform_data = &s2, 
    19      },
    20 };
    21 
    22 static int __init haoge_init(void)
    23 {
    24     sprintf(s2.a,"haoge very handsone!");
    25 
    26     platform_device_register(&haoge2_device);
    27     
    28     return 0;
    29 }
    30 
    31 static void __exit haoge_exit(void)
    32 {
    33     
    34     platform_device_unregister(&haoge2_device);
    35 }
    36 
    37 module_init(haoge_init);
    38 module_exit(haoge_exit);
    39 MODULE_LICENSE("GPL");
    40 MODULE_AUTHOR("HaoGe");


      加载第二个设备模块,就会输出"haoge very handsome!"的字样。记住一点,这两个设备模块中的platform_device结构体中的id成员必须是不同的值,否则会发生kernel的错误。

      今天就写到这,下次我会再完善一下这个简单的例子

     

      

      

  • 相关阅读:
    减少注入元
    浅谈微服务基建的逻辑
    Linux系统Java环境安装配置
    ASP.NET Core 依赖注入
    C#并发编程实例讲解-概述(01)
    Linux系统从安装开始
    关于C#获取动态的时间差函数
    SQL Server 存储过程
    jQuery选择器大全(48个代码片段+21幅图演示)
    对齐方式
  • 原文地址:https://www.cnblogs.com/Blue-Moon/p/3332385.html
Copyright © 2020-2023  润新知