采购审批表:从DM9000驱动看platform device与driver的关系

来源:百度文库 编辑:九乡新闻网 时间:2024/10/05 21:50:40
从DM9000驱动看platform device与driver的关系
内核中的platform driver机制需要将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样可以提高驱动和资源管理的独立性。本文的目的就是希望弄清楚platform device和driver之间的关系。 1.1    相关数据结构
1.1.1   device
这个结构体定义为: struct device {      struct klist       klist_children;      struct klist_node  knode_parent;      /* node in sibling list */      struct klist_node  knode_driver;      struct klist_node  knode_bus;      struct device      *parent;        struct kobject kobj;      char bus_id[BUS_ID_SIZE];   /* position on parent bus */      struct device_type *type;      unsigned      is_registered:1;      unsigned      uevent_suppress:1;      struct device_attribute uevent_attr;      struct device_attribute *devt_attr;        struct semaphore   sem; /* semaphore to synchronize calls to                         * its driver.                         */        struct bus_type    * bus;        /* type of bus device is on */      struct device_driver *driver;    /* which driver has allocated this                           device */      void     *driver_data; /* data private to the driver */      void     *platform_data;    /* Platform specific data, device                           core doesn't touch it */      struct dev_pm_info power;   #ifdef CONFIG_NUMA      int      numa_node;    /* NUMA node this device is close to */ #endif      u64      *dma_mask;    /* dma mask (if dma'able device) */      u64      coherent_dma_mask;/* Like dma_mask, but for                             alloc_coherent mappings as                             not all hardware supports                             64 bit addresses for consistent                             allocations such descriptors. */        struct list_head   dma_pools;    /* dma pools (if dma'ble) */        struct dma_coherent_mem *dma_mem; /* internal for coherent mem                             override */      /* arch specific additions */      struct dev_archdata    archdata;        spinlock_t         devres_lock;      struct list_head   devres_head;        /* class_device migration path */      struct list_head   node;      struct class       *class;      dev_t              devt;         /* dev_t, creates the sysfs "dev" */      struct attribute_group **groups; /* optional groups */        void (*release)(struct device * dev); }; 这个结构体有点复杂,不过我们暂时用不了这么多。       1.1.2   resource
这个结构体定义为: /*  * Resources are tree-like, allowing  * nesting etc..  */ struct resource {      resource_size_t start;      resource_size_t end;      const char *name;      unsigned long flags;      struct resource *parent, *sibling, *child; }; 在这个结构体中,start和end的意义将根据flags中指定的资源类型进行解释。内核对资源进行了分类,一共有四种类型: #define IORESOURCE_IO       0x00000100    /* Resource type */ #define IORESOURCE_MEM      0x00000200 #define IORESOURCE_IRQ      0x00000400 #define IORESOURCE_DMA      0x00000800 对于DM9000来说,其定义的资源如下: static struct resource dm9000_bfin_resources[] = {      {          .start = 0x2C000000,          .end = 0x2C000000 + 0x7F,          .flags = IORESOURCE_MEM,      }, {          .start = IRQ_PF10,          .end = IRQ_PF10,          .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,      }, }; 也就是说,它定义了两种类型的资源。从这里也可以看出resource结构体里面的name成员没有太大的用处。   1.1.3   platform_device
这个结构体定义为: struct platform_device {      const char    * name;      u32      id;      struct device dev;      u32      num_resources;      struct resource    * resource; }; 它对device加了一层包装,添加了resource的内容。看看DM9000的定义: static struct platform_device dm9000_bfin_device = {      .name = "dm9000",      .id = -1,      .num_resources = ARRAY_SIZE(dm9000_bfin_resources),      .resource = dm9000_bfin_resources, }; 注意这里的name。 1.1.4   device_driver
这个结构体定义为: struct device_driver {      const char         * name;      struct bus_type        * bus;        struct kobject         kobj;      struct klist       klist_devices;      struct klist_node  knode_bus;        struct module      * owner;      const char         * mod_name;   /* used for built-in modules */      struct module_kobject  * mkobj;        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); };     1.1.5   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 (*suspend_late)(struct platform_device *, pm_message_t state);      int (*resume_early)(struct platform_device *);      int (*resume)(struct platform_device *);      struct device_driver driver; }; 它在device_driver的基础上封装了几个操作函数。 1.1.6   bus_type
这个结构体定义为: struct bus_type {      const char         * name;      struct module      * owner;        struct kset        subsys;      struct kset        drivers;      struct kset        devices;      struct klist       klist_devices;      struct klist       klist_drivers;        struct blocking_notifier_head bus_notifier;        struct bus_attribute   * bus_attrs;      struct device_attribute * dev_attrs;      struct driver_attribute * drv_attrs;      struct bus_attribute drivers_autoprobe_attr;      struct bus_attribute drivers_probe_attr;        int      (*match)(struct device * dev, struct device_driver * drv);      int      (*uevent)(struct device *dev, char **envp,                      int num_envp, char *buffer, int buffer_size);      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 (*suspend_late)(struct device * dev, pm_message_t state);      int (*resume_early)(struct device * dev);      int (*resume)(struct device * dev);        unsigned int drivers_autoprobe:1; };       1.2    资源注册
在arch/blackfin/mach-bf561/boards/ezkit.c中有这样的代码: static int __init ezkit_init(void) {      int ret;        printk(KERN_INFO "%s(): registering device resources\n", __func__);        ret = platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));      if (ret < 0)          return ret;        return 0; }   arch_initcall(ezkit_init); 这里使用了arch_initcall来对ezkit_init函数进行调用次序的限制,而驱动的加载通常是使用module_init进行限制的,因此ezkit_init函数将先于驱动加载。 在这里ezkit_devices的定义为: static struct platform_device *ezkit_devices[] __initdata = {      &dm9000_bfin_device, ………… }; 1.2.1   platform_add_devices
这个函数比较简单: /**  *   platform_add_devices - add a numbers of platform devices  *   @devs: array of platform devices to add  *   @num: number of platform devices in array  */ int platform_add_devices(struct platform_device **devs, int num) {      int i, ret = 0;        for (i = 0; i < num; i++) {          ret = platform_device_register(devs[i]);          if (ret) {               while (--i >= 0)                    platform_device_unregister(devs[i]);               break;          }      }        return ret; } 为这个数组中的每个元素调用platform_device_register,如果出错则注销此前注册的所有platform device。 1.2.2   platform_device_register
这个函数的实现为: /**  *   platform_device_register - add a platform-level device  *   @pdev:   platform device we're adding  *  */ int platform_device_register(struct platform_device * pdev) {      device_initialize(&pdev->dev);      return platform_device_add(pdev); } 也比较简单,先调用device_initialize初始化platform_device::dev,这里仅仅是对device结构体的成员赋初值,略过它不做分析。接下来的关键是platform_device_add。 1.2.3   platform_device_add
这个函数定义为: /**  *   platform_device_add - add a platform device to device hierarchy  *   @pdev:   platform device we're adding  *  *   This is part 2 of platform_device_register(), though may be called  *   separately _iff_ pdev was allocated by platform_device_alloc().  */ int platform_device_add(struct platform_device *pdev) {      int i, ret = 0;        if (!pdev)           return -EINVAL;        if (!pdev->dev.parent)          pdev->dev.parent = &platform_bus;        pdev->dev.bus = &platform_bus_type;        if (pdev->id != -1)          snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);      else          strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);        for (i = 0; i < pdev->num_resources; i++) {          struct resource *p, *r = &pdev->resource[i];            if (r->name == NULL)               r->name = pdev->dev.bus_id;            p = r->parent;          if (!p) {               if (r->flags & IORESOURCE_MEM)                    p = &iomem_resource;               else if (r->flags & IORESOURCE_IO)                    p = &ioport_resource;          }            if (p && insert_resource(p, r)) {               printk(KERN_ERR                      "%s: failed to claim resource %d\n",                      pdev->dev.bus_id, i);               ret = -EBUSY;               goto failed;          }      }        pr_debug("Registering platform device '%s'. Parent at %s\n",           pdev->dev.bus_id, pdev->dev.parent->bus_id);        ret = device_add(&pdev->dev);      if (ret == 0)          return ret;    failed:      while (--i >= 0)          if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))               release_resource(&pdev->resource[i]);      return ret; } 在这个函数里做了两件关键的事情,一个是注册device设备,它将device::bus指定为platform_bus_type。另一个是注册resource。看下面的这几行代码:          if (!p) {               if (r->flags & IORESOURCE_MEM)                    p = &iomem_resource;               else if (r->flags & IORESOURCE_IO)                    p = &ioport_resource;          } 对照DM9000的资源定义: static struct resource dm9000_bfin_resources[] = {      {          .start = 0x2C000000,          .end = 0x2C000000 + 0x7F,          .flags = IORESOURCE_MEM,      }, {          .start = IRQ_PF10,          .end = IRQ_PF10,          .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,      }, }; 它的中断资源并没有进行注册。 1.2.4   device_add
这一函数定义为: /**  *   device_add - add device to device hierarchy.  *   @dev:    device.  *  *   This is part 2 of device_register(), though may be called  *   separately _iff_ device_initialize() has been called separately.  *  *   This adds it to the kobject hierarchy via kobject_add(), adds it  *   to the global and sibling lists for the device, then  *   adds it to the other relevant subsystems of the driver model.  */ int device_add(struct device *dev) { ……………………..        if ((error = device_add_attrs(dev)))          goto AttrsError;      if ((error = device_pm_add(dev)))          goto PMError;      if ((error = bus_add_device(dev)))          goto BusError; ………………….. } 这里有一个关键调用bus_add_device,它将把dev添加到platform_bus_type这一全局变量中的列表。 1.2.5   bus_add_device
这个函数定义为: /**  *   bus_add_device - add device to bus  *   @dev:    device being added  *  *   - Add the device to its bus's list of devices.  *   - Create link to device's bus.  */ int bus_add_device(struct device * dev) {      struct bus_type * bus = get_bus(dev->bus);      int error = 0;        if (bus) {          pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);          error = device_add_attrs(bus, dev);          if (error)               goto out_put;          error = sysfs_create_link(&bus->devices.kobj,                             &dev->kobj, dev->bus_id);          if (error)               goto out_id;          error = sysfs_create_link(&dev->kobj,                    &dev->bus->subsys.kobj, "subsystem");          if (error)               goto out_subsys;          error = make_deprecated_bus_links(dev);          if (error)               goto out_deprecated;      }      return 0;   out_deprecated:      sysfs_remove_link(&dev->kobj, "subsystem"); out_subsys:      sysfs_remove_link(&bus->devices.kobj, dev->bus_id); out_id:      device_remove_attrs(bus, dev); out_put:      put_bus(dev->bus);      return error; } 注意当执行到此函数时dev->bus指向platform_bus_type这一全局变量,因而这一函数将把dev添加到platform_bus_type的链表中。     1.3    驱动注册
下面是DM9000网卡的驱动加载代码: static int __init dm9000_init(void) {      printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME);        return platform_driver_register(&dm9000_driver);   /* search board and register */ } module_init(dm9000_init); 很简单的代码,直接调用platform_driver_register注册驱动,这里dm9000_driver的定义为: static struct platform_driver dm9000_driver = {      .driver  = {          .name    = "dm9000",          .owner   = THIS_MODULE,      },      .probe   = dm9000_probe,      .remove  = dm9000_drv_remove,      .suspend = dm9000_drv_suspend,      .resume  = dm9000_drv_resume, };   1.3.1   platform_driver_register
这个函数定义为: /**  *   platform_driver_register  *   @drv: platform driver structure  */ 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); } 注意由于DM9000的platform_driver中指定了probe,remove,suspend,resume这四个函数,因此 device_driver结构体中的这几个函数指针将进行初始化设置。最后再调用driver_register注册driver成员,有点奇怪,怎么 就抛弃了platform_driver呢? 1.3.2   driver_register
这个函数定义为: /**  *   driver_register - register driver with bus  *   @drv:    driver to register  *  *   We pass off most of the work to the bus_add_driver() call,  *   since most of the things we have to do deal with the bus  *   structures.  */ int driver_register(struct device_driver * drv) {      if ((drv->bus->probe && drv->probe) ||          (drv->bus->remove && drv->remove) ||          (drv->bus->shutdown && drv->shutdown)) {          printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);      }      klist_init(&drv->klist_devices, NULL, NULL);      return bus_add_driver(drv); } 当函数执行到这里的时候,drv->bus指向的是platform_bus_type这一全局变量。 struct bus_type platform_bus_type = {      .name         = "platform",      .dev_attrs    = platform_dev_attrs,      .match        = platform_match,      .uevent       = platform_uevent,      .suspend = platform_suspend,      .suspend_late = platform_suspend_late,      .resume_early = platform_resume_early,      .resume       = platform_resume, };   1.3.3   bus_add_driver
这个函数定义为: /**  *   bus_add_driver - Add a driver to the bus.  *   @drv:    driver.  *  */ int bus_add_driver(struct device_driver *drv) {      struct bus_type * bus = get_bus(drv->bus);      int error = 0;        if (!bus)          return -EINVAL;        pr_debug("bus %s: add driver %s\n", bus->name, drv->name);      error = kobject_set_name(&drv->kobj, "%s", drv->name);      if (error)          goto out_put_bus;      drv->kobj.kset = &bus->drivers;      if ((error = kobject_register(&drv->kobj)))          goto out_put_bus;        if (drv->bus->drivers_autoprobe) {          error = driver_attach(drv);          if (error)               goto out_unregister;      }      klist_add_tail(&drv->knode_bus, &bus->klist_drivers);      module_add_driver(drv->owner, drv);        error = driver_add_attrs(bus, drv);      if (error) {          /* How the hell do we get out of this pickle? Give up */          printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",               __FUNCTION__, drv->name);      }      error = add_bind_files(drv);      if (error) {          /* Ditto */          printk(KERN_ERR "%s: add_bind_files(%s) failed\n",               __FUNCTION__, drv->name);      }        return error; out_unregister:      kobject_unregister(&drv->kobj); out_put_bus:      put_bus(bus);      return error; } 当函数执行到此的时候,drv->bus将指向platform_bus_type这一全局变量,而这一全局变量的 drivers_autoprobe成员在bus_register这一全局初始化函数中设置为1。因此这里将调用driver_attach函数,注意 此时传递进去的参数drv指向的是dm9000_driver的driver成员。 1.3.4   driver_attach
这一函数定义为: /**  *   driver_attach - try to bind driver to devices.  *   @drv:    driver.  *  *   Walk the list of devices that the bus has on it and try to  *   match the driver with each one.  If driver_probe_device()  *   returns 0 and the @dev->driver is set, we've found a  *   compatible pair.  */ int driver_attach(struct device_driver * drv) {      return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); } 很简单,转向bus_for_each_dev。 1.3.5   bus_for_each_dev
这一函数定义为: /**  *   bus_for_each_dev - device iterator.  *   @bus:    bus type.  *   @start:  device to start iterating from.  *   @data:   data for the callback.  *   @fn: function to be called for each device.  *  *   Iterate over @bus's list of devices, and call @fn for each,  *   passing it @data. If @start is not NULL, we use that device to  *   begin iterating from.  *  *   We check the return of @fn each time. If it returns anything  *   other than 0, we break out and return that value.  *  *   NOTE: The device that returns a non-zero value is not retained  *   in any way, nor is its refcount incremented. If the caller needs  *   to retain this data, it should do, and increment the reference  *   count in the supplied callback.  */   int bus_for_each_dev(struct bus_type * bus, struct device * start,               void * data, int (*fn)(struct device *, void *)) {      struct klist_iter i;      struct device * dev;      int error = 0;        if (!bus)          return -EINVAL;        klist_iter_init_node(&bus->klist_devices, &i,                    (start ? &start->knode_bus : NULL));      while ((dev = next_device(&i)) && !error)          error = fn(dev, data);      klist_iter_exit(&i);      return error; } 简单枚举此总线上注册的device,然后为其调用__driver_attach函数,试图将一个device和传递进来的driver相匹配。 1.3.6   __driver_attach
这一函数定义为: static int __driver_attach(struct device * dev, void * data) {      struct device_driver * drv = data;        /*       * Lock device and try to bind to it. We drop the error       * here and always return 0, because we need to keep trying       * to bind to devices and some drivers will return an error       * simply if it didn't support the device.       *       * driver_probe_device() will spit a warning if there       * is an error.       */        if (dev->parent)   /* Needed for USB */          down(&dev->parent->sem);      down(&dev->sem);      if (!dev->driver)          driver_probe_device(drv, dev);      up(&dev->sem);      if (dev->parent)          up(&dev->parent->sem);        return 0; } 很简单,转而调用driver_probe_device进行驱动的匹配。 1.3.7   driver_probe_device
这个函数定义为: /**  * driver_probe_device - attempt to bind device & driver together  * @drv: driver to bind a device to  * @dev: device to try to bind to the driver  *  * First, we call the bus's match function, if one present, which should  * compare the device IDs the driver supports with the device IDs of the  * device. Note we don't do this ourselves because we don't know the  * format of the ID structures, nor what is to be considered a match and  * what is not.  *  * This function returns 1 if a match is found, -ENODEV if the device is  * not registered, and 0 otherwise.  *  * This function must be called with @dev->sem held.  When called for a  * USB interface, @dev->parent->sem must be held as well.  */ int driver_probe_device(struct device_driver * drv, struct device * dev) {      int ret = 0;        if (!device_is_registered(dev))          return -ENODEV;      if (drv->bus->match && !drv->bus->match(dev, drv))          goto done;        pr_debug("%s: Matched Device %s with Driver %s\n",           drv->bus->name, dev->bus_id, drv->name);        ret = really_probe(dev, drv);   done:      return ret; } 此时的drv->bus指向platform_bus_type这一全局变量,而它的match函数为platform_match,且让我们看看它是如何确定device和driver是否匹配的。 /**  *   platform_match - bind platform device to platform driver.  *   @dev:    device.  *   @drv:    driver.  *  *   Platform device IDs are assumed to be encoded like this:  *   "", where is a short description of the  *   type of device, like "pci" or "floppy", and is the  *   enumerated instance of the device, like '0' or '42'.  *   Driver IDs are simply "".  *   So, extract the from the platform_device structure,  *   and compare it against the name of the driver. Return whether  *   they match or not.  */   static int platform_match(struct device * dev, struct device_driver * drv) {      struct platform_device *pdev = container_of(dev, struct platform_device, dev);        return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); } 也就是说,它通过比较pdev->name和drv->name是否匹配来决定。 对于DM9000的驱动来说,这里的pdev指向dm9000_bfin_device,看看它的初始值: static struct platform_device dm9000_bfin_device = {      .name = "dm9000",      .id = -1,      .num_resources = ARRAY_SIZE(dm9000_bfin_resources),      .resource = dm9000_bfin_resources, }; 再看drv,其指向dm9000_driver这一变量中的driver成员。 static struct platform_driver dm9000_driver = {      .driver  = {          .name    = "dm9000",          .owner   = THIS_MODULE,      },      .probe   = dm9000_probe,      .remove  = dm9000_drv_remove,      .suspend = dm9000_drv_suspend,      .resume  = dm9000_drv_resume, }; 在进行了正确的名称匹配之后,将调用really_probe进行硬件检测。 1.3.8   really_probe
这一函数定义为: static int really_probe(struct device *dev, struct device_driver *drv) {      int ret = 0;        atomic_inc(&probe_count);      pr_debug("%s: Probing driver %s with device %s\n",           drv->bus->name, drv->name, dev->bus_id);      WARN_ON(!list_empty(&dev->devres_head));        dev->driver = drv;      if (driver_sysfs_add(dev)) {          printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",               __FUNCTION__, dev->bus_id);          goto probe_failed;      }        if (dev->bus->probe) {          ret = dev->bus->probe(dev);          if (ret)               goto probe_failed;      } else if (drv->probe) {          ret = drv->probe(dev);          if (ret)               goto probe_failed;      }        driver_bound(dev);      ret = 1;      pr_debug("%s: Bound Device %s to Driver %s\n",           drv->bus->name, dev->bus_id, drv->name);      goto done;   probe_failed:      devres_release_all(dev);      driver_sysfs_remove(dev);      dev->driver = NULL;        if (ret != -ENODEV && ret != -ENXIO) {          /* driver matched but the probe failed */          printk(KERN_WARNING                 "%s: probe of %s failed with error %d\n",                 drv->name, dev->bus_id, ret);      }      /*       * Ignore errors returned by ->probe so that the next driver can try       * its luck.       */      ret = 0; done:      atomic_dec(&probe_count);      wake_up(&probe_waitqueue);      return ret; } 此时的drv->bus指向platform_bus_type这一全局变量,其probe回调函数没有指定,而 drv->probe函数则指向dm9000_probe。因此转向dm9000_probe执行,并将dm9000_bfin_device做为 参数传递进去。 1.4    结论
platform device和driver分别向platform_bus_type这一中介注册,并通过名称进行相互间的匹配。很是有点婚姻中介的味道,还有点对暗号的神秘,呵呵!  

 原文地址 http://blog.csdn.net/lights_joy/archive/2009/06/08/4251003.aspx 发表于: 2010-06-15,修改于: 2010-06-15 18:35,已浏览112次,有评论0条 推荐 投诉