1. 初始化显示子系统核心数据结构
任务说明
本案例要求编写Linux内核DRM显示子系统初始化代码,完成drm_device、drm_minor等核心结构体的初始化,并将设备注册到内核。目标是在内核模块加载时,创建一个最小可用的DRM设备节点,可通过/dev/dri/card0访问。
环境依赖
- Linux内核源码树(版本≥4.19,本文以5.10为例)
- 已启用CONFIG_DRM内核配置选项
- 内核头文件:
include/drm/drm_device.h、include/drm/drm_drv.h
核心实现
以下代码实现了一个最小DRM驱动,完成drm_device分配与初始化、drm_minor索引分配、以及设备注册。该驱动不绑定具体硬件,仅用于演示核心数据结构初始化流程。
// minimal_drm.c
#include <linux/module.h>
#include <linux/pci.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_print.h>
static int minor_allocated;
static int fake_drm_load(struct drm_device *dev, unsigned long flags)
{
// 核心:分配DRM minor索引(即设备节点号)
int ret = drm_dev_register(dev, flags);
if (ret) {
DRM_ERROR("drm_dev_register failed: %d\n", ret);
return ret;
}
minor_allocated = dev->primary->index;
DRM_INFO("DRM device registered, minor index = %d\n", minor_allocated);
return 0;
}
static void fake_drm_unload(struct drm_device *dev)
{
drm_dev_unregister(dev);
DRM_INFO("DRM device unregistered\n");
}
static const struct drm_driver fake_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM,
.load = fake_drm_load,
.unload = fake_drm_unload,
.name = "fake_drm",
.desc = "Minimal DRM init example",
.date = "20250101",
.major = 1,
.minor = 0,
};
static struct drm_device *fake_dev;
static int __init fake_drm_init(void)
{
// 1. 分配并初始化drm_device结构体
fake_dev = drm_dev_alloc(&fake_drm_driver, NULL);
if (IS_ERR(fake_dev)) {
pr_err("drm_dev_alloc failed: %ld\n", PTR_ERR(fake_dev));
return PTR_ERR(fake_dev);
}
// 2. 设置设备参数(此处无真实硬件,仅设置最小必要字段)
fake_dev->dev = NULL; // 无真实struct device,仅演示
// 3. 调用load回调完成注册
int ret = fake_drm_load(fake_dev, 0);
if (ret) {
drm_dev_put(fake_dev);
return ret;
}
return 0;
}
static void __exit fake_drm_exit(void)
{
if (fake_dev) {
fake_drm_unload(fake_dev);
drm_dev_put(fake_dev);
fake_dev = NULL;
}
}
module_init(fake_drm_init);
module_exit(fake_drm_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kernel Display Example");
MODULE_DESCRIPTION("Minimal DRM device init example");
编译与加载
将上述代码放入内核源码树drivers/gpu/drm/目录下,创建Kconfig和Makefile条目,或使用独立模块编译方式:
# 独立编译(需内核源码树)
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
# 加载模块
sudo insmod minimal_drm.ko
# 验证设备节点
ls -l /dev/dri/
# 预期输出:crw-rw---- 1 root video 226, 0 ... card0
验证方法
- 模块加载:执行
dmesg | tail,应看到DRM device registered, minor index = 0日志。 - 设备节点:
/dev/dri/card0应存在,主设备号226,次设备号0。 - 卸载测试:
sudo rmmod minimal_drm后,/dev/dri/card0消失,dmesg显示DRM device unregistered。
通过条件:上述三步全部符合预期,且无内核错误日志(dmesg中无BUG/ERROR字样)。
关键说明
drm_dev_alloc()内部完成drm_device内存分配和drm_minor结构体初始化,但drm_minor的索引分配发生在drm_dev_register()中。- 本示例未绑定真实PCI/USB设备,因此
drm_device.dev为NULL,仅用于演示数据结构初始化流程。实际驱动需在probe回调中传入真实struct device。 DRIVER_MODESET特性标志使设备节点创建为card0而非renderD128。