分类: LINUX
2012-04-19 23:22:56
设备模型之一 kobject & kset
2012-04-09
标准C 是面对过程的设计方法,并不像C++ 那样面对对象编程方法,因此它对像庞大的内核代码进行整体管理也就越来越困难。因此内核开发人员就想能不能也采用面对对象的编程思想来对内核模块进行管理,从而设备模型的思想运应而生。
Kobject的特点:
1、它采用面对对象的思想而设计的特殊的数据结构,既然是面对对象,那么它就有父类节点,可以呈层次结构排列的对象。
2、Kobject对本身的结构不感兴趣,而对嵌有 kobject 结构的数据结构才是它真正感兴趣的。犹如struct cdev 这个结构是字符驱动时内核感兴趣的结构,而我们最感兴趣的是自己设计的数据结构,因此将struct cdev结构被嵌入自己设计的数据结构中;这就产生了一个问题Q:我们如何获取自己感兴趣的数据结构? 【container_of(pointer, type, member)】
==>原因是它是在与用户空间通信
3、 通常情况下,一个结构只能嵌有一个kobject,否则在编译时会出现bug。
Eg、
struct uio_mem {
struct kobject kobj;
unsigned long addr;
unsigned long size;
int memtype;
void __iomem *internal_addr;
};
/*kp 可获取 struct uio_mem 结构中 */
struct uio_mem *u_mem = container_of(kp, struct uio_mem, kobj);
Ktype 的特点:
1、 它是被嵌入kobject对象的类型,每个kobject对象应有相对应的ktype类型。
2、它的作用:kobject创建和销毁时,应该做哪些操作。
Kset 的特点:
1、简单的说 Kset 就是 kobject 的集合,kset就像一个容器来包容kobject这些子集。Kset中的所有kobject可以拥有相同的ktype,也可以各自属于自己的ktype。
2、 kset中也有处于自己的kobject,不过该kobject处于自动处理的,可以忽略它核心代码处理的过程。
【友情提醒】如果不对属于kset自己kobject 赋值name,就会产生段错误?
大家去看下kset_init()源代码就可以了解。
////////////////////////////////////////////////////////////////////
////////////////////////操作方法///////////////////////////////////
【使用方法】
1、kobject 初始化并添加 【采用一步到位简单快捷】
2、struct kobj_type *ktype 中 struct sysfs_ops 操作接口
3、struct kobj_type *ktype 中 struct attribute **default_attrs \
缺省时默认的属性。
4、实现对应的那些attr的show和store函数,实现你所需要的功能
5、kobject的uevent事件处理
若要加入kset中则在首先就要手动赋值 kobj.kset = &ksetp
头文件:
#include
实现方法:lib/kobject.c
[数据结构]
struct kobject {
const char *name; /*指向设备名称的指针*/
struct list_head entry; /*挂载在 kset 中的单元*/
struct kobject *parent; /*指向父对象的指针(即父目录)*/
struct kset *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;
};
[NOTE]
1、kref域表示该对象引用的计数,内核通过kref实现对象引用计数管理,内
核提供两个函数kobject_get()、kobject_put()分别用于增加和减少引用计
数,当引用计数为0时,所有该对象使用的资源将被释放。
2、Ktype域是一个指向kobj_type结构的指针,表示该对象的类型。Kobj_type
数据结构包含三个域:一个release方法用于释放kobject占用的资源;一 个
sysfs_ops指针指向sysfs操作表和一个sysfs文件系统缺省属性列表。
Sysfs操作表包括两个函数store()和show()。当用户态读取属性时,show()
函数被调用,该函数编码指定属性值存入buffer中返回给用户态;而store()
函数用于存储用户态传入的属性值。
struct kobj_type {
void (*release)(struct kobject *kobj); /*当kobject引用计数为0*/
struct sysfs_ops *sysfs_ops; /*sysfs 文件属性操作*/
struct attribute **default_attrs; /*指针数组,每个指针均是
一个属性【一定要以NULL结束】*/
};
头文件:
#inclde
/*类似于 struct file_operations*/
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
/*文件属性*/
struct attribute {
const char *name;
struct module *owner;
mode_t mode;
};
/*kobj_attribute 是否包含了上面的两个结构呢*/
struct kobj_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count);
};
eg、
static struct kobj_attribute baz_attribute =
__ATTR(baz, 0666, b_show, b_store);
【操作方法】
/*
* @brief 初始化 struct kobject 结构对象
* @param[in] kobj struct kobject 结构指针
* @param[in] ktype struct kobj_type 对象类型
* @return no
*/
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
/*
* @brief 通知内核 struct kobject 对象可用
* @param[in] kobj struct kobject 结构指针
* @param[in] parent 父目录
* @param[in] fmt 一般为创建的 parent 子目录《名字》
* @return no
*/
int kobject_add(struct kobject *kobj, struct kobject *parent,
const char *fmt, ...)
/*@brief: 给struct kobject 命名*/
int kobject_set_name(struct kobject *kobj, const char *name)
【一步到位】
/*
*参数解释同上
*/
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...)
/*
* kref 引用计数加 1
*/
struct kobject *kobject_get(struct kobject *kobj)
/*
* kref 引用计数减 1
* 如果 kref = 0; 则调用 kobject_cleanup()
*/
void kobject_put(struct kobject *kobj)
/*
* 释放 kobject 资源 【释放与注销不同哦】
*/
void kobject_cleanup(struct kobject *kobj)
/*
* 注销 kobject 资源
*/
void kobject_del(struct kobject *kobj)
/*创建文件属性*/
struct kobject *kobject_create_and_add(char *name, struct kobject *parent);
int sysfs_create_file(struct kobject *kobj, struct attribute *attr);
int sysfs_create_group(struct kobject *kobj, struct attribute_group *grp);
【操作方法】
1、set_name kset中的kobject
2、kset热插拔事件处理
3、通知内核
#include
struct kset {
struct list_head list; /*链接所有 kset 的 kobject 指针头*/
spinlock_t list_lock; /*避免竞态的自旋锁*/
struct kobject kobj; /*内嵌的 kobject 干嘛用?*/
struct kset_uevent_ops *uevent_ops; /*原有的热拔插结构被该结构替代*/
};
/*以下什么时候被调用,有何作用,参数来龙去脉*/
struct kset_uevent_ops
{
int (*filter)(struct kset *kset, struct kobject *kobj);
const char *(*name)(struct kset *kset, struct kobject *kobj);
int (*uevent)(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env);
};
[NOTE]
filter==>决定是否将事件传递到用户空间。 0:禁止 1:传递
name ==>用于将字符串传递给用户空间的热插把处理程序
uevent==>将用户空间需要的参数添加到环境变量中
/*与kobject操作类似*/
void kset_init(struct kset *kset);
int kset_add(struct kset *kset);
int kset_register(struct kset *kset);
void kset_unregister(struct kset *kset);
struct kset *kset_get(struct kset *kset);
void kset_put(struct kset *kset);