1. DRM 子系统模块加载与卸载

DRM 子系统模块加载与卸载 学习卡片

任务目标

编写一个最小可用的DRM驱动模块,完成平台设备的初始化和DRM驱动的注册,使得系统在加载模块后能够在/dev/dri/card0创建设备节点。该驱动不实现具体的显示输出功能,仅验证DRM子系统的基础框架能够正确挂载。

环境与依赖

  • Linux内核源码树(版本 ≥ 4.19,本文以5.10为例)
  • 内核已开启CONFIG_DRM=y或CONFIG_DRM=m
  • 目标平台:QEMU virt或任何支持DRM的设备模拟环境

核心实现

驱动通过platform_driver匹配一个虚拟平台设备,在probe回调中调用drm_dev_alloc分配DRM设备结构体,设置最小化的drm_driver回调集合,然后注册drm_dev。由于不涉及具体硬件,无需实现irq_handler或fops中的复杂操作。

// minimal_drm.c
#include <linux/module.h>
#include <linux/platform_device.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_print.h>

static int min_drm_open(struct drm_device *dev, struct drm_file *file)
{
    return 0;
}

static void min_drm_release(struct drm_device *dev, struct drm_file *file)
{
}

static const struct drm_driver min_drm_driver = {
    .driver_features = DRIVER_GEM | DRIVER_RENDER,
    .open = min_drm_open,
    .release = min_drm_release,
    .name = "minimal_drm",
    .desc = "Minimal DRM driver for device registration",
    .major = 1,
    .minor = 0,
};

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

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

    platform_set_drvdata(pdev, drm);

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

    drm_info(drm, "minimal DRM device registered\n");
    return 0;
}

static int min_drm_remove(struct platform_device *pdev)
{
    struct drm_device *drm = platform_get_drvdata(pdev);

    drm_dev_unregister(drm);
    drm_dev_put(drm);
    return 0;
}

static const struct of_device_id min_drm_of_match[] = {
    { .compatible = "virtual,minimal-drm" },
    { }
};
MODULE_DEVICE_TABLE(of, min_drm_of_match);

static struct platform_driver min_drm_platform_driver = {
    .probe = min_drm_probe,
    .remove = min_drm_remove,
    .driver = {
        .name = "minimal_drm",
        .of_match_table = min_drm_of_match,
    },
};

module_platform_driver(min_drm_platform_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("DRM Course");
MODULE_DESCRIPTION("Minimal DRM driver for device node creation");

设备树节点(QEMU virt平台)

// 在qemu virt设备树中追加(或使用dtb overlay)
minimal-drm {
    compatible = "virtual,minimal-drm";
    status = "okay";
};

编译与加载

# 编译为内核模块
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

# 加载模块
insmod minimal_drm.ko

# 验证设备节点
ls -l /dev/dri/card0

验证方法与通过条件

  1. 模块加载:insmod无报错,dmesg尾部出现minimal DRM device registered。
  2. 设备节点:执行ls -l /dev/dri/card0,确认存在字符设备节点,主设备号为226(DRM_MAJOR),次设备号为0。
  3. 模块卸载:rmmod minimal_drm后/dev/dri/card0消失,无内核错误。

若设备节点未出现,检查设备树节点是否被正确匹配(dmesg中是否有platform minimal-drm: Driver minimal_drm requests probe deferral),以及内核是否启用了DRM子系统。