0
点赞
收藏
分享

微信扫一扫

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform

禾木瞎写 2022-03-30 阅读 50


20150226 IMX257 总线设备驱动模型编程之平台总线设备platform

2015-02-26 李海沿

前面我们实现了总线设备驱动模型,下面我们来了解一下平台总线,平台设备驱动

分为平台设备和平台驱动两种,和前面所说的设备驱动差不多

platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。

一、平台设备介绍

1. platform_bus_type 结构体


struct bus_type platform_bus_type = {

    .name = "platform",

  .dev_attrs = platform_dev_attrs,

  .match = platform_match, //设备和驱动使用match函数来判断是否匹配

  .uevent = platform_uevent,

  .pm = PLATFORM_PM_OPS_PTR,

};


这个结构体就是linux中平台设备的结构体,所以在sysfs文件系统中的/sys/bus/目录下面会有一个 名字为platform的目录。


2. platform_match 函数

platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。


/* platform_match函数用于匹配总线中的驱动和设备 */

static int platform_match(struct device *dev, struct device_driver *drv)

{

  struct platform_device *pdev = to_platform_device(dev);

  struct platform_driver *pdrv = to_platform_driver(drv);


  /* match against the id table first */

  if (pdrv->id_table)

  return platform_match_id(pdrv->id_table, pdev) != NULL;


  /* fall-back to driver name match */

  return (strcmp(pdev->name, drv->name) == 0);

}



3. platform_device 结构体


struct platform_device {

  const char * name; /* 名字 。这个名字用于与驱动进行匹配*/

  int id; /* 设备编号 */

  struct device dev;

  u32 num_resources; /* 资源总数 */

  struct resource * resource; /* 资源 */

  struct platform_device_id *id_entry;

};


其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。


struct resource {

  resource_size_t start; //资源的起始值

  resource_size_t end; //资源的结束值

  const char *name;

  unsigned long flags; //资源的类型,

  //如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA

  struct resource *parent, *sibling, *child;

};


有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源


/**

* platform_get_resource - get a resource for a device

* @dev: platform device

* @type: resource type

* @num: resource index

*/

struct resource *platform_get_resource(struct platform_device *dev,

unsigned int type, unsigned int num)

{

  int i;

  for (i = 0; i < dev->num_resources; i++) {

    struct resource *r = &dev->resource[i];

     if (type == resource_type(r) && num-- == 0)

      return r;

  }

  return NULL;

}



4. platform平台设备注册函数


int platform_device_register(struct platform_device *pdev)

{

  device_initialize(&pdev->dev);

  return platform_device_add(pdev);

}


从上面代码得知,platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。



  1. int platform_device_add(struct platform_device *pdev)  

  2. {  

  3.     int i, ret = 0;  

  4.     if (!pdev)  /* 如果pdev为空则返回EINVAL */  

  5.         return -EINVAL;  

  6.     /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */  

  7.     if (!pdev->dev.parent)  

  8.         pdev->dev.parent = &platform_bus;  

  9.     pdev->dev.bus = &platform_bus_type;  /* 设置总线类型 */  

  10.     if (pdev->id != -1)      /* 如果id = -1则表示自动分配name */  

  11.         dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);  

  12.     else  

  13.         dev_set_name(&pdev->dev, pdev->name);  

  14.     for (i = 0; i < pdev->num_resources; i++) {  

  15.         struct resource *p, *r = &pdev->resource[i]; /* 获取资源 */  

  16.         if (r->name == NULL)  

  17.             r->name = dev_name(&pdev->dev);  

  18.         p = r->parent;  

  19.         if (!p) {  

  20.             if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */  

  21.                 p = &iomem_resource;  

  22.             else if (resource_type(r) == IORESOURCE_IO)  

  23.                 p = &ioport_resource;  

  24.         }  

  25.         if (p && insert_resource(p, r)) {  

  26.             printk(KERN_ERR  

  27.                    "%s: failed to claim resource %d\n",  

  28.                    dev_name(&pdev->dev), i);  

  29.             ret = -EBUSY;  

  30.             goto failed;  

  31.         }  

  32.     }  

  33.     pr_debug("Registering platform device '%s'. Parent at %s\n",  

  34.          dev_name(&pdev->dev), dev_name(pdev->dev.parent));  

  35.     /* 向内核添加一个device */  

  36.     ret = device_add(&pdev->dev);  

  37.     if (ret == 0)  

  38.         return ret;  

  39.  failed:  

  40.     while (--i >= 0) {  

  41.         struct resource *r = &pdev->resource[i];  

  42.         unsigned long type = resource_type(r);  

  43.         if (type == IORESOURCE_MEM || type == IORESOURCE_IO)  

  44.             release_resource(r);  

  45.     }  

  46.     return ret;  

  47. }  


platform_device_add最终调用device_add来完成平台设备的注册。

相反地,如果要注销平台设备则使用platform_device_unregister函数


void platform_device_unregister(struct platform_device *pdev)

{

    platform_device_del(pdev);

    platform_device_put(pdev);

}


platform_device_unregister函数调用platform_device_del函数来注销平台设备


void platform_device_del(struct platform_device *pdev)

{

  int i;

  if (pdev) {

    device_del(&pdev->dev);


    for (i = 0; i < pdev->num_resources; i++) {

      struct resource *r = &pdev->resource[i];

      unsigned long type = resource_type(r);


      if (type == IORESOURCE_MEM || type == IORESOURCE_IO)

        release_resource(r);

    }

  }

}


platform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO


二、平台驱动介绍

1. platform_driver


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;

    const struct platform_device_id *id_table;

};


platform_driver结构体有device_driver成员

2. device_driver


