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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

研究UEVENT相关东西,看到2篇优秀的博文,转载与此

發(fā)布時(shí)間:2024/4/14 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 研究UEVENT相关东西,看到2篇优秀的博文,转载与此 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

http://blog.chinaunix.net/u3/92745/showart_2145668.html
LINUX設(shè)備驅(qū)動(dòng)之設(shè)備模型一--kobject

LINUX設(shè)備驅(qū)動(dòng)驅(qū)動(dòng)程序模型的核心數(shù)據(jù)結(jié)構(gòu)是kobjectkobject數(shù)據(jù)結(jié)構(gòu)在\linux\kobject.h中定義:?

struct kobject {

?????? const char???????????? *name;

?????? struct list_head?????? entry;

?????? struct kobject???????? *parent;

?????? struct 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;

};

每個(gè)kobject都有它的父節(jié)點(diǎn)parentksetkobj_type指針,這三者是驅(qū)動(dòng)模型的基本結(jié)構(gòu),ksetkobject的集合,在\linux\kobject.h中定義:

struct kset {

?????? struct list_head list;

?????? spinlock_t list_lock;

?????? struct kobject kobj;

?????? struct kset_uevent_ops *uevent_ops;

};

可以看到每個(gè)kset內(nèi)嵌了一個(gè)kobjectkobj字段),用來(lái)表示其自身節(jié)點(diǎn),其list字段指向了所包含的kobject的鏈表頭。我們?cè)诤竺娴姆治鲋袑⒖吹?/span>kobject如果沒(méi)有指定父節(jié)點(diǎn),parent將指向其kset內(nèi)嵌的kobject

每個(gè)kobject都有它的kobj_type字段指針,用來(lái)表示kobject在文件系統(tǒng)中的操作方法,kobj_type結(jié)構(gòu)也在\linux\kobject.h中定義:

struct kobj_type {

?????? void (*release)(struct kobject *kobj);

?????? struct sysfs_ops *sysfs_ops;

?????? struct attribute ** default_attrs;

};

release方法是在kobject釋放是調(diào)用,sysfs_ops指向kobject對(duì)應(yīng)的文件操作,default_attrskobject的默認(rèn)屬性,sysfs_ops的將使用default_attrs屬性(在后面的分析中我們將會(huì)看到)。

從上面的分析我們可以想象到kobjectksetkobj_type的層次結(jié)構(gòu):

500)this.width=500;" width="500" border="0">

我們可以把一個(gè)kobject添加到文件系統(tǒng)中去(實(shí)際上是添加到其父節(jié)點(diǎn)所代表的kset中去),內(nèi)核提供kobject_create_and_add()接口函數(shù):

struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)

{

?????? struct kobject *kobj;

?????? int retval;

?

?????? kobj = kobject_create();

?????? if (!kobj)

????????????? return NULL;

?

?????? retval = kobject_add(kobj, parent, "%s", name);

?????? if (retval) {

????????????? printk(KERN_WARNING "%s: kobject_add error: %d\n",

????????????? ?????? __func__, retval);

????????????? kobject_put(kobj);

????????????? kobj = NULL;

?????? }

?????? return kobj;

}

kobject _create()為要?jiǎng)?chuàng)建的kobject分配內(nèi)存空間并對(duì)其初始化。

struct kobject *kobject_create(void)

{

?????? struct kobject *kobj;

?

?????? kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);

?????? if (!kobj)

????????????? return NULL;

?

?????? kobject_init(kobj, &dynamic_kobj_ktype);

?????? return kobj;

}

kobject_init()對(duì)kobject基本字段進(jìn)行初始化,用輸入?yún)?shù)設(shè)置kobj_type屬性。

這里粘出代碼以供參考:

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

