1.首先明白一点platform的创建是基于bus和device。而且platform的创建分为两步:在devicesmu目录下的创建。和bus目录下的创建。
不多说直接看代码
int __init platform_bus_init(void)
{
int error;
early_platform_cleanup();
error = device_register(&platform_bus);
if (error)
return error;
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}
struct device platform_bus = {
.init_name = "platform",
};
(1)首先明白__init 这个字段,说明了platform_bus_init函数在内核启动的时候就会被调用执行。我猜测,这个执行的顺序肯定是device和bus先被执行调用,接着platform才会被创建的。(至于device和bus谁先辈调用我也不知道,具体的可以去查看__init 宏定义)
(2)接下来就是early_platform_cleanup,这个函数无关紧要,就是清楚了platform以前的数据。
(3)device_register函数,完成了在device下面的注册和创建了platform目录
int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
void device_initialize(struct device *dev)
{
//设置platform的容器属于devices_kset(这个变量在device初始化的时候就已经填充了。)
dev->kobj.kset = devices_kset;
//初始化platform的属性和方法
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);
set_dev_node(dev, -1);
}
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
//这里是引用计数的,不太懂
dev = get_device(dev);
//下面一大堆都是参数校验的
if (!dev)
goto done;
if (!dev->p) {
error = device_private_init(dev);
if (error)
goto done;
}
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
//我看了代码,dev->parent好像是没设置,所以这两句代码也没多大作用。(不知道是不是我分析错了)
parent = get_device(dev->parent);
setup_parent(dev, parent);
/* use parent numa_node */
if (parent)
set_dev_node(dev, dev_to_node(parent));
//重要的是这个函数,下面我会简单的分析一下
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
if (error)
goto Error;
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
//创建uevent_attr属性,对应的就是/sys/devices/platform/uevent
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
devtmpfs_create_node(dev);
}
//没有设置class所以不会创建符号连接
error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
//没有设置文件描述群集,所以不会创建attrs
error = device_add_attrs(dev);
if (error)
goto AttrsError;
//没有设置bus,所以不会被创建
error = bus_add_device(dev);
if (error)
goto BusError;
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev);
//检测驱动中有无适合的设备进行匹配,但没有设置bus,所以不会进行匹配
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_probe_device(dev);
if (parent)
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
//也没有设置class所以也不会进入if语句
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
&dev->class->p->class_devices);
list_for_each_entry(class_intf,
&dev->class->p->class_interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
mutex_unlock(&dev->class->p->class_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, &devt_attr);
ueventattrError:
device_remove_file(dev, &uevent_attr);
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;
}
(2)在kobject_add -> kobject_add_varg -> kobject_add_internal里面的这段代码
//这里kobj->kset在device_initialize函数被设置了,所以会进入if语句
if (kobj->kset) {
//parent是NULL所以也会进入if语句
if (!parent)
//无则使用父容器为父对象
parent = kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj);
//设置父对象
kobj->parent = parent;
}
(4)到这里devices目录下的platform就创建完成了。我也是学习,所以借鉴了大神的图。
2.在bus目录下的创建,因为bus本身的注册函数不怎么懂,我也是学习大神的博客:大神的链接
int bus_register(struct bus_type *bus)
{
int retval;
struct bus_type_private *priv;
//为在bus下申请一个私自的数据空间
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
//互相关联
priv->bus = bus;
bus->p = priv;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
//设置bus下面私自创建数据的名字,也就是platform
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
goto out;
//设置platform的kset属于bus_set,属性和方法属于bus_ktype
priv->subsys.kobj.kset = bus_kset;
priv->subsys.kobj.ktype = &bus_ktype;
priv->drivers_autoprobe = 1;
//正确设置了platform的父类关系,创建了目录,
retval = kset_register(&priv->subsys);
if (retval)
goto out;
//创建uevent属性文件
retval = bus_create_file(bus, &bus_attr_uevent);
if (retval)
goto bus_uevent_fail;
//priv->subsys.kobj也就是platform,所以就在platform下创建了devices目录
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 = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&priv->klist_drivers, NULL, NULL);
retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;
retval = bus_add_attrs(bus);
if (retval)
goto bus_attrs_fail;
pr_debug("bus: '%s': registered\n", bus->name);
return 0;
bus_attrs_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);
kfree(bus->p);
out:
bus->p = NULL;
return retval;
}
(1)到这里bus目录下的platform也创建了。又要借用大神的图了哈哈。我都不好意思了。不过还是感谢大神 博客的教导
3.platform的注册函数和相关的结构体
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* arch specific additions */
struct pdev_archdata archdata;
};
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
(1)接下来的分析我也不太懂,去看大神的博客。
大神威武