类是一个设备的高层视图,它抽象出了底层的实现细节。类允许用户空间使用设备所提供的功能,而不关心设备时如何连接的,以及它们时怎么工作的。
几乎所有的类都显示在/sys/class目录中。举个例子,网络接口都集中在/sys/class/net下。
结构体:
/**
* struct class - device classes
* @name: Name of the class.
* @owner: The module owner.
* @class_attrs: Default attributes of this class.
* @dev_groups: Default attributes of the devices that belong to the class.
* @dev_kobj: The kobject that represents this class and links it into the hierarchy.
* @dev_uevent: Called when a device is added, removed from this class, or a
* few other things that generate uevents to add the environment
* variables.
* @devnode: Callback to provide the devtmpfs.
* @class_release: Called to release this class.
* @dev_release: Called to release the device.
* @suspend: Used to put the device to sleep mode, usually to a low power
* state.
* @resume: Used to bring the device from the sleep mode.
* @shutdown: Called at shut-down time to quiesce the device.
* @ns_type: Callbacks so sysfs can detemine namespaces.
* @namespace: Namespace of the device belongs to this class.
* @pm: The default device power management operations of this class.
* @p: The private data of the driver core, no one other than the
* driver core can touch this.
*
* A class is a higher-level view of a device that abstracts out low-level
* implementation details. Drivers may see a SCSI disk or an ATA disk, but,
* at the class level, they are all simply disks. Classes allow user space
* to work with devices based on what they do, rather than how they are
* connected or how they work.
*/
struct class {
const char *name;
struct module *owner;
struct class_attribute *class_attrs;
const struct attribute_group **dev_groups;
struct kobject *dev_kobj;
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
char *(*devnode)(struct device *dev, umode_t *mode);
void (*class_release)(struct class *class);
void (*dev_release)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
int (*shutdown)(struct device *dev);
const struct kobj_ns_type_operations *ns_type;
const void *(*namespace)(struct device *dev);
const struct dev_pm_ops *pm;
struct subsys_private *p;
};
主要接口:
class_create和class_destroy
//创建
/* This is a #define to keep the compiler from merging different
* instances of the __key variable */
#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name, &__key); \
})
/**
* class_create - create a struct class structure
* @owner: pointer to the module that is to "own" this struct class
* @name: pointer to a string for the name of this class.
* @key: the lock_class_key for this class; used by mutex lock debugging
*
* This is used to create a struct class pointer that can then be used
* in calls to device_create().
*
* Returns &struct class pointer on success, or ERR_PTR() on error.
*
* Note, the pointer created here is to be destroyed when finished by
* making a call to class_destroy().
*/
struct class *__class_create(struct module *owner, const char *name,
struct lock_class_key *key)
{
//...
}
//销毁
/**
* class_destroy - destroys a struct class structure
* @cls: pointer to the struct class that is to be destroyed
*
* Note, the pointer to be destroyed must have been created with a call
* to class_create().
*/
void class_destroy(struct class *cls)
{
if ((cls == NULL) || (IS_ERR(cls)))
return;
class_unregister(cls);
}
还有一组用法是:
class_register和class_unregister
/* This is a #define to keep the compiler from merging different
* instances of the __key variable */
#define class_register(class) \
({ \
static struct lock_class_key __key; \
__class_register(class, &__key); \
})
int __class_register(struct class *cls, struct lock_class_key *key) {
//...
}
void class_unregister(struct class *cls)
{
pr_debug("device class '%s': unregistering\n", cls->name);
remove_class_attrs(cls);
kset_unregister(&cls->p->subsys);
}
这两对接口完成的工作几乎是一致的,class_register和class_unregister需要自己申请class结构的内存。
调用完class_create后,会在/sys/class下创建对应的文件夹。
static struct class* longlong_class = NULL;
longlong_class = class_create(THIS_MODULE, "longlong");
if(IS_ERR(longlong_class)){
err = PTR_ERR(longlong_class);
printk(KERN_ALERT "Failed to create longlong class.\n");
goto destroy_cdev;
}
//...
destroy_class:
class_destroy(longlong_class);
以上代码会创建一个名为longlong的文件夹。
后面可以通过device_create()、device_register()、deivce_add()创建设备,当然设备节点也有其对应销毁方法device_destroy。
struct device* mdevice= NULL;
mdevice= device_create(longlong_class, NULL, dev, "%s", "longlong");
if(IS_ERR(temp)){
err = PTR_ERR(temp);
printk(KERN_ALERT "Failed to create longlong device.\n");
goto destroy_class;
}
//...
destroy_device:
device_destroy(longlong_class, dev);
以上代码会在/dev/和sys/class/longlong下创建文件longlong
而后可以使用device_create_file创建设备文件
/**
* device_create_file - create sysfs attribute file for device.
* @dev: device.
* @attr: device attribute descriptor.
*/
int device_create_file(struct device *dev,
const struct device_attribute *attr)
/* interface for exporting device attributes */
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
/*
* show: 显示函数,cat该文件时,此函数被调用。
* store:写函数,echo内容到该文件时,此函数被调用。
*/
err = device_create_file(mdevice, &dev_attr_val);
if(err < 0){
printk(KERN_ALERT "Failed to create attribute val.\n");
goto destroy_device;
}
当然到这里之后device_attribute里面show和store还是要我们自己实现的。
这里需要提到一个宏DEVICE_ATTR
#define DEVICE_ATTR(_name,_mode,_show,_store)
其中最后两个参数就是show和store函数。
// * define the device properties
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, longlong_val_show, longlong_val_store);
除了show和store之外,这里的第一个参数_name也很好玩,在上面提到的device_create_file中的第二个参数,需要传入dev_attr_[_name]。这个_name也是最后在sys/class/longlong/longlong/下显示的名字,可以对它进行cat和echo。
如果非要问为什么会这样的话,那就要看看DEVICE_ATTR宏的内容了。
#define DEVICE_ATTR(_name,_mode,_show,_store) \
struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store)
这个宏用名字拼接的方法创建了device_attribute结构。