06、注册 platform 设备
一、platform_device_register 注册函数
函数原型与作用
int platform_device_register(struct platform_device *pdev);
- 作用:将平台设备(由
platform_device
结构体描述)注册到Linux内核中,使其能参与资源分配和驱动匹配。 - 头文件:
#include <linux/platform_device.h>
参数与返回值
参数:
pdev
是一个指向platform_device
结构体的指针,该结构体包含设备名称、资源(如内存地址、中断号)、设备ID等信息。返回值:
- 成功:返回
0
。 - 失败:返回负数(如
-EINVAL
表示无效参数)。
- 成功:返回
函数实现
该函数定义在/drivers/base/platform.c
中,主要执行以下三步操作:
- 初始化设备结构体
device_initialize(&pdev->dev);
对设备的底层结构体(pdev->dev
)进行初始化,设置基本属性(如引用计数、设备类型)。
- 设置架构相关数据
arch_setup_pdev_archdata(pdev);
根据不同CPU架构(如ARM、x86)的需求,为设备添加特定配置。
- 将设备添加到内核
return platform_device_add(pdev);
调用platform_device_add
函数,完成设备的最终注册。
关键函数 **platform_device_add**
的步骤
int platform_device_add(struct platform_device *pdev)
{
// 1. 检查参数是否为空
if (!pdev) return -EINVAL;
// 2. 设置设备的父设备(若未指定则默认为平台总线)
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
// 3. 绑定设备到平台总线
pdev->dev.bus = &platform_bus_type;
// 4. 根据设备ID设置设备名称
switch (pdev->id) {
case PLATFORM_DEVID_AUTO:
// 自动分配ID并命名(如"devname.id.auto")
// ...
break;
default:
// 使用默认命名(如"devname.id")
// ...
break;
}
// 5. 处理设备资源
for (每个资源) {
// 设置资源名称、父资源,并尝试插入系统资源树
// 若失败则返回错误
}
// 6. 最终将设备添加到内核
return device_add(&pdev->dev);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
核心步骤解释
参数检查:若
pdev
为空,直接返回错误。父设备设置:若未指定父设备,将其设为系统默认的平台总线。
总线绑定:将设备关联到
platform_bus_type
总线类型。设备命名:
- 自动ID:动态分配唯一ID,并在名称后添加
.auto
(如uart.0.auto
)。 - 手动ID:直接使用用户提供的ID(如
uart.0
)。
- 自动ID:动态分配唯一ID,并在名称后添加
资源管理:
- 为每个资源设置名称(默认为设备名)。
- 根据资源类型(内存/IO)分配默认父资源。
- 将资源插入系统资源树,失败则报错。
最终注册:调用
device_add
将设备加入内核设备树,完成注册。
二、platform_device_unregister 反注册函数
platform_device_unregister 函数详解
作用: 这个函数用来从系统中删除已经注册的平台设备,完成设备的清理工作。
用法:
void platform_device_unregister(struct platform_device *pdev);
- 参数:
pdev
是指向要删除的设备的指针。 - 返回值:没有返回结果。
内部操作分两步:
第一步:platform_device_del(pdev)
- 将设备从系统的设备列表中移除。
- 停止设备的资源分配(如内存、中断等),并解除它和驱动程序的关联。
第二步:platform_device_put(pdev)
- 减少设备的「使用计数」(记录有多少地方在用这个设备)。
- 如果计数归零,系统会自动释放设备占用的所有资源(如内存空间)。
整体流程总结:
- 先「摘掉设备」:从系统设备列表中删除,断开驱动连接。
- 再「清理残留」:如果设备不再被任何地方使用,彻底释放它占用的资源。
适用场景: 当设备不再需要(比如硬件被拔掉或驱动卸载时),调用此函数确保系统资源被正确回收。
三、platform_device 结构体
platform_device结构体用于描述平台设备的基本信息。它定义在内核的"include/linux/platform_device.h"文件中,主要包含以下内容:
- 设备名称(name) 设备的名字,就像设备的身份证,用来在系统中唯一识别这个设备。
- 设备ID(id) 用来区分多个同类型设备的编号。如果只有一台设备,可以设为-1表示不需要编号。
- 设备对象(dev) 包含设备基础信息的容器。必须正确设置这个字段,并且必须实现它的释放方法,否则编译会报错。
- 资源数量(num_resources) 设备需要使用的硬件资源数量(比如内存地址、中断号等)。
- 资源列表(resource) 指向资源具体信息的指针,保存设备需要的所有硬件资源细节。
其他重要成员:
- id_entry:用来匹配设备和驱动程序的标识表。
- driver_override:强制指定要使用的驱动程序名称(特殊情况使用)。
- mfd_cell:用于管理多功能芯片中的子设备。
- archdata:存储与特定硬件架构相关的额外数据。
简单来说,这个结构体就是给设备制作的"信息档案",包含设备名称、编号、硬件资源等所有关键信息,方便系统管理和驱动匹配。每个字段都对应设备的一个具体属性,开发者需要根据实际硬件情况填写这些信息。
四、resource 结构体
struct resource
用于描述系统设备的资源信息,比如内存区域、I/O 端口、中断等。它定义在内核头文件 linux/ioport.h
中。
核心参数
结构体的前四个参数最重要,具体含义如下:
- 起始地址(
**start**
) 资源的起始位置,比如内存或端口的起始地址。 - 结束地址(
**end**
) 资源的结束位置,表示资源占用的最后一个地址。 - 名称(
**name**
) 一个字符串,用于标识资源的名称(例如 "PCI Memory" 或 "Serial Port")。 - 标志位(
**flags**
) 一组二进制标志,用来标记资源的类型、属性或状态。例如,是否为只读、是否支持缓存等。
标志位分类及含义
标志位通过二进制位组合表示不同特性,分为三类:
1. 资源类型标志
IORESOURCE_IO
:表示这是 I/O 端口 资源。IORESOURCE_MEM
:表示这是 内存 资源。IORESOURCE_IRQ
:表示这是 中断 资源。IORESOURCE_DMA
:表示这是 DMA(直接内存访问) 资源。
2. 资源属性标志
IORESOURCE_READONLY
:资源是 只读 的。IORESOURCE_CACHEABLE
:资源 支持缓存(例如内存可以被缓存)。IORESOURCE_MEM_64
:表示这是 64位内存 资源。IORESOURCE_SYSRAM
:表示这是 系统内存(RAM)。
3. 状态与控制标志
IORESOURCE_DISABLED
:资源当前 被禁用。IORESOURCE_AUTO
:地址由系统 自动分配。IORESOURCE_BUSY
:资源已被驱动 占用。IORESOURCE_UNSET
:资源尚未分配具体地址。
其他说明
- 标志位通常通过位运算组合使用(例如
flag |= IORESOURCE_MEM
)。 - 这些标志的具体含义可能因系统或驱动需求略有不同,但上述是常见用法。
通过这个结构体,内核可以统一管理硬件资源的分配和冲突检测,确保设备正常运行。