2. DRM框架基础:DRM架构与核心数据结构

DRM(Direct Rendering Manager)是Linux内核中负责图形显示和渲染管理的核心框架。它向上提供统一的用户空间接口(通过/dev/dri/card0等设备节点),向下抽象不同GPU和显示控制器的硬件差异。理解DRM的架构和核心数据结构,是掌握KMS组件初始化流程的前提。

核心观点: DRM框架通过drm_device和drm_driver两个核心结构体,将硬件驱动、显示管理、内存管理、渲染调度等子系统有机整合在一起。

2.1 DRM架构分层

DRM框架在Linux内核中位于字符设备层与硬件驱动层之间,其架构可分为三个层次:

  1. 用户空间接口层: 提供ioctl系统调用,用户态程序(如Xorg、Wayland compositor、Mesa)通过/dev/dri/card0访问DRM功能。
  2. DRM核心层: 实现设备注册、文件操作、缓冲区管理、帧缓冲(FB)、模式设置(KMS)、同步对象(fence)等通用逻辑。
  3. 硬件驱动层: 由具体GPU厂商(Intel、AMD、NVIDIA、Qualcomm等)实现,填充drm_driver结构体中的回调函数,操作具体硬件寄存器。
DRM架构分层示意图 用户空间:Xorg / Wayland / Mesa / 应用程序 DRM核心层:drm_device / drm_driver / KMS / GEM 硬件驱动层:i915 / amdgpu / nouveau / msm 内核

2.2 核心数据结构:drm_device

drm_device是DRM框架中最重要的核心结构体,代表一个DRM设备实例。每个物理GPU或显示控制器对应一个drm_device对象。该结构体聚合了所有子系统的状态信息。

字段名 类型 说明
dev struct device * 指向内核通用设备结构体,用于电源管理、DMA等
driver struct drm_driver * 指向驱动回调函数集合
primary struct drm_minor * 主设备节点(card0)对应的minor结构
render struct drm_minor * 渲染设备节点(renderD128)对应的minor结构
mode_config struct drm_mode_config KMS模式配置管理结构,包含所有encoder、crtc、connector、plane
filelist struct list_head 已打开该设备的文件描述符链表
event_lock spinlock_t 保护事件队列的自旋锁
vblank struct drm_vblank_crtc * 垂直消隐(vblank)控制结构数组
开发提示: 驱动初始化时,通常通过drm_dev_alloc()分配drm_device,然后调用drm_dev_register()注册到系统。在KMS驱动中,mode_config字段是初始化显示管线的核心入口。

2.3 核心数据结构:drm_driver

drm_driver是驱动开发者需要重点实现的结构体。它定义了一组回调函数指针,DRM核心层在特定时机调用这些回调,驱动通过填充这些回调来操作硬件。

回调函数 调用时机 典型实现
load() 设备探测时(已废弃,推荐使用drm_dev_init) 初始化硬件、分配资源
open() 用户空间打开设备节点时 分配文件私有数据
postclose() 用户空间关闭设备节点时 清理文件私有数据
lastclose() 最后一个文件描述符关闭时 恢复显示模式、释放资源
irq_handler() 硬件中断触发时 处理vblank、fence信号
enable_vblank() 开启垂直消隐中断 写寄存器使能vblank中断
disable_vblank() 关闭垂直消隐中断 写寄存器屏蔽vblank中断
gem_create_object() 创建GEM对象时 分配显存或系统内存
drm_device 与 drm_driver 关系图 struct drm_device dev: struct device * driver: struct drm_driver * mode_config: struct drm_mode_config filelist: struct list_head vblank: struct drm_vblank_crtc * struct drm_driver load() / open() / postclose() lastclose() / irq_handler() enable_vblank() / disable_vblank() gem_create_object() ... 其他回调函数 驱动开发者主要填充此结构体

2.4 设备初始化流程

一个典型的DRM设备初始化流程包含以下步骤:

  1. 平台驱动探测: 内核调用驱动的probe()函数,传入struct platform_device或struct pci_dev。
  2. 分配drm_device: 调用drm_dev_alloc()分配并初始化drm_device,同时绑定drm_driver。
  3. 硬件初始化: 驱动进行寄存器映射、时钟使能、中断注册等硬件操作。
  4. KMS组件初始化: 创建crtc、encoder、connector、plane等KMS对象,并添加到mode_config。
  5. 注册设备: 调用drm_dev_register()创建设备节点,暴露给用户空间。
注意事项: 在旧版本内核中,驱动通常使用drm_platform_init()或drm_get_pci_dev()等辅助函数。现代内核推荐使用drm_dev_alloc() + drm_dev_register()的组合,并配合devm_drm_dev_init()实现资源管理。

2.5 代码示例:最小DRM驱动骨架

以下代码展示了一个最小DRM驱动的初始化骨架,重点展示drm_driver和drm_device的使用:

#include <linux/module.h>
#include <drm/drm_drv.h>
#include <drm/drm_device.h>

static int my_driver_open(struct drm_device *dev, struct drm_file *file)
{
    pr_info("DRM device opened\n");
    return 0;
}

static void my_driver_postclose(struct drm_device *dev, struct drm_file *file)
{
    pr_info("DRM device closed\n");
}

static struct drm_driver my_drm_driver = {
    .driver_features    = DRIVER_MODESET | DRIVER_GEM,
    .open               = my_driver_open,
    .postclose          = my_driver_postclose,
    .name               = "my_drm_driver",
    .desc               = "My Minimal DRM Driver",
    .date               = "20250101",
    .major              = 1,
    .minor              = 0,
};

static int my_probe(struct platform_device *pdev)
{
    struct drm_device *drm;
    int ret;

    drm = drm_dev_alloc(&my_drm_driver, &pdev->dev);
    if (IS_ERR(drm))
        return PTR_ERR(drm);

    /* 硬件初始化代码在此 */

    ret = drm_dev_register(drm, 0);
    if (ret) {
        drm_dev_put(drm);
        return ret;
    }

    platform_set_drvdata(pdev, drm);
    return 0;
}

static int my_remove(struct platform_device *pdev)
{
    struct drm_device *drm = platform_get_drvdata(pdev);
    drm_dev_unregister(drm);
    drm_dev_put(drm);
    return 0;
}

static struct platform_driver my_pdrv = {
    .probe  = my_probe,
    .remove = my_remove,
    .driver = {
        .name = "my_drm_driver",
    },
};
module_platform_driver(my_pdrv);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("KMS Expert");
MODULE_DESCRIPTION("Minimal DRM Driver Example");

2.6 关键概念对比

概念 作用域 生命周期 由谁实现
drm_device 每个GPU/显示控制器一个实例 从probe到remove DRM核心分配,驱动填充
drm_driver 全局静态定义,所有设备共享 模块加载到卸载 驱动开发者定义
drm_file 每个打开的设备节点一个实例 open到close DRM核心分配
drm_mode_config 每个drm_device一个实例 与drm_device相同 驱动初始化时填充
总结: DRM框架通过drm_device聚合所有显示子系统状态,通过drm_driver定义硬件操作接口。理解这两个结构体及其关系,是后续学习KMS组件初始化(crtc、encoder、connector、plane)的基础。下一章将深入分析这些KMS组件的初始化细节。