日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux通常把设备对象抽象为,linux 设备模型(1)

發(fā)布時(shí)間:2025/3/21 linux 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux通常把设备对象抽象为,linux 设备模型(1) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

設(shè)備模型(一)

一、概述

從2.6內(nèi)核引入了sysfs文件系統(tǒng),與proc, devfs, devpty同類別,屬于虛擬的文件系統(tǒng)。目的是展示設(shè)備驅(qū)動(dòng)模型中各組件的層次關(guān)系,第一層目錄:block, device, bus, drivers, class, power, firmware.

block 塊設(shè)備;devices 系統(tǒng)所有的設(shè)備并根據(jù)設(shè)備掛接的總線類型組織成層次結(jié)構(gòu);bus 系統(tǒng)所有的總線類型;drivers 內(nèi)核中所有已經(jīng)注冊(cè)的設(shè)備驅(qū)動(dòng)程序;class 系統(tǒng)中的設(shè)備類型(如網(wǎng)卡 設(shè)備、聲卡設(shè)備、輸入設(shè)備等)。在/sys/bus下和/sys/bus/下也會(huì)有設(shè)備文件,但那只是符號(hào)鏈接,它指向/sys/devices/下的真實(shí)設(shè)備。此即為Linux設(shè)備模型。

總線(bus)、設(shè)備(device)、驅(qū)動(dòng)(driver)3個(gè)數(shù)據(jù)結(jié)構(gòu)構(gòu)成了設(shè)備的上層建筑,而kobject、kset、kobj_type(ktype)這三個(gè)數(shù)據(jù)結(jié)構(gòu)構(gòu)成了設(shè)備模型的經(jīng)濟(jì)基礎(chǔ)。內(nèi)核引入內(nèi)核這概念最主要的目的無非就是為了省電,便于管理。Linux設(shè)備模型的目的是:為內(nèi)核建立起一個(gè)統(tǒng)一的設(shè)備模型,從而有一個(gè)對(duì)系統(tǒng)結(jié)構(gòu)的一般性抽象描述。設(shè)備模型提供了這個(gè)抽象. 現(xiàn)在它用在內(nèi)核來支持不同的任務(wù), 包括:

1.電源管理,根據(jù)設(shè)備的層次關(guān)系,當(dāng)系統(tǒng)進(jìn)入睡眠的時(shí)候,不需要一個(gè)一個(gè)設(shè)備的關(guān),只需要關(guān)一個(gè)總線設(shè)備,接在總線下的設(shè)備就都會(huì)關(guān)掉。

2.sysfs虛擬文件系統(tǒng)的實(shí)現(xiàn)與設(shè)備模型的緊密相關(guān),并向外界展示它所表述的結(jié)構(gòu)。向用戶空間提供系統(tǒng)信息、改變操作參數(shù)的接口正越來越多地通過 sysfs,也就是設(shè)備模型來完成。

3.關(guān)于熱插拔,這跟掃描有關(guān)系,比如說,你把一個(gè)設(shè)備直接接在USB上,系統(tǒng)就會(huì)去掃描設(shè)備,并且在USB總線上尋找匹配的設(shè)備驅(qū)動(dòng),最后初始化設(shè)備,等待用戶使用。

4.設(shè)備模型的實(shí)現(xiàn)需要?jiǎng)?chuàng)建一系列機(jī)制來處理對(duì)象的生命周期、對(duì)象間的關(guān)系和對(duì)象在用戶空間的表示。Linux設(shè)備模型是一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。但對(duì)模型的大部分來說,Linux設(shè)備模型代碼會(huì)處理好這些關(guān)系,而不是把他們強(qiáng)加于驅(qū)動(dòng)作者。模型隱藏于交互的背后,與設(shè)備模型的直接交互通常由總線級(jí)的邏輯和其他的內(nèi)核子系統(tǒng)處理。所以許多驅(qū)動(dòng)作者可完全忽略設(shè)備模型, 并相信設(shè)備模型能處理好他所負(fù)責(zé)的事。

