在《 Linux 内核中设备树中的节点是如何转换为platform_device的》一文中已经介绍了编译进内核的驱动在内核中已经存在,内核启动的时候将设备树节点转换为平台设备,然后与内核中已经存在的驱动去如何进行匹配已经绑定。本文介绍另一个情况,就是驱动没有被编译到内核,内核启动时平台设备没有找到匹配的平台驱动,启动完成后我们动态加载驱动是如何实现匹配与绑定的。
我们以gpio_led_driver为例,分析整个注册过程:
static struct platform_driver gpio_led_driver = { .probe = gpio_led_probe, .shutdown = gpio_led_shutdown, .driver = { .name = "leds-gpio", .of_match_table = of_gpio_leds_match, }, }; module_platform_driver(gpio_led_driver);
展开以后就是:
#define module_platform_driver(__platform_driver) \ module_driver(__platform_driver, platform_driver_register, \ platform_driver_unregister)
module_driver --> platform_driver_register --> __platform_driver_register :
int __platform_driver_register(struct platform_driver *drv, struct module *owner) { drv->driver.owner = owner; drv->driver.bus = &platform_bus_type; drv->driver.probe = platform_drv_probe; drv->driver.remove = platform_drv_remove; drv->driver.shutdown = platform_drv_shutdown; return driver_register(&drv->driver); }
上面注册了相应的probe remove shutdown 等函数后,开始调用driver_register
drv->driver.bus = &platform_bus_type;
其中platform_bus_type也在文件. /drivers/base/platform.c 中有具体定义:
struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .dma_configure = platform_dma_configure, .pm = &platform_dev_pm_ops, };
我们是已platform为例讲解,所以注册驱动的总线类型是platform的。如果是I2C总线呢?
int i2c_register_driver(struct module *owner, struct i2c_driver *driver) { …… driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; …… }
所以,如果注册的是i2c驱动,那么总线类型初始化为i2c_bus_type,也可以在文件 ./ drivers/i2c/i2c-core.c 中看到其定义
struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, .pm = &i2c_device_pm_ops, };当总线类型和probe、remove、shutdown等函数注册后,就开始调用driver_register注册对应的驱动了。
int driver_register(struct device_driver *drv) { int ret; struct device_driver *other; if (!drv->bus->p) { pr_err("Driver '%s' was unable to register with bus_type '%s' because the bus was not initialized.\n", drv->name, drv->bus->name); return -EINVAL; } 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); //查找总线上是否已经有了本驱动 if (other) { printk(KERN_ERR "Error: Driver '%s' is already registered, " "aborting...\n", drv->name); return -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; } kobject_uevent(&drv->p->kobj, KOBJ_ADD); //注册uevent事件 return ret; }
首先来看driver_find,其实就是在总线的私有数据的drivers_kset列表中查找有没有这个驱动的名字:
struct device_driver *driver_find(const char *name, struct bus_type *bus) { struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); struct driver_private *priv; if (k) { /* Drop reference added by kset_find_obj() */ kobject_put(k); priv = to_driver(k); return priv->driver; } return NULL; }
struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ const struct of_device_id *of_match_table; const struct acpi_device_id *acpi_match_table; int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };
这个结构体里面包含了设备驱动的重要信息,例如名字(name)、总线类型(bus)、所述模块(owner)和一些用于回调的函数指针(probe,remove,suspend...)。
通过判断driver_find的返回值other,如果 if(other) 条件成立,说明other 不是NULL ,也就是说driver_find查找成功。但driver_register是注册驱动程序,如果驱动已经注册过,就不需要再次注册了。如果已经注册,那么直接 return -EBUSY; 后面的操作就不需要进行了。
看完driver_find,再来看bus_add_driver(drv):
int bus_add_driver(struct device_driver *drv) { struct bus_type *bus; struct driver_private *priv; int error = 0; bus = bus_get(drv->bus); //获取驱动所属的总线,也就是platform总线 if (!bus) return -EINVAL; pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); priv = kzalloc(sizeof(*priv), GFP_KERNEL); //分配一个priv结构体的空间 if (!priv) { error = -ENOMEM; goto out_put_bus; } klist_init(&priv->klist_devices, NULL, NULL);//初始化priv下的klist_devices列表,就是挂这个驱动所属的设备
priv->driver = drv; //priv下的驱动指向驱动 drv->p = priv; //驱动的p指向priv,也就是这里分配的priv是driver下的priv priv->kobj.kset = bus->p->drivers_kset; //driver下的priv的kobj.kset指向总线的私有数据的drivers_kset列表
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name); //kset, kobject节点初始化,koject插入kset链表(尾插) if (error) goto out_unregister; klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } 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_groups(drv, bus->drv_groups); if (error) { /* How the hell do we get out of this pickle? Give up */ printk(KERN_ERR "%s: driver_create_groups(%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); } } return 0; out_unregister: kobject_put(&priv->kobj); /* drv->p is freed in driver_release() */ drv->p = NULL; out_put_bus: bus_put(bus); return error; }
我们看下klist_init(&priv->klist_devices, NULL, NULL),第一个参数是本驱动的私有数据下的设备列表,后面两个参数传入的是NULL:
void klist_init(struct klist *k, void (*get)(struct klist_node *), void (*put)(struct klist_node *)) { INIT_LIST_HEAD(&k->k_list); spin_lock_init(&k->k_lock); k->get = get; k->put = put; }
在文件./include/linux/list.h中有INIT_LIST_HEAD定义
static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; }
很明显,这是一个 内联函数(有inline)。实现的功能也很简单,list是链表,我们在实现循环链表时总会定义两个指针 next 和 prev 。next指向下一个节点的地址,prev指向上一个节点的地址。所以INIT_LIST_HEAD其实就是使next和prev都指向自己的地址,我们判断链表是否为空的时候不就是看看next和prev指向的地址是否相同吗,相同表示为空。
因为驱动新创建所以挂在本驱动的设备驱动列表是空的,也就是建立一个空列表,初始化列表的头,列表的get和put都指向空。
再来看kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,"%s", drv->name);
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...) { va_list args; int retval; kobject_init(kobj, ktype); //里边主要对kobj->state_开头的一些变量赋初值,将驱动下的私有数据的kobj->type = driver_ktype va_start(args, fmt); //对传入的可变参数drv->name做处理 retval = kobject_add_varg(kobj, parent, fmt, args); va_end(args); return retval; }
kobject_init源码也在文件./lib/kobject.c 中:
void kobject_init(struct kobject *kobj, struct kobj_type *ktype) { char *err_str; if (!kobj) {//检查kobj指针是否指向有效的kobject err_str = "invalid kobject pointer!"; goto error; } if (!ktype) {//检查ktype是否指向有效的kobj_type err_str = "must have a ktype to be initialized properly!\n"; goto error; } if (kobj->state_initialized) {//检查kobj的初始化状态是否已经被初始化 /* do not error out as sometimes we can recover */ printk(KERN_ERR "kobject (%p): tried to init an initialized " "object, something is seriously wrong.\n", kobj); dump_stack(); } kobject_init_internal(kobj);//如果上面检查都通过,那么开始初始化 kobj->ktype = ktype; return; error: printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str); dump_stack(); }
static __printf(3, 0) int kobject_add_varg(struct kobject *kobj, struct kobject *parent, const char *fmt, va_list vargs) { int retval; retval = kobject_set_name_vargs(kobj, fmt, vargs); if (retval) { pr_err("kobject: can not set name properly!\n"); return retval; } kobj->parent = parent; return kobject_add_internal(kobj); }
kobject_add_varg(kobj, parent, fmt, args)==》kobject_set_name_vargs(kobj, fmt, vargs) :
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list vargs) { const char *s; if (kobj->name && !fmt) return 0; s = kvasprintf_const(GFP_KERNEL, fmt, vargs); if (!s) return -ENOMEM; /* * ewww... some of these buggers have '/' in the name ... If * that's the case, we need to make sure we have an actual * allocated copy to modify, since kvasprintf_const may have * returned something from .rodata. */ if (strchr(s, '/')) { char *t; t = kstrdup(s, GFP_KERNEL); kfree_const(s); if (!t) return -ENOMEM; strreplace(t, '/', '!'); s = t; } kfree_const(kobj->name); kobj->name = s; return 0; }
其实就是把drv->name做了一些格式化处理后赋值给了drv->priv_>kobj->name。
return kobject_add_internal(kobj);过kobject_add_internal将准备好的kobject添加到kset的循环列表中,并且在sys/目录下创建kobject的目录。
static int kobject_add_internal(struct kobject *kobj) { int error = 0; struct kobject *parent; if (!kobj) return -ENOENT; if (!kobj->name || !kobj->name[0]) { WARN(1, "kobject: (%p): attempted to be registered with empty name!\n", kobj); return -EINVAL; } parent = kobject_get(kobj->parent); 读取kobject的parent指针 /* join kset if set, use it as parent if we do not already have one */ if (kobj->kset) { //判断kobject的kset是否为空 if (!parent) //如果kobj->parent为空,则赋值为kobject的kset自带的kobject parent = kobject_get(&kobj->kset->kobj); kobj_kset_join(kobj);//把kobject挂到他的kset的列表kobj->kset->list上 kobj->parent = parent; } pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n", kobject_name(kobj), kobj, __func__, parent ? kobject_name(parent) : "<NULL>", kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>"); error = create_dir(kobj); //创建kobject的相关目录 if (error) { kobj_kset_leave(kobj); kobject_put(parent); kobj->parent = NULL; /* be noisy on error issues */ if (error == -EEXIST) pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n", __func__, kobject_name(kobj)); else pr_err("%s failed for %s (error: %d parent: %s)\n", __func__, kobject_name(kobj), error, parent ? kobject_name(parent) : "'none'"); } else kobj->state_in_sysfs = 1; //更改kobject的sys文件系统状态标志 return error; }
sysfs创建目录的代码就不详细说明了,记得在前面分析 kobject_init_and_add 时,有这样的一句注释 initialize a kobject structure and add it to the kobject hierarchy
static int populate_dir(struct kobject *kobj) { struct kobj_type *t = get_ktype(kobj); struct attribute *attr; int error = 0; int i; if (t && t->default_attrs) { for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) { error = sysfs_create_file(kobj, attr); if (error) break; } } return error; }
static struct platform_driver gpio_led_driver = { .probe = gpio_led_probe, .shutdown = gpio_led_shutdown, .driver = { .name = "leds-gpio", .of_match_table = of_gpio_leds_match, }, };
可以看到driver->name 是“leds-gpio”。通过platform_driver_register(&gpio_led_driver);注册platform架构驱动。当代码执行到上述过程,肯定会在sysfs下创建相关的目录,并且以 kobject->name 命名。
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); 就是把drv->priv->knode_bus挂在了platform总线的私有数据的驱动列表里。
接着就到了最重要的driver_attach(drv):
int driver_attach(struct device_driver *drv) { return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); }
展开以后:
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 || !bus->p) return -EINVAL; klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->p->knode_bus : NULL)); while (!error && (dev = next_device(&i))) error = fn(dev, data); klist_iter_exit(&i); return error; }
其实就是对平台总线的私有数据中的设备列表中挂的每一个设备与本驱动传入到__driver_attach执行一遍,也就是进行匹配。
static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; int ret; /* * 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. */ ret = driver_match_device(drv, dev); if (ret == 0) { /* no match */ return 0; } else if (ret == -EPROBE_DEFER) { dev_dbg(dev, "Device match requests probe deferral\n"); driver_deferred_probe_add(dev); } else if (ret < 0) { dev_dbg(dev, "Bus failed to match device: %d", ret); return ret; } /* ret > 0 means positive match */ if (driver_allows_async_probing(drv)) { /* * Instead of probing the device synchronously we will * probe it asynchronously to allow for more parallelism. * * We only take the device lock here in order to guarantee * that the dev->driver and async_driver fields are protected */ dev_dbg(dev, "probing driver %s asynchronously\n", drv->name); device_lock(dev); if (!dev->driver) { get_device(dev); dev->p->async_driver = drv; async_schedule(__driver_attach_async_helper, dev); } device_unlock(dev); return 0; } device_driver_attach(drv, dev); return 0; }
然后就是进行匹配,匹配成功调用本驱动的probe函数,这些在《 Linux 内核中设备树中的节点是如何转换为platform_device的》一文中已经介绍过,此处不再重复。