zoukankan      html  css  js  c++  java
  • Platform device/driver注册过程 (转)

    cnblogs.com/fellow1988/p/6212676.html 看了个大概

    Platform是一种虚拟总线,Platform机制将设备本身的资源注册进内核,有内核统一管理,在驱动程序使用这些资源时使用统一的接口,这样提高了程序的可移植性。

    Linux的大部分设备驱动都可以使用platform 机制,用platform device 表示设备,用platform driver 表示驱动。

    Platform总线的定义如下:

    struct bus_type platform_bus_type = {
      .name = "platform",//总线名字,总线注册后新建目录sys/bus/platform
      .dev_groups = platform_dev_groups,
      .match = platform_match,//当有总线或者设备注册到platform总线时,内核自动调用match函数,判断设备和驱动的name是否一致。
      .uevent = platform_uevent,
      .pm = &platform_dev_pm_ops,
    };

    Platform device定义如下:

    struct platform_device {
      const char *name;//device名字,应该与platform driver对应。注册后,会在/sys/device/目录下创建一个以name命名的目录,并且创建软连接到/sys/bus/platform/device下。
      int id;
      bool id_auto;
      struct device dev;//基本的device结构
      u32 num_resources;//资源数
      struct resource *resource;//资源

      const struct platform_device_id *id_entry;
      char *driver_override; /* Driver name to force a match */

      /* MFD cell pointer */
      struct mfd_cell *mfd_cell;

      /* arch specific additions */
      struct pdev_archdata archdata;
    };

    Platform driver定义如下:

    struct platform_driver {
      int (*probe)(struct platform_device *);//platform driver注册时,如果总线上已有匹配的device,将调用probe函数。
      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;//基本的device driver结构.platform driver注册成功后,/sys/bus/platform/driver/目录下创建一个名字为driver->name的目录
      const struct platform_device_id *id_table;
      bool prevent_deferred_probe;
    };

     Platform device 注册过程:

    int platform_device_register(struct platform_device *pdev)
    {
      device_initialize(&pdev->dev);//初始化platform device结构体中的dev结构
      arch_setup_pdev_archdata(pdev);
      return platform_device_add(pdev);//add platform到platform bus.
    }

    int platform_device_add(struct platform_device *pdev)
    {
      int i, ret;

      if (!pdev)
        return -EINVAL;

      if (!pdev->dev.parent)
        pdev->dev.parent = &platform_bus;//dev的parent device为platform_bus

      pdev->dev.bus = &platform_bus_type;//dev的bus 类型

      switch (pdev->id) {//设置dev 名字。
      default:
        dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
      break;
      case PLATFORM_DEVID_NONE:
        dev_set_name(&pdev->dev, "%s", pdev->name);
      break;
      case PLATFORM_DEVID_AUTO:
    /*
    * Automatically allocated device ID. We mark it as such so
    * that we remember it must be freed, and we append a suffix
    * to avoid namespace collision with explicit IDs.
    */
        ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
        if (ret < 0)
          goto err_out;
        pdev->id = ret;
        pdev->id_auto = true;
        dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
        break;
      }

      for (i = 0; i < pdev->num_resources; i++) {//添加resource
        struct resource *p, *r = &pdev->resource[i];

        if (r->name == NULL)
        r->name = dev_name(&pdev->dev);

        p = r->parent;
        if (!p) {
          if (resource_type(r) == IORESOURCE_MEM)
          p = &iomem_resource;
          else if (resource_type(r) == IORESOURCE_IO)
          p = &ioport_resource;
        }

        if (p && insert_resource(p, r)) {
          dev_err(&pdev->dev, "failed to claim resource %d ", i);
          ret = -EBUSY;
          goto failed;
        }
      }

      pr_debug("Registering platform device '%s'. Parent at %s ",
      dev_name(&pdev->dev), dev_name(pdev->dev.parent));

      ret = device_add(&pdev->dev);//add dev到bus
      if (ret == 0)
      return ret;

    failed:
      if (pdev->id_auto) {
        ida_simple_remove(&platform_devid_ida, pdev->id);
        pdev->id = PLATFORM_DEVID_AUTO;
      }

      while (--i >= 0) {
        struct resource *r = &pdev->resource[i];
        if (r->parent)
        release_resource(r);
      }

    err_out:
      return ret;
    }

    在device_add函数中调用bus_add_device函数将device加到bus,并调用bus_probe_device来调用总线上与之匹配的driver的probe函数。

    在bus_probe_device函数中主要调用device_initial_probe,

    void device_initial_probe(struct device *dev)
    {
      __device_attach(dev, true);
    }

    在__device_attach中主要的代码如下:

    ret = bus_for_each_drv(dev->bus, NULL, &data,
    __device_attach_driver);//遍历总线上的driver,并调用__device_attach_driver

    在__device_attach_driver中主要调用driver_match_device判断driver和device是否match,如果match则调用driver_probe_device来probe driver

    static inline int driver_match_device(struct device_driver *drv,
    struct device *dev)
    {
      return drv->bus->match ? drv->bus->match(dev, drv) : 1;//drv所属bus的match函数。
    }

    bus->match即platform bus的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);

      /* When driver_override is set, only bind to the matching driver */
      if (pdev->driver_override)
        return !strcmp(pdev->driver_override, drv->name);

      /* Attempt an OF style match first */
      if (of_driver_match_device(dev, drv))
      return 1;

      /* Then try ACPI style match */
      if (acpi_driver_match_device(dev, drv))
      return 1;

      /* Then try to match against the id table */
      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);//比较driver和device的名字。
    }

    在driver_probe_device中主要调用really_probe,really_probe的主要代码如下。

    if (dev->bus->probe) {//如果bus定义了probe,就调用bus的probe
      ret = dev->bus->probe(dev);
      if (ret)
      goto probe_failed;
    } else if (drv->probe) {//调用bus所属driver的probe函数。
      ret = drv->probe(dev);
      if (ret)
      goto probe_failed;
    }

     Platform driver的注册过程:

    int __platform_driver_register(struct platform_driver *drv,
    struct module *owner)
    {
      drv->driver.owner = owner;
      drv->driver.bus = &platform_bus_type;//driver的bus type为Platform bus
      drv->driver.probe = platform_drv_probe;//driver的probe函数,如果platform driver定义了probe函数,里面调用的platform定义的probe
      drv->driver.remove = platform_drv_remove;
      drv->driver.shutdown = platform_drv_shutdown;

      return driver_register(&drv->driver);//主要注册函数。
    }

    在driver_register函数中,通过driver_find查找driver是否已经注册,如果没有注册,则调用bus_add_driver将driver add到bus。

    在bus_add_driver最主要的操作是driver 和匹配的device进行绑定。

    int driver_attach(struct device_driver *drv)
    {
      return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);//遍历bus上所有的device,并调用__driver_attach
    }

    在__driver_attach函数中与上面__device_attach_driver过程类似,调用driver_match_device判断driver和device是否match,如果match则调用driver_probe_device来probe driver。如果bus上没有注册过与platform driver匹配的platform device,那platform driver的probe函数将不会调用到。

    从上述注册过程可以看出platform device和platform driver注册并不需要区分先后。

    设备挂接到总线上时,与总线上的所有驱动进行匹配(用bus_type.match进行匹配)。如果匹配成功,则调用bus_type.probe或者driver.probe初始化该设备;挂接到总线上如果匹配失败,则只是将该设备挂接到总线上。 

     驱动挂接到总线上时,与总线上的所有设备进行匹配(用bus_type.match进行匹配)。如果匹配成功,则调用bus_type.probe或者driver.probe初始化该设备;挂接到总线上如果匹配失败,则只是将该驱动挂接到总线上。

  • 相关阅读:
    Leetcode 191.位1的个数 By Python
    反向传播的推导
    Leetcode 268.缺失数字 By Python
    Leetcode 326.3的幂 By Python
    Leetcode 28.实现strStr() By Python
    Leetcode 7.反转整数 By Python
    Leetcode 125.验证回文串 By Python
    Leetcode 1.两数之和 By Python
    Hdoj 1008.Elevator 题解
    TZOJ 车辆拥挤相互往里走
  • 原文地址:https://www.cnblogs.com/idyllcheung/p/13212126.html
Copyright © 2011-2022 走看看