kobject,kset,ktype三个很重要的概念贯穿Linux内核驱动架构,特转载一篇博文:

(转载自http://blog.csdn.net/gdt_a20/article/details/6424597

一、sysfs文件系统下的每个目录对应于一个kobj,kset是kobj的封装,内嵌了一个kobj,其代表kset自身,ktype代表属性操作集,但由于通用性,因此把ktype单独剥离出来,kobj,kset,ktype成为了各个驱动模型最底层的关联元素,并由此形成了sys下的各种拓扑结构。

二、关于kobject

首先看一下kobject的原型

struct kobject {
const char *name; //名字
struct list_head entry; //连接到kset建立层次结构
struct kobject *parent; //指向父节点,面向对象的层次架构
struct kset *kset;
struct kobj_type *ktype; //属性文件
struct sysfs_dirent *sd;
struct kref kref; //引用计数
unsigned int state_initialized:1; //初始化状态...
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};

  

分析一下kobject的初始化过程

初始化函数为

---int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,  //参数为kobject和属性结构体
struct kobject *parent, const char *fmt, ...)
{
va_list args;
int retval;
kobject_init(kobj, ktype);
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);
va_end(args);
return retval;
}
---void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
if (!kobj) { //kobj为NULL错误退出
err_str = "invalid kobject pointer!";
goto error;
}
if (!ktype) { //ktype为NULL错误退出
err_str = "must have a ktype to be initialized properly!/n";
goto error;
}
if (kobj->state_initialized) { //如果初始化状态为1报错
/* do not error out as sometimes we can recover */
printk(KERN_ERR "kobject (%p): tried to init an initialized "
"object, something is seriously wrong./n", kobj);
dump_stack();
}
kobject_init_internal(kobj); //初始化kobj
kobj->ktype = ktype; //关联obj和ktype
return;
error:
printk(KERN_ERR "kobject (%p): %s/n", kobj, err_str);
dump_stack();
}
-------static void kobject_init_internal(struct kobject *kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref); //计数变成1
INIT_LIST_HEAD(&kobj->entry); //都指向自己,prev和next
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
kobj->state_initialized = 1;
}
-------static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
const char *fmt, va_list vargs)
{
int retval;
retval = kobject_set_name_vargs(kobj, fmt, vargs); //设置名字,名字中不能有“/”
if (retval) {
printk(KERN_ERR "kobject: can not set name properly!/n");
return retval;
}
kobj->parent = parent; //设置parent,其父节点
return kobject_add_internal(kobj);
}
----static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
if (!kobj->name || !kobj->name[0]) { //名字不能为空
WARN(1, "kobject: (%p): attempted to be registered with empty "
"name!/n", kobj);
return -EINVAL;
}
parent = kobject_get(kobj->parent); //如果parent为真,则增加kobj->kref计数,也就是父节点的引用计数
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) {
if (!parent)
parent = kobject_get(&kobj->kset->kobj); //如果kobj-parent父节点为NULL那么就用kobj->kset->kobj
// 作其父节点,并增加其引用计数
kobj_kset_join(kobj); //把kobj的entry成员添加到kobj->kset>list的尾部,现在的层次就是
kobj->parent = parent; //kobj->kset->list指向kobj->parent
} // ->parent 指向kset->kobj
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'/n",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "<NULL>",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
error = create_dir(kobj); //利用kobj创建目录和属性文件,其中会判断,如果parent为NULL那么就在sysfs_root下创建
if (error) {
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;
/* be noisy on error issues */
if (error == -EEXIST)
printk(KERN_ERR "%s failed for %s with "
"-EEXIST, don't try to register things with "
"the same name in the same directory./n",
__func__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s (%d)/n",
__func__, kobject_name(kobj), error);
dump_stack();
} else
kobj->state_in_sysfs = 1;
return error;
}
---static int create_dir(struct kobject *kobj)
{
int error = 0;
if (kobject_name(kobj)) {
error = sysfs_create_dir(kobj); //创建目录
if (!error) {
error = populate_dir(kobj); //创建属性文件
if (error)
sysfs_remove_dir(kobj);
}
}
return error;
}

  

三、关于 kset

首先看一下kset的原型

struct kset {
struct list_head list; //连接着他下面的kobj成员,与kobj-entry关联
spinlock_t list_lock;
struct kobject kobj; //代表kset自己
const struct kset_uevent_ops *uevent_ops;
};

  再来看一下kset的初始化操作,kset表现为更高级一点的kobj,其初始化操作仍然是围绕其内部的kobj展开的。

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); //创建kset,关联操作函数和其父节点
if (!kset)
return NULL;
error = kset_register(kset);
if (error) {
kfree(kset);
return NULL;
}
return kset;
}
---static struct kset *kset_create(const char *name,
const struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int retval;
kset = kzalloc(sizeof(*kset), GFP_KERNEL); //申请结构体内存
if (!kset)
return NULL;
retval = kobject_set_name(&kset->kobj, name); //设置名字
if (retval) {
kfree(kset);
return NULL;
}
kset->uevent_ops = uevent_ops; //关联操作函数
kset->kobj.parent = parent_kobj; //关联父节点
/*
* The kobject of this kset will have a type of kset_ktype and belong to
* no kset itself. That way we can properly free it when it is
* finished being used.
*/
kset->kobj.ktype = &kset_ktype; //关联属性文件
kset->kobj.kset = NULL;
return kset;
}
----int kset_register(struct kset *k)
{
int err;
if (!k)
return -EINVAL;
kset_init(k);
err = kobject_add_internal(&k->kobj); //调用kobj操作函数
if (err)
return err;
kobject_uevent(&k->kobj, KOBJ_ADD);
return 0;
}
----void kset_init(struct kset *k)
{
kobject_init_internal(&k->kobj); //调用kobj操作函数
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}

  四、上面给出了kobj,kset的初始化过程,以及相互产生关联的关键点,下面给出整体的一个流程图:

