linux设备驱动模型一上层容器之class

本文深入解析了Linux设备模型中的核心概念——设备类(class),详细介绍了其数据结构、操作函数及其实现机制,帮助读者理解设备类如何组织和管理设备。
class,是设备类,完全是抽象出来的概念,没有对应的实体。所谓设备类,是指提供的用户接口相似的一类设备的集合,常见的设备类的有block、tty、input、usb等等。

 类是一个设备的高层视图,它抽象出了底层的实现细节,从而允许用户空间使用设备所提供的功能,而不用关心设备是如何连接和工作的。类成员通常由上层代码所控制,而无需驱动的明确支持。但有些情况下驱动也需要直接处理类。

在驱动开发中,多使用mknod命令手动创建设备节点,但当动态申请设备号时必须通过命令查出设备号,再添加。或者使用DEVFS文件系统函数添加设备节点。DEVFS在现在linux内核中已取消,取而代之的是UDEV,UDEV是处于用户态的程序。它根据内核发出的EVENTS,动态创建事件。内核是通过device_create发出event.而在device_create中就有一个参数是class,这个参数最终会在device_create中->device_create_vargs->device_register->device_add中调用device_create_sys_dev_entry在/sys/dev目录建立对设备的软链接。、

首先还是来看下calss相关的数据结构:

  1. struct class {  
  2.     const char      *name; //设备的名称,出现在/sys/class目录下  
  3.     struct module       *owner; //所属模块  
  4.     struct class_attribute      *class_attrs;//类属性  
  5.     struct device_attribute     *dev_attrs;//类设备属性  
  6.     struct kobject          *dev_kobj;//记录本类设备应属于的哪种设备  
  7.   
  8.     int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);//跟热插拔有关  
  9.     char *(*devnode)(struct device *dev, mode_t *mode);//)返回设备节点的相对路径名  
  10.   
  11.     void (*class_release)(struct class *class); //class释放时调用  
  12.     void (*dev_release)(struct device *dev);     //设备释放时调用  
  13.   
  14.     int (*suspend)(struct device *dev, pm_message_t state);/* 设备暂停 */  
  15.     int (*resume)(struct device *dev); /* 设备启动 */  
  16.   
  17.     const struct kobj_ns_type_operations *ns_type;  
  18.     const void *(*namespace)(struct device *dev);  
  19.   
  20.     const struct dev_pm_ops *pm;//电源管理用的函数集  
  21.   
  22.     struct class_private *p;  
  23. };  
struct class {
	const char		*name; //设备的名称,出现在/sys/class目录下
	struct module		*owner; //所属模块
	struct class_attribute		*class_attrs;//类属性
	struct device_attribute		*dev_attrs;//类设备属性
	struct kobject			*dev_kobj;//记录本类设备应属于的哪种设备

	int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);//跟热插拔有关
	char *(*devnode)(struct device *dev, mode_t *mode);//)返回设备节点的相对路径名

	void (*class_release)(struct class *class); //class释放时调用
	void (*dev_release)(struct device *dev); 	 //设备释放时调用

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

	const struct kobj_ns_type_operations *ns_type;
	const void *(*namespace)(struct device *dev);

	const struct dev_pm_ops *pm;//电源管理用的函数集

	struct class_private *p;
};
struct class就是设备驱动模型中通用的设备类结构,和bus,device一样,它也有一个private结构:

  1. struct class_private {  
  2.     struct kset class_subsys;//kset类型,代表class在sysfs中的位置  
  3.     struct klist class_devices; //klist类型,是class下的设备链表  
  4.     struct list_head class_interfaces;//list_head类型的类接口链表  
  5.     struct kset class_dirs;  
  6.     struct mutex class_mutex;//互斥信号量,  
  7.     struct class *class//回指所属的struct class结构  
  8. };  
struct class_private {
	struct kset class_subsys;//kset类型,代表class在sysfs中的位置
	struct klist class_devices; //klist类型,是class下的设备链表
	struct list_head class_interfaces;//list_head类型的类接口链表
	struct kset class_dirs;
	struct mutex class_mutex;//互斥信号量,
	struct class *class; //回指所属的struct class结构
};
class_interfaces是类接口链表

  1. //描述设备类对外的一种接口  
  2. struct class_interface {  
  3.     struct list_head    node;//class->p->class_interface链表上的节点  
  4.     struct class        *class;//指向所属class的指针  
  5.   
  6.     int (*add_dev)      (struct device *, struct class_interface *);//有设备添加到所属class时调用的函数  
  7.     void (*remove_dev)  (struct device *, struct class_interface *);//remove_dev()是在设备删除时调用  
  8. };  
