LINUX设备驱动之设备模型五--device&driver&bus(三)

    技术2025-09-27  85

    uthor: Eric Fang 

    Date:     2010-01-18

    -----------------------------------------------------------------

    本站分析linux内核源码,版本号为2.6.32.3

    转载请注明出处:http://ericfang.cublog.cn/

    -----------------------------------------------------------------

    接上一篇文章,继续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->busmatch方法进行匹配,如果成功就会继续调用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存在,则调用它,否则调用drvprobe()函数,返回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()函数撤销驱动注册,这里不再分析。

     

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

    最新回复(0)