5.4.1.何谓驱动框架
5.4.1.1、驱动是谁写的
真正的驱动开发 从 今天的 课程开始!!!
(1)驱动开发工程师
内核开发者 预留一些 驱动开发的接口,让我们来使用合作
(2)内核维护者
5.4.1.2、驱动编程协作要求
(1)接口标准化
(2)尽量降低驱动开发者难度
5.4.1.3、到底什么是驱动框架
驱动框架:部分厂家相同的一部分内核维护者已经写好了,再把不同的部分预留好接口,让驱动开发工程师来写。
(1)内核中驱动部分维护者针对每个种类的驱动设计一套成熟的、标准的、典型的驱动实现,然后把不同厂家的同类硬件驱动中相同的部分抽出来自己实现好,再把不同部分留出接口给具体的驱动开发工程师来实现,这就叫驱动框架。
(2)内核维护者在内核中设计了一些统一管控系统资源的体系,这些体系让内核能够对资源在各个驱动之间的使用统一协调和分配,保证整个内核的稳定健康运行。譬如系统中所有的GPIO就属于系统资源,每个驱动模块如果要使用某个GPIO就要先调用特殊的接口先申请,申请到后使用,使用完后要释放。又譬如中断号也是一种资源,驱动在使用前也必须去申请。这也是驱动框架的组成部分。
(3)一些特定的接口函数、一些特定的数据结构,这些是驱动框架的直接表现。
例如我们要 用LED 框架 : 我们就要去看内核实现了那些代码?我们要去实现那些代码
5.4.2.内核驱动框架中LED的基本情况
5.4.2.1、相关文件
(1)drivers/leds目录,这个目录就是驱动框架规定的LED这种硬件的驱动应该待的地方。
(2)led-class.c和led-core.c,这两个文件加起来属于LED驱动框架的第一部分,这两个文件是内核开发者提供的,他们描述的是内核中所有厂家的不同LED硬件的相同部分的逻辑。
(3)leds-xxxx.c,这个文件是LED驱动框架的第2部分,是由不同厂商的驱动工程师编写添加的,厂商驱动工程师结合自己公司的硬件的不同情况来对LED进行操作,使用第一部分提供的接口来和驱动框架进行交互,最终实现驱动的功能。
5.4.2.2、九鼎移植的内核中led驱动
(1)九鼎实际 未使用内核推荐的led驱动框架
使用LED驱动框架和 不使用LED驱动框架的区别?
(2)drivers/char/led/x210-led.c
5.4.2.3、案例分析驱动框架的使用
(1)以leds-s3c24xx.c为例。leds-s3c24xx.c中通过调用led_classdev_register来完成我们的LED驱动的注册,
而led_classdev_register是在drivers/leds/led-class.c中定义的。
所以其实SoC厂商的驱动工程师是调用内核开发者在驱动框架中提供的接口来实现自己的驱动的。
(2)驱动框架的关键点就是:分清楚内核开发者提供了什么,驱动开发者自己要提供什么
5.4.2.4、典型的驱动开发行业现状
(1)内核开发者对驱动框架进行开发和维护、升级,对应led-class.c和led-core.c
(2)SoC厂商的驱动工程师对设备驱动源码进行编写、调试,提供参考版本,对应leds-s3c24xx.c
(3)做产品的厂商的驱动工程师以SoC厂商提供的驱动源码为基础,来做移植和调试
5.4.3_4.初步分析led驱动框架源码1_2 subsys_initcall
5.4.3.1、涉及到的文件
(1)led-core.c
(2)led-class.c : 驱动框架需要关注的,内核开发者写的
class : 类
我们拿到一个驱动,我们应该怎么看呢?
正确的方式是 :从下往上
5.4.3.2、subsys_initcall
(1)经过基本分析,发现LED驱动框架中内核开发者实现的部分主要是led-class.c
(2)我们发现led-class.c就是一个内核模块,对led-class.c分析应该从下往上,遵从对模块的基本分析方法。
因为模块入口在下面!
(3)为什么LED驱动框架中内核开发者实现的部分要实现成一个模块?
因为内核开发者希望这个驱动框架是可以被装载/卸载的。这样当我们内核使用者不需要这个驱动框架时可以完全去掉,需要时可以随时加上。
(4)subsys_initcall是一个宏,定义在linux/init.h中。经过对这个宏进行展开,发现这个宏的功能是:
为什么要创建一个类? 因为我们的 驱动框架 是实现 LED 一类的
下面的链接是 创建一个类
5.3.7.自动创建字符设备驱动的设备文件 class_create device_create_大漠飞鹰6666的博客-CSDN博客
(4)subsys_initcall是一个宏,定义在linux/init.h中。经过对这个宏进行展开,发现这个宏的功能是:
将其声明的函数放到一个特定的段:.initcall4.init。
subsys_initcall
__define_initcall("4",fn,4)
(5)分析module_init宏,可以看出它将函数放到了.initcall6.init段中。
module_init (之前的 安装模块)
__initcall
device_initcall
__define_initcall("6",fn,6)
subsys_initcall 和 module_init,都是调用 __define_initcall
(6)内核在启动过程中需要顺序的做很多事,内核如何实现按照先后顺序去做很多初始化操作。内核的解决方案就是给内核启动时要调用的所有函数归类,然后每个类按照一定的次序去调用执行。这些分类名就叫.initcalln.init。n的值从1到8。内核开发者在编写内核代码时只要将函数设置合适的级别,这些函数就会被链接的时候放入特定的段,内核启动时再按照段顺序去依次执行各个段即可。
(7)经过分析,可以看出,subsys_initcall和module_init的作用是一样的,只不过前者所声明的函数要比后者在内核启动时的执行顺序更早。
vi打开: o 只读
5.4.3.3、led_class_attrs brightness
(1)什么是attribute,对应将来/sys/class/leds/目录里的内容,一般是文件和文件夹。这些文件其实就是sysfs开放给应用层的一些操作接口(非常类似于/dev/目录下的那些设备文件)
(2)attribute有什么用,作用就是让应用程序可以通过/sys/class/leds/目录下面的属性文件来操作驱动进而操作硬件设备。
(3)attribute其实是另一条驱动实现的路线。有区别于之前讲的file_operations那条线。
应用程序调用驱动的的两条路:
第一条路:
我们之前学习的 file_operations test_fops 结构体
/dev/目录下的那些设备文件
第二条路:led_class_attrs
我们的 led 走的就是 led_class_attrs 这条路
5.4.3.4、led_classdev_register
led_classdev_register
device_create
5.3.7.自动创建字符设备驱动的设备文件 class_create device_create_大漠飞鹰6666的博客-CSDN博客
(1)分析可知,led_classdev_register这个函数其实就是去创建一个属于leds这个类的一个设备。其实就是去注册一个设备。所以这个函数其实就是led驱动框架中内核开发者提供给SoC厂家驱动开发者的一个注册驱动的接口。
(2)当我们使用led驱动框架去编写驱动的时候,这个led_classdev_register函数的作用类似于我们之前使用file_operations方式去注册字符设备驱动时的register_chrdev函数。
5.2.6-9.字符设备驱动工作原理1 file_iperations register_chrdev_大漠飞鹰6666的博客-CSDN博客