內存文件系統 /sys文件 bus總線 kobject kset(一)

sysfs掛載/sys目錄下 如

bloak目錄,存放塊設備信息。每一個塊設備都會對應bloak目錄下的一個子目錄記錄設備的相關信息。linux

bus 每條總線在該文件夾下對應一個子目錄,如i2c目錄,子目錄如i2c下又對應兩個子目錄 Devices目錄和Drivers目錄 Drivers目錄:包括註冊到該總線的全部的設備驅動 Devices目錄:對應屬於該總線類型的設備網絡

class目錄:按照設備功能進行分類,如net子目錄包含了網絡接口
函數

devices:全部設備測試

kernel:內核的配置參數
spa

module:系統中全部模塊的信息指針

firmware:系統中的固件code

FS:系統中的文件系統orm

power:系統中電源選項
對象

全部的設備都位於devices目錄中,別的目錄下設備會經過連接鏈接到device目錄下接口

kobject 面向對象的管理機制,建立一個kobject對象,就會在/sys下建立一個目錄

structk object {
constchar
*name;
structlist_head
entry;
structkobject
*parent;//指向父對象
structkset
*kset;
structkobj_type
*ktype;
structsysfs_dirent *sd;
structkref
kref;//對象引用計數
unsignedint state_initialized:1;
unsignedint state_in_sysfs:1;
unsignedint state_add_uevent_sent:1;
unsignedint state_remove_uevent_sent:1;
};

註冊kobject步驟 函數

kobject_init(struct kobject * kobj) 初始化
kobject_add(struct kobject * kobj) 添加對象
kobject_init_and_add(struct kobject *kobj, struct kobj_type*ktype,struct kobject *parent, const char *fmt, ...) 至關於完成上面兩步。struct kobject *parent表示目錄,若是爲空建立在sysfs目錄下,*fmt表示設備名字
kobject_del() 刪除對象
kobject_get()將kobject對象計數加1
kobject_put()  kobject對象計數減1

文件屬性

Kobject的ktype成員是一個指向kobj_type結構的指針, 該結構中記錄了kobject對象的一些屬性以及一些操做。
struct kobj_type {
void(*release)(struct kobject *kobj);   
struct sysfs_ops *sysfs_ops;       //讀寫 屬性文件
struct attribute **default_attrs;  //屬性文件
};
release:用於釋放kobject佔用的資源,當kobject的引用計數爲0時被調用。

屬性結構體

struct attribute {
char *name; /*屬性文件名*/
mode_tmode; /*屬性的保護位*/ //讀寫屬性
};
struct attribute (屬性):對應於kobject的目錄下的一個文件,Name成員就是文件名。

結構體讀寫

struct sysfs_ops
{
ssize_t(*show)(struct kobject *, struct attribute *,char *);
ssize_t(*store)(struct kobject *,struct attribute *,const char *,size_t);
};

Show:當用戶讀屬性文件時,該函數被調用,該函數將屬性值存入buffer中返回給用戶態;
Store:當用戶寫屬性文件時,該函數被調用,用於存儲用戶傳入的屬性值。

kobject模塊測試源碼

#include <linux/device.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/string.h> 
#include <linux/sysfs.h> 
#include <linux/stat.h> 
  
MODULE_AUTHOR("cicue"); 
MODULE_LICENSE("Dual BSD/GPL");
 
/*聲明release、show、store函數*/

void obj_test_release(struct kobject *kobject); 
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
/*對應於kobject的目錄下的一個文件,Name成員就是文件名*/  
struct attribute test_attr = { 
        .name = "kobj_config", 
        .mode = S_IRWXUGO, 
}; 
  
static struct attribute *def_attrs[] = { 
        &test_attr, 
        NULL, 
}; 
  
/kobject對象的操做 
struct sysfs_ops obj_test_sysops = 
{ 
        .show = kobj_test_show, 
        .store = kobj_test_store, 
}; 
 
