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. 汤姆大叔的6道js题目

    汤姆大叔的6道javascript编程题题解 看汤姆大叔的博文,其中有篇(猛戳这里)的最后有6道编程题,于是我也试试,大家都可以先试试. 1.找出数字数组中最大的元素(使用Math.max函数) 1 ...

  2. source insight 使用技巧

    一.在所有文件中查找字符串 1.菜单栏选择“search project” 2.在随便一个工程文件中把所要查找的字符串输入到空白的地方,然后点连接

  3. JDK下sun.net.www.protocol.http.HttpURLConnection类-----Http客户端实现类的实现分析

    HttpClient类是进行TCP连接的实现类, package sun.net.www.http; import java.io.*; import java.net.*; import java. ...

  4. java相关各种页面跳转

    AK相信页面跳转在这个圈圈圆圆里是个地球人都能经常遇到的事,AK也在平时的工作学习中记录了一些,这里就做一个小小的总结,有任何的疑问和质疑都希望您能告诉我,不用担心后果,必定至少您还能理我,AK万分感 ...

  5. 根据http协议传送数据

    发送的内容: [50 4f 53 54 20 2f 64 65 78 2f 66 69 72 65 70 6f 77 65 72 20 48 54 54 50 2f 31 2e 31 0d 0a 43 ...

  6. 【Java】Checked、Unchecked Exception

    Checked Exception:需要强制catch的异常, Unchecked Exception:这种异常时无法预料的,即RuntimeException,就是运行时的异常. Exception ...

  7. 2016 年开发者应该掌握的十个 Postgres 技巧

    [编者按]作为一款开源的对象-关系数据库,Postgres 一直得到许多开发者喜爱.近日,Postgres 正式发布了9.5版本,该版本进行了大量的修复和功能改进.而本文将分享10个 Postgres ...

  8. PHP日常杂记

    1.php点击按钮跳转页面 <input type="button" onclick="window.location.href='login.php'" ...

  9. 译文: async/await SynchronizationContext 上下文问题

    async / await 使异步代码更容易写,因为它隐藏了很多细节. 许多这些细节都捕获在 SynchronizationContext 中,这些可能会改变异步代码的行为完全由于你执行你的代码的环境 ...

  10. XAMPP下的composer的安装

    很多开源软件,都需要通过composer来安装,Composer 是 PHP 的一个依赖管理工具.它允许你申明项目所依赖的代码库,它会在你的项目中为你安装他们. 声明关系 比方说,你正在创建一个项目, ...