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

相关推荐
上学的小垃圾5 小时前
基于docker安装MySQL(openEuler系统)
linux·mysql·docker·容器
一直C6 小时前
Linux网络编程|HTTP协议详解(报文、请求方法、状态码)
linux·http·wireshark·vim·visual studio
Brilliantwxx9 小时前
【Linux】 进程(10) 进程控制深度解析:创建、终止与等待
linux·运维·服务器·c语言·开发语言·网络
欧米欧9 小时前
Linux基础指令上
linux·运维·服务器
ARM|X86+FPGA工业主板厂家10 小时前
基于嵌入式 GPU 的智能服务机器人
linux·运维·arm开发·fpga开发·机器人
sulikey10 小时前
Linux 粘滞位(Sticky Bit)完全指南:为什么共享目录需要“防删除“?
linux·服务器
mengge.cloud11 小时前
网络技术基础小白教程
linux·服务器·网络·云计算
学代码的CJY11 小时前
Linux 重定向、管道与环境变量
linux·spring boot·spring
treacle田11 小时前
达梦数据库-Linux DM数据守护主备集群缩改为单机-记录总结
linux·服务器·数据库·主备集群改单机
IT大白鼠12 小时前
CentOS 7.9 自建 Yum 源服务器搭建指南
linux·服务器·centos