在具體實(shí)現(xiàn)方面分兩個(gè)層次:

一是底層數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn)基本對(duì)象及其層次關(guān)系:kobjects和ksets。

二是基于這兩個(gè)底層數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)的設(shè)備模型:總線,設(shè)備,驅(qū)動(dòng)。

二、底層數(shù)據(jù)結(jié)構(gòu):kobject,kset

1)Kobject

1.概念

Kobject實(shí)現(xiàn)基本的面向?qū)ο蠊芾頇C(jī)制,是構(gòu)成設(shè)備模型的核心結(jié)構(gòu)。它與sysfs文件系統(tǒng)緊密相連,在內(nèi)核中注冊(cè)每個(gè)kobject對(duì)象對(duì)應(yīng)sysfs文件系統(tǒng)中的一個(gè)目錄。

內(nèi)核通過kobject 結(jié)構(gòu)將各個(gè)對(duì)象連接起來組成一個(gè)分層的結(jié)構(gòu)體系,可以把kobject理解為面向?qū)ο蟮幕?#xff0c;確切的說kobject也可以理解為所有驅(qū)動(dòng)對(duì)象的基類,作為基類的kobject并不關(guān)心自己是如何實(shí)現(xiàn)的,所以,在內(nèi)核中,沒有用kobject直接定義的變量,kobject只是作為一個(gè)抽象的基類而存在,而由于Linux內(nèi)核是C編寫的,通過查看device_driver、device等結(jié)構(gòu)體中內(nèi)嵌了kobject結(jié)構(gòu)體。

2.結(jié)構(gòu),定義在

struct kobject {

const char * k_name;/*指向設(shè)備名稱的指針 */

char name[KOBJ_NAME_LEN];/*kobject 的名字?jǐn)?shù)組,設(shè)備名稱*/

struct kref kref;/*kobject 的引用計(jì)數(shù)*/

struct list_head entry;/*kobject 之間的雙向鏈表,與所屬的kset形成環(huán)形鏈表*/

struct kobject * parent;/*在sysfs分層結(jié)構(gòu)中定位對(duì)象,指向上一級(jí)kset中的struct kobject kobj*/

struct kset * kset;/*指向所屬的kset*/

struct kobj_type * ktype;/*負(fù)責(zé)對(duì)該kobject類型進(jìn)行跟蹤的struct kobj_type的指針*/

struct dentry * dentry;/*sysfs文件系統(tǒng)中與該對(duì)象對(duì)應(yīng)的文件節(jié)點(diǎn)路徑指針*/

wait_queue_head_t poll;/*等待隊(duì)列頭*/

};

2.1 kobj_type結(jié)構(gòu)

//kobject的ktype對(duì)象是一個(gè)指向kobject_type結(jié)構(gòu)的指針,該結(jié)構(gòu)記錄了kobject對(duì)象的一些屬性。每個(gè)kobject都需要對(duì)應(yīng)一個(gè)相應(yīng)的kobj_type結(jié)構(gòu)。

struct kobj_type{

void (*release)(struct kobject *kobj);//release方法用于釋放kobject占用的資源,當(dāng)kobject引用計(jì)數(shù)為0時(shí)被調(diào)用。

struct sysfs_ops *sysfs_ops;

struct attribute **default_attrs;//對(duì)應(yīng)于kobject的目錄下一個(gè)文件,name就是文件名。

};

2.1.1 kobje_type的attribute結(jié)構(gòu)

struct attribute{

char*name;//屬性文件名

struct module *owner;//所屬的模塊

mode_t mode;//屬性文件的操作模式(可讀,可寫...)

}

2.1.2 kobje_type的struct sysfs_ops結(jié)構(gòu)

struct sysfs_ops

