linux设备驱动模型
随笔--linux设备驱动模型
以
kobject
为底层,组织类class
、总线bus
、设备device
、驱动driver
等高级数据结构,同时实现对象引用计数、维护对象链表、对象上锁、对用户空间的表示等服务
参考博客:
Linux设备驱动模型http://blog.csdn.net/xiahouzuoxin/article/details/8943863
Linux设备模型--设备驱动模型和sysfs文件系统解读http://www.cnblogs.com/Ph-one/p/5052191.html
[TOC]
linux设备驱动模型简介
站在设备驱动这个角度分析,设备驱动模型是如何构建出来,起到什么作用,认识它并在写驱动的时候去利用设备驱动模型
####什么是设备驱动模型
从以下几个角度去描述折别驱动模型
-
类class、总线bus、设备device、驱动driver
四个词并非四个简单概念,还是linux驱动的四个结构体,也可以理解为linux设备驱动模型的四个框架。 分别对应我们源代码的四个结构体。 class :例如class_create bus :例如USB总线,SPI总线 device:设备 driver:驱动 为何需要这四个结构体-----生产这些结构体类型的变量,每一个结构体变量就代表一个实例
-
kobject和对象生命周期的管理
linux内核源代码里面的一个结构体,k是kernel object物体,kobject就是内核的一个东西。一个高度抽象的结构体,表示内 核里面的一个对象,就是内核里面的所有对象抽象出来的一个总类。所以说linux内核是面向对象编程。这个kobject就类似于面 向对象体系的一个总的基类,总的父类 对象生命周期,例如某一个驱动,insmod诞生,rmmod消亡。如何管理这个对象的生命周期?在kobject有一种机制,能够让每一个 对象具有自我管理生命周期的特性,即自己管理自己,当自身不被需要的时候就自己释放。比如为A malloc 申请一段内存,当不需 要的时候不用去free A,它自己会自己free掉。如何知道自己没用了呢?肯定需要一种方法
-
sysfs
在内核空间和我们用户空间建立一个映射关系
-
udev
为了实现内核空间和用户空间的信息的一个同步
####为什么需要设备驱动模型
(1)早期内核(2.4之前)没有统一的设备驱动模型,但照样可以用
(2)2.6版本中正式引入设备驱动模型,目的是在设备越来越多,功耗要求等新特性要求的情况下让驱动体系更易用、更优秀
(3)设备驱动模型负责统一实现和维护一些特性,诸如:电源管理、热插拔、对象生命周期、用户空间和驱动空间的交互等基础设施
(4)设备驱动模型目的是简化驱动程序编写,但是客观上设备驱动模型本身设计和实现很复杂。主要学会如何使用设备驱动模型
驱动开发的2个点:
(1)驱动源码本身编写、调试。重点在于对硬件的了解。
(2)驱动什么时候被安装(被安装就是insmod,而且insmod方式是自动的,比如一个触摸屏的芯片已经装上,开机后就能够自动装上,
然后一拔掉这个驱动就自己卸载)、驱动中的函数什么时候被调用(即在应用层怎么做就能调用驱动写好的东西)。这些跟硬件无关,完
全和设备驱动模型有关
设备驱动模型的底层架构
####kobject
(1)定义在linux/kobject.h中
(2)各种对象最基本单元,提供一些公用型服务如:对象引用计数、维护对象链表、对象上锁、对用户空间的表示
(3)设备驱动模型中的各种对象其内部都会包含一个kobject
(4)地位相当于面向对象体系架构中的总基类
####kobj_type
(1)很多书中简称为ktype,每一个kobject都需要绑定一个ktype来提供相应功能
(绑定和包含意思不一样,包含是实体,绑定是实体的一个指针)
(2)关键点0:release,释放。用release而不用close,因为可能需要反复去打开,第一次打开第二次打开就打开了两次,如果
用close就一次把两个都关掉了。release不一样,当去release时,会先判断有没有被其他人打开过,如果被其他人打开着,那
么就只是减少它的一次引用计数;如果没有被其他人打开,当前就只有我打开它,那关闭时就彻底的把它的东西全部释放掉
(3)关键点1:sysfs_ops,提供该对象在sysfs中的操作方法(show和store)
struct sysfs_ops {
ssize_t (*show )(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
};
show方法用于将传入的指定属性编码后放到char *类型的buffer中
store则执行相反功能:将buffer中的编码信息解码后传递给struct attribute类型变量。两者都是返回实际的属性长度
(4)关键点2:attribute,提供在sysfs中以文件形式存在的属性,其实就是应用接口
struct attribute {
const char *name;/* 属性名称 */
mode_t mode; /* 属性保护:只读设为S_IRUGO,可写设为S_IWUSR */
}
####kset
(1)kset的主要作用是做顶层kobject的容器类,用来这种上下文的
(2)kset的主要目的是将各个kobject(代表着各个对象)组织出目录层次架构
(3)可以认为kset就是为了在sysfs中弄出目录,从而让设备驱动模型中的多个对象能够有层次有逻辑性的组织在一起
可以理解为上面三个底层架构是为了实现/sys目录下的那些东西。kobject提供的是一个最基本的功能,是构成别的的一个基础;kobj_type是提供目录底下的那些文件以及对文件操作的方法;kset是用来构建目录层次架构。这三个结合起来就提供了 [/sys目录下的那些东西被实现] 的基础架构
总线式设备驱动组织方式
总线是在 [设备驱动模型的以kobject为代表的底层]之上的层次,可以把它看作是中间层,实际上字符设备驱动模型的层次不止三个层,可能有五个六个层次。层次越往上,越靠近实际的编程,越下的话越靠近写内核的那些人
####总线(struct bus_type)
(1)物理上的真实总线及其作用(英文bus)
(2)驱动框架中的总线式设计
(3)bus_type结构体,关键是match函数和uevent函数
总线的bus_type
结构体就是一种抽象,抽象出了总线里面所有需要管理的事情所有需要具备的功能。将来去内核构造一个一个总线的时候就是产生bus_type
这个结构体的一个结构体变量,然后把它适当的填充
####设备(struct device)
(1)struct device是硬件设备在内核驱动框架中的抽象
(2)device_register用于向内核驱动框架注册一个设备
(3)通常device不会单独使用,而是被包含在一个具体设备结构体中,如struct usb_device
####驱动(struct device_driver)
(1)struct device_driver是驱动程序在内核驱动框架中的抽象
(2)关键元素1:name,驱动程序的名字,很重要,经常被用来作为驱动和设备的匹配依据
(3)关键元素2:probe,驱动程序的探测函数,用来检测一个设备是否可以被该驱动所管理。
probe函数对于一个驱动函数非常重要,有些简单的驱动没有探测函数,因为没有使用到linux内核的驱动框架,没有用到总线式
驱动框架来写。即非总线式的写法是不需要probe函数的,probe函数是总线式的框架才需要的。在总线方式下probe函数就是驱
动最重要的函数。
官方对它的解释是检测一个设备是否可以被该驱动所管理。意思就是当装载了一个设备,驱动中的probe函数就会去看它和装载的这个设备匹配不匹配。probe是驱动程序的入口
总线、设备、驱动是一组的,只有总线没有意义,只有设备、驱动则工作不起来
###类(class)
(1)相关结构体:struct class 和 struct class_device 前者是xx类,后者是xx类下面的某一个设备
(2)udev的使用离不开class 像基础篇的设备类操作class_create,device_create
(3)class的真正意义在于作为同属于一个class的多个设备的容器。也就是说,class是一种人造概念,目的就是为了对各种设备进行分类管理。当然,class在分类的同时还对每个类贴上了一些“标签”,这也是设备驱动模型为实际写驱动提供的基础设施
class的真正意义在于作为同属于一个class的多个设备的容器,其实类被发明出来就是用来管理设备的。上面讲的总线也是
用来管理设备的,设备这个东西接受多重管理。一方面某一个设备从属于某一总线,另一方面某一个设备也从属于某一个类
注:从目录关系也能体现总线和类的管理方式,/sys/devices 放的是真正的设备相关的东西,你从class目录进去或者从bus目录进去最后都会由函数指针指向devices这个目录里面来
驱动这个东西并不复杂,就是由上面提到的这些理论来指导,由实践来构成