Chinaunix首页 | 论坛 | 博客
  • 博客访问: 561195
  • 博文数量: 105
  • 博客积分: 3274
  • 博客等级: 中校
  • 技术积分: 1161
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-21 12:14
文章分类

全部博文(105)

文章存档

2011年(1)

2010年(104)

分类: LINUX

2010-07-22 20:17:18

platform设备这端的就分析完了,下面开始platform驱动端,还是以spi为例。

初始化代码

static struct platform_driver atmel_spi_driver = {

       .driver            = {

              .name      = "atmel_spi",

              .owner    = THIS_MODULE,

       },

       .suspend  = atmel_spi_suspend,

       .resume          = atmel_spi_resume,

       .remove          = __exit_p(atmel_spi_remove),

};

 

static int __init atmel_spi_init(void)

{

       return platform_driver_probe(&atmel_spi_driver, atmel_spi_probe);

}

module_init(atmel_spi_init);

 

static void __exit atmel_spi_exit(void)

{

       platform_driver_unregister(&atmel_spi_driver);

}

module_exit(atmel_spi_exit);

上节中at91sam9263_spi0_device结构体里面的.name= "atmel_spi",刚好与这里.driver           = {

              .name      = "atmel_spi",

              .owner    = THIS_MODULE,

       },对应起来了,这样就把总线的设备和驱动联系起来了。

进入platform_driver_probe看看,代码很少

/**

 * platform_driver_probe - register driver for non-hotpluggable device

 * @drv: platform driver structure :platform 驱动结构体

 * @probe: the driver probe routine, probably from an __init section :driver probe

 *

 * Use this instead of when you know the device

 * is not hotpluggable and has already been registered, and you want to

 * remove its run-once probe() infrastructure from memory after the driver

 * has bound to the device.

当你知道设备不是可热插拔的,设备已经被注册,并且你想在驱动被绑定到设备 之后,运行一次probe()就删除掉probe时,就用这个来代替platform_driver_register()

 * One typical use for this would be with drivers for controllers integrated

 * into system-on-chip processors, where the controller devices have been

 * configured as part of board setup.

 *一个典型的应用就是SOC上的驱动控制器,因为这些控制器设备在板子启动时就已经配置好了。

 * Returns zero if the driver registered and bound to a device, else returns

 * a negative error code and with the driver not registered.

 */如果驱动注册且绑定到设备成功则返回1,否则返回错误代码,并且驱动没有不会被注册。

int __init_or_module platform_driver_probe(struct platform_driver *drv,

              int (*probe)(struct platform_device *))

{

       int retval, code;

 

       /* temporary section violation during probe() */

       drv->probe = probe;

       retval = code = platform_driver_register(drv);

 

       /* Fixup that section violation, being paranoid about code scanning

        * the list of drivers in order to probe new devices.  Check to see

        * if the probe was successful, and make sure any forced probes of

        * new devices fail.

        */

       spin_lock(&platform_bus_type.p->klist_drivers.k_lock);

       drv->probe = NULL;

       if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))

              retval = -ENODEV;

       drv->driver.probe = platform_drv_probe_fail;

       spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);

 

       if (code != retval)

              platform_driver_unregister(drv);

       return retval;

}

接下来进入retval = code = platform_driver_register(drv);这个函数很简单,就是简单的函数指针赋地址,最后再注册驱动

/**

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

       if (drv->pm)

              drv->driver.pm = &drv->pm->base;

       return driver_register(&drv->driver);

}

分析下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)

{

       int ret;

       struct device_driver *other;

 

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

 

       other = driver_find(drv->name, drv->bus);  // 寻找drv是否已经注册

       if (other) {                            // 如果注册,则返回错误

              put_driver(other);

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

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

              return -EEXIST;

       }

 

       ret = bus_add_driver(drv);   // 没有注册则在总线上寻找驱动

       if (ret)

              return ret;

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

       if (ret)

              bus_remove_driver(drv);

       return ret;

}

跟踪ret = bus_add_driver(drv);

/**

 * bus_add_driver - Add a driver to the bus.

 * @drv: driver.

 */在总线上增加一个驱动

int bus_add_driver(struct device_driver *drv)

{

       struct bus_type *bus;

       struct driver_private *priv;

       int error = 0;

 

       bus = bus_get(drv->bus);   // bus计数加1

       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);  //增加showstore属性

       if (error)

              goto out_unregister;

 

       if (drv->bus->p->drivers_autoprobe) {  // 需要自动探测

              error = driver_attach(drv);      // 尝试把driver绑定到设备上

              if (error)

                     goto out_unregister;

       }

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

       module_add_driver(drv->owner, drv);  // 配置模块下的driver属性

 

       error = driver_create_file(drv, &driver_attr_uevent); // driver创建sysfs

       if (error) {

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

                     __func__, drv->name);

       }

       error = driver_add_attrs(bus, drv); // 增加driver属性

       if (error) {

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

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

                     __func__, drv->name);

       }

       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); // 增加uevent属性

       return error;

out_unregister:

       kobject_put(&priv->kobj);

out_put_bus:

       bus_put(bus);

       return error;

}

我们把重点放在error = driver_attach(drv);  

/**

 * 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了吧,是不是有种似曾相识的感觉

/**

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

 */该函数迭代了在总线上的每个设备,并将相关的设备结构传递给fn,同时传递给data,如果startNULL,则将从总线上的第一个设备迭代,否则将从start后的第一个设备迭代。如果fn返回一个非零值,则停止迭代,而这个值也会返回

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->p->klist_devices, &i,

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

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

              error = fn(dev, data);

       klist_iter_exit(&i);

       return error;

}

看看bus_for_each_devfn参数,调用了__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;

}

该函数与__device_attach一样也调用了driver_probe_device()

 

从以上分析我们可以看出平台驱动注册的流程

platform_driver_probe->platform_driver_register->driver_register-> bus_add_driver

匹配总线上的设备的流程如下

bus_add_driver->driver_attach->bus_for_each_dev->__driver_attach->driver_probe_device->really_probe-> driver_bound

至此,平台设备的分析就结束了。

阅读(1513) | 评论(0) | 转发(0) |
0

上一篇:Platform 分析(1)

下一篇:at91sam9263升级模式

给主人留下些什么吧!~~