DRM系列三:drm core模块入口
本系列文章基于linux 5.15
一、drm_core_init
执行一些drm core的初始化工作
static int __init drm_core_init(void)
{
int ret;
drm_connector_ida_init();
idr_init(&drm_minors_idr);
drm_memcpy_init_early();
ret = drm_sysfs_init();
if (ret < 0) {
DRM_ERROR("Cannot create DRM class: %d\n", ret);
goto error;
}
/*在/sys/kernel/debug/下创建dri目录*/
drm_debugfs_root = debugfs_create_dir("dri", NULL);
/*为drm申请主设备号,这里是DRM_MAJOR*/
ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops);
if (ret < 0)
goto error;
drm_core_init_complete = true;
DRM_DEBUG("Initialized\n");
return 0;
error:
drm_core_exit();
return ret;
}
1.drm_connector_ida_init
为每个连接器类型分配一个独立的 IDA,IDA(ID Allocator,ID 分配器) 是一种用于分配和管理唯一 ID 的机制,通常用于内核中需要分配唯一标识符的场景。其好处是:内核开发者可以方便地管理唯一 ID 的分配和释放,从而避免 ID 冲突和资源浪费。
static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },
{ DRM_MODE_CONNECTOR_VGA, "VGA" },
{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
{ DRM_MODE_CONNECTOR_Composite, "Composite" },
{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },
{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
{ DRM_MODE_CONNECTOR_Component, "Component" },
{ DRM_MODE_CONNECTOR_9PinDIN, "DIN" },
{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },
{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
{ DRM_MODE_CONNECTOR_TV, "TV" },
{ DRM_MODE_CONNECTOR_eDP, "eDP" },
{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
{ DRM_MODE_CONNECTOR_DSI, "DSI" },
{ DRM_MODE_CONNECTOR_DPI, "DPI" },
{ DRM_MODE_CONNECTOR_WRITEBACK, "Writeback" },
{ DRM_MODE_CONNECTOR_SPI, "SPI" },
{ DRM_MODE_CONNECTOR_USB, "USB" },
};
void drm_connector_ida_init(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(drm_connector_enum_list); i++)
ida_init(&drm_connector_enum_list[i].ida);
}
2.drm_sysfs_init
创建class类drm_class,同时会在/sys/class/目录下创建一个新的文件夹drm,并设置设备节点
int drm_sysfs_init(void)
{
int err;
/*创建设备类,此函数的执行会在/sys/class/目录下创建一个新的文件夹drm*/
drm_class = class_create(THIS_MODULE, "drm");
if (IS_ERR(drm_class))
return PTR_ERR(drm_class);
err = class_create_file(drm_class, &class_attr_version.attr);
if (err) {
class_destroy(drm_class);
drm_class = NULL;
return err;
}
/*设置设备节点*/
drm_class->devnode = drm_devnode;
return 0;
}
2.1 drm_devnode
在/sys/class/drm下创建节点,例如/sys/class/drm/dri/card0、/sys/class/drm/dri/card1
static char *drm_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
}
二、drm_core_exit
针对drm_core_init做的一些注销工作
static void drm_core_exit(void)
{
unregister_chrdev(DRM_MAJOR, "drm");
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
idr_destroy(&drm_minors_idr);
drm_connector_ida_destroy();
}