platform框架(二)kobject,kset,kobj_type,sys关系

上一篇博客中只介绍了基于platform的驱动编写架构,但platform本身又是如何工作的呢?在后续的章节中,我会重点阐述该问题。

准备工作

其实从uboot开始到kernel启动再到init进程的启动,这个过程发生的所有事情均是为应用程序提供一个工作环境,即准备工作。
对于platform准备工作流程如下:
kernel_init()->do_basic_setup()->driver_init()->devices_init->buses_init()-> platform_bus_init()初始化platform_bus(虚拟总线)
(其中devices_init,buses_init(), platform_bus_init()均包含在函数deiver_init()中)

接下来来分析这个流程中与platform相关的内容

重要结构体 kobject,kset,ktypes

在platform准备工作流程过程中有个重要结构体struct kobject,struct kset,struct ktypes该结构体把所有设备连接在一起,关于这三个结构体,可以参考内核源码中Documentation/kobject.txt,此处只做简单描述。
1.struct kobject
Kobjects are usually embedded within some other structure which contains the stuff
the code is really interested in.
其实上述是官方描述,但这个描述不太容易理解,其实他想表达的有两方面信息,其一
是一个kobject代表一个设备(此处的设备相对内核来说,比如platform_device,
platform_driver均是设备),其二kobject不直接代表设备,因为不同的设备会有不同的
功能及实现所需的结构里,但可以通过设备的结构体间接访问对应的kobject
比如platform_device 和platform_driver里面的成员间接包含可struct kobject。
注意一个设备,最多只能有一个kobject与之对应
struct kobject另外一个用途与sysfs文件系统,对每一个struct kobject,可以在/sys/找到对应的kobject,其上层目录通过 kobj->parent指出

2.struct kset
a set of kobjects of a specific type, belonging to a specific subsystem.
A kset defines a group of kobjects. They can be individually different “types” but overall
these kobjects all want to be grouped together and operated on in the same manner.
ksets are used to define the attribute callbacks and other common events that happen to
a kobject.
上述描述是摘自内核代码,直白的讲,就是kset是一类kobject的集合,set翻译成中文正好是集合
对应到sysfs文件系统中,对kset,也会存在对应的目录,其上层目录通过 kset.kobj->parent指出

3.struct kobj_type
Every structure that embeds a kobject needs a corresponding ktype. The ktype controls
what happens to the kobject when it is created and destroyed.

之前看到一篇关于kset和kobject的blog,再此分享给大家https://blog.csdn.net/lizuobin2/article/details/51523693

devices_kset初始化

下述代码展示了devices_init函数的实现,其实就是通过 kset_create_and_add和kobject_create_and_add创建了几个设备,并进行设备间的关联。 kset_create_and_add和kobject_create_and_add在下一个小节进行描述。

int __init devices_init(void)
{
	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
	if (!devices_kset)
		return -ENOMEM;
	dev_kobj = kobject_create_and_add("dev", NULL);
	if (!dev_kobj)
		goto dev_kobj_err;
	sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
	if (!sysfs_dev_block_kobj)
		goto block_kobj_err;
	sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
	if (!sysfs_dev_char_kobj)
		goto char_kobj_err;

	return 0;

 char_kobj_err:
	kobject_put(sysfs_dev_block_kobj);
 block_kobj_err:
	kobject_put(dev_kobj);
 dev_kobj_err:
	kset_unregister(devices_kset);
	return -ENOMEM;
}

devices_kset创建并注册时没有父节点,所以其在/sys下,其对应路径是/sys/devices
dev_kobj创建并注册时没有父节点,所以其在/sys下,其对应路径是/sys/dev
sysfs_dev_block_kobj 创建并注册时父节点为dev_kobj,其对应路径是/sys/dev/block
sysfs_dev_char_kobj 创建并注册时父节点为dev_kobj,其对应路径是/sys/dev/char

bus总线初始化

目录/sys/bus/platform是platform的标准目录,从目录路径上可以看出,先有bus,才有platform,同时内核启动时也是先进性buses_init(),之后才会调用platform_bus_init()。

bus的注册在/drivers/base/bus.c里,其初始化函数如下

static const struct kset_uevent_ops bus_uevent_ops = {
	.filter = bus_uevent_filter,
};

static struct kset *bus_kset;
static struct kset *system_kset;

int __init buses_init(void)
{
	bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
	if (!bus_kset)
		return -ENOMEM;

	//devices_kset对应的路径为/sys/devices,在bus_init之前,已经设置好了devices_kset
	system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
	if (!system_kset)
		return -ENOMEM;

	return 0;
}
/*This function creates a kset structure dynamically and registers it
 * with sysfs.  When you are finished with this structure, call
 * kset_unregister() and the structure will be dynamically freed when it
 * is no longer being used.
 */
struct kset *kset_create_and_add(const char *name,
				 const struct kset_uevent_ops *uevent_ops,
				 struct kobject *parent_kobj)
{
	struct kset *kset;
	int error;

	kset = kset_create(name, uevent_ops, parent_kobj);  //分配空间并进行初始化
	if (!kset)
		return NULL;
	error = kset_register(kset);          //注册到sysfs中,前面介绍过kobject和kset与/sys下的路径有关
	if (error) {                                     //其各个路径的关系就是通过kset_register在此处进行建立的
		kfree(kset); 
		return NULL;
	}
	return kset;
}

nt kset_register(struct kset *k)
{
	int err;

	if (!k)
		return -EINVAL;

	kset_init(k);
	err = kobject_add_internal(&k->kobj);
	if (err)
		return err;
	kobject_uevent(&k->kobj, KOBJ_ADD);
	return 0;
}

当busbus_init()运行完成后,其个结构体如下图所示
buses_init结果
上图中没有特意体现struct kobj_type,该变量与platform无关,在此只做简单描述,下述为其结构体,不同版本可能会有区别,主要用来说明对应的struct kobject的属性和操作方式,比如使用cat命令时,其实调用sysfs_ops的show 函数

    struct kobj_type {
	    void (*release)(struct kobject *kobj);
	    //control how objects of this type are represented insysfs
	    const struct sysfs_ops *sysfs_ops; //操作描述符
	    struct attribute **default_attrs;       //属性
	    const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
	    const void *(*namespace)(struct kobject *kobj);
    };

buses_init对应的两个路径分别是/sys/bus和/sys/devices/system。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值