{

ssize_t (*show)(structkobejct *, struct attribute *, char *name);//當(dāng)用戶讀屬性文件時(shí),該函數(shù)被調(diào)用,該函數(shù)將屬性值存入buffer中返回給用戶態(tài);

ssize_t (*store)(structkobejct *, struct attribute *, char *name);//當(dāng)用戶寫屬性文件時(shí),該函數(shù)被調(diào)用,用于存儲(chǔ)用戶存入的屬性值。

}

3.這個(gè)在層次上處理最頂層的kobject結(jié)構(gòu)提供了所有模型需要的最基本的功能:

(1)引用計(jì)數(shù):跟蹤對(duì)象生命周期的一種方法是使用引用計(jì)數(shù)。當(dāng)沒有內(nèi)核代碼持有該對(duì)象的引用時(shí), 該對(duì)象將結(jié)束自己的有效生命期并可被刪除。

(2)sysfs表示每個(gè)sys/下的對(duì)象對(duì)應(yīng)著一個(gè)kobject。

(3)熱拔插事件處理。處理設(shè)備的熱拔插事件。

在 sysfs 中創(chuàng)建kobject的入口是kobject_add的工作的一部分,只要調(diào)用 kobject_add 就會(huì)在sysfs 中顯示,還有些知識(shí)值得記住:

(1)kobjects 的 sysfs 入口始終為目錄, kobject_add 的調(diào)用將在sysfs 中創(chuàng)建一個(gè)目錄,這個(gè)目錄包含一個(gè)或多個(gè)屬性(文件);

(2)分配給 kobject 的名字( 用 kobject_set_name ) 是 sysfs 中的目錄名,出現(xiàn)在 sysfs 層次的相同部分的 kobjects 必須有唯一的名字. 分配給 kobjects 的名字也應(yīng)當(dāng)是合法的文件名字: 它們不能包含非法字符(如:斜線)且不推薦使用空白。

(3)sysfs 入口位置對(duì)應(yīng) kobject 的 parent 指針。若 parent 是 NULL ,則它被設(shè)置為嵌入到新 kobject 的 kset 中的 kobject;若 parent 和 kset 都是 NULL, 則sysfs 入口目錄在頂層目錄,通常不推薦。

4.相關(guān)函數(shù):

void kobjet_init(struct kobject*kobj)//初始化Kobject

int kobject_add(struct kobject*kobj)//將Kobject對(duì)象注冊(cè)到linux系統(tǒng),如果失敗則返回一個(gè)錯(cuò)誤碼.

struct kobject *kobject_get(struct kobject *kobj);/*若成功,遞增 kobject 的引用計(jì)數(shù)并返回一個(gè)指向 kobject 的指針,否則返回 NULL。必須始終測(cè)試返回值以免產(chǎn)生競(jìng)態(tài)*/

void kobject_put(struct kobject *kobj);/*遞減引用計(jì)數(shù)并在可能的情況下釋放這個(gè)對(duì)象*/

int kobject_init_and_add(structkobject *kobj, kobj_type *ktype, struct kobject *parent, const *fmt…)

//初始化并注冊(cè)kobject,kobject傳入要初始化的Kobject對(duì)象,ktype將在后面介紹到,parent指向上級(jí)的kobject對(duì)象,如果指定位NULL,將在/sys的頂層創(chuàng)建一個(gè)目錄。*fmt為kobject對(duì)象的名字。

5.實(shí)例

#include

#include

#include

#include

#include

#include

#include

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);

struct attribute test_attr = {

.name = "kobj_config",

.mode = S_IRWXUGO,

};

static struct attribute *def_attrs[] = {

&test_attr,

NULL,

};

struct sysfs_ops obj_test_sysops =

{

.show = kobj_test_show,

.store = kobj_test_store,

};

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("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;

static int kobj_test_init()

{

printk("kboject test init.\n");

kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");

return 0;

}

static int kobj_test_exit()

{

printk("kobject test exit.\n");

kobject_del(&kobj);

return 0;

}

module_init(kobj_test_init);

module_exit(kobj_test_exit);

在/sys目錄下創(chuàng)建了kobject_test目錄,在kobject_test目錄下有kobj_config文件。

讀kobject_config文件則調(diào)用了show函數(shù)。并在用戶空間顯示了show返回的kobject對(duì)象名字。寫kobject_config文件調(diào)用了store函數(shù)。

2)kset

