#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設備模型是一棟摩天大廈,那么這幾個函數就是把這個大廈建立起來的最
底層的建築工人。