LINUX设备驱动模型之class

1、LINUX设备驱动模型中的bus、device、driver,。其中bus:实际的总线,device:实际的设备和接口,而driver:对应存在的驱动。

2、但本节要介绍的class,是设备类,完全是抽象出来的概念,没有对应的实体。所谓设备类,是指提供的用户接口相似的一类设备的集合,常见的设备类的有block、tty、input、usb等等。

3、class对应的代码在drivers/base/class.c中,对应的头文件在include/linux/device.h和drivers/base/base.h中。

还是先来看class涉及的结构。

[cpp]  view plain  copy
 print ?
  1. struct class {  
  2.     const char      *name;  
  3.     struct module       *owner;  
  4.   
  5.     struct class_attribute      *class_attrs;  
  6.     struct device_attribute     *dev_attrs;  
  7.     struct kobject          *dev_kobj;  
  8.   
  9.     int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);  
  10.     char *(*devnode)(struct device *dev, mode_t *mode);  
  11.   
  12.     void (*class_release)(struct class *class);  
  13.     void (*dev_release)(struct device *dev);  
  14.   
  15.     int (*suspend)(struct device *dev, pm_message_t state);  
  16.     int (*resume)(struct device *dev);  
  17.   
  18.     const struct dev_pm_ops *pm;  
  19.   
  20.     struct class_private *p;  
  21. };  

struct class就是设备驱动模型中通用的设备类结构。

name代表类名称,会在“/sys/class/”目录下体现,例如:sys/class/p但和bus/device/driver中的名称一样,是初始名称,实际使用的是内部kobj包含的动态创建的名称。

owner是class所属的模块,虽然class是涉及一类设备,但也是由相应的模块注册的。比如usb类就是由usb模块注册的。

class_atrrs,该class的默认attribute,会在class注册到内核时,自动在“/sys/class/xxx_class”下创建对应的attribute文件

dev_attrs,该class下每个设备的attribute,会在设备注册到内核时,自动在该设备的sysfs目录下创建对应的attribute文件。

dev_bin_attrs,类似dev_attrs,只不过是二进制类型attribute。

class_attrs是class给自己添加的属性,dev_attrs是class给所包含的设备添加的属性。这里就像bus中一样,只是bus是bus、driver、device全部包含的。

dev_kobj是一个kobject指针。如果你的记性很好(至少要比我好得多),你应该记得在device注册时,会在/sys/dev下创建名为自己设备号的软链接。但设备不知道自己属于块设备还是字符设备,所以会请示自己所属的class,class就是用dev_kobj记录本类设备应属于的哪种设备。表示该class下的设备在/sys/dev/下的目录,现在一般有char和block两个,如果dev_kobj为NULL,则默认选择char。

dev_uevent()是在设备发出uevent消息时添加环境变量用的。还记得在core.c中的dev_uevent()函数,其中就包含对设备所属bus或class中dev_uevent()方法的调用,只是bus结构中定义方法用的函数名是uevent。

devnode()返回设备节点的相对路径名。在core.c的device_get_devnode()中有调用到。

class_release()是在class释放时调用到的。类似于device在结构中为自己定义的release函数。

dev_release()自然是在设备释放时调用到的。具体在core.c的device_release()函数中调用。
suspend()是在设备休眠时调用。

resume()是恢复设备时调用。

pm是电源管理用的函数集合,在bus、driver、class中都有看到,只是在device中换成了dev_pm_info结构,但device_type中还是隐藏着dev_pm_ops的指针。可见电源管理还是很重要的,只是这些东西都要结合具体的设备来分析,这里的设备驱动模型能给的,最多是一个函数指针与通用数据的框架。

p是指向class_private结构的指针。