1.概念

Kset是具有相同類型的kobject的集合,在sysfs中體現(xiàn)成一個(gè)目錄,在內(nèi)核中用kset數(shù)據(jù)結(jié)構(gòu)表示。

一個(gè)kset的主要功能是容納;它可被當(dāng)作頂層的給kobjects的容器類.實(shí)際上,每個(gè)kset在內(nèi)部容納它自己的 kobject,并且它可以,在許多情況下,如同一個(gè)kobject相同的方式被對(duì)待.值得注意的是ksets一直在sysfs中出現(xiàn),一旦一個(gè) kset已被建立并且加入到系統(tǒng), 會(huì)有一個(gè)sysfs目錄給它.kobjects沒有必要在sysfs中出現(xiàn), 但是每個(gè)是 kset 成員的 kobject 都出現(xiàn)在那里.

通俗的講,kobject建立一級(jí)的子目錄里面只能包含文件,kset可以為kobject建立多級(jí)的層次性的父目錄。

2.結(jié)構(gòu)體

如果這個(gè) kobject 是一個(gè)kset的成員, kset會(huì)提供kobj_type指針。通常情況下kobject只需要在葉節(jié)點(diǎn)里使用,上層的節(jié)點(diǎn)要使用kset。

struct kset {

struct kobj_type * ktype; /*指向該kset對(duì)象類型的指針*/

struct list_head list;/*用于連接該kset中所有kobject以形成環(huán)形鏈表的鏈表頭*/

spinlock_t list_lock;/*用于避免競(jìng)態(tài)的自旋鎖*/

struct kobject kobj; /*嵌入的kobject*/

struct kset_uevent_ops * uevent_ops; //指向熱插拔操作表的指針

};

包含在kset中的所有的kobject被組織成一個(gè)上相的循環(huán)鏈表list域是該鏈表的頭指針,ktype域指向一個(gè)kobj_type結(jié)構(gòu),被該kset中的所有kobject共享,表示這些對(duì)象的類型,kset數(shù)據(jù)結(jié)構(gòu)還內(nèi)嵌了一個(gè)kobject對(duì)象,所有屬于這個(gè)kset的kobject對(duì)象的parent域指向這個(gè)內(nèi)嵌的對(duì)象,此外kset還依賴于kobj維護(hù)引用計(jì)數(shù):這就明了,kset的引用計(jì)數(shù)其實(shí)就是其內(nèi)嵌對(duì)象kobject對(duì)象的的引用計(jì)數(shù),具有相同類型的kobject集合在一起組成了kset,許多kset集合在一起組成了子系統(tǒng)subsystem。

kset 在一個(gè)標(biāo)準(zhǔn)的內(nèi)核鏈表中保存了它的子節(jié)點(diǎn),在大部分情況下, 被包含的 kobjects 在它們的 parent 成員中保存指向 kset內(nèi)嵌的 kobject的指針,關(guān)系如下:

(1)ksets 有類似于kobjects初始化和設(shè)置接口。

(2)ksets 還有一個(gè)指針指向kobj_type結(jié)構(gòu)來描述它包含的kobject,這個(gè)類型優(yōu)先于kobject自身中的ktype。因此在典型的應(yīng)用中, 在 struct kobject中的ktype成員被設(shè)為 NULL, 而kset中的ktype是實(shí)際被使用的。

(3)在新的內(nèi)核里, kset不再包含一個(gè)子系統(tǒng)指針struct subsystem * subsys, 而且subsystem已經(jīng)被kset取代。

