二、注册 platform_driver

来源:互联网 发布:windows 7 远程桌面 编辑:程序博客网 时间:2024/05/06 06:52

// kernel/drivers/i2c/busses/i2c_sc8810.c

static int __init i2c_adap_sc8810_init(void)

{

       printk(KERN_INFO"I2c:sc8810 driver$Revision:1.0 $\n");

      

       return platform_driver_register(&sc8810_i2c_driver); 

}

 

 

/*platform_driver_register - register a driver for platform-level devices

 * @drv: platform driver structure

 */

//kernel/drivers/base/platform.c

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;

 

       return  driver_register(&drv->driver);

}

 

 

/**

 * driver_register - register driver with bus

 * @drv: driver to register

 * We pass off most of the work to thebus_add_driver() call,

 * since most of the things we have to do dealwith the bus

 * structures.

 */

//kernel\drivers\base\driver.c

int driver_register(struct device_driver *drv)

{

       int ret;

       struct device_driver *other;

 

       BUG_ON(!drv->bus->p);

 

       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_typemethods\n", drv->name);

 

       other = driver_find(drv->name,drv->bus);

       if (other) {

              put_driver(other);

              printk(KERN_ERR "Error:Driver '%s' is already registered, "

                     "aborting...\n",drv->name);

              return -EBUSY;

       }

       ret = bus_add_driver(drv);

       if (ret)

              return ret;

       ret = driver_add_groups(drv,drv->groups);

       if (ret)

              bus_remove_driver(drv);

       return ret;

}

 

 

/**

 * bus_add_driver - Add a driver to the bus.

 * @drv: driver.

 */

//kernel/drivers/base/bus.c

int bus_add_driver(struct device_driver *drv)

{

       struct bus_type *bus;

       struct driver_private *priv;

       int error = 0;

 

       bus = bus_get(drv->bus);

       if (!bus)

              return -EINVAL;

 

       pr_debug("bus: '%s': add driver%s\n", bus->name, drv->name);

       priv = kzalloc(sizeof(*priv),GFP_KERNEL);

       if (!priv) {

              error = -ENOMEM;

              goto out_put_bus;

       }

       klist_init(&priv->klist_devices,NULL, NULL);

       priv->driver = drv;

       drv->p = priv;

       priv->kobj.kset =bus->p->drivers_kset;

       error =kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,

                                 "%s", drv->name);

       if (error)

              goto out_unregister;

 

       if(drv->bus->p->drivers_autoprobe) {

              error = driver_attach(drv);

              if (error)

                     goto out_unregister;

       }

  

       klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers);

       module_add_driver(drv->owner, drv);

       error = driver_create_file(drv,&driver_attr_uevent);

       if (error) {

              printk(KERN_ERR "%s: ueventattr (%s) failed\n",

                     __func__, drv->name);

       }

//如果有 device platform_driver->device_driver匹配,就把 platform_driver->device_driver添加到总线中。

       error = driver_add_attrs(bus, drv);

       if (error) {

              /* How the hell do we get out ofthis pickle? Give up */

              printk(KERN_ERR "%s:driver_add_attrs(%s) failed\n",

                     __func__, drv->name);

       }

 

       if (!drv->suppress_bind_attrs) {

              error = add_bind_files(drv);

              if (error) {

                     /* Ditto */

                     printk(KERN_ERR "%s:add_bind_files(%s) failed\n",

                            __func__,drv->name);

              }

       }

       kobject_uevent(&priv->kobj,KOBJ_ADD);

       return 0;

out_unregister:

       kobject_put(&priv->kobj);

       kfree(drv->p);

       drv->p = NULL;

out_put_bus:

       bus_put(bus);

       return error;

}

 

 

/**

 * driver_attach - try to bind driver todevices.

 * @drv: driver.

 *

 * Walk the list of devices that the bus has onit 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.

 */

//kernel/drivers/base/dd.c

intdriver_attach(structdevice_driver *drv)

{

       return bus_for_each_dev(drv->bus,NULL, drv, __driver_attach);

}



/**

 * 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, andcall @fn for each,

 * passing it @data. If @start is not NULL, weuse that device to

 * begin iterating from.

 *

 * We check the return of @fn each time. If itreturns anything

 * other than 0, we break out and return thatvalue.

 *

 * NOTE: The device that returns a non-zerovalue is not retained

 * in any way, nor is its refcount incremented.If the caller needs

 * to retain this data, it should do so, andincrement the reference

 * count in the supplied callback.

 */

//kernel/drivers/base/bus.c

int bus_for_each_dev(structbus_type *bus, struct device *start,

                   void *data, int (*fn)(structdevice *, void *))

{

       struct klist_iter i;

       struct device *dev;

       int error = 0;

 

       if (!bus)

              return -EINVAL;

   //bus_add_driver()函数中可知bus = bus_get(drv->bus); bus是由platform_bus_type而来,而platform_bus_type并未初始化p变量,不知&bus->p->klist_devices从何而来?

       klist_iter_init_node(&bus->p->klist_devices,&i,

                          (start ? &start->p->knode_bus :NULL));

 

  //为总线上的所有device调用__driver_attach,不知这里的dev是不是platform_device,如果是的话应该会进行4match,然后运行4次probe函数。

while ((dev = next_device(&i))&& !error)

              error = fn(dev, data);

       klist_iter_exit(&i);

       return error;

}



//kernel\drivers\base\dd.c

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 (!driver_match_device(drv, dev))

              return 0;

 

       if (dev->parent)   /* Needed for USB */

              device_lock(dev->parent);

       device_lock(dev);

       if (!dev->driver)

              driver_probe_device(drv, dev);

       device_unlock(dev);

       if (dev->parent)

              device_unlock(dev->parent);

 

       return 0;

}

 


 

先执行 driver_match_device,当devicedriver匹配时,再调用driver_probe_device。下面我们先看看driver_match_device

//kernel\drivers\base\base.h

static inline int driver_match_device(struct device_driver *drv,

                                  struct device *dev)

{

       return drv->bus->match ?drv->bus->match(dev, drv) : 1;

   //当总线的match函数存在时,调用总线的match函数

}

 

 

还记得在 platform_driver_register中对总线的初始化吗?

//kernel/drivers/base/platform.c

int  platform_driver_register(struct platform_driver *drv)

{

       drv->driver.bus = &platform_bus_type;

       … …

 

//kernel/drivers/base/platform.c

struct bus_type platform_bus_type = {

       .name           ="platform",

       .dev_attrs     = platform_dev_attrs,

       .match   = platform_match,

       .uevent         =platform_uevent,

       .pm           = &platform_dev_pm_ops,

};



/**

 * platform_match - bind platform device toplatform driver.

 * @dev: device.

 * @drv: driver.

 *

 * Platform device IDs are assumed to beencoded like this:

 * "<name><instance>",where <name> is a short description of the type of

 * device, like "pci" or"floppy", and <instance> is the enumerated

 * instance of the device, like '0' or'42'.  Driver IDs are simply

 * "<name>".  So, extract the <name> from theplatform_device structure,

 * and compare it against the name of thedriver. Return whether they match

 * or not.

 */

//kernel/drivers/base/platform.c

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 */

    //如果platform_driver结构体中有 id_table ,就用 id_table 中的 name platform_device结构体中的 name做比较,详见platform_match_id()。

     if (pdrv->id_table)

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

  

 

       /* fall-back to driver name match */

 //如果platform_driver结构体中没有 id_table,就用platform_device

//platform_driver->device_driver结构体中的 name做比较。

//想想之前的platform_device_register()函数。

 

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

}


我们首先来看一下 platform_driver结构体的定义

//kernel/include/linux/platform_device.h

structplatform_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;

};

 

接下来再看一下我们为该结构体定义的变量

// kernel/drivers/i2c/busses/i2c_sc8810.c

static structplatform_driver sc8810_i2c_driver = {

       .probe           =sc8810_i2c_probe,

       .remove        =sc8810_i2c_remove,

       .driver          ={

              .owner   = THIS_MODULE,

              .name    = "sc8810-i2c",

       },

};

如上所示在实际定义中,我们只定义了 device_driver结构体,没有定义 id_table,因此会走下面的strcmp(pdev->name, drv->name),比较  platform_deviceplatform_driver->device_driver中的name("sc8810-i2c")

 

 

 

driver_match_device完了后,接下来我们再看看 driver_probe_device

