bloak目錄,存放塊設備信息。每一個塊設備都會對應bloak目錄下的一個子目錄記錄設備的相關信息。linux
bus 每條總線在該文件夾下對應一個子目錄,如i2c目錄,子目錄如i2c下又對應兩個子目錄 Devices目錄和Drivers目錄 Drivers目錄:包括註冊到該總線的全部的設備驅動 Devices目錄:對應屬於該總線類型的設備網絡
class目錄:按照設備功能進行分類,如net子目錄包含了網絡接口
函數
devices:全部設備測試
kernel:內核的配置參數
spa
module:系統中全部模塊的信息指針
firmware:系統中的固件code
FS:系統中的文件系統orm
power:系統中電源選項
對象
全部的設備都位於devices目錄中,別的目錄下設備會經過連接鏈接到device目錄下接口
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:當用戶寫屬性文件時,該函數被調用,用於存儲用戶傳入的屬性值。
#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,一個通知會從內核空間移動到用戶空間,這既是熱插拔,熱插拔會致使用戶空間相應的處理程序被調用,這些程序經過調用設備驅動,建立設備節點來響應熱插拔。
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狀態發生變化時(如被加入,移動),這三個函數將被調用。
#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
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)
刪除屬性
#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 文件