您的位置:首页 > 运维架构 > Linux

linux中platform总线解析(一)(platform总线初始化)

2017-11-17 11:35 323 查看
platform初始化的函数调用:

start_kernel-->rest_init-->kernel_init-->kernel_init_freeable-->do_base_setup--->driver_init--->platform_bus_init

初始化函数:

platform初始化函数:

int __init platform_bus_init(void)
{
int error;
//平台初始化前的一些清理工作
early_platform_cleanup();
//注册platform_bus设备
error = device_register(&platform_bus);
if (error)
return error;
//注册platform_bus_type总线
error =  bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}

下面就分开解析初始化函数所作的工作。
1, eraly_platform_cleanup函数

早期清理工作,主要是清理early_platform_device_list链表

static __initdata LIST_HEAD(early_platform_driver_list);
static __initdata LIST_HEAD(early_platform_device_list);
void __init early_platform_cleanup(void)
{
struct platform_device *pd, *pd2;

//把early_platform_device_list链表中的元素删除,并把元素占据空间清零
list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
dev.devres_head) {
list_del(&pd->dev.devres_head);
memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
}
}

2,platform设备的定义
struct device platform_bus = {
.init_name = "platform",
};

可以看到设备只是初始化了名字

3,platform总线的定义

struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match, //总线匹配函数(device和driver)
.uevent = platform_uevent, //事件(热插拔)函数
.pm = &platform_dev_pm_ops,//电源管理相关的操作函数
};
在这里对总线的定义主要是设置总线的操作函数
4,platform设备注册函数device_register

对于platform总线就是初始化了操作总线的函数。

/*设备的注册分为两个步骤

*第一步:初始化设备

*第二部:把设备加载到系统中

*/


int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}


4-1,设备初始化
/*
*注册设备时的i初始化动作
*/
void device_initialize(struct device *dev)
{
//这是设置设备在sysfs文件系统中的显示位置(sys/device目录下)
//这里知道作用就好,后面会再来介绍kset,kobject和sysfs文件系统的相关内容
dev->kobj.kset = devices_kset;
//初始化设备对应的kobj_type的类型,主要时sysfs相关的,包含了对sysfs的操作函数
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);
}


4-2,把设备加入到系统中
/*
*把设备注册进系统中
*这个函数中很多跟sysfs相关的了解就好,后面会仔细分析
*/
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct kobject *kobj;
struct class_interface *class_intf;
int error = -EINVAL;
//如果设备不为空,就增加一次对设备的引用计数
dev = get_device(dev);
if (!dev)
goto done;
//红帽相关的结构体
if (!dev->device_rh)
device_rh_alloc(dev);
//初始化设备的私有化数据
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()
*把设备在sysfs中显示的名字设备为当时初始化的init_name的值
*并把设备的dev->init_name设置为空
*/
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}

/*设置设备的名字,不过这里条件不符合,跳过*/
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__);
//增加父设备的引用计数,并返回父设备的结构体
parent = get_device(dev->parent);
//返回父设备的kobject的结构体,platfrom没有父设备,所以父设备名字是virtual,虚拟设备
kobj = get_device_parent(dev, parent);
if (kobj)
dev->kobj.parent = kobj;

/* use parent numa_node
*根据父设备的numa_node设置本设备的numa_node
*/
if (parent)
set_dev_node(dev, dev_to_node(parent));

/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL
* 在sysfs中创建对应的目录
*/
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);

/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
//在platform目录下,创建uevent文件
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
//如果devt>>20大于0,就创建dev这个文件
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中为这个设备创建链接文件(platforms不是设备,不会创建)
error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
//为设备创建属性文件
error = device_add_attrs(dev);
if (error)
goto AttrsError;
//把设备加入到设备对应总线的链表中(platformo没有对应的总线)
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);
//为这个刚注册的设备查找一个对应的驱动
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);
//把设备加入到设备对应的class的设备链表中
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, &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;
}

4-3,获取设备名字dev_name
/*
*获取设备的名字
*/
static inline const char *dev_name(const struct device *dev)
{
/*
*如果由init_name就返回init_name,否则返回kobject中的名字
*/
if (dev->init_name)
return dev->init_name;

return kobject_name(&dev->kobj);
}

4-4,为设备寻找驱动
/*为设备查找驱动
*因为这里的platform没有bus,所以直接返回
*/
void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
struct subsys_interface *sif;
int ret;

if (!bus)
return;
//调用device_attach为设备找驱动
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);
}

[b]这时platform设备就加入到系统中了。
[/b]

5,向系统注册总线

总线注册:
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);
if (!priv)
return -ENOMEM;
//分配subsys_private结构,用于存储设备和驱动
priv->bus = bus;
bus->p = priv;
//初始化bus上的通知连
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
//为subsys设置name
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
goto out;
//指示属于哪一个子系统
priv->subsys.kobj.kset = bus_kset;
//设置总线对应的sysfs上的操作方法
priv->subsys.kobj.ktype = &bus_ktype;
//设置自动匹配驱动
priv->drivers_autoprobe = 1;
//注册子系统
retval = kset_register(&priv->subsys);
if (retval)
goto out;
//创建总线的uevent文件
retval = bus_create_file(bus, &a
d4fc
mp;bus_attr_uevent);
if (retval)
goto bus_uevent_fail;
//创建devices目录
priv->devices_kset = kset_create_and_add("devices", NULL,
&priv->subsys.kobj);
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}
//创建drivers目录
priv->drivers_kset = kset_create_and_add("drivers", NULL,
&priv->subsys.kobj);
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}

INIT_LIST_HEAD(&priv->interfaces);
__mutex_init(&priv->mutex, "subsys mutex", key);
//设置klist_devices对应的操作方法函数
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&priv->klist_drivers, NULL, NULL);
//创建bus_attr_drivers_probe和bus_attr_drivers_autoprobe文件
retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;
//为bus增加默认的属性文件
retval = bus_add_attrs(bus);
if (retval)
goto bus_attrs_fail;
//创建groups的属性文件
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:
bus_remove_attrs(bus);
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);
out:
kfree(bus->p);
bus->p = NULL;
return retval;
}

其中使用到的重要的数据结构:

//存储device,driver,bus上关于挂接的设备相关信息
struct subsys_private {
struct kset subsys; //定义在哪个子系统
struct kset *devices_kset; //在这个子系统中的device目录
struct list_head interfaces; //子系统结构
struct mutex mutex;

struct kset *drivers_kset; //子系统中driver目录
struct klist klist_devices; //分配的设备,在bus中指挂接的设备
struct klist klist_drivers; //分配的驱动,在bus中指挂接的驱动
struct blocking_notifier_head bus_notifier; //通知连
unsigned int drivers_autoprobe:1; //是否自动匹配驱动
struct bus_type *bus; //指向所属的bus

struct kset glue_dirs;
struct class *class; //指向所属的class
};


哦啦,这时就把platform总线加入到了系统中了。

其中好多对于sysfs的操作,以及在sysfs中的显示等,在这里只是需要了解就可以了,后面会详细介绍相关的内容。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: