Linux设备驱动模型——kobject、kset、subsystem的关系

kobject

Linux内核中有大量的驱动和设备,而这些驱动和设备往往具有类似的结构,根据面向对象的思想,我们就可以将这些共同的部分提取为父类,这个父类就是kobject,也就是驱动编程中使用的.ko文件的由来,而三大类设备驱动都需要包含这个kobject结构,也就是"继承"自kobject。一个kobject对象就对应sys目录中的一个设备,也可以理解为一个kobject就对应sys目录中的一个目录。
内核源码中的kobject结构定义如下

struct kobject {
	/**
	 * 指向容器名称。
	 */
	char			* k_name;
	/**
	 * 如果容器名称不超过20个字符,就存在这里。
	 */
	char			name[KOBJ_NAME_LEN];
	/**
	 * 容器的引用计数。
	 */
	struct kref		kref;
	/**
	 * 用于将kobject插入某个链表。
	 */
	struct list_head	entry;
	/**
	 * 指向父kobject
	 */
	struct kobject		* parent;
	/**
	 * 指向包含的kset,kset是同类型的kobject结构的一个集合体。
	 */
	struct kset		* kset;
	/**
	 * 指向kobject的类型描述符。
	 */
	struct kobj_type	* ktype;
	/**
	 * 指向与kobject对应的sysfs文件的dentry数据结构。
	 */
	struct dentry		* dentry;
};

初始化kobject

void kobject_init(struct kobject * kobj)
{
	// 初始化引用计数为1
	kref_init(&kobj->kref);
	atomic_set(&kref->refcount,1);
	INIT_LIST_HEAD(&kobj->entry);
	// 获取kobj的kset对象,如果kset不为空,就会将对应kset的kobject引用计数加1
	kobj->kset = kset_get(kobj->kset);
	return k ? to_kset(kobject_get(&k->kobj)) : NULL;
}

添加kobject到kset

int kobject_add(struct kobject * kobj)
	// 将此对象的引用计数加1
	kobj = kobject_get(kobj)
	// 将父对象的引用计数加1
	parent = kobject_get(kobj->parent);
	//设置对象的父对象,如果原本就用父对象,就不变,否则就把父对象设置成对应kset的对象,还要通过entry,将该对象加入到对应kset的list链表中
	if (kobj->kset) 
		if (!parent)
		parent = kobject_get(&kobj->kset->kobj);
		list_add_tail(&kobj->entry,&kobj->kset->list);
	kobj->parent = parent;
	create_dir(kobj);
		//创建该对象对应的目录
		sysfs_create_dir(kobj);
			// 如果该对象的父对象不为空,则创建的目录就位于父对象目录下面,否则创建的目录就位于sysfs根目录下面
			if (kobj->parent)
				parent = kobj->parent->dentry;
			else if (sysfs_mount && sysfs_mount->mnt_sb)
				parent = sysfs_mount->mnt_sb->s_root;
			// 在parent目录下,创建一个名为kobject_name(kobj)的目录
			create_dir(kobj,parent,kobject_name(kobj),&dentry);
			//设置该对象的dentry
			kobj->dentry = dentry;
	// 创建kobject的属性文件
	populate_dir(kobj);
		struct kobj_type * t = get_ktype(kobj);
			if (k->kset && k->kset->ktype)
				return k->kset->ktype;
			else 
				return k->ktype;
		if (t && t->default_attrs)
			for (i = 0; (attr = t->default_attrs[i]) != NULL; i++)
				//在kobj目录下,创建属性文件
				sysfs_create_file(kobj,attr)

kobject_add主要作用有两个
(1)设置kobject的父对象,如果kobject没有父对象,就把父对象设置为父kset的对象。
(2)在父对象目录下创建kobject对应的目录和属性文件。

注册kobject

int kobject_register(struct kobject * kobj)
{	
kobject_init(kobj);
	kobject_add(kobj);
	return error;
}

kobject_register首先调用kobject_init初始化对象,然后调用kobject_add添加kobject到kset

kset

