一. Linux平台设备和平台驱动模型简介
Linux在系统总线有一类总线成为平台总线(platform bus),平台总线包括平台设备(platform device)和平台驱动(platform driver),平台总线是一种虚拟的总线,但是同spi和i2c等物理总线一样,Linux通过系统总线来管理他们。
总线及其设备和驱动模型是Linux驱动中一种基本模型,可以将一类总线的多个设备和多个驱动管理起来,当总线的驱动和设备匹配成功后,会使驱动产生probe行为。由于将一个驱动功能分成了设备部分和驱动部分代码,当板级引脚资源发生变化时,只需要修改代码中的设备部分就可以,驱动部分代码可以不动。
由于本文会用到较多的kobject相关的函数,如果对此不熟,可以先参考我前面的博文设备模型管理对象kobject介绍
二. Linux系统总线和平台总线分析
1. 系统总线初始化
在了解平台总线之前需要先了解系统总线的初始化过程。
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
if (!bus_kset)
return -ENOMEM;
......
return 0;
}
所有的总线都是由一个struct kset类型的bus_kset结构管理的,kset_create_and_add函数没有指定parent,所以会在/sys下创建一个bus的目录。bus_kset->kobj.name初始化为bus,bus_kset->kobj->kset为NULL。
2. 平台总线初始化
平台总线是由一个全局结构体platform_bus_type管理,通过bus_register函数注册到bus_kset,并做一些初始化工作。
int bus_register(struct bus_type *bus)
{
int retval;
struct subsys_private *priv;
struct lock_class_key *key = &bus->lock_key;
/* 每个总线分配一个struct subsys_private结构体,用于管理驱动和设备 */
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* 通过priv->bus可以访问platform_bus_type */
priv->bus = bus;
/* platform_bus_type.p可以访问到priv结构 */
bus->p = priv;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); /* */
if (retval)
goto out;
/* priv->subsys.kobj.kset指向bus_kset */
priv->subsys.kobj.kset = bus_kset;
/* priv->subsys.kobj.ktype指向bus_ktype */
priv->subsys.kobj.ktype = &bus_ktype;
/* 表示device和driver match成功后,driver自动probe */
priv->drivers_autoprobe = 1;
/* 将priv->subsys链入到bus_kset */
retval = kset_register(&priv->subsys);
if (retval)
goto out;
/* 创建/sys/bus下的platform目录 */
retval = bus_create_file(bus, &bus_attr_uevent);
if (retval)
goto bus_uevent_fail;
/* 将priv->devices_kset链入到priv->subsys.kobj中 */
priv->devices_kset = kset_create_and_add("devices", NULL,
&priv->subsys.kobj);
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}
/* 将priv->drivers_kset链入到priv->subsys.kobj中 */
priv->drivers_kset = kset_create_and_add("drivers", NULL,
&priv->subsys.kobj);
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}
/* 初始化priv->interface链表 */
INIT_LIST_HEAD(&priv->interfaces);
__mutex_init(&priv->mutex, "subsys mutex", key);
/* 初始化priv->klist_devices klist,这个链表用来链入总线下的设备 */
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
/* 初始化priv->klist_drivers */
klist_init(&priv->klist_drivers, NULL, NULL);
retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;
retval = bus_add_groups(bus, bus->bus_groups);
if (retval)
goto bus_groups_fail;
pr_debug("bus: '%s': registered\n", bus->name);
return 0;
bus_groups_fail:
remove_probe_files(bus);
bus_probe_files_fail:
kset_unregister(bus->p->drivers_kset);
bus_drivers_fail:
kset_unregister(bus->p->devices_kset);
bus_devices_fail:
bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
kset_unregister(&bus->p->subsys);
out:
kfree(bus->p);
bus->p = NULL;
return retval;
}
int __init platform_bus_init(void)
{
int error;
......
/* 通过bus_register函数将platform_bus_type注册到bus_kset */
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}
通过上面的代码,bus_register通过内存分配创建struct subsys_private结构,并且链入到bus_kset中。
三. LInux平台驱动和平台设备分析
本章以一个具体的代码案例开始,通过分析案例代码执行过程,进一步分析平台设备和平台驱动的工作原理。代码如下:
platform_driver.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
int platform_drviver_probe(struct platform_device *pdev)
{
printk("platform driver probe !\n");
return 0;
}
struct platform_driver platform_drv = {
.probe = platform_drviver_probe,
.driver = {
.name = "platform_driver_test",
}
};
static int platform_driver_init(void)
{
platform_driver_register(&platform_drv);
return 0;
}
void platform_driver_exit(void)
{
platform_driver_unregister(&platform_drv);
return;
}
module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("GPL");
platform_device.c :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
struct platform_device platform_dev = {
.name = "platform_driver_test",
};
static int platform_device_init(void)
{
platform_device_register(&platform_dev);
return 0;
}
void platform_device_exit(void)
{
platform_device_unregister(&platform_dev);
return;
}
module_init(platform_device_init);
module_exit(platform_device_exit);
MODULE_LICENSE("GPL");
Makefile模板:
obj-m := platform_device.o
CROSS_COMPILE:=/opt/mipsel-mt7620-linux-gnu/bin/mipsel-mt7620-linux-gnu-
KDIR:=/opt/linux-3.18.45
all:
make CROSS_COMPILE=$(CROSS_COMPILE) ARCH="mips" -C $(KDIR) M=$$PWD
代码效果:
/media/platform_model/platform_driver # insmod platform_driver.ko
/media/platform_model/platform_driver # cd ../platform_device/
/media/platform_model/platform_device # insmod platform_device.ko
[ 70.540000] platform driver probe !
[ 70.550000] platform_driver_test: probe of platform_driver_test.0 failed with error 23
当platform_drver.ko加载后,再加载platform_device.ko驱动后,打印了"platform driver probe !",说明platform_driver.c中的platform_drviver_probe函数被调用了。接下来就通过分析platform_driver_register和platform_device_register,了解平台驱动和平台设备的工作原理。
1. platformm_driver_register函数分析
struct kobject *kset_find_obj(struct kset *kset, const char *name)
{
struct kobject *k;
struct kobject *ret = NULL;
spin_lock(&kset->list_lock);
/* 通过遍历devices_kset的驱动的kobj链表,找出是否有与name相同的驱动 */
list_for_each_entry(k, &kset->list, entry) {
if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
/* kobj->kref这里会加1 */
ret = kobject_get_unless_zero(k);
break;
}
}
spin_unlock(&kset->list_lock);
return ret;
}
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 */
/* 在设备树中找和dev匹配的drv */
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 */
/* 通过比较pdev->name和drv->name是否一致 */
return (strcmp(pdev->name, drv->name) == 0);
}
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
/* 此处drv->bus->match指向platform_match函数 */
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
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 */
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;
}
/* dev->bus->probe为NULL */
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
/* 运行platform_driver中指定的probe函数 */
} 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;
dev_set_drvdata(dev, NULL);
if (ret == -EPROBE_DEFER) {
/* Driver requested deferred probing */
dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
driver_deferred_probe_add(dev);
/* Did a trigger occur while probing? Need to re-trigger if yes */
if (local_trigger_count != atomic_read(&deferred_trigger_count))
driver_deferred_probe_trigger();
} else 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);
} else {
pr_debug("%s: probe of %s rejects match %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;
}
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
/* dev->kobj->state_in_sysfs是否为1 */
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;
}
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);
/* 如果dev没有指定driver,调用probe */
if (!dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
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;
/* 初始化struct klist_iter i, i.i_klist = &bus->p->klist_devices, i.i_cur = NULL */
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
/* 遍历bus->p->klist_devices,执行__driver_attach(dev, drv) */
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
/* 检查drv->bus是否为空,并且drv->bus->p->subsys.kobj.kref加1,返回drv->bus */
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
/* 分配一个struct driver_private结构 */
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
/* 初始化struct driver_private priv->klist_devices链表 */
klist_init(&priv->klist_devices, NULL, NULL);
/* struct driver_private priv->driver指向drv */
priv->driver = drv;
/* drv->p也指向priv结构 */
drv->p = priv;
/* priv->kobj.kset指向platform_bus_type.p->drivers_kset */
priv->kobj.kset = bus->p->drivers_kset;
/* 初始化priv->kobj,priv->kobj->name为drv->name */
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
/* priv->knode_bus加入到bus->p->klist_drivers链表中 */
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
/* 判断驱动是否设置为自动probe */
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
module_add_driver(drv->owner, drv);
/* 在/sys/bus/platform/drivers下创建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;
}
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() */
/* kset_find_obj使kobj->kref加1,这里需要减1 */
kobject_put(k);
/* 通过kobj地址获取struct driver_private结构的地址 */
priv = to_driver(k);
/* 返回找到的已注册的struct device_driver结构的地址 */
return priv->driver;
}
return NULL;
}
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);
/* 检查drv->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;
}
struct bus_type platform_bus_type = {
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
int __platform_driver_register(struct platform_driver *drv,
struct module *owner)
{
drv->driver.owner = owner;
/* drv->driver.bus指向platform_bus_type */
drv->driver.bus = &platform_bus_type;
/* drv->probe指定的情况,drv->driver.probe指向platform_drv_probe */
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);
}
/* include/linux/platform_device.h */
#define platform_driver_register(drv) \
__platform_driver_register(drv, THIS_MODULE)
重要代码的解析在代码的上方。经过上面的代码处理,结构大概如下所示。
2. 系统设备分析
在介绍平台设备之前需要先介绍系统设备,也就是我们在/sys/devices下看到的设备,其实/sys/bus/platform/devices下的设备都是链接的/sys/devices下的设备,所以需要先分析它。
int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;
......
}
此处会在/sys下创建devices目录,初始化结构示意图如下
3. platform_device_register函数分析
int device_private_init(struct device *dev)
{
/* 分配一个struct device_private结构 */
dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
if (!dev->p)
return -ENOMEM;
/* dev->p->device指向dev */
dev->p->device = dev;
/* 初始化dev->p->klist_children链表 */
klist_init(&dev->p->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->p->deferred_probe);
return 0;
}
int bus_add_device(struct device *dev)
{
struct bus_type *bus = bus_get(dev->bus);
int error = 0;
if (bus) {
pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
/* 在dev->kobject.name目录下创建文件属性文件 */
error = device_add_attrs(bus, dev);
if (error)
goto out_put;
/* 在dev->kobject.name目录下创建group文件 */
error = device_add_groups(dev, bus->dev_groups);
if (error)
goto out_id;
/* /sys/bus/*/devices/的设备文件链接到/sys/devices/*下的设备文件,参考下面的参考例子*/
error = sysfs_create_link(&bus->p->devices_kset->kobj,
&dev->kobj, dev_name(dev));
if (error)
goto out_groups;
/* /sys/devices/*下subsystem文件链接到/sys/bus/*/devices/的设备路径,参考下面的参考例子 */
error = sysfs_create_link(&dev->kobj,
&dev->bus->p->subsys.kobj, "subsystem");
if (error)
goto out_subsys;
/* dev->p->knode_bus会被加入到platform_bus_type的subsys_private的klist_devices */
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
}
return 0;
out_subsys:
sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
out_groups:
device_remove_groups(dev, bus->dev_groups);
out_id:
device_remove_attrs(bus, dev);
out_put:
bus_put(dev->bus);
return error;
}
参考:
/sys/bus/platform/devices/下文件会链接到/sys/devices下的某个设备文件的目录文件
例如:
/sys/devices/platform/platform_driver_test.0
/sys/bus/platform/devices/platform_driver_test.0 -> ../../../devices/platform/platform_driver_test.0
int device_attach(struct device *dev)
{
int ret = 0;
device_lock(dev);
/* dev->driver有指定情况,一般不指定 */
if (dev->driver) {
if (klist_node_attached(&dev->p->knode_driver)) {
ret = 1;
goto out_unlock;
}
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
/* dev->driver没有指定情况,这里通过dev找到bus,通过bus找到driver,遍历bus->p->klist_drivers,一个个进行匹配,找到名字相同的driver,调用really_probe */
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
pm_request_idle(dev);
}
out_unlock:
device_unlock(dev);
return ret;
}
void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
struct subsys_interface *sif;
int ret;
/* 判断dev的bus指针是否为空 */
if (!bus)
return;
/* device都是默认自动probe的,此处为1 */
if (bus->p->drivers_autoprobe) {
ret = device_attach(dev);
WARN_ON(ret < 0);
}
mutex_lock(&bus->p->mutex);
list_for_each_entry(sif, &bus->p->interfaces, node)
if (sif->add_dev)
sif->add_dev(dev, sif);
mutex_unlock(&bus->p->mutex);
}
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct kobject *kobj;
struct class_interface *class_intf;
int error = -EINVAL;
/* dev->kobj加1 */
dev = get_device(dev);
if (!dev)
goto done;
if (!dev->p) {
error = device_private_init(dev);
if (error)
goto done;
}
/*
* for statically allocated devices, which should all be converted
* some day, we need to initialize the name. We prevent reading back
* the name, and force the use of dev_name()
*/
/* plateform_device_register注册的pdev->dev一般不指定init_name */
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}
/* subsystems can specify simple device enumeration */
/* dev_name前面dev_set_name设置过dev->kobj.name,所以此处不满足条件 */
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
/* 此处也不满足条件 */
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
/* 因为dev->parent的是platform_bus(struct device),此处获取platform_bus,并使platform_bus.kobj.kref加1 */
parent = get_device(dev->parent);
/* 获取platform_bus的kobj */
kobj = get_device_parent(dev, parent);
if (kobj)
/* 如果platform_bus的kobj存在,则dev->kobj.parent指向platform_bus的kobj */
dev->kobj.parent = kobj;
/* use parent numa_node */
if (parent)
/* 设置platform_bus的numa_node到dev->numa_node */
set_dev_node(dev, dev_to_node(parent));
/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
/* 将dev->kobj加入到platform_bus中,platform_bus的kobj的kset指向devices_kset */
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
if (error)
goto Error;
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
error = device_create_file(dev, &dev_attr_uevent);
if (error)
goto attrError;
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
if (error)
goto ueventattrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
devtmpfs_create_node(dev);
}
error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
error = device_add_attrs(dev);
if (error)
goto AttrsError;
error = bus_add_device(dev);
if (error)
goto BusError;
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev);
/* Notify clients of device addition. This call must come
* after dpm_sysfs_add() and before kobject_uevent().
*/
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
/* match函数如果通过,则调用driver的probe函数, */
bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
if (dev->class) {
mutex_lock(&dev->class->p->mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->klist_devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf,
&dev->class->p->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->mutex);
}
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))
devtmpfs_delete_node(dev);
if (MAJOR(dev->devt))
device_remove_sys_dev_entry(dev);
devtattrError:
if (MAJOR(dev->devt))
device_remove_file(dev, &dev_attr_dev);
ueventattrError:
device_remove_file(dev, &dev_attr_uevent);
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;
}
int platform_device_add(struct platform_device *pdev)
{
int i, ret;
if (!pdev)
return -EINVAL;
/* pdev->dev的父设备为platform_bus */
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
/* pdev->dev.bus指向platform_bus_type */
pdev->dev.bus = &platform_bus_type;
/* pdev->id用来设置设备后缀 */
switch (pdev->id) {
default:
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
break;
case PLATFORM_DEVID_NONE:
dev_set_name(&pdev->dev, "%s", pdev->name);
break;
case PLATFORM_DEVID_AUTO:
/*
* Automatically allocated device ID. We mark it as such so
* that we remember it must be freed, and we append a suffix
* to avoid namespace collision with explicit IDs.
*/
ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
if (ret < 0)
goto err_out;
pdev->id = ret;
pdev->id_auto = true;
dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
break;
}
/* 解析resource */
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = dev_name(&pdev->dev);
p = r->parent;
if (!p) {
if (resource_type(r) == IORESOURCE_MEM)
p = &iomem_resource;
else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
}
if (p && insert_resource(p, r)) {
dev_err(&pdev->dev, "failed to claim resource %d\n", i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
failed:
if (pdev->id_auto) {
ida_simple_remove(&platform_devid_ida, pdev->id);
pdev->id = PLATFORM_DEVID_AUTO;
}
while (--i >= 0) {
struct resource *r = &pdev->resource[i];
if (r->parent)
release_resource(r);
}
err_out:
return ret;
}
void device_initialize(struct device *dev)
{
/* dev->kobj.kset指向devices_kset */
dev->kobj.kset = devices_kset;
/* 初始化dev->kobj的ktype */
kobject_init(&dev->kobj, &device_ktype);
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
lockdep_set_novalidate_class(&dev->mutex);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_pm_init(dev);
/* 设置dev->numa_node为-1 */
set_dev_node(dev, -1);
}
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
arch_setup_pdev_archdata(pdev);
return platform_device_add(pdev);
}
执行完上面的代码,内核对设备的管理示意图大概是这样:
从上面代码来看注册的pdev->dev设备并没有被platform_bus_type.p->devices_kset管理,而是被devices_kset管理的,初始化platform_bus_type.p->devices_kset只是为了在/sys/bus/platform下创建devices目录,/sys/bus/platform/devices下的文件都是链接到/sys/devices下的文件。
五. 总结
platform_device->dev.bus和platform_driver->driver.bus都是指向platform_bus_type,由platform_bus_type.p管理驱动和设备链表,当加载驱动或设备ko时候,platform_drver_register和platform_device_register最终都会去匹配同一名称的驱动和设备,最终调用驱动代码的probe函数。