//描述设备类对外的一种接口
struct class_interface {
	struct list_head	node;//class->p->class_interface链表上的节点
	struct class		*class;//指向所属class的指针

	int (*add_dev)		(struct device *, struct class_interface *);//有设备添加到所属class时调用的函数
	void (*remove_dev)	(struct device *, struct class_interface *);//remove_dev()是在设备删除时调用
};
  1. static const struct sysfs_ops class_sysfs_ops = {  
  2.     .show   = class_attr_show,  
  3.     .store  = class_attr_store,  
  4. };  
  5.   
  6. static struct kobj_type class_ktype = {  
  7.     .sysfs_ops  = &class_sysfs_ops,  
  8.     .release    = class_release,  
  9.     .child_ns_type  = class_child_ns_type,  
  10. };  
static const struct sysfs_ops class_sysfs_ops = {
	.show	= class_attr_show,
	.store	= class_attr_store,
};

static struct kobj_type class_ktype = {
	.sysfs_ops	= &class_sysfs_ops,
	.release	= class_release,
	.child_ns_type	= class_child_ns_type,
};
关于ktype和bus,device一样,提供了一些默认的属性和操作函数。

再来看一下相关的操作函数:

  1. int __init classes_init(void)  
  2. {  
  3.     class_kset = kset_create_and_add("class", NULL, NULL);//在sysfs顶层创建class目录  
  4.     if (!class_kset)  
  5.         return -ENOMEM;  
  6.     return 0;  
  7. }  
int __init classes_init(void)
{
	class_kset = kset_create_and_add("class", NULL, NULL);//在sysfs顶层创建class目录
	if (!class_kset)
		return -ENOMEM;
	return 0;
}
init也跟bus等一样,创建kset,注册到sysfs.

再来看下提供给外面调用的创建class函数

  1. #define class_create(owner, name)       \  
  2. ({                      \  
  3.     static struct lock_class_key __key; \  
  4.     __class_create(owner, name, &__key);    \  
  5. })  
#define class_create(owner, name)		\
({						\
	static struct lock_class_key __key;	\
	__class_create(owner, name, &__key);	\
})
继续跟踪__class_create

  1. struct class *__class_create(struct module *owner, const char *name,  
  2.                  struct lock_class_key *key)  
  3. {  
  4.     struct class *cls;  
  5.     int retval;  
  6.   
  7.     cls = kzalloc(sizeof(*cls), GFP_KERNEL);//分配class结构  
  8.     if (!cls) {  
  9.         retval = -ENOMEM;  
  10.         goto error;  
  11.     }  
  12.   
  13.     cls->name = name;//设置name  
  14.     cls->owner = owner;//设置owner  
  15.     cls->class_release = class_create_release;//设置类释放函数  
  16.   
  17.     retval = __class_register(cls, key);//注册calss  
  18.     if (retval)  
  19.         goto error;  
  20.   
  21.     return cls;  
  22.   
  23. error:  
  24.     kfree(cls);  
  25.     return ERR_PTR(retval);  
  26. }  
struct class *__class_create(struct module *owner, const char *name,
			     struct lock_class_key *key)
{
	struct class *cls;
	int retval;

	cls = kzalloc(sizeof(*cls), GFP_KERNEL);//分配class结构
	if (!cls) {
		retval = -ENOMEM;
		goto error;
	}

	cls->name = name;//设置name
	cls->owner = owner;//设置owner
	cls->class_release = class_create_release;//设置类释放函数

	retval = __class_register(cls, key);//注册calss
	if (retval)
		goto error;