kset表示一组kobject的集合,kobject通过kset组织成层次化的结构,所有属于该kset的kobjetc结构的parent指针指向kset包含的kobject对象,构成一个父子层次关系,这些kobject可以是不同或相同的类型(kobj_type)。同时一个kset也是一个kobject,kset也含有自己的kobject。sysfs中的设备组织结构很大程度上都是根据kset进行组织的,比如"/sys/drivers"目录就是一个kset对象,包含系统中的驱动程序对应的目录,驱动程序的目录由kobject表示。比如在平台设备模型中,当我们注册一个设备或驱动到平台总线,其实是将对应的kobject挂接到platform总线的kset上,每种总线都是维护两条链表(两个kset),一条用于链接挂接在上面的驱动(驱动kset),一条用于链接挂接在上面的设备(设备kset)。

struct 	 {
	/**
	 * 所属子系统。
	 */
	struct subsystem	* subsys;
	/**
	 * 所包含的kobjec的类型。
	 */
	struct kobj_type	* ktype;
	/**
	 * 第一个kobject节点。
	 */
	struct list_head	list;
	/**
	 * 嵌入的kobject
	 */
	struct kobject		kobj;
	/**
	 * 用于处理kobject结构的过滤和热插拨操作的回调函数表。
	 */
	struct kset_hotplug_ops	* hotplug_ops;
};

list_head还是那个用来挂在链表上的结构,包含在一个kset的所有kobject构成了一个双向循环链表,list_head就是这个链表的头部,这个链表用来连接第一个和最后一个kobject对象,第一个kobject使用entry连接kset集合以及第二个kobject对象,第二个kobject对象使用entry连接第一个kobject对象和第三个kobject对象,依次类推,最终形成一个kobject对象的链表
kobject是归属于该kset的所有的kobject的共有parent,这个parent就是体现内核设备组织结构的关键,同时,kset的引用计数就是内嵌的kobject对象的引用次数。从这里就可以看出来kset也是继承了kobject。

注册kset

int kset_register(struct kset * k)
{
	kset_init(k);
		kobject_init(&k->kobj);
		INIT_LIST_HEAD(&k->list);
	return kset_add(k);
		if (!k->kobj.parent && !k->kobj.kset && k->subsys)
			k->kobj.parent = &k->subsys->kset.kobj;
		return kobject_add(&k->kobj);
}

kset_register的作用有两个
(1)初始化数据结构,主要就是初始化对应kobject。
(2)设置kset的父对象,也就是设置对应kobject的父kobject,如果父对象为空,对应kobject所属的kset为空,并且kset对应的subsys不为空,就把父对象设置为&k->subsys->kset.kobj。从这里可以看到kobject属于设备的最底层结构,多个kobject可以属于同一个kset,这是通过kobject的parent字段指向kset的kobject来连接的,kset可以看做kobject的继承类,所以kset本质上也是一个kobject,subsystem是kset的继承类,所以subsystem本质上是一个kset,同时也是一个kobject。subsystem的子kset通过对象的parnet字段指向父subsystem的kobj来关联起来的。

subsystem

一个子系统下可以包含多种kset,子系统通常显示在sysfs分层结构中的顶层,包含block_subsys、devices_subsys以及各种总线等子系统,对应于sys/block、sys/devices等目录。

struct subsystem {
	/**
	 * 下层对象集合。
	 */
	struct kset		kset;
	/**
	 * 访问子系统所用的读写信号量。
	 */
	struct rw_semaphore	rwsem;
};

子系统注册

subsystem_register(struct subsystem * s)
	//初始化子系统
	subsystem_init(s);
		init_rwsem(&s->rwsem);
		kset_init(&s->kset);
	//添加子系统对应的kset
	kset_add(&s->kset));
	if (!s->kset.subsys)
		s->kset.subsys = s;

subsystem_register主要包含两个内容
(1)初始化子系统对象
(2)调用kset_add来添加子系统,调用subsystem_register时,如果对应kobject的父对象为空,kset_add就会在/sys下创建目录。

subsystem、kset、kobject的关系如下图所示,黑色连线代表包含关系,红色连线代表指向关系:

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值