(4)子系統(tǒng)是對(duì)整個(gè)內(nèi)核中一些高級(jí)部分的表述。子系統(tǒng)通常出現(xiàn)在sysfs分層結(jié)構(gòu)中的頂層,內(nèi)核子系統(tǒng)包括 block_subsys(/sys/block 塊設(shè)備)、 devices_subsys(/sys/devices 核心設(shè)備層)以及內(nèi)核已知的用于各種總線的特定子系統(tǒng)。對(duì)于新的內(nèi)核已經(jīng)不再有subsystem數(shù)據(jù)結(jié)構(gòu)了,用kset代替了。每個(gè) kset 必須屬于一個(gè)子系統(tǒng),子系統(tǒng)成員幫助內(nèi)核在分層結(jié)構(gòu)中定位kset。

3.Kset操作:

struct kset *kset_create_and_add(const char *name,const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)

int kset_register(struct kset*kset)//注冊(cè)kset

void kset_unregister(struct kset*kset)//注銷kset

4.實(shí)例

#include

#include

#include

#include

#include

#include

#include

#include

struct kset kset_p;

struct kset kset_c;

int kset_filter(struct kset *kset, struct kobject *kobj)

{

printk("Filter: kobj %s.\n",kobj->name);

return 1;

}

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;

}

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;

}

struct kset_uevent_ops uevent_ops =

{

.filter = kset_filter,

.name = kset_name,

.uevent = kset_uevent,

};

int kset_test_init()

{

printk("kset test init.\n");

kobject_set_name(&kset_p.kobj,"kset_p");

kset_p.uevent_ops = &uevent_ops;

kset_register(&kset_p);

kobject_set_name(&kset_c.kobj,"kset_c");

kset_c.kobj.kset = &kset_p;

kset_register(&kset_c);

return 0;

}

int kset_test_exit()

{

printk("kset test exit.\n");

kset_unregister(&kset_p);

kset_unregister(&kset_c);

return 0;

}

module_init(kset_test_init);

module_exit(kset_test_exit);

可以看出當(dāng)kset加載時(shí),在/sys下創(chuàng)建了一個(gè)kset_p目錄,在kset_p下面創(chuàng)建了kset_c目錄,當(dāng)kset模塊被加載和卸載時(shí)都產(chǎn)生了熱插拔事件。

三、代碼分析

/*****************************************************************************************************/

1.kobject對(duì)象的初始化以及添加到sysfs文件系統(tǒng)中

/*****************************************************************************************************/

int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,struct kobject *parent, const char *fmt, ...)

{

va_list args;

int retval;

//初始化kobject

kobject_init(kobj, ktype);

va_start(args, fmt);

//為kobjcet設(shè)置名稱,在sysfs中建立相關(guān)信息

retval = kobject_add_varg(kobj, parent, fmt, args);

va_end(args);

return retval;

}

//上面的流程主要分為兩部份。一部份是kobject的初始化。在這一部份,它將kobject與給定的ktype關(guān)聯(lián)起來。初始化kobject中的各項(xiàng)結(jié)構(gòu)。

//另一部份是kobject的名稱設(shè)置。空間層次關(guān)系的設(shè)置,具體表現(xiàn)在sysfs文件系統(tǒng)中.

void kobject_init(struct kobject *kobj, struct kobj_type *ktype)

{

char *err_str;

if (!kobj) {//指針不能為空

err_str = "invalid kobject pointer!";

goto error;

}

if (!ktype) {//kobj_type指針也不能為空

err_str = "must have a ktype to be initialized properly!\n";

goto error;

}

if (kobj->state_initialized) {//標(biāo)志為1表示kobject已經(jīng)初始化過

printk(KERN_ERR "kobject (%p): tried to init an initialized ""object, something is seriously wrong.\n", kobj);

dump_stack();

}

kobject_init_internal(kobj);//初始化

kobj->ktype = ktype;//將kobject與給定的ktype關(guān)聯(lián)起來

return;

error:

printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);

dump_stack();

}

static void kobject_init_internal(struct kobject *kobj)

