原创 设备Class

2010-7-19 17:54 1319 7 7 分类: MCU/ 嵌入式

 


作者:李强,华清远见嵌入式学院讲师。


class是设备的高层的视图,他抽象出了底层的实现细节。


类允许用户空间使用设备所提供的功能,而不需要关系设备是如何连接的,以及他们是如何工作的。


几乎所有的类都是显示在 sys/class,但是有一个例外,就是block,其出现在 sys/block下。


系统导出了两个不同接口来供用户来使用一个是class_simple和正规的接口。


class_simple接口:


第一步:创建类本身。
        class_simple_create()
        class_simple_destroy()
        class_simple_device_add()
        class_simple_device_remove()


此类函数在比较新的版本上已经不存在了,2.6.13之前存在,2.6.13之后就需要把中间的_simple去掉了。


/*
        * device classes
        */
        struct class {
                const    char              * name;
                struct    module        * owner;


        struct    kset                     subsys;
                struct    list_head            children;
                struct    list_head            devices;
                struct    list_head            interfaces;
                struct    kset                     class_dirs;
                struct    semaphore        sem;        /* locks both the children and interfaces lists */


        struct    class_attribute                          * class_attrs;
                struct    class_device_attribute            * class_dev_attrs;
                struct    device_attribute                        * dev_attrs;


        /* 以下两个函数跟热插拔相关的函数 */
                int         (*uevent)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
                int         (*dev_uevent)(struct device *dev, char **envp, int num_envp,char *buffer, int buffer_size);


        void        (*release)(struct class_device *dev);         /* 删掉类里面的设备 */
                void         (*class_release)(struct class *class);        /* 删掉类本身 */
                void         (*dev_release)(struct device *dev);        /* 删掉设备本身 */


        int         (*suspend)(struct device *, pm_message_t state);         /* 设备暂停 */
                int        (*resume)(struct device *);        /* 设备启动 */
        };


/* 类的注册函数 */


int class_register(struct class * cls)
        {
                int error;


        pr_debug("device class '%s': registering\n", cls->name);


        INIT_LIST_HEAD(&cls->children);
                INIT_LIST_HEAD(&cls->devices);
                INIT_LIST_HEAD(&cls->interfaces);
                kset_init(&cls->class_dirs);
                init_MUTEX(&cls->sem);
                error = kobject_set_name(&cls->subsys.kobj, "%s", cls->name);
                if (error)
                        return error;


        subsys_set_kset(cls, class_subsys);


        error = subsystem_register(&cls->subsys);
                if (!error) {
                        error = add_class_attrs(class_get(cls));
                        class_put(cls);
                }
                return error;
        }


struct class_attribute {
                struct attribute attr;
                ssize_t (*show)(struct class *, char * buf);
                ssize_t (*store)(struct class *, const char * buf, size_t count);
        };


int class_create_file(struct class * cls, const struct class_attribute * attr)
        {
                int error;
                if (cls) {
                        error = sysfs_create_file(&cls->subsys.kobj, &attr->attr);
                } else
                        error = -EINVAL;
                return error;
        }


void class_remove_file(struct class * cls, const struct class_attribute * attr)
        {
                if (cls)
                        sysfs_remove_file(&cls->subsys.kobj, &attr->attr);
        }


类的主要目的就是为类成员提供容器。
        用class_device结构来表示类的成员。


struct class_device {
                struct list_head        node;


        struct kobject                    kobj;
                struct class                      * class;                          /* required */
                dev_t                                   devt;                              /* dev_t, creates the sysfs "dev" */
                struct class_device_attribute *devt_attr;
                struct class_device_attribute uevent_attr;
                struct device                      * dev;                           /* not necessary, but nice to have */
                void                                     * class_data;              /* class-specific data */
                struct class_device         *parent;                        /* parent of this child device, if there is one */
                struct attribute_group        ** groups;                 /* optional groups */


        void        (*release)(struct class_device *dev);
                int         (*uevent)(struct class_device *dev, char **envp,
                                                int         num_envp, char *buffer, int buffer_size);
                char         class_id[BUS_ID_SIZE]; /* unique to this class */
        };


/* 为类里面添加具体的设备,来让udev使用创建具体的设备文件。 */
        struct class_device *class_device_create(struct class *cls,struct class_device *parent,dev_t devt,struct device *device,const char *fmt, ...)
        {
                va_list args;
                struct class_device *class_dev = NULL;
                int         retval = -ENODEV;


        if (cls == NULL || IS_ERR(cls))
                        goto error;


        class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
                if (!class_dev) {
                        retval = -ENOMEM;
                        goto error;
                }


        class_dev->devt = devt;
                class_dev->dev = device;
                class_dev->class = cls;
                class_dev->parent = parent;
                class_dev->release = class_device_create_release;
                class_dev->uevent = class_device_create_uevent;


        va_start(args, fmt);
                vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
                va_end(args);
                retval = class_device_register(class_dev);
                if (retval)
                        goto error;


        return class_dev;


error:
                kfree(class_dev);
                return ERR_PTR(retval);
        }


具体的应用例子:


struct class *test_class = class_create(THIS_MODULE, “test_device_driver”);
        class_device_create(test_class, NULL, MKDEV(major_num, 0), NULL, “test_device”);


一个类是一个设备的高层视图,它抽象掉了底层的实现细节。例如,在驱动层面时,你可能会见到SCSI磁盘或者ATA磁盘;但在类层面时,它们都是磁盘。类允许用户空间基于它们做什么来使用设备,而不是它们如何被连接或者它们如何工作。


class表示一类设备,所有class都属于class_subsys(class子系统),即出现在/sys/class目录下,除了块设备(可能出现在/sys/block/或/sys/class/block,上面讲过了)。


其实,class在/sys/class下生成的目录也就是上面提到subsystem。这样第1点就有了。
        /* class结构体 */
        struct class {
                const char        * name;         /* class的名称 */
                struct module        * owner;        /* 拥有该class的模块 */


        struct kset        subsys;         /* 该class对应的子系统 */
                struct list_head        children;          /* 该class的class_device列表 */
                struct list_head        devices;
                struct list_head        interfaces;
                struct kset                class_dirs;
                struct semaphore        sem;          /* locks both the children and interfaces lists */


        struct class_attribute                * class_attrs; /* 该class的默认属性,以NULL结尾 */
                struct class_device_attribute        * class_dev_attrs; /* 添加到class的class_device所拥有的默认属性 */
                struct device_attribute                 * dev_attrs;


        /* 该函数提供在产生热插拔class_device事件时,添加环境变量的能力 */
                int        (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
                /* 该函数提供在产生热插拔device(物理设备)事件时,添加环境变量的能力 */
                int        (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);


        /* 添加到class的class_device移除时,调用该函数进行必要的清理工作 */
                void (*release)(struct class_device *dev);
                /* class被移除时,调用该函数进行必要的清理工作 */
                void (*class_release)(struct class *class);
                void (*dev_release)(struct device *dev);


        int        (*suspend)(struct device *, pm_message_t state);
                int        (*resume)(struct device *);
        };


/* class注册函数 */
        int __must_check class_register(struct class *);
        void class_unregister(struct class *);


建立一个class有两种方法
        a、根据需要,填充一个struct class,然后再调用class_register注册该class就ok了(此法比较灵活,可以自己定制很多东西)
        b、就是通过下面的class_create来创建一个class,该函数会返回一个指向刚建立的class的指针(创建class的最简单方法)
        /* class_create用于创建一个名为name的class,其owner参数一般为THIS_MODULE。class_create内部调用了class_register */
        struct class *class_create(struct module *owner, const char *name);
        /* class_destroy用于删除一个class,实际上其内部只是简单调用了class_unregister(cls)来注销cls */
        void class_destroy(struct class *cls);


一个class属性对应于/sys/class/class.name(class.name就是该class的名称)目录里的一个文件。通过这些文件,可以向用户空间输出一些关于该class的信息,也可从用户空间获取到一些信息。
        /* class属性结构体 */
        struct class_attribute {
                struct attribute        attr;
                /* 当用户空间读取该属性时,调用show函数输出一个"属性值"给用户空间 */
                ssize_t (*show)(struct class *, char * buf);
                /* 当用户空间写该属性时,调用store函数保存用户写入的"属性值" */
                ssize_t (*store)(struct class *, const char * buf, size_t count);
        };


struct attribute {
                const char        * name;
                struct module        * owner;
                mode_t                mode;
        };


/* CLASS_ATTR可以在编译时创建一个class属性,该属性的名称为class_attr_name */
        #define CLASS_ATTR(_name,_mode,_show,_store) \
        struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store)


/* class_create_file与class_remove_file用于创建与删除class默认属性外的属性 */
        int __must_check class_create_file(struct class *,const struct class_attribute *);
        void class_remove_file(struct class *, const struct class_attribute *);

文章评论0条评论)

登录后参与讨论
我要评论
0
7
关闭 站长推荐上一条 /2 下一条