一.驱动模型包含什么?
1.1. 类class
1.1.2. 它能够自动创建/dev下的设备节点,不需要mknod /dev/xxx c x x创建。当然class还有其另外的作用,且自动创建设备节点的还有udev系统,udev是处于用户空间的,其自动创建设备节点也是依赖于sysfs文件系统中提供的class类
1.2. 总线bus
1.2.1. 总线是处理器和设备之间的通道。总线有多种类型,每种总线可以挂载多个设备
1.3. 设备device
1.3.1. 驱动程序是在CPU运行时,提供操作的软件接口。所有的设备必须有与之配套驱动程序才能正常工作。一个驱动程序可以驱动多个类似或者完全不同的设备。
1.4. 驱动driver
1.4.1. 设备就是连接在总线上的物理实体。设备是有功能之分的。具有相同功能的设备被归到一个类,如输入设备(鼠标,键盘,游戏杆等)。
1.5. 三者的关系
1.5.1. 总线上有两个重要的链表:1)设备(device)链表;2)驱动(driver)链表
1.5.2. 每次出现一个设备就要向总线汇报,每次出现一个驱动,也要向总线注册。系统初始化的时候,会扫描连接了哪些设备,为每一个设备建立起一个struct device的变量,并加入设备链表;每次注册一个驱动,就要准备一个struct device_driver结构的变量,并加入驱动链表。这样所有的设备都挂载到总线上,当加载驱动时,驱动就去总线上找到自己对应的设备,或者先把驱动注册上,来了一个设备就去总线找驱动。如果只有设备却没有对应的驱动,那么设备无法工作,如果只有驱动却没有设备,驱动也起不了任何作用。
1.5.3. 每种总线下面可以挂载许多设备。(通过kset devices)
1.5.4. 每种总线下可以用很多驱动。(通过包含一个kset drivers)
1.5.5. 每个驱动可以处理一个或多个设备。
1.6. 其它内容
1.6.1. 对象的引用计数
1.6.1.1. 通常一个内核对象被创建时,不可能知道该对象存活的时间。跟踪此对象生命周期的一个方法是使用引用计数。当内核中没有代码持有该对象的引用时,该对象将结束自己的有效生命周期,并且可以被删除
1.6.2. sysfs表述sysfs表述
1.6.2.1. 在sysfs中显示的每一个对象,都对应一个kobject,它被用来与内核交互并创建它的可见表述。
1.6.2.2. 数据结构关联:从整体上看,设备模型是一个友好而复杂的数据结构,通过在其间的大量连接而构成一个多层次的体系结构。Kobject实现了该结构并把它们聚合在一起
1.6.3. uevent事件处理
1.6.3.1. 当系统中的硬件被热插拔时,在kobject子系统控制下,将产生事件以通知用户空间
1.6.3.2. Kobjects 在内核中对应有一套申请,初始化,添加,注册,计数操作,释放等函数
二. 为什么需要设备驱动模型
2.1. linux 2.6版本中正式引入设备驱动模型,目的是在设备越来越多,功耗要求等新特性要求的情况下让驱动体系更易用、更优秀。
2.2. 设备驱动模型负责统一实现和维护一些特性,诸如:电源管理、热插拔、对象生命周期、用户空间和驱动空间的交互等基础设施
2.3. 设备驱动模型目的是简化驱动程序编写,但是客观上设备驱动模型本身设计和实现很复杂
三. 驱动模型中重要结构体
3.1. kobject结构体
3.1.1. 定义在linux/kobject.h中
struct kobject { const char *name; ///*kobject的名字,每个kobject都对应着sysfs下的一个文件夹,该名字也是对应的文件夹的名字。*/ struct list_head entry; ///*双向链表指针,用于将同一kset集合中的kobject链接到一起,便于访问*/ struct kobject *parent; ///*kobject对应的父kobject节点,在sysfs表现为上一级目录*/ struct kset *kset; ///*kobject所在的集合的指针,kset概念将在kset一节中描述*/ struct kobj_type *ktype; // /*kobject对象类型指针,随后将会介绍*/ struct sysfs_dirent *sd; // /*sd用于表示VFS文件系统的目录项,由此可见它是设备与文件之间的桥梁。在sysfs节会对此结构进行分析*/ struct kref kref; // /*对象引用计数器。 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; };