对于驱动工程师而言,在移植porting对应设备的driver时,要在devicetree中增加对应的设备节点,其中有一个compatible属性,这个属性的字符串要和driver里面的of_device_id.compatible字符串要一致才能匹配调用驱动probe函数。 那device和driver是如何匹配?device,driver匹配后三者之间的数据结构联系是什么样的?
这是三者之间的联系图,后面我们从platform bus注册,platform_device创建注册和platform_driver注册。在其注册过程中产生如下的关系
图一
1.platform bus注册时主要做了什么
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,
};
int __init platform_bus_init(void)
{
int error;
early_platform_cleanup();
error = device_register(&platform_bus);
if (error) {
put_device(&platform_bus);
return error;
}
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
of_platform_register_reconfig_notifier();
return error;
}
int bus_register(struct bus_type *bus)
{
int retval;
struct subsys_private *priv;
struct lock_class_key *key = &bus->lock_key;
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); //先分配struct subsys_private空间
if (!priv)
return -ENOMEM;
priv->bus = bus; //指向bus
bus->p = priv; //把bus的p指针指向struct subsys_private
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //把bus的name赋值给subsys.kobj,用于后面再/sys/bus/下面创建platform文件夹
if (retval)
goto out;
priv->subsys.kobj.kset = bus_kset; //给subsys.kob指定bus_kset, 由于没由给subsys.kobj指定parent,所以后面subsys.kobj->parent会指向bus_kset.kobj
priv->subsys.kobj.ktype = &bus_ktype; //主要是这种类型的release的回调函数,和sysfs_ops
priv->drivers_autoprobe = 1; //允许增加device或driver时自动匹配probe
retval = kset_register(&priv->subsys); //在前面的bus_kset.kobj下面创建文件夹,这里就是上面的bus_kset,也就是对应/sys/bus文件夹
if (retval)
goto out;
retval = bus_create_file(bus, &bus_attr_uevent); //在/sys/bus/platform下创建uevent属性文件
if (retval)
goto bus_uevent_fail;
priv->devices_kset = kset_create_and_add("devices", NULL,
&priv->subsys.kobj); //在/sys/bus/platform下创建devices文件夹用于存放platform_device
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}
priv->drivers_kset = kset_create_and_add("drivers", NULL,
&priv->subsys.kobj); //在/sys/bus/platform下创建drivers文件夹用于存放platform_driver
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}
INIT_LIST_HEAD(&priv->interfaces);
__mutex_init(&priv->mutex, "subsys mutex", key);
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); //初始化bus的存放devices的链表,用于存放device
klist_init(&priv->klist_drivers, NULL, NULL); //初始化bus的存放drivers的链表,用于存放driver
retval = add_probe_files(bus); //在/sys/bus/platform下创建drivers_autoprobe和drivers_probe两个属性文件
if (retval)
goto bus_probe_files_fail;
retval = bus_add_groups(bus, bus->bus_groups); //这一块没看懂,但是理论上就是在对应的platform/devices/xxx/创建modalias和driver_override
if (retval)
goto bus_groups_fail;
pr_debug("bus: '%s': registered\n", bus->name);
return 0;
}
注册platform bus,最主要的事情,应该有一下几点:
1). 初始化bus的存放klist_devices的链表,用于链接platform_device.dev.p->knode_bus
2.) 初始化bus的存放klist_drivers的链表,用于链接platform_driver.device_driver.p->knode_bus
3.) 注册platform_match回调函数,用于platform_device, platform_driver的匹配函数
2.platform_device创建注册
由于流程比较长,这里先上图
图二
platform_device初始化
static struct platform_device *of_platform_device_create_pdata(
struct device_node *np,
const char *bus_id,
void *platform_data,
struct device *parent)
{
struct platform_device *dev;
if (!of_device_is_available(np) ||
of_node_test_and_set_flag(np, OF_POPULATED))
return NULL;
/*
* of_device_alloc主要给platform_device分配空间,调用了device_initialize,
* 并初始化了一些resource包含irq, reg,并将resource赋值给platform_device->resource
*/
dev = of_device_alloc(np, bus_id, parent);
if (!dev)
goto err_clear_flag;
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
if (!dev->dev.dma_mask)
dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
/*
* 注意这里,这里将platform_device->dev.bus赋值为platform_bus_type, 后面
* platform_device, platform_driver就是根据这里的bus调用对应的platform_match函数
*/
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
of_msi_configure(&dev->dev, dev->dev.of_node);
if (of_device_add(dev) != 0) {
platform_device_put(dev);
goto err_clear_flag;
}
return dev;
err_clear_flag:
of_node_clear_flag(np, OF_POPULATED);
return NULL;
}
根据上面图二的调用流程,我们解下来简单分析一下device_add函数
//下面函数有精简
int device_add(struct device *dev)
{
struct device *parent;
struct kobject *kobj;
struct class_interface *class_intf;
int error = -EINVAL, fw_ret;
struct kobject *glue_dir = NULL;
dev = get_device(dev);
if (!dev)
goto done;
if (!dev->p) {
/*
* 初始化device.p,后续会用到p->knode_driver, p->knode_bus,分别用来关联driver, bus
*/
error = device_private_init(dev);
if (error)
goto done;
}
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
error = device_create_file(dev, &dev_attr_uevent);
if (error)
goto attrError;
error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
error = device_add_attrs(dev);
if (error)
goto AttrsError;
/*
* 将dev->p->knode_bus加入到bus的&bus->p->klist_devices链表里面去,这就将device和bus关
* 联起来了
*/
error = bus_add_device(dev);
if (error)
goto BusError;
/*
* 下面是从bus的klist_drivers链表里面每个节点的driver进行匹配,匹配上后调用driver的probe
*/
bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
done:
put_device(dev);
return error;
}
接着我们跳到driver_match_device函数
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
/*
* 能走到这里的前提是platform_driver已经注册到了platform bus上去了,那么这里先看流程。
* platform_driver注册的时候platform_driver.drv->bus已经赋值为platform_bus_type,所以
* 调用bus->match函数就会调用到platform_bus_type.match, 也就是platform_match。
*/
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
上面就match完成了,解下来要调用platform_driver的probe函数。下面看看调用probe前做了哪些事。
//下面这个函数略有精简
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = -EPROBE_DEFER;
int local_trigger_count = atomic_read(&deferred_trigger_count);
bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
!drv->suppress_bind_attrs;
re_probe:
//这里将device->driver指向匹配的device_driver, 如果probe失败下面会赋值为NULL
dev->driver = drv;
/* If using pinctrl, bind pins now before probing */
/*
* 会从pinctrl_list里面获取device对应的pinctrl, 如果存在"init"名称的pinctrl, 那么就选择
* 设置“init”的pinctrl模式。如不存在"init"的pinctrl, 就选择设置为"default"名字的pinctrl
*/
ret = pinctrl_bind_pins(dev);
if (ret)
goto pinctrl_bind_failed;
//dma配置相关的
ret = dma_configure(dev);
if (ret)
goto probe_failed;
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
if (dev->pm_domain && dev->pm_domain->activate) {
ret = dev->pm_domain->activate(dev);
if (ret)
goto probe_failed;
}
// 对于platform_bus_type这里的probe是没有赋值的,所以不会走这个分支
if (dev->bus->probe) {
BOOTPROF_TIME_LOG_START(ts);
ret = dev->bus->probe(dev);
BOOTPROF_TIME_LOG_END(ts);
bootprof_probe(ts, dev, drv, (unsigned long)dev->bus->probe);
if (ret)
goto probe_failed;
} else if (drv->probe) {
BOOTPROF_TIME_LOG_START(ts);
/* 具体platform_driver的probe是有赋值的,这里device_driver->probe会回调到platform_driver的
* Probe。后面分析platform_driver注册的时候,再来看看。
*/
ret = drv->probe(dev);
BOOTPROF_TIME_LOG_END(ts);
bootprof_probe(ts, dev, drv, (unsigned long)drv->probe);
if (ret)
goto probe_failed;
}
pinctrl_init_done(dev);
/*
* 将&dev->p->knode_driver放到driver的dev->driver->p->klist_devices链表中,这样device和
* driver就建立了联系
*/
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;
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}
上面platform_device整个注册流程就走完了。
3.platform_driver的注册流程
图三
下面看看platform_driver的注册流程
#define platform_driver_register(drv) \
__platform_driver_register(drv, THIS_MODULE)
int __platform_driver_register(struct platform_driver *drv,
struct module *owner)
{
drv->driver.owner = owner;
//这里直接将platform_driver->driver.bus直接赋值为platform_bus_type
drv->driver.bus = &platform_bus_type;
//将platform_driver->driver.probe 直接赋值为platform_drv_probe
drv->driver.probe = platform_drv_probe;
drv->driver.remove = platform_drv_remove;
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);
}
static int platform_drv_probe(struct device *_dev)
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
int ret;
ret = of_clk_set_defaults(_dev->of_node, false);
if (ret < 0)
return ret;
ret = dev_pm_domain_attach(_dev, true);
if (ret)
goto out;
//如果platform_driver->probe有赋值的,那么直接调用platform_driver->probe, 这里就是上面讲relly_probe时说的,会回调到platform_driver->probe
if (drv->probe) {
ret = drv->probe(dev);
if (ret)
dev_pm_domain_detach(_dev, true);
}
out:
if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
dev_warn(_dev, "probe deferral not supported\n");
ret = -ENXIO;
}
return ret;
}
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);
//到对应的bus上找又没有名字叫drv->name,如存在则说明已经这个driver在该类型的bus上已经注册上了
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);
return ret;
}
根据图三函数调用流程__platform_driver_register->driver_register, 来看一下driver_register
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);
//这里初始化driver_private,driver->p
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
//初始化klist_devices,后面用来存放对应的device->p->knode_driver节点
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;
//这里讲drvier和bus建立链接,把driver->p->knode_bus加入到了bus的bus->p->klist_drivers链表中
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
if (driver_allows_async_probing(drv)) {
pr_debug("bus: '%s': probing driver %s asynchronously\n",
drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else {
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;
}
下面看一下__driver_attach, driver_attach->__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.
*/
//这里还是调用drv->bus->match(dev, drv),也就是调用到platform_bus_type->match函数
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 (dev->parent && dev->bus->need_parent_lock)
device_lock(dev->parent);
device_lock(dev);
if (!dev->p->dead && !dev->driver)
//这函数里面会调用really_probe,这个就和前面注册device是一样,就不往下分析了
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent && dev->bus->need_parent_lock)
device_unlock(dev->parent);
return 0;
}