Platform是如何工作的?(以一个i2c控制器驱动为例)
这里有两者情况:
- device加入了(device_add函数触发)
- driver加入(driver_register函数触发)
这里的基础是bus_type下有device list和driver list
struct bus_type
->subsys_private
->struct klist klist_devices;
->struct klist klist_drivers;
开始分析,我们分析driver加入,从熟悉的platform_driver_register开始
static int __init i2c_adap_imx_init(void)
{
return platform_driver_register(&i2c_imx_driver);
}
subsys_initcall(i2c_adap_imx_init);//如果使用了,那么i2c_adap_imx_init就会在内核启动过程中被do_one_initcall调用。
-
platform_driver_register
#define platform_driver_register(drv) \ __platform_driver_register(drv, THIS_MODULE)
-
__platform_driver_register
int __platform_driver_register(struct platform_driver *drv, struct module *owner) { drv->driver.owner = owner; drv->driver.bus = &platform_bus_type;//这里指定了driver的bus if (drv->probe) drv->driver.probe = platform_drv_probe;//这里将platform_drv_probe给了driver的probe,最后执行really_probe要用到。 if (drv->remove) drv->driver.remove = platform_drv_remove; if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown; return driver_register(&drv->driver); }
-
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); 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; }
-
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; 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); kfree(drv->p); drv->p = NULL; out_put_bus: bus_put(bus); return error; }
-
driver_attach
int driver_attach(struct device_driver *drv) { return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); }
-
bus_for_each_dev
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,i->i_klist为bus的device list ;i->i_cur = NULL; (start ? &start->p->knode_bus : NULL)); while ((dev = next_device(&i)) && !error)//在这个循环中会便利bus上的dev,依次执行match,找到匹配的 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; /* * 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. */ if (!driver_match_device(drv, dev)) return 0; if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev);//如果成功匹配到那么就准备执行其bus上的probe device_unlock(dev); if (dev->parent) device_unlock(dev->parent); return 0; }
-
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要追溯到__platform_driver_register中的drv->driver.bus = &platform_bus_type;这里指定了driver的bus是platform_bus_type }
-
platform_bus_type
struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .pm = &platform_dev_pm_ops, };
-
platform_match
static int platform_match(struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); /* When driver_override is set, only bind to the matching driver */ if (pdev->driver_override) return !strcmp(pdev->driver_override, drv->name); /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1; /* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0); }
接下来分析match的匹配:(这里需要拿到platform_device与platform_driver)
-
platform_device
name: 字符串类型,表示设备的名称。用于在内核中唯一标识设备。 id: 整数类型,表示设备的ID。用于在同类型设备中区分不同的设备实例。 id_auto: 布尔类型,表示是否自动生成设备的ID。如果为真,则内核会自动分配设备的ID;如果为假,则使用id字段指定的ID。 dev: 包含struct device结构体的成员,用于描述设备的常规属性,如父设备、设备地址等。 num_resources: 无符号整数类型,表示设备资源的数量。可以是IO内存区域、中断等。 resource: 指向struct resource结构体的指针,用于描述设备的资源信息,如IO内存、中断的起始地址和范围。 id_entry: 指向struct platform_device_id结构体的指针,用于支持在设备驱动程序中根据设备ID进行匹配和绑定操作。 driver_override: 字符串类型,用于强制匹配设备与指定驱动程序的名称。当设备的driver_override字段被设置时,设备只会与该名称匹配的驱动程序进行绑定。 mfd_cell: 指向struct mfd_cell结构体的指针,用于支持多功能设备(Multifunction Device)的描述。 archdata: 特定于架构的扩展字段,用于存储与架构相关的设备信息。
-
platform_driver
static struct platform_driver i2c_imx_driver = { .probe = i2c_imx_probe, .remove = i2c_imx_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = i2c_imx_dt_ids, .pm = IMX_I2C_PM, }, .id_table = imx_i2c_devtype, };
-
/* When driver_override is set, only bind to the matching driver */ if (pdev->driver_override) return !strcmp(pdev->driver_override, drv->name);//这里跟.name = DRIVER_NAME,有关,由于对于driver_override的来由(设备树部分)不太熟这里具体情况分析不了,知道的可以告诉我
-
/* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1;
static inline int of_driver_match_device(struct device *dev, const struct device_driver *drv) { return of_match_device(drv->of_match_table, dev) != NULL;//用到了.driver中的of_match_table,与设备树的compatible进行匹配 }
由于目前我对于内核(总线)如何解析和拿到设备树不太清楚,所以不能展开分析。
-
/* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv))//与电源管理相关的驱动和设备有关 return 1;
-
/* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL;//使用.id_table
static const struct platform_device_id *platform_match_id( const struct platform_device_id *id, struct platform_device *pdev) { while (id->name[0]) {//遍历id_table与pdev->name去匹配(但是这里的pdev不太清楚是什么) if (strcmp(pdev->name, id->name) == 0) { pdev->id_entry = id; return id; } id++; } return NULL; }
-
/* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0);//再次使用.driver下的name与pdev->name匹配(第一次也是使用driver的name
ok,匹配过程说完了,那么匹配到了呢?回到我们的__driver_attach
-
__driver_attach
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_barrier(dev); ret = really_probe(dev, drv);//进入 pm_request_idle(dev); return ret; }
-
really_probe
static int really_probe(struct device *dev, struct device_driver *drv) { int ret = 0; int local_trigger_count = atomic_read(&deferred_trigger_count); 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 using pinctrl, bind pins now before probing */ ret = pinctrl_bind_pins(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; } if (dev->bus->probe) { ret = dev->bus->probe(dev);//不是执行总线的默认probe(而且有些总线还没有) if (ret) goto probe_failed; } else if (drv->probe) { ret = drv->probe(dev);//应该执行的是这个,前面应该把对应platform_driver的probe给了driver的probe if (ret) goto probe_failed; } if (dev->pm_domain && dev->pm_domain->sync) dev->pm_domain->sync(dev); 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; ....... ....... done: atomic_dec(&probe_count); wake_up(&probe_waitqueue); return ret;
drv->driver.probe = platform_drv_probe;
-
platform_drv_probe
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 != -EPROBE_DEFER) { ret = drv->probe(dev);//这里最终执行platform_driver的probe if (ret) dev_pm_domain_detach(_dev, true); } if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { dev_warn(_dev, "probe deferral not supported\n"); ret = -ENXIO; } return ret; }
最终执行:
static struct platform_driver i2c_imx_driver = {
.probe = i2c_imx_probe,
.remove = i2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = i2c_imx_dt_ids,
.pm = IMX_I2C_PM,
},
.id_table = imx_i2c_devtype,
};
中的i2c_imx_probe。
不足之处就是没有分析总线的dev信息是如何由设备树而来的。
补充一点:(其实really_probe中最终调用哪个probe是因总线而异的)
if (dev->bus->probe) {
ret = dev->bus->probe(dev);//就行i2c_bus是走这条
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);//platform是走这条
if (ret)
goto probe_failed;
}
为什么说i2c_bus能走那条呢?
因为i2c_bus上有默认的probe,而不需要像platform一样将另一个probe传给driver的probe
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
int status;
.......
.......
if (status != -EPROBE_DEFER) {
status = driver->probe(client, i2c_match_id(driver->id_table,
client));//执行真正的probe
if (status)
dev_pm_domain_detach(&client->dev, true);
}
return status;
}