{

?????? char *err_str;

?

?????? if (!kobj) {

????????????? err_str = "invalid kobject pointer!";

????????????? goto error;

?????? }

?????? if (!ktype) {

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

????????????? goto error;

?????? }

?????? if (kobj->state_initialized) {

????????????? /* do not error out as sometimes we can recover */

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

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

?????? 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_add()函數(shù):

int kobject_add(struct kobject *kobj, struct kobject *parent,

????????????? const char *fmt, ...)

{

?????? va_list args;

?????? int retval;

?

?????? if (!kobj)

????????????? return -EINVAL;

?

?????? if (!kobj->state_initialized) {

????????????? printk(KERN_ERR "kobject '%s' (%p): tried to add an "

????????????? ?????? "uninitialized object, something is seriously wrong.\n",

????????????? ?????? kobject_name(kobj), kobj);

????????????? dump_stack();

????????????? return -EINVAL;

?????? }

?????? va_start(args, fmt);

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

?????? va_end(args);

?

?????? return retval;

}

在上面的初始化中已把位變量設(shè)位1

va_start(args, fmt)va_end(args)使用可變參數(shù)(可見(jiàn)參數(shù)用法不在這里分析),在kobject_add_varg中將把fmt指向的內(nèi)容賦給kobjectname字段。下面我們?cè)敿?xì)看看kobject_add_varg函數(shù):

static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,

???????????????????? ??? const char *fmt, va_list vargs)

{

?????? int retval;

?

?????? retval = kobject_set_name_vargs(kobj, fmt, vargs);

?????? if (retval) {

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

????????????? return retval;

?????? }

?????? kobj->parent = parent;

?????? return kobject_add_internal(kobj);

}

kobject_set_name_vargs(kobj, fmt, vargs),如果kobjname字段指向的內(nèi)容為空,則為分配一個(gè)內(nèi)存空間并用fmt指向的內(nèi)容初始化,把地址賦給kobjname字段。

int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,

??????????????????????????? ? va_list vargs)

{

?????? const char *old_name = kobj->name;

?????? char *s;

?

?????? if (kobj->name && !fmt)

????????????? return 0;

?

?????? kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);

?????? if (!kobj->name)

????????????? return -ENOMEM;

?

?????? /* ewww... some of these buggers have '/' in the name ... */

?????? while ((s = strchr(kobj->name, '/')))

????????????? s[0] = '!';

?

?????? kfree(old_name);

?????? return 0;

}

char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)

{

?????? unsigned int len;

?????? char *p;

?????? va_list aq;

?

?????? va_copy(aq, ap);

?????? len = vsnprintf(NULL, 0, fmt, aq);

?????? va_end(aq);

?

?????? p = kmalloc(len+1, gfp);

?????? if (!p)

????????????? return NULL;

?

?????? vsnprintf(p, len+1, fmt, ap);

?

?????? return p;

}

繼續(xù)kobject_add_varg()返回kobject_add_internal(kobj),就是在這個(gè)函數(shù)理為kobj創(chuàng)建文件系統(tǒng)結(jié)構(gòu):

static int kobject_add_internal(struct kobject *kobj)

{

?????? int error = 0;

?????? struct kobject *parent;

?

?????? if (!kobj)

????????????? return -ENOENT;

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

????????????? WARN(1, "kobject: (%p): attempted to be registered with empty "

???????????????????? ?"name!\n", kobj);

????????????? return -EINVAL;

?????? }

檢查kobj和它的name字段,不存在則返回錯(cuò)誤信息。

?

?????? parent = kobject_get(kobj->parent);

獲得其父節(jié)點(diǎn),并增加父節(jié)點(diǎn)的計(jì)數(shù)器,kobject結(jié)構(gòu)中的kref字段用于容器的計(jì)數(shù),kobject_getkobject_put分別增加和減少計(jì)數(shù)器,如果計(jì)數(shù)器為0,則釋放該kobjectkobject_get返回該kobject

?????? /* join kset if set, use it as parent if we do not already have one */

?????? if (kobj->kset) {

????????????? if (!parent)

???????????????????? parent = kobject_get(&kobj->kset->kobj);

????????????? kobj_kset_join(kobj);

????????????? kobj->parent = parent;

?????? }

在這里我們可以看到,如果調(diào)用kobject_create_and_add()時(shí)參數(shù)parent設(shè)為NULL,則會(huì)去檢查kobjkset是否存在,如果存在就會(huì)把kset所嵌套的kobj作為其父節(jié)點(diǎn),并把kobj添加到kset中去。

?????? ?????? pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",

????????????? ?kobject_name(kobj), kobj, __func__,

????????????? ?parent ? kobject_name(parent) : "<NULL>",

