Chinaunix首页 | 论坛 | 博客
  • 博客访问: 452186
  • 博文数量: 90
  • 博客积分: 2158
  • 博客等级: 大尉
  • 技术积分: 1435
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-12 17:02
个人简介

怎么了选择

文章分类
文章存档

2024年(1)

2023年(1)

2019年(1)

2018年(5)

2017年(5)

2015年(1)

2014年(1)

2013年(1)

2012年(74)

分类: LINUX

2012-01-13 11:35:24

接上一篇文章,继续device_add()中的代码:

      error = bus_add_device(dev);

       if (error)

              goto BusError;

在对应总线目录下的 device 目录下创建几个到 device 的链接文件。

       error = dpm_sysfs_add(dev);

       if (error)

              goto DPMError;

       device_pm_add(dev);

添加 power 文件。

       /* Notify clients of device addition.  This call must come

         * after dpm_sysf_add() and before kobject_uevent().

         */

       if (dev->bus)

              blocking_notifier_call_chain(&dev->bus->p->bus_notifier,

                                        BUS_NOTIFY_ADD_DEVICE, dev);

调用 bus 的回调函数。

       kobject_uevent(&dev->kobj, KOBJ_ADD);

产生一个 add 事件。

       bus_probe_device(dev);

这个函数将匹配已经注册到总线的驱动程序,如下:

void bus_probe_device(struct device *dev)

{

       struct bus_type *bus = dev->bus;

       int ret;

 

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

              ret = device_attach(dev);

              WARN_ON(ret < 0);

       }

}

只有 bus->p->drivers_autoprobe 设置为 1 是才会去匹配, device_attach() 如下:

int device_attach(struct device *dev)

{

       int ret = 0;

 

       down(&dev->sem);

       if (dev->driver) {

              ret = device_bind_driver(dev);

              if (ret == 0)

                     ret = 1;

              else {

                     dev->driver = NULL;

                     ret = 0;

              }

       } else {

              pm_runtime_get_noresume(dev);

              ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

              pm_runtime_put_sync(dev);

       }

       up(&dev->sem);

       return ret;

}

如果已指定了 dev->driver ,则直接在相应的 driver 目录下建立链接文件,将驱动和设备绑定。

int device_bind_driver(struct device *dev)

{

       int ret;

 

       ret = driver_sysfs_add(dev);

       if (!ret)

              driver_bound(dev);

       return ret;

}

driver_bound() 函数如下:

static void driver_bound(struct device *dev)

{

       if (klist_node_attached(&dev->p->knode_driver)) {

              printk(KERN_WARNING "%s: device %s already bound/n",

                     __func__, kobject_name(&dev->kobj));

              return;

       }

 

       pr_debug("driver: '%s': %s: bound to device '%s'/n", dev_name(dev),

                __func__, dev->driver->name);

 

       if (dev->bus)

              blocking_notifier_call_chain(&dev->bus->p->bus_notifier,

                                        BUS_NOTIFY_BOUND_DRIVER, dev);

 

       klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);

}

通知总线绑定驱动,将设备添加到驱动的设备链表。

否则调用 bus_for_each_drv() 匹配总线上的驱动:

int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,

                   void *data, int (*fn)(struct device_driver *, void *))

{

       struct klist_iter i;

       struct device_driver *drv;

       int error = 0;

 

       if (!bus)

              return -EINVAL;

 

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

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

       while ((drv = next_driver(&i)) && !error)

              error = fn(drv, data);

       klist_iter_exit(&i);

       return error;

}

历遍总线上的驱动,每次都调用回调函数 fn() (这里是 __device_attach ),如果 fn() 返回 1 则匹配成功, __device_attach() 如下:

static int __device_attach(struct device_driver *drv, void *data)

{

       struct device *dev = data;

 

       if (!driver_match_device(drv, dev))

              return 0;

 

       return driver_probe_device(drv, dev);

}

driver_match_device() 如下:

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 方法进行匹配,如果成功就会继续调用 driver_probe_device() 

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: matched device %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;

}

进行一下验证和同步后调用 really_probe() 最终详细的匹配:

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

{

       int ret = 0;

 

       atomic_inc(&probe_count);

       pr_debug("bus: '%s': %s: probing driver %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;

       }

 

       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("bus: '%s': %s: bound device %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 probe failed */

              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;

}

先假定 dev 的驱动为 drv ,然后如果总线闪的 probe 存在,则调用它,否则调用 drv  probe ()函数,返回 0 则匹配成功,调用 driver_bound() 进行设备和驱动的绑定。 driver_bound() 函数在上面已经分析。

 

接着 device_add() 函数中的代码:

       if (dev->class) {

              mutex_lock(&dev->class->p->class_mutex);

              /* tie the class to the device */

              klist_add_tail(&dev->knode_class,

                            &dev->class->p->class_devices);

 

              /* notify any interfaces that the device is here */

              list_for_each_entry(class_intf,

                                &dev->class->p->class_interfaces, node)

                     if (class_intf->add_dev)

                            class_intf->add_dev(dev, class_intf);

              mutex_unlock(&dev->class->p->class_mutex);

       }

Dev 所属 class 的一些操作。

done:

       put_device(dev);

       return error;

  DPMError:

       bus_remove_device(dev);

  BusError:

       device_remove_attrs(dev);

  AttrsError:

       device_remove_class_symlinks(dev);

  SymlinkError:

       if (MAJOR(dev->devt))

              device_remove_sys_dev_entry(dev);

  devtattrError:

       if (MAJOR(dev->devt))

              device_remove_file(dev, &devt_attr);

  ueventattrError:

       device_remove_file(dev, &uevent_attr);

  attrError:

       kobject_uevent(&dev->kobj, KOBJ_REMOVE);

       kobject_del(&dev->kobj);

  Error:

       cleanup_device_parent(dev);

       if (parent)

              put_device(parent);

name_error:

       kfree(dev->p);

       dev->p = NULL;

       goto done;

最后是一下除错撤销处理。

} 

至此,已经详细的分析了创建和注册设备的函数。

内核撤销设备注册的函数为 device_unregister() ,这里不再分析。

  

 

内核提供注册驱动的函数为 driver_register() 

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_type methods/n", drv->name);

验证 driver 的包含了需要的方法,并打印信息。

       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;

       }

如果驱动已注册则返回 -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() 代码如下:

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: uevent attr (%s) failed/n",

                     __func__, drv->name);

       }

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

                     __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:

       kfree(drv->p);

       drv->p = NULL;

       kobject_put(&priv->kobj);

out_put_bus:

       bus_put(bus);

       return error;

}

简单的分析一下:  drv 分配内存并初始化,创建文件系统中相应的目录、属性文件和链接,调用driver_attach() 匹配总线上的设备,将驱动注册到 bus 上,产生一个 kobject_uevent() ADD 事件。详细的过程请参考内核源码。

同样内核提供 driver_unregister() 函数撤销驱动注册,这里不再分析。

 

至此,已经清楚了设备驱动模型的 device  driver  bus ,在此基础上就可以轻松的去分析各个模块的驱动程序了 ^_^!  

阅读(962) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~