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

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.     
  5.     if (!pdev)  /* 如果pdev为空则返回EINVAL */  
  6.         return -EINVAL;  
  7.     
  8.     /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */  
  9.     if (!pdev->dev.parent)  
  10.         pdev->dev.parent = &platform_bus;  
  11.     
  12.     pdev->dev.bus = &platform_bus_type;  /* 设置总线类型 */  
  13.     
  14.     if (pdev->id != -1)      /* 如果id = -1则表示自动分配name */  
  15.         dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);  
  16.     else  
  17.         dev_set_name(&pdev->dev, pdev->name);  
  18.     
  19.     for (i = 0; i < pdev->num_resources; i++) {  
  20.         struct resource *p, *r = &pdev->resource[i]; /* 获取资源 */  
  21.     
  22.         if (r->name == NULL)  
  23.             r->name = dev_name(&pdev->dev);  
  24.     
  25.         p = r->parent;  
  26.         if (!p) {  
  27.             if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */  
  28.                 p = &iomem_resource;  
  29.             else if (resource_type(r) == IORESOURCE_IO)  
  30.                 p = &ioport_resource;  
  31.         }  
  32.     
  33.         if (p && insert_resource(p, r)) {  
  34.             printk(KERN_ERR  
  35.                    "%s: failed to claim resource %d ",  
  36.                    dev_name(&pdev->dev), i);  
  37.             ret = -EBUSY;  
  38.             goto failed;  
  39.         }  
  40.     }  
  41.     
  42.     pr_debug("Registering platform device '%s'. Parent at %s ",  
  43.          dev_name(&pdev->dev), dev_name(pdev->dev.parent));  
  44.     
  45.     /* 向内核添加一个device */  
  46.     ret = device_add(&pdev->dev);  
  47.     if (ret == 0)  
  48.         return ret;  
  49.     
  50.  failed:  
  51.     while (--i >= 0) {  
  52.         struct resource *r = &pdev->resource[i];  
  53.         unsigned long type = resource_type(r);  
  54.     
  55.         if (type == IORESOURCE_MEM || type == IORESOURCE_IO)  
  56.             release_resource(r);  
  57.     }  
  58.     
  59.     return ret;  
  60. }  

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 自定义了proberemove等函数,则会覆盖默认函数,否则使用默认的函数

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

void platform_driver_unregister(struct platform_driver *drv)

{

  driver_unregister(&drv->driver);

}

三、平台设备实例分析

1. 定义平台设备结构体

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

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

3. 在exit函数中卸载设备

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

四、平台驱动实例分析

1.定义平台驱动结构体

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

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

2.注册平台驱动

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

五、编译测试

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

http://blog.csdn.net/lwj103862095/article/details/17957637

附平台设备程序;

 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

附平台驱动程序

 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!
");
12     return 0;
13 }
14 static int my_remove(struct platform_device *dev){
15     printk("Driver found device unpluged!
");
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程序

 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
原文地址:https://www.cnblogs.com/lihaiyan/p/4301415.html