RT-Thread 设备驱动模型(Device Driver Model,简称 DM)是一个全面的框架,提供了标准化的层次化方法来管理硬件设备及其驱动程序。通过 RT_USING_DM 配置选项启用,它引入了复杂的设备-驱动匹配机制、总线抽象以及与设备树(Open Firmware)的无缝集成。
DM 框架显著增强了 RT-Thread 处理复杂硬件系统的能力,特别是那些需要动态设备发现、电源管理、时钟控制和其他硬件资源管理的系统。
DM 框架由几个关键组件组成:
┌─────────────────────────────────────────────────────────────┐
│ 应用层 │
│ (使用设备 API: clk, regulator, pinctrl, gpio 等) │
└────────────────────┬────────────────────────────────────────┘
│
┌────────────────────┴────────────────────────────────────────┐
│ 设备驱动模型 (DM) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 总线 │ │ 驱动 │ │ 设备 │ │ 平台 │ │
│ │ 子系统 │ │ 子系统 │ │ 子系统 │ │ 层 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ OFW (开放固件/设备树) │ │
│ │ - FDT 解析 - 属性读取 - IRQ 映射 │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────┬────────────────────────────────────────┘
│
┌────────────────────┴────────────────────────────────────────┐
│ 硬件资源 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 时钟 │ │ 调节器 │ │ 复位 │ │ GPIO │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 引脚控制 │ │ DMA │ │ 中断 │ │ 内存 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
总线子系统(rt_bus)为组织设备和驱动程序提供了基础:
核心结构:
struct rt_bus {
struct rt_object parent;
const char *name;
rt_list_t list;
rt_list_t dev_list; /* 此总线上的设备列表 */
rt_list_t drv_list; /* 此总线上的驱动程序列表 */
rt_bool_t (*match)(rt_driver_t drv, rt_device_t dev);
rt_err_t (*probe)(rt_device_t dev);
rt_err_t (*remove)(rt_device_t dev);
rt_err_t (*shutdown)(rt_device_t dev);
};
驱动程序实现硬件特定功能并绑定到兼容的设备:
核心结构:
struct rt_driver {
struct rt_object parent;
struct rt_bus *bus;
rt_list_t node;
rt_uint32_t ref_count;
/* 设备操作 */
rt_err_t (*init)(rt_device_t dev);
rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close)(rt_device_t dev);
rt_ssize_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_ssize_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void *args);
/* 生命周期回调 */
int (*probe)(struct rt_device *dev);
int (*remove)(struct rt_device *dev);
int (*shutdown)(struct rt_device *dev);
};
平台设备模型是 RT-Thread 中 DM 最常见的用法,处理内存映射设备:
核心结构:
struct rt_platform_device {
struct rt_device parent;
int dev_id;
const char *name;
const struct rt_ofw_node_id *id;
void *priv;
};
struct rt_platform_driver {
struct rt_driver parent;
const char *name;
const struct rt_ofw_node_id *ids; /* Compatible 字符串 */
rt_err_t (*probe)(struct rt_platform_device *pdev);
rt_err_t (*remove)(struct rt_platform_device *pdev);
rt_err_t (*shutdown)(struct rt_platform_device *pdev);
};
OFW 子系统提供设备树支持:
DM 框架中设备的典型生命周期:
设备树 平台 驱动
│ │ │
│ 解析 DT │ │
├──────────────────>│ │
│ │ │
│ 创建平台 │ │
│ 设备 │ │
│ │ │
│ 在平台总线上 │ │
│ 注册设备 │ │
│ │ │
│ │ 匹配设备 │
│ │ 与驱动 │
│ ├─────────────────>│
│ │ │
│ │ 驱动探测 │
│ │<─────────────────┤
│ │ │
│ │ 初始化硬件 │
│ │ │
│ │ 注册 API │
│ │ │
│ │ 运行中 │
│ │ │
│ │ 驱动移除 │
│ ├─────────────────>│
│ │ │
│ │ 清理 │
│ │<─────────────────┤
│ │ │
通过主 Kconfig 选项启用设备驱动模型:
config RT_USING_DM
bool "Enable device driver model with device tree"
default n
help
Enable device driver model with device tree (FDT). It will use more memory
to parse and support device tree feature.
在 menuconfig 中的位置:RT-Thread Components → Device Drivers → Enable device driver model with device tree
config RT_USING_DEV_BUS
bool "Using Device Bus device drivers"
default y if RT_USING_SMART
default n
menuconfig RT_USING_OFW
bool "Using Open Firmware (OFW)"
select RT_USING_ADT
select RT_USING_ADT_REF
select RT_USING_ADT_BITMAP
select RT_USING_MEMBLOCK
depends on RT_USING_DM
default n
位置:RT-Thread Components → Device Drivers → Using Open Firmware (OFW)
config RT_USING_BUILTIN_FDT
bool "Using builtin fdt in kernel"
depends on RT_USING_OFW
default n
config RT_BUILTIN_FDT_PATH
string "Builtin fdt path, will rebuild if have dts"
depends on RT_USING_BUILTIN_FDT
default "rtthread.dtb"
当启用 RT_USING_DM 和 RT_USING_OFW 时,RT-Thread 可以解析和使用设备树(FDT)来描述硬件:
/ {
compatible = "myboard,example";
#address-cells = <1>;
#size-cells = <1>;
clocks {
osc24M: osc24M_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
clock-output-names = "osc24M";
};
};
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
uart0: serial@10000000 {
compatible = "myvendor,uart";
reg = <0x10000000 0x1000>;
interrupts = <32>;
clocks = <&osc24M>;
clock-names = "baudclk";
status = "okay";
};
};
regulators {
vcc_3v3: regulator-vcc-3v3 {
compatible = "regulator-fixed";
regulator-name = "vcc-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
};
};
#include <drivers/ofw.h>
struct rt_ofw_node *np = dev->ofw_node;
/* 读取字符串属性 */
const char *status;
rt_ofw_prop_read_string(np, "status", &status);
/* 读取 u32 属性 */
rt_uint32_t freq;
rt_ofw_prop_read_u32(np, "clock-frequency", &freq);
/* 读取数组 */
rt_uint32_t reg[2];
rt_ofw_prop_read_u32_array(np, "reg", reg, 2);
/* 获取内存资源 */
rt_uint64_t addr, size;
rt_dm_dev_get_address(dev, 0, &addr, &size);
/* 获取 IRQ */
int irq = rt_dm_dev_get_irq(dev, 0);
/* 映射 MMIO */
void *base = rt_dm_dev_iomap(dev, 0);
/* 获取时钟 */
struct rt_clk *clk = rt_clk_get_by_name(dev, "baudclk");
设备驱动模型支持众多硬件子系统。每个模块为应用层和驱动实现提供标准化的 API:
| 模块 | 描述 | 文档 |
|---|---|---|
| clk | 时钟管理框架 | clk.md |
| regulator | 电压/电流调节 | regulator.md |
| pinctrl | 引脚复用和配置 | pinctrl.md |
| reset | 复位控制器管理 | reset.md |
| pmdomain | 电源域管理 | pmdomain.md |
| pic | 平台中断控制器 | pic.md |
| nvmem | 非易失性内存框架 | nvmem.md |
| mailbox | 邮箱/门铃通信 | mailbox.md |
| thermal | 热管理 | thermal.md |
| mfd | 多功能设备 | mfd.md |
| dma | DMA 引擎管理 | dma.md |
| iio | 工业 I/O 子系统 | iio.md |
| phy | PHY(物理层)框架 | phy.md |
| phye | 以太网 PHY 框架 | phye.md |
| pci | PCI 总线支持 | pci.md |
| ofw | 开放固件/设备树 | ofw.md |
/* 通过 master_id 和 device_id 查找设备 */
rt_device_t rt_dm_device_find(int master_id, int device_id);
/* 设置设备名称 */
int rt_dm_dev_set_name(rt_device_t dev, const char *format, ...);
int rt_dm_dev_set_name_auto(rt_device_t dev, const char *prefix);
/* 获取设备名称 */
const char *rt_dm_dev_get_name(rt_device_t dev);
int rt_dm_dev_get_name_id(rt_device_t dev);
/* 获取地址资源 */
int rt_dm_dev_get_address_count(rt_device_t dev);
rt_err_t rt_dm_dev_get_address(rt_device_t dev, int index,
rt_uint64_t *out_address, rt_uint64_t *out_size);
rt_err_t rt_dm_dev_get_address_by_name(rt_device_t dev, const char *name,
rt_uint64_t *out_address, rt_uint64_t *out_size);
/* 映射 MMIO 区域 */
void *rt_dm_dev_iomap(rt_device_t dev, int index);
void *rt_dm_dev_iomap_by_name(rt_device_t dev, const char *name);
/* 获取 IRQ 资源 */
int rt_dm_dev_get_irq_count(rt_device_t dev);
int rt_dm_dev_get_irq(rt_device_t dev, int index);
int rt_dm_dev_get_irq_by_name(rt_device_t dev, const char *name);
/* 读取各种属性类型 */
int rt_dm_dev_prop_read_u8_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint8_t *out_values);
int rt_dm_dev_prop_read_u32_array_index(rt_device_t dev, const char *propname,
int index, int nr, rt_uint32_t *out_values);
int rt_dm_dev_prop_read_string_index(rt_device_t dev, const char *propname,
int index, const char **out_string);
/* 简化的单值读取 */
#define rt_dm_dev_prop_read_u32(dev, propname, out_value) \
rt_dm_dev_prop_read_u32_array_index(dev, propname, 0, 1, out_value)
/* 注册平台驱动 */
rt_err_t rt_platform_driver_register(struct rt_platform_driver *pdrv);
/* 注册平台设备 */
rt_err_t rt_platform_device_register(struct rt_platform_device *pdev);
/* 从设备树创建平台设备 */
rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np);
#include <rtthread.h>
#include <drivers/platform.h>
#include <drivers/ofw.h>
struct mydevice_data {
void *base;
int irq;
struct rt_clk *clk;
};
static rt_err_t mydevice_probe(struct rt_platform_device *pdev)
{
struct mydevice_data *data;
struct rt_device *dev = &pdev->parent;
/* 分配私有数据 */
data = rt_calloc(1, sizeof(*data));
if (!data)
return -RT_ENOMEM;
/* 映射 MMIO 区域 */
data->base = rt_dm_dev_iomap(dev, 0);
if (!data->base) {
rt_free(data);
return -RT_ERROR;
}
/* 获取 IRQ */
data->irq = rt_dm_dev_get_irq(dev, 0);
/* 获取时钟 */
data->clk = rt_clk_get_by_name(dev, "baudclk");
if (data->clk) {
rt_clk_prepare_enable(data->clk);
}
/* 存储私有数据 */
pdev->priv = data;
/* 初始化硬件 */
/* ... */
return RT_EOK;
}
static rt_err_t mydevice_remove(struct rt_platform_device *pdev)
{
struct mydevice_data *data = pdev->priv;
/* 清理硬件 */
/* ... */
/* 释放资源 */
if (data->clk) {
rt_clk_disable_unprepare(data->clk);
rt_clk_put(data->clk);
}
rt_free(data);
return RT_EOK;
}
static const struct rt_ofw_node_id mydevice_ofw_ids[] = {
{ .compatible = "myvendor,mydevice" },
{ /* sentinel */ }
};
static struct rt_platform_driver mydevice_driver = {
.name = "mydevice",
.ids = mydevice_ofw_ids,
.probe = mydevice_probe,
.remove = mydevice_remove,
};
/* 启动时自动注册驱动 */
RT_PLATFORM_DRIVER_EXPORT(mydevice_driver);
mydev: mydevice@10000000 {
compatible = "myvendor,mydevice";
reg = <0x10000000 0x1000>;
interrupts = <32>;
clocks = <&osc24M>;
clock-names = "baudclk";
status = "okay";
};
static rt_err_t mydevice_probe(struct rt_platform_device *pdev)
{
rt_err_t ret;
struct mydevice_data *data;
data = rt_calloc(1, sizeof(*data));
if (!data)
return -RT_ENOMEM;
data->base = rt_dm_dev_iomap(&pdev->parent, 0);
if (!data->base) {
ret = -RT_ERROR;
goto err_free;
}
data->clk = rt_clk_get_by_name(&pdev->parent, "baudclk");
if (!data->clk) {
ret = -RT_ERROR;
goto err_unmap;
}
ret = rt_clk_prepare_enable(data->clk);
if (ret)
goto err_put_clk;
/* 成功 */
pdev->priv = data;
return RT_EOK;
err_put_clk:
rt_clk_put(data->clk);
err_unmap:
rt_iounmap(data->base);
err_free:
rt_free(data);
return ret;
}
DM 增加了内存开销:
建议:
#define DBG_TAG "mydriver"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
LOG_D("调试消息");
LOG_I("信息消息");
LOG_W("警告消息");
LOG_E("错误消息");
/* 在 menuconfig 中启用 OFW 调试 */
RT-Thread Components → Device Drivers → Using Open Firmware (OFW)
传统 RT-Thread 驱动:
rt_device_t dev = rt_device_find("uart0");
rt_device_open(dev, RT_DEVICE_OFLAG_RDWR);
使用 DM:
/* 设备从设备树自动创建 */
rt_device_t dev = rt_device_find("uart0");
rt_device_open(dev, RT_DEVICE_OFLAG_RDWR);
/* 用户 API 保持不变 */
驱动实现变化:
components/drivers/core/、components/drivers/ofw/