当前位置: 首页 > article >正文

显示设备驱动开发

当代显卡设备驱动包括了显示、GPU计算两个主要功能,在DRM框架下的显卡驱动通常有内核驱动模块(KMD)、用户空间驱动模块(UMD)组成,KMD主要是和显卡硬件交互,UMD则完成2D、3D图形的渲染、视频硬件界面。UMD与KMD配合将显卡的功能最大限度发挥出来。

文章目录

  • 一、注册驱动
  • 二、设备初始化
  • 三、注册DRM设备
  • 四、显卡驱动集成方案

在这里插入图片描述
在这里插入图片描述


下面我们以Linux虚拟环境中常用的qxl显卡为例来看添加一个新的显卡驱动,都要完成哪些内容。

一、注册驱动

目前除去一些片内的显示芯片,常见显卡板卡都是pci接口,所以这里注册一个pci驱动。

static int __init qxl_init(void)

{

...

        qxl_driver.num_ioctls = qxl_max_ioctls;

        return pci_register_driver(&qxl_pci_driver);

}

pci驱动的结构中,probe函数是pci设备的初始化过程,这个pci设备作为一个显卡设备会被初始化化。

static struct pci_driver qxl_pci_driver = {

         .name = DRIVER_NAME,

         .id_table = pciidlist,

         .probe = qxl_pci_probe,

         .remove = qxl_pci_remove,

         .driver.pm = qxl_pm_ops,

};

二、设备初始化

在pci设备初始化过程中,将设备初始化为DRM框架下的一个显示驱动设备。如下代码中,这列举出了qxl_pci_probe核心功能函数,完整源码参考Uos源码仓库源码包或Uos社区内核源码。

static int

qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)

{

...

ret = pci_enable_device(pdev);

...

ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, 0, "qxl");

...

ret = qxl_device_init(qdev, &qxl_driver, pdev);

...

ret = qxl_modeset_init(qdev);

...

ret = drm_dev_register(&qdev->ddev, ent->driver_data);

...

}

pci_enable_device()函数初始化一个pci设备,这是在被使用前的必要步骤,通常是设置底层使能I/O和内存。

drm_fb_helper_remove_conflicting_pci_framebuffers()函数清楚之前使用的framebuffer设置,从这里开始qxl驱动负责显示framebuffer的管理。 这通常是在启动过程中framebuffer的管理权限专一的时候使用。

qxl_device_init()、qxl_modeset_init()是实际做qxl初始化的部分,这部分要在注册drm驱动之前完成。这部分是显卡专有的参数、功能的准备,保证注册为drm设备后就可以正常工作。qxl_driver是qxl提供的qxl这个DRM设备对应的DRM驱动。这里需要关注一下drm_driver结构体里的load函数,通常是显卡驱动加载kms的入口。

static struct drm_driver qxl_driver = {

        .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |

                           DRIVER_ATOMIC | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,

        .dumb_create = qxl_mode_dumb_create,

        .dumb_map_offset = qxl_mode_dumb_mmap,

#if defined(CONFIG_DEBUG_FS)

        .debugfs_init = qxl_debugfs_init,

#endif

        .prime_handle_to_fd = drm_gem_prime_handle_to_fd,

        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,

        .gem_prime_export = drm_gem_prime_export,

        .gem_prime_import = drm_gem_prime_import,

        .gem_prime_pin = qxl_gem_prime_pin,

        .gem_prime_unpin = qxl_gem_prime_unpin,

        .gem_prime_get_sg_table = qxl_gem_prime_get_sg_table,

        .gem_prime_import_sg_table = qxl_gem_prime_import_sg_table,

        .gem_prime_vmap = qxl_gem_prime_vmap,

        .gem_prime_vunmap = qxl_gem_prime_vunmap,

        .gem_prime_mmap = qxl_gem_prime_mmap,

        .gem_free_object_unlocked = qxl_gem_object_free,

        .gem_open_object = qxl_gem_object_open,

        .gem_close_object = qxl_gem_object_close,

        .fops = qxl_fops,

        .ioctls = qxl_ioctls,

        .irq_handler = qxl_irq_handler,

        .name = DRIVER_NAME,

        .desc = DRIVER_DESC,

        .date = DRIVER_DATE,

        .major = 0,

        .minor = 1,

        .patchlevel = 0,

};

qxl_fops是用户层操作设备节点/dev/dri/cardX的时候,对应的操作方法。显卡驱动往往是在这里封装drm的函数,比如: 自定义qxl_open()函数,做专业的操作,然后调用drm_open()。

static const struct file_operations qxl_fops = {

        .owner = THIS_MODULE,

        .open = drm_open,

        .release = drm_release,

        .unlocked_ioctl = drm_ioctl,

        .poll = drm_poll,

        .read = drm_read,

        .mmap = qxl_mmap,

};

drm_dev_register()函数将qxl注册到DRM框架,成为一个DRM设备

