一、Platform总线在内核中的位置

1、Linux驱动模型的层次结构

Platform 总线处于驱动模型的核心位置,它连接了:

  • 上层的字符设备框架(cdev)
  • 下层的硬件资源(寄存器、中断等)

2、Platform总线的内核实现位置

Platform 总线相关的核心代码在内核源码中的位置:

TaishanPi-3-Linux/kernel-6.1/drivers/base/
├── platform.c          # Platform 总线核心实现
├── dd.c                # 设备-驱动匹配核心逻辑
└── core.c              # 设备模型核心代码

TaishanPi-3-Linux/kernel-6.1/include/linux/platform_device.h/
├── platform_device.h   # platform_device 结构体定义
└── of_platform.h       # 设备树相关的 Platform 接口

内核启动时会自动注册 Platform 总线:struct bus_type platform_bus_type 和 platform_bus_init()

二、Platform总线的核心数据结构

1、三大核心结构体

2、设备结构体

struct platform_device(设备结构体)用来描述一个 Platform 设备的硬件资源:

struct platform_device {
    const char  *name;
    int     id;
    bool        id_auto;
    struct device   dev;
    u64     platform_dma_mask;
    struct device_dma_parameters dma_parms;
    u32     num_resources;
    struct resource *resource;

    const struct platform_device_id *id_entry;
    /*
    * Driver name to force a match.  Do not set directly, because core
    * frees it.  Use driver_set_override() to set or clear it.
    */
    const char *driver_override;

    /* MFD cell pointer */
    struct mfd_cell *mfd_cell;

    /* arch specific additions */
    struct pdev_archdata    archdata;
};
  1. const char *name:用于标识设备的名称字符串,通常与对应的platform_driver的name匹配,例如:"serial"、"i2c-controller"等。
  2. int id:当系统中存在多个相同类型的设备时,用于区分不同实例。
  3. bool id_auto:系统自动为设备分配唯一ID。
  4. struct device dev:所有设备的基础结构,包含设备模型的核心信息。
  5. u64 platform_dma_mask:用于指示设备可以访问的物理地址范围。
  6. struct device_dma_parameters dma_parms:包含设备DMA传输的具体参数,如最大段大小、对齐要求等。
  7. u32 num_resources:该设备拥有的资源(如内存、中断、IO端口等)的总数。
  8. struct resource *resource:指向struct resource数组,描述设备使用的硬件资源。
  9. const struct platform_device_id *id_entry:指向匹配的platform_device_id条目。
  10. const char *driver_override:用于绕过正常的设备-驱动匹配机制,强制绑定到指定的驱动。
  11. struct mfd_cell *mfd_cell:当设备是MFD的子设备时使用,指向描述该子功能的mfd_cell结构。
  12. struct pdev_archdata archdata:存储特定CPU架构所需的私有数据。

资源类型(struct resource):

/*
 * Resources are tree-like, allowing
 * nesting etc..
 *
 * 资源结构体 - 描述硬件资源(内存、IO、IRQ等)
 * 采用树形结构,支持资源的嵌套和层次管理
 */
struct resource {
    resource_size_t start;      /* 资源起始地址/编号 */
    resource_size_t end;        /* 资源结束地址/编号 (包含) */
    const char *name;       /* 资源名称 */
    unsigned long flags;        /* 资源类型和标志 (IORESOURCE_MEM/IRQ/IO/DMA等) */
    unsigned long desc;     /* 资源描述符 (如E820内存类型) */
    struct resource *parent;    /* 父资源 (所属的更大资源范围) */
    struct resource *sibling;   /* 兄弟资源 (同级的下一个资源) */
    struct resource *child;     /* 子资源 (嵌套在此资源内的子范围) */
};

设备树如何转换成 platform_device:

3、驱动结构体

struct platform_driver {
    int (*probe)(struct platform_device *); // 设备探测函数,设备和驱动匹配成功时调用
    int (*remove)(struct platform_device *); // 设备移除函数(旧版本)
    void (*remove_new)(struct platform_device *); // 设备移除函数(新版本)
    void (*shutdown)(struct platform_device *); // 系统关闭/重启时调用
    int (*suspend)(struct platform_device *, pm_message_t state); // 系统挂起(休眠)时调用
    int (*resume)(struct platform_device *); // 系统恢复(唤醒)时调用
    struct device_driver driver; // 通用设备驱动结构体,包含驱动名称、匹配表等
    const struct platform_device_id *id_table; // 设备 ID 匹配表(用于非设备树匹配)
    bool prevent_deferred_probe; // 阻止延迟探测
    bool driver_managed_dma; // 驱动自行管理 DMA
};

设备树匹配表(of_device_id):

struct of_device_id {
    char    name[32];           /* 设备节点名称 */
    char    type[32];           /* 设备类型 */
    char    compatible[128];        /* 设备兼容性字符串 */
    const void *data;           /* 驱动私有数据指针 */
};

驱动代码如何定义匹配表:

// 驱动代码中定义匹配表
static const struct of_device_id my_of_match[] = {
    { .compatible = "lckfb,mychardev" },  // 告知总线匹配这个compatible
    { /* 结束符 */ }
};

static struct platform_driver my_driver = {
    .probe = my_probe,
    .remove = my_remove,
    .driver = {
        .name = "mychardev",
        .of_match_table = my_of_match,    // 指定匹配表
    },
};

三、Platform总线的工作流程详解

1、时序图

2、设备注册流程

3、驱动注册流程

4、设备与驱动匹配流程

匹配优先级:

优先级匹配方式匹配字段应用场景
1设备树匹配compatibleARM/ARM64 平台
2ACPI 匹配ACPI IDx86 平台
3ID 表匹配id_table. name兼容旧代码
4名称匹配device.name == driver.name手动注册设备

5、probe函数调用流程

四、总线上的设备和驱动链表

1、链表结构示意图

2、查看系统中的设备和驱动

通过 sysfs 查看系统中注册的所有 Platform 设备和驱动:

# 02. platform总线架构
ls /sys/bus/platform/devices/

# 查看所有 Platform 驱动
ls /sys/bus/platform/drivers/

# 查看某个设备的详细信息
cat /sys/bus/platform/devices/mychardev.0/uevent

# 查看某个驱动绑定的设备
ls /sys/bus/platform/drivers/mychardev/

五、Platform总线架构总结

1、核心组件关系图

概念说明
platform_bus_typePlatform 总线的核心结构体,内核启动时注册
platform_device描述硬件资源,由设备树自动创建
platform_driver描述驱动能力,由我们编写并注册
of_match_table设备树匹配表,包含 compatible 字符串
platform_match()总线的匹配函数,有4种匹配方式
probe()匹配成功后自动调用,用于初始化设备
resource硬件资源(寄存器地址、中断号等)
设备链表bus->devices,存储所有已注册的设备
驱动链表bus->drivers,存储所有已注册的驱动

2、数据流向图

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