kobject和kset的一些学习心得
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
static struct kobject * parent;
static struct kobject *child;
static struct kset *c_kset;
static unsigned long flag= 1;
static ssize_t att_show(struct kobject *kobj,struct attribute *attr,char *buf)
{
size_t count = 0;
count += sprintf(&buf[count],"%lu\n",flag);
return count;
}
static ssize_t att_store(struct kobject *kobj,struct attribute *attr,
const char *buf,size_t count)
{
flag = buf[0]-'0';
//通过kobject_uevent来将内核对象kobj的状态变化通知用户程序
switch(flag){
case 0:
kobject_uevent(kobj,KOBJ_ADD);
break;
case 1:
kobject_uevent(kobj,KOBJ_REMOVE);
break;
case 2:
kobject_uevent(kobj,KOBJ_CHANGE);
break;
case 3:
kobject_uevent(kobj,KOBJ_MOVE);
break;
case 4:
kobject_uevent(kobj,KOBJ_ONLINE);
break;
case 5:
kobject_uevent(kobj,KOBJ_OFFLINE);
break;
}
return count;
}
static struct attribute cld_att = {
.name = "cldatt",
.mode = 0777,
};
static const struct sysfs_ops att_ops = {
.show = att_show,
.store = att_store,
};
static struct kobj_type cld_ktype = {
.sysfs_ops = &att_ops,
};
static int kobj_demo_init(void)
{
int err;
parent = kobject_create_and_add("pa_obj",NULL);
child = kzalloc(sizeof(*child),GFP_KERNEL);
if(!child)
return PTR_ERR(child);
//一个能够通知用户空间状态变化的kobject必须隶属于某一个kset,也就是所谓的
//subsystem,所以此处给内核对象child创建一个kset对象c_kset
c_kset = kset_create_and_add("c_kset",NULL,parent);
if(!c_kset)
return -1;
child->kset = c_kset;
err = kobject_init_and_add(child,&cld_ktype,NULL,"cld_obj");
if(err)
return err;
err = sysfs_create_file(child,&cld_att);
return err;
}
static void kobj_demo_exit(void)
{
sysfs_remove_file(child,&cld_att);
kset_unregister(c_kset);
kobject_del(child);
kobject_del(parent);
}
module_init(kobj_demo_init);
module_exit(kobj_demo_exit);
MODULE_LICENSE("GPL");
陈学松大虾的这个例子十分好。赞一个。
kobject_create_and_add这个函数首先会调用kobject_create来分配并初始化一个kobject对象,
然后调用kobject_add函数在sysfs文件系统中为新生成的kobject对象建立一个新的目录。那么这个目录建立在
sysfs文件系统中的哪个位置呢?kobject_add最后是通过sysfs_craete_dir函数来创建一个目录的,看一下这个函数
的关键代码便能知道
/*fs/sysfs/dir.c*/
int sysfs_create_dir(struct kobject *kobj)
{
...
if(kobj->parent)
parent_sd = kobj->parent->sd;
else
parent_sd = &sysfs_root;
...
error =create_dir(kobj,parent_sd,type,ns,kobject_name(kobj),&sd);
if(!error)
kobj->sd = sd;
return error;
}
可以看到,如果kobj->parent字段为空,那么该函数就会调用create_dir在sysfs文件树的根目录下为kobj创建
一个新的目录,否则就在parent的目录下为该kobj创建一个新的目录。
kobject_add首先会将参数parent赋值给kobj的parent成员 kobj->parent =parent,然后调用kobject_add_internal(kobj)函数,
在kobject_add_internal函数内部,如果调用kobject_add时parent是一个NULL指针,那么要看该kobj是否在一个
kset对象中,如果是就把该kset中的kobject成员作为kobj的parent;否则kobj的parent值仍然为NULL,那么在接下来
调用sysfs_create_dir的时候,该kobj就会在/sys目录创建一个新的文件夹。
/*struct kobject * kobject_create_and_add(const char * name,struct kobject *parent)*/
例如上面的kobject_create_and_add("pa_obj",NULL);这个函数传入的parent为空,那么他将会在/sys下创建一个目录名为pa_obj的新目录。
/*struct kset *kset_create_and_add(const char *name,
struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)*/
再看下面的kset_create_and_add("c_kset",NULL,parent);kset里面也有一个内嵌的kobject,所以传入的第一个和第三个参数是
给这个内嵌的kobject用的,第二个参数是给kset用的。
看一下kset的结构体原形:
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
struct kset_uevent_ops *uevent_ops;
};
多么简单,其实kset在sysfs文件系统中没有实体表现的,他不像kobject,一个kobject对应一个sysfs文件系统下的一个目录,kset的存在无法就是为了
方便管理kobject。
kset_create_and_add最终也会调用kobject_create_and_add,传入的参数肯定是""c_kset"和parent,那么将会在/sys/pa_obj的目录下面创建
一个目录名为c_kset的新目录.
再来看下面的
child->kset = c_kset;
err = kobject_init_and_add(child,&cld_ktype,NULL,"cld_obj");
kobject_init_and_add与kobject_create_and_add的其中一个区别便是前者可以使用自己定义的kobj_type,而后者内核会提供一个默认的kobj_type
(读者自己深入函数内部就会看到这个默认的kobj_type)。
这个函数原型为:int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...)
上面的程序在调用这个函数的时候把parent设置为NULL,由于在调用这个函数之前有这么一行:child->kset = c_kset,如上所分析的那样,
由于设置了child所属的kset,那么在kobject_init_and_add内部会把child->parent设置为c_kset->kobj,这意味着将会在/sys/pa_obj/c_kset目录下
创建一个目录名为cld_obj的新目录,如果你把这kobject_init_and_add参数中的NULL改为parent(parent = kobject_create_and_add("pa_obj",NULL);
这个parent就是pa_obj的对象kobj),那么这么一改,cld_obj目录就和c_kset目录一样都是在/sys/pa_obj目录之下了。
再下面的sysfs_create_file是在相应的目录下面创建一个属性文件(注意,现在是创建文件而不是目录了)
上面几个函数是构建linux设备模型框架的最基本的函数。。如果说linux设备模型是一栋摩天大厦,那么这几个函数就是把这个大厦建立起来的最
底层的建筑工人。
kobject和kset的一些学习心得的更多相关文章
- [翻译]你不会想知道的kobject,kset,和ktypes
---------------------------------------------------------------------------------------------------- ...
- linux设备驱动模型(kobject与kset)
Linux设备模型的目的:为内核建立一个统一的设备模型,从而又一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要 ...
- 我的MYSQL学习心得(一) 简单语法
我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(二) 数据类型宽度
我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(三) 查看字段长度
我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(四) 数据类型
我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(五) 运算符
我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...
- 我的MYSQL学习心得(六) 函数
我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
- 我的MYSQL学习心得(七) 查询
我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
随机推荐
- virtualbox+vagrant学习-5-Boxes-2-Box Versioning
Box Versioning 从Vagrant 1.5版本开始, box支持版本控制.这允许创建box的人将更新推送到box中,使用box的人有一个简单的工作流,用于检查更新.更新box以及查看发生了 ...
- linux各种压缩包的压缩和解压方法
.tar/.war(tar是打包,不是压缩) 解包:tar xvf FileName.tar / FileName.war 打包:tar cvf FileName.tar DirName .gz 解压 ...
- Spring(九)之事件处理
Spring的核心是ApplicationContext,它管理bean的完整生命周期.ApplicationContext在加载bean时发布某些类型的事件.例如,ContextStartedEve ...
- PHP面试系列 之Linux(五)---- 案例
题:如何实现每天0点重新启动服务器? 答: (1)创建定时任务,并进行编辑 crontab -e (2)编写脚本内容 * * * reboot 0分 0时 每日 每月 每周 执行的命令:reb ...
- postman请求失败
注意右上角 我点亮了左边的图标,导致任何请求都没法获取到结果,后来知道是右上角的问题,然后就可以成功请求了
- 单片机采集的MPU6050原始数据对应关系
转自:https://blog.csdn.net/u013636775/article/details/69668860 单片机采集的MPU6050原始数据对应关系 1.陀螺仪 如下图, 陀螺仪的范围 ...
- ios开发UI篇—UISlider
概述 UISlider用于从连续范围的值中选择单个值的控件. 当您移动滑块的大拇指时,会将其更新后的值传递给附加的任何动作.滑块的外观是可配置的; 您可以对曲目和大拇指进行着色,并提供出现在滑块末端的 ...
- CH4402 小Z的袜子(莫队)
描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只袜子从1到N编号, ...
- 1005. Spell It Right(20)—PAT 甲级
Given a non-negative integer N, your task is to compute the sum of all the digits of N, and output e ...
- Web前端---HTTP协议
目录 HTTP协议 一.http协议概述 二.http请求报文 1.GET请求 2.POST请求 三.http响应报文 1.响应报文内容 2.状态码(Status Code) HTTP协议 一.htt ...