????????????? ?kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");

打印一些調(diào)試信息,接著為kobj創(chuàng)建目錄:

?????? error = create_dir(kobj);

?????? if (error) {

????????????? 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",

???????????????????? ?????? __func__, kobject_name(kobj));

????????????? else

???????????????????? printk(KERN_ERR "%s failed for %s (%d)\n",

???????????????????? ?????? __func__, kobject_name(kobj), error);

????????????? dump_stack();

?????? } else

????????????? kobj->state_in_sysfs = 1;

?

?????? return error;

}

如果創(chuàng)建不成功,則回滾上面的操作,成功的話(huà)則設(shè)置kobjstate_in_sysfs標(biāo)志。

在看看create_dir()函數(shù)中具體創(chuàng)建了那些內(nèi)容:

static int create_dir(struct kobject *kobj)

{

?????? int error = 0;

?????? if (kobject_name(kobj)) {

????????????? error = sysfs_create_dir(kobj);

????????????? if (!error) {

???????????????????? error = populate_dir(kobj);

???????????????????? if (error)

??????????????????????????? sysfs_remove_dir(kobj);

????????????? }

?????? }

?????? return error;

}

sysfs_create_dir()先為kobj創(chuàng)建了一個(gè)目錄文件

int sysfs_create_dir(struct kobject * kobj)

{

?????? struct sysfs_dirent *parent_sd, *sd;

?????? int error = 0;

?

?????? BUG_ON(!kobj);

?

?????? if (kobj->parent)

????????????? parent_sd = kobj->parent->sd;

?????? else

????????????? parent_sd = &sysfs_root;

?

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

?????? if (!error)

????????????? kobj->sd = sd;

?????? return error;

}

如果kobj->parentNULL,就把&sysfs_root作為父節(jié)點(diǎn)sd,即/sys下面創(chuàng)建結(jié)點(diǎn)。

然后調(diào)用populate_dir

static int populate_dir(struct kobject *kobj)

{

?????? struct kobj_type *t = get_ktype(kobj);

?????? struct attribute *attr;

?????? int error = 0;

?????? int i;

?

?????? if (t && t->default_attrs) {

????????????? for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {

???????????????????? error = sysfs_create_file(kobj, attr);

???????????????????? if (error)

??????????????????????????? break;

????????????? }

?????? }

?????? return error;

}

得到kobjkobj_type,歷遍kobj_typedefault_attrs并創(chuàng)建屬性文件,文件的操作會(huì)回溯到sysfs_opsshowstore會(huì)調(diào)用封裝了attributekobj_attribute結(jié)構(gòu)的storeshow方法(在后面的代碼中將會(huì)分析)。

由于上面kobject_init(kobj, &dynamic_kobj_ktype)用默認(rèn)dynamic_kobj_ktype作為kobj_type參數(shù),而dynamic_kobj_ktypedefault_attrsNULL,所以這里沒(méi)有創(chuàng)建屬性文件。

至此,我們已經(jīng)知道了kobject_create_and_add()函數(shù)創(chuàng)建kobject,掛到父kobject,并設(shè)置其kobj_type,在文件系統(tǒng)中為其創(chuàng)建目錄和屬性文件等。

另外,如果我們已靜態(tài)定義了要?jiǎng)?chuàng)建的kobject,則可以調(diào)用kobject_init_and_add()來(lái)注冊(cè)kobject,其函數(shù)如下:

int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,

???????????????????? ?struct kobject *parent, const char *fmt, ...)

{

?????? va_list args;

?????? int retval;

?

?????? kobject_init(kobj, ktype);

?

?????? va_start(args, fmt);

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

?????? va_end(args);

?

?????? return retval;

}

通過(guò)上面的分析我們很輕松就能理解這個(gè)函數(shù)。

?

內(nèi)核提供注銷(xiāo)kobject的函數(shù)是kobject_del()

void kobject_del(struct kobject *kobj)

{

?????? if (!kobj)

????????????? return;

?

?????? sysfs_remove_dir(kobj);

?????? kobj->state_in_sysfs = 0;

?????? kobj_kset_leave(kobj);

?????? kobject_put(kobj->parent);

?????? kobj->parent = NULL;

}

