嵌入式软件开发之------浅谈linux设备驱动模型(一)kobject和kset


Linux代码版本:linux3.0

开发板环境: tiny4412

导读:说起linux设备驱动,很容易想到一切皆文件的思想、busdevicedriver还有sysfs文件系统。说起总线又很容易想到platformI2cUSB等等,devicedriver都挂接在一种总线上,然后通过xxx_match函数进行匹配,各种书籍资料也更多的是介绍如果调用接口进行驱动开发,却很少谈及注册一个设备和驱动的时候都发生了什么,驱动和设备是如何匹配的,sys下的目录和文件是如何产生的。如果不去理解驱动内部的机制,那么就只能开发过一种驱动学会一种驱动框架,而这种积累方式未免会显得低效,时间长了不用还容易忘。当了解驱动模型的内部机制后,就会发现各种类型的驱动框架有很大相似性,即使要开发一种新的硬件的驱动,看一下代码很快就知道框架是怎样的。

一、kobjectkset

    俗话说万丈高楼平地起,再高的大楼也是由砖和钢筋等基本材料堆积起来的,同样linux驱动模型也有自己的基本材料,那就是kobjectksetsys下的每一个目录,都对应一个kobjectsys下的目录层次结构,其实也就是kobject的层次结构。而kset则是kobject的集合。

下面先看kobjectkset的结构体

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;    

};

const char *name

kobject 名称,当包含此kobject的内核对象被加入内核时,那么将会以这个namesys建立一个目录。

struct list_head entry

用于将一系列内核对象构成链表

struct kobject *parent

指该kobject的上一层节点,在sys表现为上一层目录,用于表现层次关系

struct kset *kset

前面说kset是一系列kobject的集合,该成员指向所属的kset

struct kobj_type *ktype

kobject对象的类型,不同的内核对象类型有不同的属性和操作函数如下面的device_typekset_type,具体用途后面用到的时候再详说。

static struct kobj_type device_ktype = {
	.release	= device_release,
	.sysfs_ops	= &dev_sysfs_ops,
	.namespace	= device_namespace,
};
static struct kobj_type kset_ktype = {
	.sysfs_ops	= &kobj_sysfs_ops,
	.release = kset_release,
};

struct sysfs_dirent *sd

kobjectsysfs中对应的目录目录实例

unsigned int state_initialized:

表示该内核对象是否初始化过,表示已经初始化,表示未初始化

unsigned int state_in_sysfs

表示该kobject所代表的内核对象是否在sys中是否建立的目录

unsigned int state_add_uevent_sent

unsigned int state_remove_uevent_sent

add和让remove事件的标志位

unsigned int uevent_suppress

kobject对象发生变化时,将会导致该对象所属的kset向用户空间发送event消息,uevent_suppress是用来表明当kobject状态发生变化时,是否允许ket向用户空间发送event消息。0表示允许,1表示不允许。

一般应用都是将kobject嵌入对象中,单独说kobject每个成员也很难理解,当kobject成员被使用时就容易理解其用途。其实kset也是一个嵌入了kobject的内核对象,是一个很好的例子。

struct kset {
	struct list_head list;
	spinlock_t list_lock;
	struct kobject kobj;
	const struct kset_uevent_ops *uevent_ops;
};

struct list_head list

前面说了kset就是 kobject的集合,此成员就是要将kobject串起来(还记得kobject中的entry成员吗)

spinlock_t list_lock

自旋锁,用来进行互斥访问

struct kobject kobj

kset也是封装了kobject

const struct kset_uevent_ops *uevent_ops

kset中的某些kobject成员状态发生变化需要通知用户空间时,调用其中的函数

struct kset_uevent_ops {
	int (* const filter)(struct kset *kset, struct kobject *kobj);
	const char *(* const name)(struct kset *kset, struct kobject *kobj);
	int (* const uevent)(struct kset *kset, struct kobject *kobj,
		      struct kobj_uevent_env *env);
};

这三个函数将会在kobject_uevent中调用到,后面具体实例再分析。

二、ksetkobject实例

    一块砖,怎么看也很难想象出来和高楼大厦有啥关系,可当你看着工人一块一块用起来就知道它的作用。对于kobjectkset做再详细的说明,也很难理解,当我们看到他们的每个成员在代码中的应用时,自然很容易理解其用途,所以对于kobjectkset结构体就知道它有些什么进行了,具体用途在代码中进行理解。

很多资料都会说sysfs是用户和内核空间的交互接口,kobject对应sys的一个目录(kset也是封装了一个kobjectkset对应的目录还是通过kobect实现),下面就看一下ksetkobject究竟是怎么对应的sys下的目录的。

先看下sys下的几个目录

[root@FriendlyARM /sys]# ls

block     class     devices   fs        module

bus       dev       firmware  kernel    power

下面是 创建这些目录的函数:

block

sys目录下创建bolck目录

static int __init genhd_device_init(void)
{
    ......

    block_depr = kobject_create_and_add("block", NULL);
    ......
}

class:

sys目录下创建class目录

int __init classes_init(void)
{
    ......

    class_kset = kset_create_and_add("class", NULL, NULL);
    ......
}

devices dev

sys下创建了devices dev 目录,又在dev目录下创建了blockchar两个目录

int __init devices_init(void)
{
    ......
    devices_kset = kset_create_and_add("devices", &device_uevent_ops, 	NULL);
	
    ......

    dev_kobj = kobject_create_and_add("dev", NULL);

    sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
	
    sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
}

fs

sys目录下创建fs目录

void __init mnt_init(void)
{
    ......

    fs_kobj = kobject_create_and_add("fs", NULL);
    ......
}

module:

sys目录下创建module目录

static int __init param_sysfs_init(void)
{
    ......

    module_kset = kset_create_and_add("module", 
    &module_uevent_ops, NULL);

    ......
}

bus

sys目录下创建bus目录

int __init buses_init(void)
{
    ......

    bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
    ......
}

firmware:

sys目录下创建firmware目录

int __init firmware_init(void)
{
    ......

    firmware_kobj = kobject_create_and_add("firmware", NULL);
    ......
}

kernel:

sys目录下创建kernel目录

static int __init ksysfs_init(void)
{
    ......

    kernel_kobj = kobject_create_and_add("kernel", NULL);
    ......
}

power:

sys目录下创建power目录

static int __init pm_init(void)
{
    ......

    power_kobj = kobject_create_and_add("power", NULL);
    ......
}

   从函数名字上也可以看出,classdevicesmodulebuskset,其它的为kobject。接下来先解析kset_create_and_add,第一个参数为name,第二个为kset_uevent_ops,第三个为parent_kobj,注意当parent_kobjNULL时,则是在sys创建目录,后面从代码上看到;

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;

        /*创建一个kset并初始化*/
	kset = kset_create(name, uevent_ops, parent_kobj);
	if (!kset)
		return NULL;
	error = kset_register(kset);
	if (error) {
		kfree(kset);
		return NULL;
	}
	return kset;
}

接下来看一下几个ksetkset_uevent_opsclass的为NULLdevice_uevent_opsdevice_uevent_opsmodule的为module_uevent_opsbus的为bus_uevent_ops

static const struct kset_uevent_ops device_uevent_ops = {
	.filter =	dev_uevent_filter,
	.name =		dev_uevent_name,
	.uevent =	dev_uevent,
};
static const struct kset_uevent_ops module_uevent_ops = {
	.filter = uevent_filter,
};
static const struct kset_uevent_ops bus_uevent_ops = {
	.filter = bus_uevent_filter,
};

再看filter成员

static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
{
	struct kobj_type *ktype = get_ktype(kobj);

/*先判断是该kobject是不是device_type类型,再判断是否挂接在某个bus上或者是否属某个class*/

	if (ktype == &device_ktype) {
		struct device *dev = to_dev(kobj);
		if (dev->bus)
			return 1;
		if (dev->class)
			return 1;
	}
	return 0;
}
static int uevent_filter(struct kset *kset, struct kobject *kobj)
{
	struct kobj_type *ktype = get_ktype(kobj);

/* 判断该kobject是否为module_ktype类型*/
	if (ktype == &module_ktype)
		return 1;
	return 0;
}
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
{
	struct kobj_type *ktype = get_ktype(kobj);

/* 判断该kobject是否为bus_ktype类型*/

	if (ktype == &bus_ktype)
		return 1;
	return 0;
}

filter 的作用就是检查某些条件,除了devices的要求kobjecttype,挂接在某个bus或某个class上,其它两个都只检查kobjecttype,符合要求才允许上报。

再看dev_uevent_name,就是返回所指向busclassname

devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);

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;
        /*创建一个kset*/
	kset = kset_create(name, uevent_ops, parent_kobj);
            {
                struct kset *kset;
	        int retval;
                /*先为kset申请内存*/
                kset = kzalloc(sizeof(*kset), GFP_KERNEL);        
                if (!kset)
                    return NULL;
            /*设置kobject名字,kset->kobj->name = “devices”*/
                retval = kobject_set_name(&kset->kobj, name);
                if (retval) {
                    kfree(kset);
                    return NULL;
                }
			
		
                /*kset->uevent_ops = device_uevent_ops*/
                kset->uevent_ops = uevent_ops;

                /*kset->kobj.parent = NULL*/
                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;
            }

            
    if (!kset)
        return NULL;
    /*注册kset*/
    error = kset_register(kset);
            {
                int err;

                if (!k)
                    return -EINVAL;
                /*初始化kset*/
                kset_init(k);
                {
                    kobject_init_internal(&k->kobj);
                    {
                        if (!kobj)
                            return;
                            
                        /*引用计数初始化为1*/
                        kref_init(&kobj->kref);
                        
                        /*list初始化*/
			INIT_LIST_HEAD(&kobj->entry);
                        
                        /*还未在sysfs中创建目录*/
                        kobj->state_in_sysfs = 0;
                        kobj->state_add_uevent_sent = 0;
                        kobj->state_remove_uevent_sent = 0;
                        /*已经初始化*/
                        kobj->state_initialized = 1;
                    }
                    INIT_LIST_HEAD(&k->list);
                    spin_lock_init(&k->list_lock);
                }
				
				
                err = kobject_add_internal(&k->kobj);
                    {
                        int error = 0;
                        struct kobject *parent;

                        if (!kobj)
                            return -ENOENT;
                        /*初始化时设置为 kobj->name = “devices”*/
                        if (!kobj->name || !kobj->name[0]) {
                            WARN(1, "kobject: (%p): attempted to be registered with empty "
                                "name!\n", kobj);
                            return -EINVAL;
                        }

                        /*获取kobj的parent,前面初始化时设置为kset->kobj.parent = NULL*/
                        parent = kobject_get(kobj->parent);

                        /* join kset if set, use it as parent if we do not already have one */
                        /* 前面初始设置为kset->kobj.kset = NULL */
                        if (kobj->kset) {
                            if (!parent)
                        /*如果kobj有kset但没有parent,则将kset所谓parent*/
                                parent = kobject_get(&kobj->kset->kobj);
                            /*将kobj键入kset->list中*/
                                kobj_kset_join(kobj);
                                {
                                    if (!kobj->kset)
                                        return;
                                    kset_get(kobj->kset);
                                    spin_lock(&kobj->kset->list_lock);
                                    list_add_tail(&kobj->entry, &kobj->kset->list);
                                    spin_unlock(&kobj->kset->list_lock);
                                }
							
                                kobj->parent = parent;
                        }

                        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>");
                        /*在sys下创建devices目录*/
                        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
                          /*已在sys创建devices目录,将标记置1*/
                            kobj->state_in_sysfs = 1;

                        return error;
                    }
					  
                if (err)
                    return err;
                kobject_uevent(&k->kobj, KOBJ_ADD);
                {
                    return kobject_uevent_env(kobj, action, NULL);
                        {
                            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;
                            const struct kset_uevent_ops *uevent_ops;
                            int i = 0;
                            int retval = 0;
                        #ifdef CONFIG_NET
                            struct uevent_sock *ue_sk;
                        #endif
                
                            pr_debug("kobject: '%s' (%p): %s\n",
                                kobject_name(kobj), kobj, __func__);
                
                            /* search the kset we belong to */
                        /*查找kobj所属的kset,看前面kset->kobj.kset = NULL,kset->kobj->parent = NULL*/
                            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  = NULL*/
                            kset = top_kobj->kset;
                            uevent_ops = kset->uevent_ops;
                
                            /* skip the event, if uevent_suppress is set*/
                        /*如果被置1,不报uevent,看前面的代码,此位并没有被置位*/
                            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;
                            }
                            /* skip the event, if the filter returns zero. */
                        /*kset->uevent_ops在此有用了,但kset->kobj.kset = NULL ,函数在此返回*/
                            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;
                                }
                        /*下面的代码将在以后能执行至此的实例中分析*/
                            /* originating subsystem */
                            ............
                
                        }
		return 0;
	    }

    if (error) {
        kfree(kset);
        return NULL;
    }
    return kset;
}

对于kobject,以firmware为例

firmware_kobj = kobject_create_and_add("firmware", NULL);
                {
                    struct kobject *kobj;
                    int retval;

                   /*创建kobj*/
                    kobj = kobject_create();
                            {
                                struct kobject *kobj;

                                /*为kobj申请内存*/
                                kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
                                if (!kobj)
                                    return NULL;
                                /*初始化kobj*/
                                kobject_init(kobj, &dynamic_kobj_ktype);
                                {
                                    char *err_str;

                                    if (!kobj) {
                                        err_str = "invalid kobject pointer!";
                                        goto error;
                                    }
                                    /*kobj 必须有ktype,此例为dynamic_kobj_ktype*/
                                    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);
                                    {
                                        if (!kobj)
                                            return;
                                        /*引用计数初始化为1*/
                                        kref_init(&kobj->kref);
                                        /*list初始化*/
                                        INIT_LIST_HEAD(&kobj->entry);
                                        /*还未在sysfs中创建目录*/
                                        kobj->state_in_sysfs = 0;
                                        kobj->state_add_uevent_sent = 0;
                                        kobj->state_remove_uevent_sent = 0;
                                        /*初始化标志置1*/
                                        kobj->state_initialized = 1;
                                    }
                                    
                                    /*kobj->ktype = dynamic_kobj_ktype*/
                                    kobj->ktype = ktype;
                                        return;
                                    error:
                                        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
                                        dump_stack();

                                }
                                return kobj;
                            }
                            
                    if (!kobj)
                        return NULL;

                    retval = kobject_add(kobj, parent, "%s", name);
                            {
                                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);
                                        {
                                            int retval;
                                        /*设置kobj->name = “firmware”*/
                                            retval = kobject_set_name_vargs(kobj, fmt, vargs);
                                            if (retval) {
                                                printk(KERN_ERR "kobject: can not set name properly!\n");
                                                return retval;
                                            }
                                        /*设置kobj->parent = NULL*/
                                            kobj->parent = parent;
                                        /*又是kobject_add_internal,是不是很熟悉,创建kset也走这个函数*/
                                            return kobject_add_internal(kobj);
                                                {
                                                    int error = 0;
                                                    struct kobject *parent;
                                                
                                                    if (!kobj)
                                                        return -ENOENT;
                                                /* kobj->name = “firmware”*/
                                                    if (!kobj->name || !kobj->name[0]) {
                                                        WARN(1, "kobject: (%p): attempted to be registered with empty "
                                                            "name!\n", kobj);
                                                        return -EINVAL;
                                                    }
                                                
                                                /*获取kobj的patent,前面初始化时设置为kobj.parent = NULL*/
                                                    parent = kobject_get(kobj->parent);
                                                
                                                    /* join kset if set, use it as parent if we do not already have one */
                                                /* 前面未初始kobj.kset则为NULL */
                                                    if (kobj->kset) {
                                                        if (!parent)
                                                /*如果kobj有kset但没有parent,则将kset所谓parent*/
                                                            parent = kobject_get(&kobj->kset->kobj);
                                                /*将kobj键入kset->list中*/
                                                        kobj_kset_join(kobj);
                                                        {
                                                            if (!kobj->kset)
                                                                return;
                                                            kset_get(kobj->kset);
                                                            spin_lock(&kobj->kset->list_lock);
                                                            list_add_tail(&kobj->entry, &kobj->kset->list);
                                                            spin_unlock(&kobj->kset->list_lock);
                                                        }
                                                        kobj->parent = parent;
                                                    }
                                                
                                                    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>");
                                                /*在sys下创建firmware目录*/
                                                    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
                                                /*已在sys创建firmware目录,将标记置1*/
                                                        kobj->state_in_sysfs = 1;
                                                
                                                    return error;
                                                }
                                        }
                                va_end(args);

                                return retval;
                            }
                    if (retval) {
                        printk(KERN_WARNING "%s: kobject_add error: %d\n",
                               __func__, retval);
                        kobject_put(kobj);
                        kobj = NULL;
                    }
                    return kobj;
                }

所以,从上面 看出无论kset还是kobject,最终都是根据kobjectsys下面创建目录的,其它几个的目录创建过程类似。

 

 

 

 

猜你喜欢

转载自blog.csdn.net/lujian186/article/details/80875253