linux学习笔记2--diver初始化及设备模型

driver的初始化,主要是填充了device_driver里的driver_private这个结构体:

struct driver_private {
struct kobject kobj;
struct klist klist_devices;
struct klist_node knode_bus;
struct module_kobject *mkobj;
struct device_driver *driver;
};

下面一一解释:
1. kobject和 kset:在linux系统中,最基本的元素就是Kobject,而 Kobject的集合被称为Kset(kobject set),kobject的parent一定是kset的kobject,且同属于一个kset的kobjecs他们的ktype是相同的,均为kset的ktype,这点在kobject初始化的时候被确定,下面会详细解释。
2. klist_devices,这个变量代表了该driver可以驱动的device。
3. knode_bus,代表了该driver在bus的klist_driver中的节点。
4. mkobject,代表了该driver在moudles里的对象实例,在moudle_add_driver时被赋值。
5. devicer_driver 指向自己的driver指针。

driver初始化的流程:
首先,我们会在代码里用moudle_init()宏来声明我们的driver的初始化函数,在kernel初始化中,被do_initcalls依次调用。

Kernel\drivers\base\platform.c                                platform_driver_register

Kernel\drivers\base\Driver.c                                   driver_register

Kernel\drivers\base\bus.c                                        bus_add_driver

Kernel\drivers\base\dd.c                                        driver_attach

Kernel\drivers\base\bus.c                                  bus_for_each_dev

Kernel\drivers\base\dd.c                                   __device_attach

kernel\drivers\base\base.h                                  driver_match_device

Kernel\drivers\base\dd.c                                        driver_probe_device   
其中,核心函数是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);      //获取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);// 初始化diver支持的devicelist,
priv->driver = drv;  
drv->p = priv;  // 互指
priv->kobj.kset = bus->p->drivers_kset; // 将driver的kset赋值为bus的kset

error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, /* 此处会初始化driver的kobject,给driver找了个爹,即将parent指针赋值为bus的driver kset,并将其添    
                                                                                                                     加到bus的kset 链表尾部,并调用create_dir在sysfs中创建对应的目录:sys/platform/driver/mydriver
                                                                                                                           再将state_in_sysfs置为1 */

    "%s", drv->name);
if (error)
goto out_unregister;


if (drv->bus->p->drivers_autoprobe) {      
error = driver_attach(drv);                     //如果设置了自动匹配,这里会调用driverattach 尝试与bus下挂载的device绑定,下面会详细分析。
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); // 将driver添加到bus的 klistdriver里去

module_add_driver(drv->owner, drv); // 将driver添加到moudles里,这里会对mkobject赋值,创建sys/moudles/my/drivers目录,并在此目录下创建"platform:mydriver快    
                                                           //  捷方式,指向 sys/platform/drivers/mydriver",在sys/platform/drivers/mydrive下创建moudles文件,指向sys/moudles/my/drivers



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:
kobject_put(&priv->kobj);
kfree(drv->p);
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
driver_attach的代码如下,实际就是bus_for_each_dev
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
在bus_for_each_dev里会遍历当前bus的klist_devices ,逐一的调用__driver_attach与driver匹配。

static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;

if (!driver_match_device(drv, dev))         //此处实际调用的是platform的match,在platform结构体里有说明,即platform_match,单纯的匹配设备和驱动的name
return 0;


if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver)
driver_probe_device(drv, dev);      //如果没有匹配到,则调用此函数适配,而此函数真正起作用的是really_probe();
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);


return 0;
}
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)) {                                     //生成:sys/platform/dev/"drive"          /sys/platform/drive/"device",分别互相指向device路径和driver路径,就一快捷方式
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); //调用bus的prob函数
if (ret)
goto probe_failed;
} else if (drv->probe) {          //YQ: 调用driver结构体里的prob函数,这里通常会初始化一些数据,并注册中断等
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}


driver_bound(dev);  //将device添加到driver的klist_devices末尾,你是我的了~
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;
}
这样,driver和device就绑定了其实总结下来一共就那么几件事情:
1. driver的Kobject的完善,在sys/platform/drivers下创建了自己的目录,并将driver添加到 bus的 ksetlist里,其实就是按个家,找个爹
2. driver和device的匹配,如果成功,则在sys/platform/drivers/mydriver目录下创建指向sys/platform/dev/mydevice的link文件,在ys/platform/dev/mydevice创建“driver”指向sys/platform/drivers/mydrive,将driver赋值给device的driver,将device添加到driver的klist末尾,所谓心心相映,找个对象。
3. 在moudles目录下创建自己的链接,完善mkobject,方便系统调用。

T B C


你可能感兴趣的:(linux,struct,Module,null,UP,each)