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

来源:互联网 发布:互联网大数据百度百科 编辑:程序博客网 时间:2024/06/05 10:43
本站分析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 
       }
}
只有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,在此基础上就可以轻松的去分析各个模块的驱动程序了^_^!