三、注册DRM设备

这是显卡驱动将自己添加到DRM框架的入口,注册成功之后,用户层就可以正常使用这个显示设备做渲染、显示了。


int drm_dev_register(struct drm_device *dev, unsigned long flags)

{

...

ret = drm_minor_register(dev, DRM_MINOR_RENDER);

...

ret = drm_minor_register(dev, DRM_MINOR_PRIMARY);

...

if (dev->driver->load) {

        ret = dev->driver->load(dev, flags);

...

}

...

if (drm_core_check_feature(dev, DRIVER_MODESET))

        drm_modeset_register_all(dev);

...

}

DRM_MINOR_RENDER设备对应的是/dev/dri/renderX, DRM_MINOR_PRIMARY设备对应的是/dev/dri/cardX。

如果drm驱动提供了load方法,调用load函数完成kms初始化。

drm_modeset_register_all()函数完成DRM框架下的crtc、plane、encoder、connecter的初始化

int drm_modeset_register_all(struct drm_device *dev)

{               

        int ret;

        

        ret = drm_plane_register_all(dev);

        if (ret)

                goto err_plane;

                

        ret = drm_crtc_register_all(dev);

        if  (ret)

                goto err_crtc;

        

        ret = drm_encoder_register_all(dev);

        if (ret)

                goto err_encoder;

        ret = drm_connector_register_all(dev);

        if (ret) 

                goto err_connector;

        return 0;

...

}

通过上述三个步骤,显卡驱动就完成了自身初始化、并将自己添加到DRM显示框架当中。

四、显卡驱动集成方案

桌面版Linux图形显示系统的层次如下图所示,这是一个基于DRM框架的完整架构,UOS系统的显示功能也遵循这个框架层次的。

在这里插入图片描述

Linux图形显示系统层次结构

UOS支持以完全开源、部分开源已经完全闭源的方式提供的显卡方案进行集成。当前UOS设备驱动的集成的技术架构下,推荐显卡厂商以Vendor的方式提供UMD。KMD可以按照实际情况是否开源来选择是集成进内核主线源码做核内驱动,还是以dkms的方式做核外驱动。

上图蓝色框内是厂商方案涉及的部分,通常显卡驱动方案包括:

  • 显示服务的DDX,通常命名方式是xxx_drv.so,存放目/usr/lib/xorg/modules/drivers/

  • 3D渲染的支持库,通常命名方式是xxx_dri.so, 推荐存放目录/usr/lib/-linux-gpu//

  • 特有的DRM API接口库,通常命名方式是libdrm_xxx.so, 推荐存放目录/usr/lib/-linux-gpu/

  • 显卡必要的固件firmware文件已经专有配置

  • 厂商提供的vaapi、vdpau视频解码库

  • 显卡内核驱动模块

在这里插入图片描述

UOS显卡集成推荐方案层次图

UOS系统对厂商的方案支持的相关协议版本的要求如下表:

软件模块限制说明
KMD推荐使用DRM框架,支持DRIVER_ATOMIC特性
openGLUMD支持的openGL协议版本不低于3.3
glvnd推荐UMD以一个Vendor的方式在glvnd框架下加载
llvm如果适配Uos版本的llvm不满足UMD要求,需要安装多版本llvm,需要保证多版本的
Xorg兼容Xorg的ABI版本

在这里插入图片描述


http://www.kler.cn/a/428734.html

相关文章:

  • 产品经理面试题总结2025【其一】
  • 常用排序算法之插入排序
  • Dart语言的学习路线
  • C语言之图像文件的属性
  • vim文本编辑器
  • 海康工业相机的应用部署不是简简单单!?
  • 【力扣】2094.找出3为偶数
  • 【Leetcode 每日一题】3001. 捕获黑皇后需要的最少移动次数
  • 【CSS in Depth 2 精译_066】11.2 颜色的定义(上):实现示例页中的基础样式及初步布局
  • vim实用命令整理(常用的命令)
  • mybatis plus打印sql日志
  • Apache Doris 数据类型
  • 海报在线制作系统海报制作小程序PHP+Uniapp
  • Elasticsearch:使用 Elastic APM 监控 Android 应用程序
  • SPT: Revisiting the Power of Prompt for Visual Tuning
  • 【jvm】垃圾回收的重点区域
  • 【Linux内核】Hello word程序
  • AIGC实战——VQ-GAN(Vector Quantized Generative Adversarial Network)
  • C# (WinForms) 使用 iTextSharp 库将图片转换为 PDF
  • 分布式数据库:架构、挑战与未来趋势
  • MATLAB 控制系统快速入门
  • 期货分仓/风控/期货交易的原则!
  • Ubuntu系统中Redis的安装步骤及服务配置
  • Rust学习笔记_13——枚举
  • Ubuntu 22.04安装Nessus(离线激活模式)
  • Windows如何识别Linux主机名?