一、什么是设备驱动模型 (1)类class、总线bus、设备device、驱动driver 四个结构体 (2)kobject和对象生命周期 (3)sysfs cat 查看属性信息 、 echo 往里面写东西 (4)udev 同步信息
2、设备模型解决了一些什么问题? (1)设备驱动模型负责统一实现和维护一些特性,诸如:电源管理、热插拔、对象生命周期、用户空间和驱动空间的交互等基础设施 (2)设备驱动模型目的是简化驱动程序编写,但是客观上设备驱动模型本身设计和实现很复杂
二、设备驱动模型的底层架构 1、、kobject (1)定义在linux/kobject.h中 (2)各种对象最基本单元,提供一些公用型服务如:对象引用计数、维护对象链表、对象上锁、对用户空间的表示这里写代码片 (3)设备驱动模型中的各种对象其内部都会包含一个kobject (4)地位相当于面向对象体系架构中的总基类
struct kobject { const char *name; /* 对应sysfs的目录名 */ struct list_head entry; /* kobjetct双向链表 */ struct kobject *parent; /* 指向kset中的kobject,相当于指向父目录 */ struct kset *kset; /*指向所属的kset */ struct kobj_type *ktype; /*负责对kobject结构跟踪*/ struct sysfs_dirent *sd; struct kref kref; /*kobject引用计数*/ unsigned int state_initialized:1; unsigned int state_in_sysfs:1; unsigned int state_add_uevent_sent:1; unsigned int state_remove_uevent_sent:1; unsigned int uevent_suppress:1; };kobject结构是组成设备模型的基本结构,最初kobject设计只用来跟踪模块引用计数,现已增加支持, —— sysfs表述:在sysfs中的每个对象都有对应的kobject —— 数据结构关联:通过链接将不同的层次数据关联 —— 热插拔事件处理:kobject子系统将产生的热插拔事件通知用户空间 kobject一般不单独使用,而是嵌入到上层结构(比如struct device,struct device_driver)当中使用。kobject的创建者需要直接或间接设置的成员有:ktype、kset和parent。kset我们后面再说,parent设置为NULL时,kobject默认创建到/sys顶层目录下,否则创建到对应的kobject目录中。重点来分析ktype成员的类型。
2、kobj_type (1)很多书中简称为ktype,每一个kobject都需要绑定一个ktype来提供相应功能 (2)关键点1:sysfs_ops,提供该对象在sysfs中的操作方法(show和store) (2)关键点2:attribute,提供在sysfs中以文件形式存在的属性,其实就是应用接口
struct kobj_type { void (*release)(struct kobject *kobj); /* 释放 */ const stru`这里写代码片`ct sysfs_ops *sysfs_ops; /* 默认属性实现 */ struct attribute **default_attrs; /* 默认属性 */ const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj); const void *(*namespace)(struct kobject *kobj); };ktype包含了释放设备、默认属性以及属性的实现方法几个重要成员。每个kobject必须有一个release方法,并且kobject在该方法被调用之前必须保持不变(处于稳定状态)
3、kset (1)kset的主要作用是做顶层kobject的容器类 (2)kset的主要目的是将各个kobject(代表着各个对象)组织出目录层次架构 (3)可以认为kset就是为了在sysfs中弄出目录,从而让设备驱动模型中的多个对象能够有层次有逻辑性的组织在一起
struct kset { struct list_head list; /* 用于连接kset中所有kobject的链表头 */ spinlock_t list_lock; /* 扫描kobject组成的链表时使用的锁 */ struct kobject kobj; /* 嵌入的kobject */ const struct kset_uevent_ops *uevent_ops; /* kset的uevent操作 */ };这三个东西主要实现sysfs目录里面的那些玩意
下面是框图解释
三、总线式设备驱动组织方式 1、总线 (1)物理上的真实总线及其作用(英文bus) (2)驱动框架中的总线式设计 (3)bus_type结构体,关键是match函数和uevent函数
struct bus_type { const char *name; /* 总线类型名 */ struct bus_attribute *bus_attrs; /* 总线的属性 */ struct device_attribute *dev_attrs; /* 设备属性,为每个加入总线的设备建立属性链表 */ struct driver_attribute *drv_attrs; /* 驱动属性,为每个加入总线的驱动建立属性链表 */ /* 驱动与设备匹配函数:当一个新设备或者驱动被添加到这个总线时,这个方法会被调用一次或多次,若指定的驱动程序能够处理指定的设备,则返回非零值。必须在总线层使用这个函数, 因为那里存在正确的逻辑,核心内核不知道如何为每个总线类型匹配设备和驱动程序 */ int (*match)(struct device *dev, struct device_driver *drv); /*在为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量(参数和 kset 的uevent方法相同)*/ int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); /* */ int (*remove)(struct device *dev); /* 设备移除调用操作 */ void (*shutdown)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); const struct dev_pm_ops *pm; struct subsys_private *p; /* 一个很重要的域,包含了device链表和drivers链表 */ };2、设备 (1)struct device是硬件设备在内核驱动框架中的抽象 (2)device_register用于向内核驱动框架注册一个设备 (3)通常device不会单独使用,而是被包含在一个具体设备结构体中,如struct usb_device 每一个struct usb_device 都会包含struct device,struct device是所以设备的一些共有的特性。 struct device是一个父类,struct usb_device 是它的子类,子类比父类更加的具体。
struct device { struct device *parent; /* 父设备,总线设备指定为NULL */ struct device_private *p; /* 包含设备链表,driver_data(驱动程序要使用数据)等信息 */ struct kobject kobj; const char *init_name; /* 初始默认的设备名,但@device_add调用之后又重新设为NULL */ struct device_type *type; struct mutex mutex; /* mutex to synchronize calls to its driver */ struct bus_type *bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ void *platform_data; /* Platform specific data, device core doesn't touch it */ struct dev_pm_info power; #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ #endif u64 *dma_mask; /* dma mask (if dma'able device) */ u64 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as not all hardware supports 64 bit addresses for consistent allocations such descriptors. */ struct device_dma_parameters *dma_parms; struct list_head dma_pools; /* dma pools (if dma'ble) */ struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */ /* arch specific additions */ struct dev_archdata archdata; #ifdef CONFIG_OF struct device_node *of_node; #endif dev_t devt; /* dev_t, creates the sysfs "dev" 设备号 */ spinlock_t devres_lock; struct list_head devres_head; struct klist_node knode_class; struct class *class; const struct attribute_group **groups; /* optional groups */ void (*release)(struct device *dev); };3、驱动 (1)struct device_driver是驱动程序在内核驱动框架中的抽象 **(2)关键元素1:name,驱动程序的名字,很重要,经常被用来作为驱动和设备的匹配依据 (3)关键元素2:probe,驱动程序的探测函数,用来检测一个设备是否可以被该驱动所管理**
**设备和驱动是总线下的两个分支,总线的存在就是为了管理这两个东西。驱动中的probe一般是总线方式才会有的。 总线加设备、驱动是一组,是一套。**
struct device_driver { const char *name; /* 驱动名称,在sysfs中以文件夹名出现 */ struct bus_type *bus; /* 驱动关联的总线类型 */ struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ #if defined(CONFIG_OF) const struct of_device_id *of_match_table; #endif int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; }; struct driver_private { /* 定义device_driver中的私有数据类型 */ struct kobject kobj; /* 内建kobject */ struct klist klist_devices; /* 驱动关联的设备链表,一个驱动可以关联多个设备 */ struct klist_node knode_bus; struct module_kobject *mkobj; struct device_driver *driver; /* 连接到的驱动链表 */ }; #define to_driver(obj) container_of(obj, struct driver_private, kobj)4、类 在include/linux/device.h中: (1)相关结构体:struct class 和 struct class_device (2)udev的使用离不开class (3)class的真正意义在于作为同属于一个class的多个设备的容器。也就是说,class是一种人造概念,目的就是为了对各种设备进行分类管理。当然,class在分类的同时还对每个类贴上了一些“标签”,这也是设备驱动模型为我们写驱动提供的基础设施。
类又是另外一种管理方法,只是从不同的角度而已,所以这里有两组,总线式和类式。
struct class { const char *name; 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); 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和struct bus很类似,解释如下:
name,class的名称,会在“/sys/class/”目录下体现。 class_atrrs,该class的默认attribute,会在class注册到内核时,自动在“/sys/class/xxx_class”下创建对应的attribute文件。 dev_attrs,该class下每个设备的attribute,会在设备注册到内核时,自动在该设备的sysfs目录下创建对应的attribute文件。 dev_bin_attrs,类似dev_attrs,只不过是二进制类型attribute。 dev_kobj,代表本class的kobject,用于在sysfs中创建目录。 dev_uevent,当该class下有设备发生变化时,会调用class的uevent回调函数。 class_release,用于release自身的回调函数。 dev_release,用于release class内设备的回调函数。在device_release接口中,会依次检查Device、Device Type以及Device所在的class,是否注册release接口,如果有则调用相应的release接口release设备指针。