Linux kernel驱动相关抽象概念及其实现 之“linux设备模型kobject,kset,ktype”的更多相关文章

  1. Linux kernel驱动相关抽象概念及其实现 之“bus,device,driver”

    bus,device,driver三个很重要的概念贯穿Linux内核驱动架构,特转载一篇博文: (转载自http://blog.csdn.net/gdt_a20/article/details/642 ...

  2. 【原创】linux设备模型之kset/kobj/ktype分析

    背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...

  3. Linux Framebuffer 驱动框架之一概念介绍及LCD硬件原理【转】

    本文转载自:http://blog.csdn.net/liuxd3000/article/details/17464779 一.基本概念 帧缓冲(Framebuffer)是Linux系统为显示设备提供 ...

  4. linux uart驱动——相关数据结构以及API(二)

    一.核心数据结构      串口驱动有3个核心数据结构,它们都定义在<#include linux/serial_core.h>1.uart_driver     uart_driver包 ...

  5. linux系统负载相关的概念和度量

    系统负载有 CPU利用率 和 LoadAverage这2个概念. cpu利用率:cpu utilization,是进程(task)被内核调度进程实际分配了CPU资源后,在时间片内使用CPU进行工作运算 ...

  6. Linux kernel 之 uart 驱动解析

    uart 是一种非常之常见的总线,比如DEBUG信息输出,小数据量数据传输,485,以及蓝牙的控制,GPS,很多都是通过uart 进行数据传输并进行控制. 在Linux kernel 内部,uart ...

  7. 移植Linux Kernel SM750 驱动到VxWorks 7

    一.SM750简介 SM750 是SiliconMotion 推出的一款适合嵌入式设备的显卡(Embedded GPU),采用PCIe接口与CPU连接,内部集成16MB DDR SDRAM显存,产品具 ...

  8. 【原创】Linux PCI驱动框架分析(二)

    背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...

  9. Linux Kernel中断子系统来龙去脉浅析【转】

    转自:http://blog.csdn.net/u011461299/article/details/9772215 版权声明:本文为博主原创文章,未经博主允许不得转载. 一般来说,在一个device ...

随机推荐

  1. curl批处理从官方demo封装

    官方demo // 创建一对cURL资源 $ch1 = curl_init(); $ch2 = curl_init(); // 设置URL和相应的选项 curl_setopt($ch1, CURLOP ...

  2. java rest接口返回不完整的json数据

    ngix配置有问题,数据量大时把部分数据给拦截了. {"userId":237,"loginName":"mingshi","us ...

  3. spoj 3885

    简单的博弈题,用dp解: 每个人只能拿1,l,k个硬币: dp[i][j]表示第j个人拿是否能拿第i枚硬币: 代码: #include<cstdio> #define maxn 10000 ...

  4. 迅雷创始人程浩:创业公司5招做好内部创新(组建小型敢死队:一共3个人,一个产品经理,两个研发;腾讯做不做这个项目是一个伪命题;让用户来验证,而不是相反 good)

    欢迎关注“创事记”的微信订阅号:sinachuangshiji 文/程浩 编者按:本文首发于微信公众号“浩哥说”(ID:haogetalks),作者程浩,迅雷创始人.内容为作者在混沌AI成长营上的演讲 ...

  5. 有感,懂市场比懂产品重要,懂产品比懂技术重要——想起凡客诚品和YY语音了

    一个创业公司,最好三样都要有,但应该CEO是懂市场,经理懂产品,程序员最好懂技术厉害一点-这还不算,销售也要厉害一点,不能守株待兔- 美工——有钱最好请个美工,最起码也要请人设计修改一下- 财务——不 ...

  6. Delphi实现HTMLWebBrowser实现HTML界面

    HTML的界面有以下特点:图文混排,格式灵活,可以包含Flash.声音和视频等,实现图文声像的多媒体界面,而且易于建立和维护.另外,HTML的显示环境一般机器上都具备,通常不需要安装额外的软件.当然, ...

  7. c++ RAII 资源管理就是初始化

    RAII:(Resource Acquisition Is Initialization),也就是“资源获取就是初始化”,是C++语言的一种管理资源.避免泄漏的惯用法.C++标准保证任何情况下,已构造 ...

  8. 14.7.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量和大小

    14.7.2 Changing the Number or Size of InnoDB Redo Log Files 改变InnoDB Redo Log Files的数量和大小 改变 InnoDB ...

  9. Supporting Multiple Screens 翻译 支持各种屏幕(上)

    Supporting Multiple Screens 支持各种各样的屏幕尺寸.屏幕密度 Android runs on a variety of devices that offer differe ...

  10. 【HDOJ】1501 Zipper

    DFS.注意剪枝,0ms. #include <stdio.h> #include <string.h> #define False 0 #define True 1 #def ...