刪除kobj目錄及其目錄下的屬性文件,清kobjstate_in_sysfs標(biāo)志,把kobjkset中刪除,減少kobj->parent的計(jì)數(shù)并設(shè)其指針為空。

?


LINUX設(shè)備驅(qū)動(dòng)之設(shè)備模型二--kset

我們已經(jīng)知道了kset內(nèi)嵌了kobject來(lái)表示自身的節(jié)點(diǎn),創(chuàng)建kset就要完成其內(nèi)嵌kobject,注冊(cè)kset時(shí)會(huì)產(chǎn)生一個(gè)事件,事件而最終會(huì)調(diào)用uevent_ops字段指向結(jié)構(gòu)中的函數(shù),這個(gè)事件是通過(guò)用戶(hù)空間的hotplug程序處理。下面我們一步一步分析。

內(nèi)核同樣提供了創(chuàng)建和注冊(cè)kset的函數(shù)kset_create_and_add()

struct kset *kset_create_and_add(const char *name,

??????????????? ?struct kset_uevent_ops *uevent_ops,

??????????????? ?struct kobject *parent_kobj)

{

??? struct kset *kset;

??? int error;

?

??? kset = kset_create (name, uevent_ops, parent_kobj);

??? if (!kset)

??????? return NULL;

??? error = kset_register(kset);

??? if (error) {

??????? kfree(kset);

??????? return NULL;

??? }

??? return kset;

}

輸入?yún)?shù)有一個(gè)kset_uevent_ops類(lèi)型的結(jié)構(gòu)變量,其結(jié)構(gòu)包含三個(gè)函數(shù)指針,我們?cè)诤竺娴姆治龅竭@三個(gè)函數(shù)在什么時(shí)候被調(diào)用,kset_uevent_ops結(jié)構(gòu)定義如下:

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

};

繼續(xù)看上面的函數(shù),先調(diào)用kset_create ()創(chuàng)建一個(gè)kset,接著調(diào)用kset_register()注冊(cè)它。

static struct kset *kset_create(const char *name,

??????????????? struct kset_uevent_ops *uevent_ops,

??????????????? struct kobject *parent_kobj)

{

??? struct kset *kset;

??? int retval;

?

??? kset = kzalloc(sizeof(*kset), GFP_KERNEL);

??? if (!kset)

??????? return NULL;

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

??? if (retval) {

??????? kfree(kset);

??????? return NULL;

??? }

??? kset->uevent_ops = uevent_ops;

??? kset->kobj.parent = parent_kobj;

?

??? /*

??? ?* The kobject of this kset will have a type of kset_ktype and belong to

??? ?* no kset itself.? That way we can properly free it when it is

??? ?* finished being used.

??? ?*/

??? kset->kobj.ktype = &kset_ktype;

??? kset->kobj.kset = NULL;

?

??? return kset;

}

kset分配內(nèi)存,如我們上面分析,初始化了kset內(nèi)嵌的kobject(這里還未將kobject注冊(cè)到文件系統(tǒng)),另外用輸入?yún)?shù)初始化ksetuevent_ops字段。

接著看kset的注冊(cè)函數(shù)kset_register()

int kset_register(struct kset *k)

{

??? int err;

?

??? if (!k)

??????? return -EINVAL;

?

??? kset_init(k);

??? err = kobject_add_internal(&k->kobj);

??? if (err)

??????? return err;

??? kobject_uevent(&k->kobj, KOBJ_ADD);

??? return 0;

}

在這里終于看到調(diào)用kobject_add_internal()將kset內(nèi)嵌的kobject注冊(cè)到文件系統(tǒng),這個(gè)函數(shù)我們?cè)谏厦嬉呀?jīng)分析。

我們上面說(shuō)到注冊(cè)kset會(huì)產(chǎn)生一個(gè)事件,就是在這里調(diào)用了kobject_uevent(&k->kobj, KOBJ_ADD)

kobject_uevent()\lib\ kobject_uevent.c中:

int kobject_uevent(struct kobject *kobj, enum kobject_action action)

{

??? return kobject_uevent_env(kobj, action, NULL);

}

轉(zhuǎn)入kobject_uevent_env()

這個(gè)函數(shù)比較長(zhǎng),我們分段分析

int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,