{

if (!kobj)

return;

kref_init(&kobj->kref);//初始化kobject的計(jì)數(shù)器,計(jì)數(shù)器設(shè)為1

INIT_LIST_HEAD(&kobj->entry);//初始化鏈表

kobj->state_in_sysfs = 0;

kobj->state_add_uevent_sent = 0;

kobj->state_remove_uevent_sent = 0;

kobj->state_initialized = 1;//表示kobject已經(jīng)初始化過

}

static inline void kref_init(struct kref *kref)

{

atomic_set(&kref->refcount, 1);

}

//另一部份是kobject的名稱設(shè)置。空間層次關(guān)系的設(shè)置,具體表現(xiàn)在sysfs文件系統(tǒng)中.

static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,const char *fmt, va_list vargs)

{

va_list aq;

int retval;

va_copy(aq, vargs);

//設(shè)置kobject的名字。即設(shè)置kobject的name成員

retval = kobject_set_name_vargs(kobj, fmt, aq);

va_end(aq);

if (retval) {

printk(KERN_ERR "kobject: can not set name properly!\n");

return retval;

}

//設(shè)置kobject的parent。

kobj->parent = parent;

//在sysfs中添加kobjcet信息

return kobject_add_internal(kobj);

}

//設(shè)置好kobject->name后,轉(zhuǎn)入kobject_add_internal()。在sysfs中創(chuàng)建空間結(jié)構(gòu).

static int kobject_add_internal(struct kobject *kobj)

{

int error = 0;

struct kobject *parent;

if (!kobj)

return -ENOENT;

//如果kobject的名字為空.退出

if (!kobj->name || !kobj->name[0]) {

pr_debug("kobject: (%p): attempted to be registered with empty ""name!\n", kobj);

WARN_ON(1);

return -EINVAL;

}

//取kobject的父結(jié)點(diǎn),并遞增父kobject的計(jì)數(shù)

parent = kobject_get(kobj->parent);

//如果kobject的父結(jié)點(diǎn)沒有指定,而且kobj->kset已設(shè)定,就將kobj->kset->kobject做為它的父結(jié)點(diǎn)

if (kobj->kset) {

if (!parent)

parent = kobject_get(&kobj->kset->kobj);//遞增計(jì)數(shù),返回kset->kobject

kobj_kset_join(kobj);//遞增kobj對(duì)象中的kset計(jì)數(shù),并且將kobj->kset連接到kobj->entry隊(duì)列中

kobj->parent = parent;//設(shè)定父kobject

}

//在sysfs中創(chuàng)建kobject的相關(guān)信息

error = create_dir(kobj);

if (error) {

//v如果創(chuàng)建失敗。減少相關(guān)的引用計(jì)數(shù)

kobj_kset_leave(kobj);

kobject_put(parent);

kobj->parent = NULL;

/* be noisy on error issues */

if (error == -EEXIST)

printk(KERN_ERR "%s failed for %s with ""-EEXIST, don't try to register things with ""the same name in the same directory.\n",__FUNCTION__, kobject_name(kobj));

else

printk(KERN_ERR "%s failed for %s (%d)\n",__FUNCTION__, kobject_name(kobj), error);

dump_stack();

} else

//如果創(chuàng)建成功。將state_in_sysfs建為1。表示該object已經(jīng)在sysfs中了

kobj->state_in_sysfs = 1;

return error;

}

static int create_dir(struct kobject *kobj)

{

int error = 0;

if (kobject_name(kobj)) {//kobject名稱不為空

error = sysfs_create_dir(kobj);//為kobject創(chuàng)建目錄

if (!error) {

error = populate_dir(kobj);//創(chuàng)建目錄成功,為kobject->ktype中的屬性創(chuàng)建屬性文件

if (error)

sysfs_remove_dir(kobj);

}

}

return error;

}

//kobject所表示的目錄創(chuàng)建過程,這是在sysfs_create_dir()中完成的。

