一、Linux 中“设备”与“驱动”的区别
Linux内核采用了一种“驱动模型”,其核心思想就是将“设备”和“驱动”分离。
设备 (Device)
它是什么:代表一块真实的、物理的硬件。它存在于电路板上,有一个具体的物理地址(如SPI总线1,片选0)。
它的职责:描述“这是什么”以及“它在哪里”。它负责提供硬件的资源信息,例如:
它的内存地址(IOREMAP)或端口地址。
它使用的中断号(IRQ)。
它的时钟配置。
它在哪条总线上(例如,挂在哪个SPI控制器的哪个片选上)。
如何描述:在Linux中,设备信息通常通过设备树 (Device Tree) 或 ACPI表 来静态声明,或者在板级代码中注册。它最终在内核中表现为一个
device
对象。
驱动 (Driver)
它是什么:代表一段控制设备的软件代码。它本身不是硬件,而是操作硬件的程序。
它的职责:描述“如何操作”这个设备。它负责实现硬件的操作接口,例如:
如何初始化设备。
如何从设备读取数据。
如何向设备写入数据。
如何配置设备的工作模式。
如何处理设备产生的中断。
如何描述:驱动是一个内核模块,其中包含一个
device_driver
结构体,并实现了各种操作函数(如probe()
,remove()
,read()
,write()
)。
一个生动的比喻:
设备 就像是一把 锁。它有一个具体的形状(钥匙孔),固定在一个具体的位置(一扇门上)。
驱动 就像是这把锁的 钥匙。它知道如何与锁的钥匙孔匹配并转动,从而打开或关闭这扇门。
总线(如SPI)就像是 管理整栋楼所有门和钥匙的物业经理。它负责匹配“锁”和“钥匙”(即设备和驱动)。
匹配过程 (Probing):
系统启动时,内核(总线核心)会知道所有注册的“设备”和“驱动”。它会不断地尝试为每个设备寻找其匹配的驱动,也为每个驱动寻找其匹配的设备。匹配通常基于:
设备树中的
compatible
属性(最常用)。设备名称。
设备ID(如USB的PID/VID)。
一旦匹配成功,驱动的 probe()
函数就会被调用。在这个函数中,驱动会获取设备提供的资源(IRQ、地址等),并初始化设备,最终让设备变得可用(如生成一个 /dev/xxx
设备节点)。
二、SPI, USB, I2C 属于驱动还是设备?
这是一个非常常见的问题。答案是:它们既是驱动,也是设备,但更准确的说法是,它们是一种“总线类型”和“框架”。
严格来说,SPI、I2C、USB 在 Linux 中代表的是总线类型和核心框架。它们本身包含了“总线驱动”和“总线设备”的概念,并为挂载在其上的外部设备提供服务和匹配规则。
为了更清晰地理解,我们以 SPI 为例进行分解:
SPI 控制器 (Controller) / 适配器 (Adapter)
它是“设备”:它是一块真实的、SoC内部的硬件,例如STM32的SPI1外设。它的资源(寄存器地址、中断号)需要通过设备树来描述。
它有“驱动”:内核有对应的驱动程序(如
spi-stm32.c
)来操作这个SoC内部的SPI控制器硬件。这个驱动会向内核注册一个 SPI 总线。
SPI 核心 (SPI Core)
这是Linux内核提供的一个中间层框架。它定义了SPI的总线类型 (
spi_bus_type
),实现了设备和驱动的匹配规则,并为SPI控制器驱动和外部设备驱动提供了一系列API接口。
挂载在SPI总线上的外部设备 (例如,一个SPI Flash芯片)
它是“设备”:它是物理芯片,通过设备树描述(
compatible = "jedec,spi-nor"
;reg = <0>;
// 代表片选0)。它有“驱动”:内核有对应的设备驱动(如
spi-nor.c
),其compatible
属性与设备树中的值匹配。这个驱动通过SPI核心提供的API来发起SPI读写操作,从而控制外部的SPI Flash芯片。
总结关系图:
[ SPI Flash设备驱动 (spi-nor.ko) ] // 知道如何操作SPI Flash芯片
↑ ↓ 通过SPI核心API通信
[ SPI Core ] // 内核框架,提供通用接口和匹配规则
↑ ↓
[ SPI控制器驱动 (spi-stm32.ko) ] // 知道如何操作SoC内部的SPI1硬件
↑ ↓ 操作硬件寄存器
[ SPI控制器硬件 ] // 真实的SPI1外设,挂在SoC内部总线上
↑ ↓ 产生SCLK, MOSI...信号
[ SPI Flash芯片 ] // 真实的物理芯片
结论:
SPI/I2C/USB 首先是一种“总线类型”。
它们各自在Linux内核中都有一个核心框架(如
SPI Core
,I2C Core
,USB Core
)来管理这种总线。对于这种总线本身,有控制器驱动(控制SoC内部的硬件控制器)。
对于挂载在这种总线上的外部设备,有对应的设备驱动。
所以,说“SPI驱动”时,需要明确指的是控制SoC内部SPI控制器的驱动,还是控制外部SPI设备的驱动。通常大家说的是后者。USB和I2C同理。