3. DRM 帧缓冲设备创建与基本操作
任务目标
为显卡设备创建DRM minor设备,并注册到DRM子系统,确保生成card0和controlD0设备节点。本案例基于Linux内核DRM框架,使用drm_dev_alloc、drm_dev_register接口完成最小可复现实现。
核心实现
#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 fake_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct drm_device *dev;
int ret;
/* 1. 分配DRM设备,minor号自动分配 */
dev = drm_dev_alloc(&fake_driver, &pdev->dev);
if (IS_ERR(dev))
return PTR_ERR(dev);
/* 2. 设置driver_data便于remove时访问 */
pci_set_drvdata(pdev, dev);
/* 3. 注册DRM设备,生成card0/controlD0节点 */
ret = drm_dev_register(dev, 0);
if (ret) {
drm_dev_put(dev);
return ret;
}
drm_info(dev, "DRM minor registered: card%d, controlD%d\n",
dev->primary->index, dev->control->index);
return 0;
}
static void fake_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
drm_dev_unregister(dev);
drm_dev_put(dev);
}
static const struct pci_device_id fake_ids[] = {
{ PCI_DEVICE(0x1234, 0x5678) },
{ }
};
static struct pci_driver fake_driver = {
.name = "fake_drm_minor",
.id_table = fake_ids,
.probe = fake_probe,
.remove = fake_remove,
};
/* DRM驱动结构:需提供fops和name */
static const struct file_operations fake_fops = {
.owner = THIS_MODULE,
};
struct drm_driver fake_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET,
.fops = &fake_fops,
.name = "fake_drm_minor",
.desc = "Fake DRM minor registration example",
.date = "20250101",
.major = 1,
.minor = 0,
};
module_pci_driver(fake_driver);
MODULE_DEVICE_TABLE(pci, fake_ids);
MODULE_LICENSE("GPL");
编译与加载
# 内核树外编译(需内核头文件)
obj-m := fake_drm_minor.o
make -C /lib/modules/$(uname -r)/build M=$PWD modules
# 加载模块(需root)
sudo insmod fake_drm_minor.ko
# 查看生成的设备节点
ls -l /dev/dri/
验证方法
- 加载模块后执行
ls -l /dev/dri/,预期输出包含card0和controlD0两个节点(若系统已有其他DRM设备,编号可能递增为card1/controlD1等)。 - 执行
dmesg | tail,应看到内核日志:DRM minor registered: card0, controlD0。 - 卸载模块
sudo rmmod fake_drm_minor后,/dev/dri/下对应节点消失。
关键说明
drm_dev_alloc内部会分配struct drm_device并初始化primary/control/render三个minor结构,但此时尚未创建字符设备节点。drm_dev_register执行时才会真正创建card%d(primary minor)和controlD%d(control minor)设备节点,并关联到drm_fops。- 本案例使用PCI驱动框架仅为模拟真实显卡设备的探测入口;若目标平台无PCI设备,可将
fake_probe改为在module_init中直接调用drm_dev_alloc+drm_dev_register,但需自行管理设备生命周期。 DRIVER_GEM和DRIVER_MODESET特性标志是DRM设备注册的必要条件,缺少会导致drm_dev_register返回-EINVAL。