int sysfs_create_dir(struct kobject * kobj)

{

struct sysfs_dirent *parent_sd, *sd;

int error = 0;

BUG_ON(!kobj);

/*如果kobject的parnet存在。就在目錄點(diǎn)的目錄下創(chuàng)建這個(gè)目錄。如果沒有父結(jié)點(diǎn)不存在,就在/sys下面創(chuàng)建結(jié)點(diǎn)。在上面的流程中,我們可能并沒有為其指定父結(jié)點(diǎn),也沒有為其指定kset。*/

if (kobj->parent)

parent_sd = kobj->parent->sd;

else

parent_sd = &sysfs_root;

//在sysfs中創(chuàng)建目錄,參見sysfs文件系統(tǒng)解析

error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);

if (!error)

kobj->sd = sd;

return error;

}

//為kobject->ktype中的屬性創(chuàng)建文件,在populate_dir()中完成的。

static int populate_dir(struct kobject *kobj)

{

struct kobj_type *t = get_ktype(kobj);//得到kobject的kobj_type結(jié)構(gòu)

struct attribute *attr;

int error = 0;

int i;

if (t && t->default_attrs) {

for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {//遍歷ktype中的屬性

error = sysfs_create_file(kobj, attr);//在sysfs文件系統(tǒng)kobject目錄下創(chuàng)建屬性文件,參見sysfs文件系統(tǒng)解析

if (error)

break;

}

}

return error;

}

/****************************************************************************************************/

2.kset對(duì)象的初始化以及添加到sysfs文件系統(tǒng)中

/****************************************************************************************************/

struct kset *kset_create_and_add(const char *name,const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)

{

struct kset *kset;

int error;

//創(chuàng)建一個(gè)kset容器

kset = kset_create(name, uevent_ops, parent_kobj);

if (!kset)

return NULL;

//注冊(cè)創(chuàng)建的kset容器

error = kset_register(kset);

if (error) {

kfree(kset);

return NULL;

}

return kset;

}

static struct kset *kset_create(const char *name,const struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)

{

struct kset *kset;

int retval;

kset = kzalloc(sizeof(*kset), GFP_KERNEL);//為kset分配內(nèi)存空間

if (!kset)

return NULL;

//設(shè)置kset中kobject的名字

retval = kobject_set_name(&kset->kobj, name);

if (retval) {

kfree(kset);

return NULL;

}

kset->uevent_ops = uevent_ops;//設(shè)置uevent操作集

kset->kobj.parent = parent_kobj;//設(shè)置父對(duì)象

kset->kobj.ktype = &kset_ktype;//設(shè)置容器操作集

kset->kobj.kset = NULL;//設(shè)置父容器為空

return kset;

}

//創(chuàng)建好了kset之后,會(huì)調(diào)用kset_register().這個(gè)函數(shù)就是kset操作的核心代碼了.

int kset_register(struct kset *k)

{

int err;

if (!k)

return -EINVAL;

//繼續(xù)初始化

kset_init(k);

//向sysfs文件系統(tǒng)添加該容器,即為k內(nèi)嵌的kobject結(jié)構(gòu)建立空間層次結(jié)構(gòu),代碼見上

err = kobject_add_internal(&k->kobj);

if (err)

return err;

//因?yàn)樘砑恿薻set,會(huì)產(chǎn)生一個(gè)事件,這個(gè)事件是通過用戶空間的hotplug程序處理的,這就是kset明顯不同于kobject的地方.

kobject_uevent(&k->kobj, KOBJ_ADD);//參見udev原理

return 0;

}

void kset_init(struct kset *k)

{

kobject_init_internal(&k->kobj);//初始化kset中的kobject結(jié)構(gòu)

INIT_LIST_HEAD(&k->list);//初始化鏈表

spin_lock_init(&k->list_lock);

}

總結(jié)

以上是生活随笔為你收集整理的Linux通常把设备对象抽象为,linux 设备模型(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。