/**//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

 *

 * This function returns -ENODEV if the deviceis not registered,

 * 1 if the device is bound successfully and 0otherwise.

 *

 * This function must be called with @dev lockheld.  When called for a

 * USB interface, @dev->parent lock must beheld as well.

 */

//kernel\drivers\base\dd.c

int driver_probe_device(struct device_driver *drv, struct device*dev)

{

       int ret = 0;

 

       if (!device_is_registered(dev))

              return -ENODEV;

 

       pr_debug("bus: '%s': %s: matcheddevice %s with driver %s\n",

               drv->bus->name, __func__, dev_name(dev),drv->name);

 

       pm_runtime_get_noresume(dev);

       pm_runtime_barrier(dev);

       ret = really_probe(dev, drv);

       pm_runtime_put_sync(dev);

 

       return ret;

}

 

 

//kernel\drivers\base\dd.c

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

{

       int ret = 0;

 

       atomic_inc(&probe_count);

       pr_debug("bus: '%s': %s: probingdriver %s with device %s\n",

               drv->bus->name, __func__, drv->name,dev_name(dev));

       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",

                     __func__, dev_name(dev));

              goto probe_failed;

       }

 

   //如果device结构相关联的总线的 probe 函数存在,先调用此 probe函数。虽然在platform_device_add()函数中为dev->bus赋过值:pdev->dev.bus =&platform_bus_type;但由于platform_bus_type中没有probe函数,因此此流程不走。

       if (dev->bus->probe) {

              ret = dev->bus->probe(dev);

              if (ret)

                     goto probe_failed;

       }

    //如果不存在就调用 device_driver结构体中的 probe函数,会走这个流程。

     else if (drv->probe) {

              ret = drv->probe(dev);

              if (ret)

                     goto probe_failed;

       }

 

       driver_bound(dev);

       ret = 1;

       pr_debug("bus: '%s': %s: bounddevice %s to driver %s\n",

               drv->bus->name, __func__, dev_name(dev),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 probefailed */

              printk(KERN_WARNING

                     "%s: probe of %s failed with error%d\n",

                     drv->name, dev_name(dev), 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;

}

 

 

还记得在 platform_driver_register中对device_driver结构体中的probe函数的初始化吗?

/**

 * platform_driver_register - register a driverfor platform-level devices

 * @drv: platform driver structure

 */

//kernel/drivers/base/platform.c

int  platform_driver_register(struct platform_driver *drv)

{

       drv->driver.bus =&platform_bus_type;

   //如果platform_driver中的probe函数存在,就将device_driver

 //结构体中的 probe函数赋值为platform_drv_probe

       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;

 

       return  driver_register(&drv->driver);

}


// kernel/drivers/i2c/busses/i2c_sc8810.c

static structplatform_driver sc8810_i2c_driver = {

       .probe         = sc8810_i2c_probe,

       .remove        =sc8810_i2c_remove,

       .driver          ={

              .owner   = THIS_MODULE,

              .name    = "sc8810-i2c",

       },

};

由此可见platform_driver中的probe函数是存在的,因此最后会调用 platform_drv_probe函数。

 

 

//kernel/drivers/base/platform.c

static int platform_drv_probe(struct device *_dev)

{

struct platform_driver*drv=to_platform_driver(_dev->driver);

       struct platform_device *dev =to_platform_device(_dev);

       return drv->probe(dev);

}

 

首先我们来看一下_dev->drive究竟是什么,回头看 really_probe函数可知,_dev->drive实际上就是device_driver。因此drv就是包含device_driver platform_driver,既sc8810_i2c_driver。则drv->probe就是sc8810_i2c_probe,如下所示:

//kernel\drivers\base\dd.c

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

{

       … …

       dev->driver = drv;

   … …

      

}

 

// kernel/drivers/i2c/busses/i2c_sc8810.c

static struct platform_driver sc8810_i2c_driver = {

       .probe         = sc8810_i2c_probe,

       .remove        =sc8810_i2c_remove,

       .driver          ={

              .owner   = THIS_MODULE,

              .name    = "sc8810-i2c",

       },

};

当platform_driver 和 platform_device匹配成功后会进入 sc8810_i2c_probe 函数,进行 i2c_adapter 和 i2c_client 的创建工作。