阅读章节:第15章 platform设备驱动实验
我们在前面几章编写的设备驱动都非常的简单,都是对 IO进行最简单的读写操作。但是面对I2C、SPI、 LCD 等这些复杂外设的驱动该怎么去写呢,还能用之前的方法去写吗, Linux 系统要考虑到驱动的可重用性,因此提出了驱动的分离与分层这样的软件思路,在这个思路下诞生了我们将来最常打交道的platform 设备驱动,也叫做平台设备驱动。本章我们就来学习一下 Linux 下的驱动分离与分层,以及 platform 框架下的设备驱动该如何编写。
1驱动的分离与分层
1.1驱动的分隔与分离
对于 Linux 这样一个成熟、庞大、复杂的操作系统,代码的重用性非常重要,否则的话就会在 Linux 内核中存在大量无意义的重复代码。尤其是驱动程序,因为驱动程序占用了 Linux
内核代码量的大头,如果不对驱动程序加以管理,任由重复的代码肆意增加,那么用不了多久Linux 内核的文件数量就庞大到无法接受的地步。假如现在有三个平台 A、 B 和 C,这三个平台(这里的平台说的是 SOC)上都有 MPU6050 这个 I2C接口的六轴传感器,按照我们写裸机 I2C 驱动的时候的思路,每个平台都有一个 MPU6050的驱动,因此编写出来的最简单的驱动框架如图
Linux为了避免代码的臃肿将主机驱动和设备驱动分开了下图可以完美的表示现在的驱动架构。
这个就是驱动的分隔,也就是将主机驱动和设备驱动分隔开来,比如 I2C、SPI 等等都会采用驱动分隔的方式来简化驱动的开发。在实际的驱动开发中,一般 I2C 主机控制器驱动已经由半导体厂家编写好了,而设备驱动一般也由设备器件的厂家编写好了,我们只需要提供设备信息即可,比如 I2C 设备的话提供设备连接到了哪个 I2C 接口上,I2C 的速度是多少等等。相当于将设备信息从设备驱动中剥离开来,驱动使用标准方法去获取到设备信息(比如从设备树中获取到设备信息),然后根据获取到的设备信息来初始化设备。 这样就相当于驱动只负责驱动,设备只负责设备,想办法将两者进行匹配即可。这个就是 Linux 中的总线(bus)、驱动(driver)和设备(device)模型,也就是常说的驱动分离。总线就是驱动和设备信息的月老,负责给两者牵线搭桥。如下图所示:
是不是感觉很神奇,书中既讲了设备驱动的分离,还像我们讲述了一种优化思想,不断的优化来形成方便操控和编写维护的系统,深入浅出的行文讲解风格我愿称之为Linux教学天花板。当我们向系统注册一个驱动的时候,总线就会在右侧的设备中查找,看看有没有与之匹配的设备,如果有的话就将两者联系起来。同样的,当向系统中注册一个设备的时候,总线就会在左侧的驱动中查找看有没有与之匹配的设备,有的话也联系起来。Linux 内核中大量的驱动程序都采用总线、驱动和设备模式。而platform驱动框架就是这一模式下的产物。
1.2驱动的分层
大家应该听说过网络的 7 层模型,不同的层负责不同的内容。同样的, Linux 下的驱动往往也是分层的,分层的目的也是为了在不同的层处理不同的内容。以其他书籍或者资料常常使用到的input(输入子系统,后面会有专门的章节详细的讲解)为例,简单介绍一下驱动的分层。 input 子系统负责管理所有跟输入有关的驱动,包括键盘、鼠标、触摸等,最底层的就是设备原始驱动,负责获取输入设备的原始值,获取到的输入事件上报给 input 核心层。 input 核心层会处理各种 IO 模型,并且提供 file_operations 操作集合。我们在编写输入设备驱动的时候只需要处理好输入事件的上报即可,至于如何处理这些上报的输入事件那是上层去考虑的,我们不用管。可以看出借助分层模型可以极大的简化我们的驱动编写,对于驱动编写来说非常的友好。
2platform框架
2.1platform总线
本章前面讲了设备驱动的分离,并且引出了总线(bus)、驱动(driver)和设备(device)模型,比如 I2C、 SPI、 USB 等总线。但是在 SOC 中有些外设是没有总线这个概念的,但是又要使用总
线、驱动和设备模型该怎么办呢?为了解决此问题, Linux 提出了 platform 这个虚拟总线,相应的就有 platform_driver 和 platform_device。
在Linux内核中,platform_driver和platform_device是平台驱动程序和平台设备之间交互的重要数据结构。
-
platform_driver:
- platform_driver是一个结构体,用于表示平台驱动程序。在Linux内核中,平台驱动程序通过注册到平台总线上来与平台设备进行匹配和绑定。
- platform_driver结构体包含了一些重要的字段,如驱动程序的名称、设备匹配函数、设备初始化函数、设备退出函数等。这些字段定义了平台驱动程序的行为和操作。
- 当平台设备与平台驱动程序匹配成功后,平台总线会调用platform_driver结构体中定义的初始化函数来初始化设备,并在设备退出时调用退出函数来释放资源。
-
platform_device:
- platform_device是一个结构体,用于表示平台设备。在Linux内核中,平台设备通过设备树描述,并在启动时由平台总线进行匹配和注册。
- platform_device结构体包含了一些重要的字段,如设备名称、设备资源信息、设备节点等。这些字段描述了平台设备的属性和资源。
- 当平台设备与平台驱动程序匹配成功后,平台总线会创建一个platform_device结构体实例,并将其传递给匹配的平台驱动程序,使得驱动程序可以正确地管理和操作设备。
-
关系:
- platform_driver和platform_device之间的关系是通过平台总线来建立的。平台驱动程序注册到平台总线上,当设备与驱动程序匹配成功时,平台总线会创建一个platform_device实例并将其传递给匹配的驱动程序。
- 平台驱动程序通过platform_device结构体中的资源信息来访问和操作设备的资源,从而实现对设备的管理和控制。
platform_driver和platform_device是Linux内核中用于描述和管理平台驱动程序和平台设备之间关系的重要数据结构。它们通过平台总线实现设备的匹配和绑定,使得设备能够被正确地管理和操作。在Linux操作系统中,platform虚拟总线是一种用于管理和抽象平台设备和平台驱动程序之间关系的机制。它提供了一种统一的接口和框架,使得平台设备和平台驱动程序之间可以进行匹配和绑定,从而实现设备的正确管理和操作。
3platform驱动
在Linux内核编程中,数据结构扮演着至关重要的角色。platform_driver
和platform_device
等结构体的定义和使用,是实现设备驱动程序的关键。编写驱动程序时,采用模块化的设计方式能够提高代码的可维护性和可扩展性。模块初始化函数和退出函数的编写,使得驱动程序能够方便地被加载和卸载。设备树在描述和配置平台设备时起着重要的作用。正确编写设备树节点,包括设备节点和资源信息等,能够帮助内核正确识别和管理设备。
4platform框架
通过以上这些机制,Linux操作系统的platform虚拟框架实现了硬件平台相关信息的抽象和管理,使得Linux内核可以更容易地适配和支持不同的硬件平台。这种虚拟框架的设计提高了Linux的可移植性和可扩展性,使得开发人员可以更方便地开发和维护平台相关的驱动程序和设备。在Linux内核中,编写一个platform驱动程序通常需要以下步骤:定义platform_driver结构体,编写设备匹配函数,编写设备初始化函数,注册platform_driver,设备树配置,编译和加载模块。通过这些步骤可以编写一个简单的platform驱动程序,并实现设备的匹配、初始化和管理。当平台设备与驱动程序匹配成功时,驱动程序会对设备进行操作,从而实现设备的功能。