	return cls;

error:
	kfree(cls);
	return ERR_PTR(retval);
}
这里主要是调用__class_register

  1. int __class_register(struct class *cls, struct lock_class_key *key)  
  2. {  
  3.     struct class_private *cp;  
  4.     int error;  
  5.   
  6.     pr_debug("device class '%s': registering\n", cls->name);  
  7.   
  8.     cp = kzalloc(sizeof(*cp), GFP_KERNEL);//分配class_private结构  
  9.     if (!cp)  
  10.         return -ENOMEM;  
  11.     klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);//初始化class_private结构  
  12.     INIT_LIST_HEAD(&cp->class_interfaces);  
  13.     kset_init(&cp->class_dirs);//初始化kset,并未加到sysfs  
  14.     __mutex_init(&cp->class_mutex, "struct class mutex", key);  
  15.     error = kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);//设置类名  
  16.     if (error) {  
  17.         kfree(cp);  
  18.         return error;  
  19.     }  
  20.   
  21.     /* set the default /sys/dev directory for devices of this class */  
  22.     if (!cls->dev_kobj)//cls->dev_kobj如果未设置,设为sysfs_dev_char_kobj  
  23.         cls->dev_kobj = sysfs_dev_char_kobj;  
  24.   
  25. #if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK)  
  26.     /* let the block class directory show up in the root of sysfs */  
  27.     if (cls != &block_class)  
  28.         cp->class_subsys.kobj.kset = class_kset;  
  29. #else  
  30.     cp->class_subsys.kobj.kset = class_kset;  
  31. #endif  
  32.     cp->class_subsys.kobj.ktype = &class_ktype;  
  33.     cp->class = cls;  
  34.     cls->p = cp;  
  35.   
  36.     error = kset_register(&cp->class_subsys);//将class注册到sysfs中  
  37.     if (error) {  
  38.         kfree(cp);  
  39.         return error;  
  40.     }  
  41.     error = add_class_attrs(class_get(cls));//添加相关的属性文件  
  42.     class_put(cls);  
  43.     return error;  
  44. }  
int __class_register(struct class *cls, struct lock_class_key *key)
{
	struct class_private *cp;
	int error;

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

	cp = kzalloc(sizeof(*cp), GFP_KERNEL);//分配class_private结构
	if (!cp)
		return -ENOMEM;
	klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);//初始化class_private结构
	INIT_LIST_HEAD(&cp->class_interfaces);
	kset_init(&cp->class_dirs);//初始化kset,并未加到sysfs
	__mutex_init(&cp->class_mutex, "struct class mutex", key);
	error = kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);//设置类名
	if (error) {
		kfree(cp);
		return error;
	}

	/* set the default /sys/dev directory for devices of this class */
	if (!cls->dev_kobj)//cls->dev_kobj如果未设置,设为sysfs_dev_char_kobj
		cls->dev_kobj = sysfs_dev_char_kobj;

#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK)
	/* let the block class directory show up in the root of sysfs */
	if (cls != &block_class)
		cp->class_subsys.kobj.kset = class_kset;
#else
	cp->class_subsys.kobj.kset = class_kset;
#endif
	cp->class_subsys.kobj.ktype = &class_ktype;
	cp->class = cls;
	cls->p = cp;

	error = kset_register(&cp->class_subsys);//将class注册到sysfs中
	if (error) {
		kfree(cp);
		return error;
	}
	error = add_class_attrs(class_get(cls));//添加相关的属性文件
	class_put(cls);
	return error;
}
这个函数主要是对private结构操作,不像bus,device它的kobject结构在private里面,所以主要的操作基本都是对private
还有 一个就是class_interface_register,把class_interface添加到指定的class上

  1. int class_interface_register(struct class_interface *class_intf)  
  2. {  
  3.     struct class *parent;  
  4.     struct class_dev_iter iter;  
  5.     struct device *dev;  
  6.   
  7.     if (!class_intf || !class_intf->class)  
  8.         return -ENODEV;  
  9.   
  10.     parent = class_get(class_intf->class);//增加class的引用计数  
  11.     if (!parent)  
  12.         return -EINVAL;  
  13.   
  14.     mutex_lock(&parent->p->class_mutex);  
  15.     list_add_tail(&class_intf->node, &parent->p->class_interfaces);  
  16.     if (class_intf->add_dev) {  
  17.         class_dev_iter_init(&iter, parent, NULL, NULL);  
  18.         while ((dev = class_dev_iter_next(&iter)))  
  19.             class_intf->add_dev(dev, class_intf);//添加到class的接口列表中  
  20.         class_dev_iter_exit(&iter);  
  21.     }  
  22.     mutex_unlock(&parent->p->class_mutex);  
  23.   
  24.     return 0;  
  25. }  
int class_interface_register(struct class_interface *class_intf)
{
	struct class *parent;
	struct class_dev_iter iter;
	struct device *dev;

	if (!class_intf || !class_intf->class)
		return -ENODEV;

	parent = class_get(class_intf->class);//增加class的引用计数
	if (!parent)
		return -EINVAL;

	mutex_lock(&parent->p->class_mutex);
	list_add_tail(&class_intf->node, &parent->p->class_interfaces);
	if (class_intf->add_dev) {
		class_dev_iter_init(&iter, parent, NULL, NULL);
		while ((dev = class_dev_iter_next(&iter)))
			class_intf->add_dev(dev, class_intf);//添加到class的接口列表中
		class_dev_iter_exit(&iter);
	}
	mutex_unlock(&parent->p->class_mutex);

	return 0;
}
class的流程图也比较简单




评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值