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

发布者:huanran最新更新时间:2024-08-15 来源: cnblogs关键字:总线设备 手机看文章 扫描二维码
随时随地手机看文章

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

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

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 %dn',  

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

  29.             ret = -EBUSY;  

  30.             goto failed;  

  31.         }  

  32.     }  

  33.     pr_debug('Registering platform device '%s'. Parent at %sn',  

  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] [2]
关键字:总线设备 引用地址:IMX257 总线设备驱动模型编程之平台总线设备platform

上一篇:IMX257 混杂设备miscdevice驱动程序
下一篇:IMX257 总线设备驱动模型编程之驱动篇

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved