linux设备驱动模型(kobject与kset)

Linux设备模型的目的:为内核建立一个统一的设备模型,从而又一个对系统结构的一般性抽象描述。换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要新添加设备或驱动提供一般性的统一接口,这使得驱动程序的开发变得更简单了,而程序员只需要去学习接口就行了。

                                     kobject                                                                                                                                   

1.sysfs文件系统

  1.1 sysfs文件系统与内核结构的关系

linux内核中的结构 sysfs中的结构             
kobject (内核对象) 目录  
kobj_type (属性)  属性文件
对象之间的关系 符号链接

 

 

 

 

  1.2 sysfs文件系统的目录结构

block:所有块设备

devices:系统所有设备(块设备特殊),对应struct device的层次结构

bus:系统中所有总线类型(指总线类型而不是总线设备,总线设备在devices下),bus的每个子目录都包含

    --devices:包含到devices目录中设备的软链接

    --drivers:与bus类型匹配的驱动程序

class:系统中设备类型(如声卡、网卡、显卡等)

fs:一些文件系统,具体可参考filesystems /fuse.txt中例子

dev:包含2个子目录

--char:字符设备链接,链接到devices目录,以<major>:<minor>命名

--block:块设备链接

 

2.设备驱动模型的核心数据结构

2.1 kobject结构体

  

  name 将显示在sysfs文件系统中,作为一个目录的名字;

  struct kobj_type *ktype 代表kobject的属性,对于sysfs中的普通文件读写操作都是kobjetc->ktype->sysfs_ops指针来完成的,即对default_attrs数组的操作

  kobject始终是sysfs文件系统中的一个目录而不是文件。

2.2设备属性kobj_type

  下图是kobject与kobj_type的关系:

  

  kobj_type结构体的定义如下:

struct kobj_type {
    void (*release)(struct kobject *kobj);//释放kobject和其他占用资源的函数
    const struct sysfs_ops *sysfs_ops;//操作下一个数组的方法
    struct attribute **default_attrs;//属性数组
    const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
    const void *(*namespace)(struct kobject *kobj);
};

 

  【1】attribute结构体如下:

struct attribute {
    const char        *name;//属性名字
    struct module        *owner;//
    mode_t            mode;//属性的读写权限
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lock_class_key    *key;
    struct lock_class_key    skey;
#endif
};

  【2】sysfs_ops 属性操作结构体: 

struct sysfs_ops {
    ssize_t    (*show)(struct kobject *, struct attribute *,char *);//读属性
    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);//写属性
};

 

  【3】release()函数

    当kobject的引用计数为0时,系统自动会调用自定义的release()来释放kobject对象。

    e.g.

      

3.实例:

#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("David Xie");
MODULE_LICENSE("Dual BSD/GPL");
 
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);

 

                                 kset                                                                                                                                             

 

 

kset是具有相同类型的kobject的集合,在sysfs中体现成一个目录;kobject不能包含目录,而kset可以包含目录。kobject通过kset组织成层次化的结构,kset将一系列相同类型的kobject使用(双向)链表连接起来,可以这样 认为,kset充当链表头作用,kset内部内嵌了一个kobject结构。

    1. #include <linux/kobject.h>
    2. struct kset {
    3.     struct list_head list; /* 用于连接kset中所有kobject的链表头 */
    4.     spinlock_t list_lock; /* 扫描kobject组成的链表时使用的锁 */
    5.     struct kobject kobj; /* 嵌入的kobject */
    6.     const struct kset_uevent_ops *uevent_ops; /* kset的uevent操作 */
    7. };

实例:

#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("David Xie");
MODULE_LICENSE("Dual BSD/GPL");
 
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);
        printk("kset_p finish\n");

        /*下面会调用热插拔函数*/
        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);

 

热插拔事件kset_uevent_ops

在Linux系统中,当系统配置发生变化时,如:添加kset到系统;移动kobject, 一个通知会从内核空间发送到用户空间,这就是热插拔事件。热插拔事件会导致用户空间中相应的处理程序(如udev,mdev)被调用, 这些处理程序会通过加载驱动程序, 创建设备节点等来响应热插拔事件。

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

当该kset所管理的kobject和kset状态发生变化时(如被加入,移动),这三个函数将被调用。

 

                     kobject与kset的关系                                                                                                                               

 

参考:http://blog.csdn.net/xiahouzuoxin/article/details/8943863 

posted on 2013-10-23 14:46  熊猫酒仙是也  阅读(2748)  评论(0编辑  收藏  举报

导航