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回调函数,完成特定显卡硬件的初始化,这部分针对不同的硬件会有所差异,后面单独说这部分。上面的过程是一个通用的过程,每一个驱动都是这个流程。

相关推荐
Harm灬小海1 小时前
【云计算学习之路】学习Centos7系统:Linux进程管理
linux·运维·服务器·学习·云计算
持梦远方1 小时前
Nginx 静态资源挂载与前端部署实战笔记
linux·前端·笔记·nginx
IMPYLH1 小时前
Linux 的 who 命令
linux·运维·服务器·bash
fanzhonghong1 小时前
javaWeb后端开发之Linux项目部署3和Docker部署1
linux·服务器·前端·docker
Bert.Cai1 小时前
Linux print命令详解
linux·运维·服务器
Harm灬小海1 小时前
【云计算学习之路】学习Centos7系统:服务搭建(NFS)
linux·运维·服务器·学习·云计算
Harm灬小海1 小时前
【云计算学习之路】学习Centos7系统-权限管理
linux·运维·服务器·学习·云计算
code monkey.1 小时前
【Linux之旅】Linux 网络基础全解析:从协议分层到 Socket 编程,构建高性能网络服务的底层基石
linux·网络·php
程序猿编码1 小时前
大模型的“文字障眼法“:FlipAttack 文本反转越狱技术全解析
linux·python·ai·大模型