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