struct device_driver {

    const char *name; //这个名字用于与设备进行匹配

    struct bus_type *bus;


    struct module *owner;

    const char *mod_name; /* used for built-in modules */


    bool suppress_bind_attrs; /* disables bind/unbind via sysfs */


    const struct of_device_id *of_match_table;

    const struct acpi_device_id *acpi_match_table;


    int (*probe) (struct device *dev);

    int (*remove) (struct device *dev);

    void (*shutdown) (struct device *dev);

    int (*suspend) (struct device *dev, pm_message_t state);

    int (*resume) (struct device *dev);

    const struct attribute_group **groups;


    const struct dev_pm_ops *pm;


    struct driver_private *p;

};


device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化

当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。


struct platform_device_id {

    char name[PLATFORM_NAME_SIZE];

    kernel_ulong_t driver_data

      __attribute__((aligned(sizeof(kernel_ulong_t))));

};



3. 平台驱动注册函数


int platform_driver_register(struct platform_driver *drv)

{

  drv->driver.bus = &platform_bus_type;

  if (drv->probe)

    drv->driver.probe = platform_drv_probe;

  if (drv->remove)

    drv->driver.remove = platform_drv_remove;

  if (drv->shutdown)

    drv->driver.shutdown = platform_drv_shutdown;

  if (drv->suspend)

    drv->driver.suspend = platform_drv_suspend;

  if (drv->resume)

    drv->driver.resume = platform_drv_resume;

  return driver_register(&drv->driver);

}


如果platform_driver 自定义了probe,remove等函数,则会覆盖默认函数,否则使用默认的函数

相反地,要注销平台驱动的话,使用platform_driver_unregister函数


void platform_driver_unregister(struct platform_driver *drv)

{

  driver_unregister(&drv->driver);

}




三、平台设备实例分析

1. 定义平台设备结构体

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_#include

2.在初始化函数中分配平台设备结构体

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_#include_02


如图所示,在init函数中先分配平台设备结构体,然后再注册设备


3. 在exit函数中卸载设备

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_设备驱动_03


很简单吧,下面我们来看看平台驱动


四、平台驱动实例分析

1.定义平台驱动结构体

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_#include_04

如图所示,先定义平台驱动结构体,然后实现相关的函数。

注意.driver = 这个是一个device_driver结构体,其中的成员.name就是用于和设备进行匹配。

2.注册平台驱动

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_设备驱动_05

如图所示,剩下的工作就是分别在 init 和exit 函数中注册和卸载驱动了。



五、编译测试


20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_设备驱动_06


20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_#include_07


20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_#include_08

上面有关平台设备的部分知识点摘自大牛文章:


附平台设备程序;

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_linux_0920150226 IMX257 总线设备驱动模型编程之平台总线设备platform_linux_10

1 //platform_device.c
2 #include <linux/device.h>
3 #include <linux/module.h>
4 #include <linux/kernel.h>
5 #include <linux/init.h>
6 #include <linux/string.h>
7 #include <linux/platform_device.h>
8
9 //定义平台设备结构体
10 static struct platform_device *my_device;
11
12 static int __init my_device_init(void){
13 int ret = 0;
14 /* 分配结构体 */
15 my_device = platform_device_alloc("my_platform_dev",-1);
16
17 /* 注册设备 */
18 ret = platform_device_add(my_device);
19
20 /* 注册失败,则释放相关内存 */
21 if(ret)
22 platform_device_put(my_device);
23 return ret;
24 }
25
26 static void my_device_exit(void){
27 platform_device_unregister(my_device);
28 }
29
30 module_init(my_device_init);
31 module_exit(my_device_exit);
32
33 MODULE_AUTHOR("Lover雪儿");
34 MODULE_LICENSE("GPL");

View Code


附平台驱动程序

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_linux_0920150226 IMX257 总线设备驱动模型编程之平台总线设备platform_linux_10

1 //platform_driver.c
2 #include <linux/device.h>
3 #include <linux/module.h>
4 #include <linux/kernel.h>
5 #include <linux/init.h>
6 #include <linux/string.h>
7 #include <linux/platform_device.h>
8
9 //探测函数
10 static int my_probe(struct platform_device *dev){
11 printk("Driver found device which my driver can handle!\n");
12 return 0;
13 }
14 static int my_remove(struct platform_device *dev){
15 printk("Driver found device unpluged!\n");
16 return 0;
17 }
18 //定义平台驱动结构体
19 static struct platform_driver my_driver = {
20 .probe = my_probe,
21 .remove = my_remove,
22 .driver = {
23 .owner = THIS_MODULE,
24 .name = "my_platform_dev",
25 },
26 };
27
28 static int __init my_driver_init(void){
29 /* 注册平台驱动 */
30 return platform_driver_register(&my_driver);
31 }
32
33 static void my_driver_exit(void){
34 platform_driver_unregister(&my_driver);
35 }
36
37 module_init(my_driver_init);
38 module_exit(my_driver_exit);
39
40 MODULE_AUTHOR("Lover雪儿");
41 MODULE_LICENSE("GPL");

View Code


附MAKEFILE程序

20150226 IMX257 总线设备驱动模型编程之平台总线设备platform_linux_0920150226 IMX257 总线设备驱动模型编程之平台总线设备platform_linux_10

1 ifeq ($(KERNELRELEASE),)
2 KERNELDIR ?= /home/study/system/linux-2.6.31
3 PWD := $(shell pwd)
4 modules:
5 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
6 modules_install:
7 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
8 clean:
9 rm -rf *.o *~ core .depend *.cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers
10
11 else
12 obj-m := platform_device.o platform_driver.o
13 endif

View Code



举报

相关推荐

0 条评论