[cpp]  view plain  copy
 print ?
  1. /** 
  2.  * struct class_private - structure to hold the private to the driver core portions of the class structure. 
  3.  * 
  4.  * @class_subsys - the struct kset that defines this class.  This is the main kobject 
  5.  * @class_devices - list of devices associated with this class 
  6.  * @class_interfaces - list of class_interfaces associated with this class 
  7.  * @class_dirs - "glue" directory for virtual devices associated with this class 
  8.  * @class_mutex - mutex to protect the children, devices, and interfaces lists. 
  9.  * @class - pointer back to the struct class that this structure is associated 
  10.  * with. 
  11.  * 
  12.  * This structure is the one that is the actual kobject allowing struct 
  13.  * class to be statically allocated safely.  Nothing outside of the driver 
  14.  * core should ever touch these fields. 
  15.  */  
  16. struct class_private {  
  17.     struct kset class_subsys;  
  18.     struct klist class_devices;  
  19.     struct list_head class_interfaces;  
  20.     struct kset class_dirs;  
  21.     struct mutex class_mutex;  
  22.     struct class *class;  
  23. };  
  24. #define to_class(obj)   \  
  25.     container_of(obj, struct class_private, class_subsys.kobj)  

struct class_private,是class连接到系统中的重要结构 私有数据。

class_subsys是kset类型,代表class在sysfs中的位置。

class_devices是klist类型,是class下的设备链表。

class_interfaces是list_head类型的类接口链表,设备类接口稍后会介绍。

class_dirs也是kset类型,它并未实际在sysfs中体现,反而是其下链接了一系列胶水kobject。记得在core.c中的get_device_parent()函数,好像小蝌蚪找妈妈一样,我们在为新注册的设备寻找sysfs中可以存放的位置。如果发现dev->class存在,而dev->parent->class不存在,就要建立一个胶水目录,在sysfs中隔离这两个实际上有父子关系的设备。linux这么做也是为了在sysfs显示时更清晰一些。但如果父设备下有多个属于同一类的设备,它们需要放在同一胶水目录下。怎么寻找这个胶水目录有没有建立过,就要从这里的class_dirs下的kobject中找了。

class_mutex是互斥信号量,用于保护class内部的数据结构。

class是指回struct class的指针。

[cpp]  view plain  copy
 print ?
  1. struct class_interface {  
  2.     struct list_head    node;  
  3.     struct class        *class;  
  4.   
  5.     int (*add_dev)      (struct device *, struct class_interface *);  
  6.     void (*remove_dev)  (struct device *, struct class_interface *);  
  7. };  

struct class_interface就是之前被串在class->p->class_interface上的类接口的结构。用于描述设备类对外的一种接口
node就是class->p->class_interface链表上的节点

class是指向所属class的指针。

add_dev()是在有设备添加到所属class时调用的函数。当然,如果class_interface比设备更晚添加到class,也会补上的。

remove_dev()是在设备删除时调用的。

从结构来看class_interface真是太简单了。我们都怀疑其到底有没有用。但往往看起来简单的内容实际可能更复杂,比如driver,还有这里的class_interface。

[cpp]  view plain  copy
 print ?
  1. struct class_attribute {  
  2.     struct attribute attr;  
  3.     ssize_t (*show)(struct class *classchar *buf);  
  4.     ssize_t (*store)(struct class *classconst char *buf, size_t count);  
  5. };  
  6.   
  7. #define CLASS_ATTR(_name, _mode, _show, _store)         \  
  8. struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store)  

从bus_attribute,到driver_attribute,到device_attribute,当然也少不了这里的class_attribute。struct attribute封装这种东西,既简单又耐用,何乐而不为?

 

结构讲完了,下面看看class.c中的实现,还是我喜欢的自上而下式。

[cpp]  view plain  copy
 print ?
  1. #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)  
  2.   
  3. static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr,  
  4.                    char *buf)  
  5. {  
  6.     struct class_attribute *class_attr = to_class_attr(attr);  
  7.     struct class_private *cp = to_class(kobj);  
  8.     ssize_t ret = -EIO;  
  9.   
  10.     if (class_attr->show)  
  11.         ret = class_attr->show(cp->class, buf);  
  12.     return ret;  
  13. }  
  14.   
  15. static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,  
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值