/*定義kobject對象的一些屬性及對應的操做*/ 
struct kobj_type ktype =  
{ 
        .release = obj_test_release, 
        .sysfs_ops=&obj_test_sysops, 
        .default_attrs=def_attrs, 
};
/*release方法釋放該kobject對象*/  
void obj_test_release(struct kobject *kobject) 
{ 
        printk("eric_test: release .\n"); 
}
/*當讀文件時執行的操做*/ 
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
{ 
        printk("have show.\n"); 
        printk("attrname:%s.\n", attr->name); 
        sprintf(buf,"%s\n",attr->name); 
        return strlen(attr->name)+2; 
}
/*當寫文件時執行的操做*/  
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
{ 
        printk("havestore\n"); 
        printk("write: %s\n",buf); 
        return count; 
} 
  
struct kobject kobj;//聲明kobject對象
 
static int kobj_test_init(void) 
{ 
        printk("kboject test init.\n"); 
        kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");//初始化kobject對象kobj,並將其註冊到linux系統
        return 0; 
} 
  
static void kobj_test_exit(void) 
{ 
        printk("kobject test exit.\n"); 
        kobject_del(&kobj); 
} 
  
module_init(kobj_test_init);
module_exit(kobj_test_exit);

運行結果是建立目錄  /sys/kobject_test/kobj_config

熱插拔事件,當系統配置發生變化時,如添加kset到系統,移動kobject,一個通知會從內核空間移動到用戶空間,這既是熱插拔,熱插拔會致使用戶空間相應的處理程序被調用,這些程序經過調用設備驅動,建立設備節點來響應熱插拔。

kset是kobject的集合

struct kset {
struct list_head list; //鏈接該kset中全部kobject的鏈表頭
spinlock_t list_lock;
struct kobject kobj; //內嵌的kobject
struct kset_uevent_ops *uevent_ops; //處理熱插拔事件的操做集合
}

子目錄中還有子目錄是kset,若是子目錄只有文件是kobject.

1)int kset_register(struct kset *kset)
在內核中註冊一個kset
2)void kset_unregister(struct kset *kset)
從內核中註銷一個kset

功能結構

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);
}
三個函數功能
1)filter:決定是否將事件傳遞到用戶空間。若是filter返回0,將不傳遞事件。(例: uevent_filter)
2)name:用於將字符串傳遞給用戶空間的熱插拔處理程序。
3)uevent:將用戶空間須要的參數添加到環境變量中。(例:dev_uevent)

當該kset所管理的kobject和kset狀態發生變化時(如被加入,移動),這三個函數將被調用。

kset模塊測試源碼

#include <linux/device.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/string.h>
    #include <linux/sysfs.h>
    #include <linux/stat.h>
    #include <linux/kobject.h>
    MODULE_AUTHOR("cicue");
    MODULE_LICENSE("GPL");
    struct kset *kset_p;
    struct kset kset_c;
    /* 函數聲明 */
    void obj_test_release(struct kobject *);
    ssize_t kobj_test_show(struct kobject *,struct attribute *,char *);
    ssize_t kobj_test_store(struct kobject *,struct attribute *,const char *,size_t);
    static struct attribute test_attr =
    {
            .name = "kobj_config",
            .mode = S_IRWXUGO,
    };
    static struct attribute *def_attrs[] =
    {
            &test_attr,
            NULL,
    };
    static struct sysfs_ops obj_test_sysops =
    {
            .show = kobj_test_show,
            .store = kobj_test_store,
    };
    static struct kobj_type ktype =
    {
            .release = obj_test_release,
            .sysfs_ops = &obj_test_sysops,
            .default_attrs = def_attrs,
};
    void obj_test_release(struct kobject *kobject)
    {
            printk("[kobj_test: release!]\n");
    }
    ssize_t kobj_test_show(struct kobject *kobject,struct attribute *attr,char *buf)
    {
            printk("Have show -->\n");
            printk("attrname: %s.\n",attr->name);
            sprintf("buf,%s\n",attr->name);
            return strlen(attr->name) + 2;
    }
    ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr, const char *buf,size_t size)
    {
            printk("Have store -->\n");
            printk("write: %s.\n",buf);
            return size;
    }
    static int kset_filter(struct kset *kset,struct kobject *kobj)
    {
        printk("Filter: kobj %s.\n",kobj->name);
        return 1;
    }
    static const char *kset_name(struct kset *kset,struct kobject *kobj)
    {
        static char buf[20];
        printk("Name kobj %s.\n",kobj->name);
        sprintf(buf,"%s","kset_name");
        return buf;
    }
    static int kset_uevent(struct kset *kset,struct kobject *kobj, struct kobj_uevent_env *env)

