DRM驱动分析01 - 初始化

在编译过程中,drm驱动的公共部分代码被build进入了内核中,而针对每一个显示硬件适配的驱动则可以选择编译成ko的形式。在系统启动过程中,init进程启动后,udevd会依据硬件设备信息,自动调用modprobe加载相应的ko文件。因此显示驱动执行在init进程之后,在执行的过程中会调用编译进内核的公共代码。

初始化过程

  1. 与显卡硬件进行匹配
    如果显卡是PCI设备,则调用pci_register_driver函数,将pci驱动与设备进行匹配;
  2. 在PCI设备层匹配成功之后,调用drm_get_pci_dev函数,为设备注册drm_driver驱动,这个驱动是关键,整个实现的接口均在此写入;
  3. 申请drm设备空间,drm_device设备是pci设备的成员,因此在申请成功内存之后,将该设备赋值给pci设备对应的成员变量中;
  4. 初始化drm设备,初始化操作包括链表、互斥量、同时将drm驱动写入到drm设备中;还包括初始化一些子设备,涉及的函数为drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
  5. 使能pci设备,将该显卡设备进行使能;
  6. 注册drm设备
    这一步是最复杂的一步,首先注册之前初始化的子设备,这里指的是DRM_MINOR_PRIMARY,注册的过程中还会初始化debug相关的一些接口,包括sys/kernel/debug/dri/目录,子设备需要用的一些接口,以及drm驱动中debugfs_init函数指针,子设备的注册就是将设备添加到全局的device链表中;然后到了最关键的一步,执行drm驱动的load回调函数,该函数通过由不同的显卡厂家来实现,一般是初始化crtc、connector等,后面会详细展开这部分;最后执行drm_modeset_register_all函数,该函数会执行plane、crtc、encoder、connector功能函数中的late_register回调函数。
关键函数
c 复制代码
int drm_modeset_register_all(struct drm_device *dev)
static int drm_minor_register(struct drm_device *dev, unsigned int type)
int drm_dev_register(struct drm_device *dev, unsigned long flags)
struct drm_device *drm_dev_alloc(struct drm_driver *driver, struct device *parent)
int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,struct drm_driver *driver)

上层调用过程

有两种方式,一种是libdrm库,另外一种是OpenGL。这两种是连接上层应用与底层驱动的中间件。上层应用一般可以是桌面、游戏等应用程序,通过调用中间件提供的接口操作底层驱动,X11就是一种linux下的桌面应用程序。中间件中通过系统调用的形式访问底层驱动,也就是ioctl。通过drm_ioctl函数去执行对应的底层函数。

例如上层应用要进行鼠标的操作,通常是隐藏或移动,系统调用这块对应的函数就是drm_mode_cursor2_ioctl,该函数会接收处理上层应用传递的信息,包括是移动鼠标还是隐藏鼠标,如果要移动鼠标,鼠标的坐标位置等。在该函数内会调用显卡驱动之前注册成功的cursor_set2或cursor_move回调函数,set函数是设置鼠标大小、隐藏、显示的,move回调函数是在移动鼠标时执行的,这两个回调函数挂到了crtc上。再具体到对应的显卡驱动,set或者move就会操作相关的寄存器,实现鼠标的大小更改、隐藏、移动等操作。上述就是整个鼠标操作的流程,主要是底层驱动这块的分析。

关键函数
c 复制代码
long drm_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
//drm_ioctls[]数组
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_UNLOCKED)
int drm_mode_cursor2_ioctl(struct drm_device *dev,void *data, struct drm_file *file_priv)
static int drm_mode_cursor_common(struct drm_device *dev,
                    struct drm_mode_cursor2 *req,
                    struct drm_file *file_priv)

总结

上述是简要的驱动初始化过程,由PCI驱动发起,在初始化的过程中会去调用具体的drm驱动的load回调函数,完成特定显卡硬件的初始化,这部分针对不同的硬件会有所差异,后面单独说这部分。上面的过程是一个通用的过程,每一个驱动都是这个流程。

相关推荐
lisanmengmeng几秒前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮42 分钟前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频
Linux-lucky12 小时前
45-Linux学习之旅之防火墙与WEB加固
linux·前端·网络·学习·ubuntu
禁默13 小时前
启元 Q1 二次开发实践:Ubuntu 部署与仿真验证,从 PrimeConsole 到 ROS 2 Humble + RViz
linux·运维·ubuntu
skywalk816313 小时前
把 去也网站 从 Ubuntu 搬到 FreeBSD:一次 Service Jail + nginx 的部署实录
linux·运维·nginx·ubuntu·freebsd
爱莉希雅&&&15 小时前
GitLab 完整学习笔记
linux·运维·服务器
风笙97815 小时前
[文件系统]文件系统挂载与卸载详解
linux
GeW16 小时前
新质生产力路线图解读:数据库性能优化与Linux调优专场
linux·数据库
陈希12317 小时前
Linux 服务器性能排查手册(2026):CPU、内存、磁盘IO、网络四大瓶颈定位
linux·服务器·网络
测试界的小码农20 小时前
【Linux 命令实战(03):文件创建、复制、移动与删除,掌握 touch、mkdir、cp、mv、rm】
linux·服务器·php