??????? ?????? char *envp_ext[])

{

??? struct kobj_uevent_env *env;

??? const char *action_string = kobject_actions[action];

??? const char *devpath = NULL;

??? const char *subsystem;

??? struct kobject *top_kobj;

??? struct kset *kset;

??? struct kset_uevent_ops *uevent_ops;

??? u64 seq;

??? int i = 0;

??? int retval = 0;

?

??? pr_debug("kobject: '%s' (%p): %s\n",

??????? ?kobject_name(kobj), kobj, __func__);

?

??? /* search the kset we belong to */

??? top_kobj = kobj;

??? while (!top_kobj->kset && top_kobj-> parent)

??????? top_kobj = top_kobj->parent;

?

??? if (!top_kobj->kset) {

??????? pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "

??????????? ?"without kset!\n", kobject_name(kobj), kobj,

??????????? ?__func__);

??????? return -EINVAL;

??? }

?

??? kset = top_kobj->kset;

??? uevent_ops = kset-> uevent_ops;

如果如果kobjksetparent字段都不存在,說(shuō)明找不到所屬kset,也就沒(méi)有uevent_ops,不能產(chǎn)生事件,返回錯(cuò)誤信息;相反則找到了存在ksetkobj或父kobject(依次往上找),并賦值給uevent_ops

?

??? /* skip the event, if uevent_suppress is set*/

??? if (kobj-> uevent_suppress) {

??????? pr_debug("kobject: '%s' (%p): %s: uevent_suppress "

??????????????? ?"caused the event to drop!\n",

??????????????? ?kobject_name(kobj), kobj, __func__);

??????? return 0;

??? }

如果設(shè)置了uevent_suppress字段,說(shuō)明不希望產(chǎn)生事件,忽略事件正確返回。注意驅(qū)動(dòng)程序?qū)⒃谶m當(dāng)?shù)牡胤疆a(chǎn)生改事件。

??? /* skip the event, if the filter returns zero. */

??? if (uevent_ops && uevent_ops->filter)

??????? if (!uevent_ops->filter(kset, kobj)) {

??????????? pr_debug("kobject: '%s' (%p): %s: filter function "

??????????????? ?"caused the event to drop!\n",

??????????????? ?kobject_name(kobj), kobj, __func__);

??????????? return 0;

??????? }

如果uevent_ops->filter返回0,同樣忽略事件正確返回。

??? if (uevent_ops && uevent_ops->name)

??????? subsystem = uevent_ops->name(kset, kobj);

??? else

??????? subsystem = kobject_name(&kset->kobj);

??? if (!subsystem) {

??????? pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "

??????????? ?"event to drop!\n", kobject_name(kobj), kobj,

??????????? ?__func__);

??????? return 0;

??? }

獲得子系統(tǒng)的名稱(chēng),不存在則返回。

??? /* environment buffer */

??? env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);

??? if (!env)

??????? return -ENOMEM;

分配一個(gè)kobj_uevent_env結(jié)構(gòu)內(nèi)存,用于存放環(huán)境變量的值。

/* complete object path */

??? devpath = kobject_get_path(kobj, GFP_KERNEL);

??? if (!devpath) {

??????? retval = -ENOENT;

??????? goto exit;

??? }

獲得引發(fā)事件的kobjectsysfs中的路徑。

??? /* default keys */

??? retval = add_uevent_var(env, "ACTION=%s", action_string);

??? if (retval)

??????? goto exit;

??? retval = add_uevent_var(env, "DEVPATH=%s", devpath);

??? if (retval)

??????? goto exit;

??? retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);

??? if (retval)

??????? goto exit;

?

??? /* keys passed in from the caller */

??? if (envp_ext) {

??????? for (i = 0; envp_ext[i]; i++) {

??????????? retval = add_uevent_var(env, "%s", envp_ext[i]);

??????????? if (retval)

??????????????? goto exit;

??????? }

??? }

調(diào)用add_uevent_var()kobj_uevent_env填充action_string,kobject路徑,子系統(tǒng)名稱(chēng)以及其他指定環(huán)境變量。

?

???? /* let the kset specific function add its stuff */

???? if (uevent_ops && uevent_ops->uevent) {

???????? retval = uevent_ops->uevent(kset, kobj, env);

???????? if (retval) {

????????????? pr_debug("kobject: '%s' (%p): %s: uevent() returned "

?????????????????? ?"%d\n", kobject_name(kobj), kobj,

?????????????????? ?__FUNCTION__, retval);

????????????? goto exit;

???????? }

???? }

調(diào)用uevent_opsuevent函數(shù),編程人員可在此函數(shù)中實(shí)現(xiàn)自定義的功能。

??? /*

??? ?* Mark "add" and "remove" events in the object to ensure proper

??? ?* events to userspace during automatic cleanup. If the object did

??? ?* send an "add" event, "remove" will automatically generated by

??? ?* the core, if not already done by the caller.

??? ?*/

??? if (action == KOBJ_ADD)

??????? kobj->state_add_uevent_sent = 1;

??? else if (action == KOBJ_REMOVE)

??????? kobj->state_remove_uevent_sent = 1;

設(shè)置KOBJ_ADDKOBJ_REMOVE的標(biāo)志。

??? /* we will send an event, so request a new sequence number */

??? spin_lock(&sequence_lock);

??? seq = ++uevent_seqnum;

??? spin_unlock(&sequence_lock);

??? retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);

??? if (retval)

??????? goto exit;

?

#if defined(CONFIG_NET)

??? /* send netlink message */

??? if (uevent_sock) {

??????? struct sk_buff *skb;

??????? size_t len;

?

??????? /* allocate message with the maximum possible size */

??????? len = strlen(action_string) + strlen(devpath) + 2;

??????? skb = alloc_skb(len + env->buflen, GFP_KERNEL);

??????? if (skb) {

??????????? char *scratch;

?

??????????? /* add header */

??????????? scratch = skb_put(skb, len);

??????????? sprintf(scratch, "%s@%s", action_string, devpath);

?

??????????? /* copy keys to our continuous event payload buffer */

??????????? for (i = 0; i < env->envp_idx; i++) {

??????????????? len = strlen(env->envp[i]) + 1;

??????????????? scratch = skb_put(skb, len);

??????????????? strcpy(scratch, env->envp[i]);

??????????? }

?

??????????? NETLINK_CB(skb).dst_group = 1;

??????????? retval = netlink_broadcast(uevent_sock, skb, 0, 1,

??????? ??????????????? ?? GFP_KERNEL);

??????????? /* ENOBUFS should be handled in userspace */

??????????? if (retval == -ENOBUFS)

??????????????? retval = 0;

??????? } else

??????????? retval = -ENOMEM;

??? }

#endif

??? /* call uevent_helper, usually only enabled during early boot */

??? if (uevent_helper[0]) {

??????? char *argv [3];

?

??????? argv [0] = uevent_helper;

??????? argv [1] = (char *)subsystem;

??????? argv [2] = NULL;

??????? retval = add_uevent_var(env, "HOME=/");

??????? if (retval)

??????????? goto exit;

??????? retval = add_uevent_var(env,

??????????????????? "PATH=/sbin:/bin:/usr/sbin:/usr/bin");

??????? if (retval)

??????????? goto exit;

添加HOMEPATH環(huán)境變量。

??????? retval = call_usermodehelper(argv[0], argv,

??????????????????? ???? env->envp, UMH_WAIT_EXEC);

??? }

?

exit:

??? kfree(devpath);

??? kfree(env);

??? return retval;

}

調(diào)用hotplug函數(shù)。

看一下kset_unregister()

void kset_unregister (struct kset *k)

{

??? if (!k)

??????? return;

??? kobject_put(&k-> kobj);

}

減少其內(nèi)嵌的kobj計(jì)數(shù),為0則釋放其內(nèi)存空間。

?

已經(jīng)分析完kobjectksetlinux的設(shè)備模型就是基于這兩個(gè)數(shù)據(jù)結(jié)構(gòu)的,在此基礎(chǔ)上,后續(xù)將分析設(shè)備模型中的devicedriver、和bus

轉(zhuǎn)載于:https://www.cnblogs.com/yuanfang/archive/2010/12/24/1916229.html

總結(jié)

以上是生活随笔為你收集整理的研究UEVENT相关东西,看到2篇优秀的博文,转载与此的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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