{
        int i = 0;
        printk("uevent: kobj %s.\n",kobj->name);
        while(i < env->envp_idx)
        {
            printk("%s.\n",env->envp[i]);
            i ++;
        }
        return 0;
    }
    static struct kset_uevent_ops uevent_ops =
    {
        .filter = kset_filter,
        .name = kset_name,
        .uevent = kset_uevent,
    };

    static int __init kset_test_init(void)
    {
        int ret = 0;
        printk("kset test init!\n");
        /* 建立並註冊 kset_p */
        kset_p = kset_create_and_add("kset_p",&uevent_ops,NULL);
        /* 添加 kset_c 到 kset_p */
        kobject_set_name(&kset_c.kobj,"kset_c");
        kset_c.kobj.kset = kset_p;
        /* 對於較新版本的內核,在註冊 kset 以前,須要  
             * 填充 kset.kobj 的 ktype 成員,不然註冊不會成功 */
        kset_c.kobj.ktype = &ktype;
        ret = kset_register(&kset_c);
        if(ret)
            kset_unregister(kset_p);
        return 0;
    }
    static void __exit kset_test_exit(void)
    {
        printk("kset test exit!\n");
        kset_unregister(kset_p);
        kset_unregister(&kset_c);
    }
    module_init(kset_test_init);
    module_exit(kset_test_exit);

運行效果爲 /sys目錄下 建立了 /kset_p/kset_c/kobj_config

bus地址總線

1)地址總線註冊bus_register(struct bus_type *bus);

若成功,新的總線將被添加進系統,並可在sysfs 的 /sys/bus 下看到。
2)總線的刪除使用:void bus_unregister(struct bus_type *bus)

總線方法
1)int (*match)(struct device * dev, struct device_driver * drv)
        當一個新設備或者驅動被添加到這個總線時,該方法被調用。用於判斷指定的驅動程序是否能處理指定的設備。若能夠,則返回非零值。
2)int (*uevent)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
在爲用戶空間產生熱插拔事件以前,這個方法容許總線添加環境變量。

總線屬性由結構bus_attribute 描述,定義以下:

struct bus_attribute {
struct attribute
attr;
ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char *
buf, size_t count);
}

1)int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
建立屬性
2)void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
刪除屬性

bus地址總線測試源碼

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
MODULE_AUTHOR("cicue");
MODULE_LICENSE("Dual BSD/GPL");
static char *Version = "$Revision: 1.0 $";
 

/*當一個新設備或者驅動被添加到這個總線時,該方法被調用。用於判斷指定的驅動程序是否能處理指定的設備。若能夠,則返回非零值。*/

static int my_match(struct device *dev, struct device_driver *driver)
{
        return !strncmp(dev->kobj.name, driver->name, strlen(driver->name));
}

/*聲明總線*/
struct bus_type my_bus_type = {
        .name = "my_bus",  //總線名字
        .match = my_match, //總線match函數指針
};
static ssize_t show_bus_version(struct bus_type *bus, char *buf)
{
        return snprintf(buf, PAGE_SIZE, "%s\n", Version);
}
/*內核代碼中如此定義:#define BUS_ATTR(_name, _mode, _show, _store) \
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store),
它將bus_attr_做爲給定的name的前綴來建立總線的真正名稱。對應下面的是bus_attr_version*/
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);
/*模塊加載函數*/
static int __init my_bus_init(void)
{
        int ret;
        /*註冊總線*/
        ret = bus_register(&my_bus_type);
        if (ret)
                return ret;
        /*建立屬性文件*/
        if (bus_create_file(&my_bus_type, &bus_attr_version))
                printk(KERN_NOTICE "Fail to create version attribute!\n");
        return ret;
}
/*模塊卸載函數*/
static void my_bus_exit(void)
{
        bus_unregister(&my_bus_type);
}
module_init(my_bus_init);
module_exit(my_bus_exit);

運行結果:建立  /sys/bus /my_bus/ 裏面包含下面的

devices drivers        目錄

drivers_autoprobe  uevent   drivers_probe  version 文件

相關文章
相關標籤/搜索