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

相关推荐
七歌杜金房1 小时前
我终于又有了自己的 Linux 电脑
linux·debian·mac
tntxia1 天前
linux curl命令详解_curl详解
linux
扛枪的书生1 天前
Linux 网络管理器用法速查
linux
顺风尿一寸1 天前
Java Socket 内核之旅:从 SocketChannel.read() 到 tcp_recvmsg 与 epoll 的完整调用链路
linux
XIAOHEZIcode2 天前
Ubuntu 终端美化全栈指南:Bash 到 Kitty 踩坑实录
linux·ubuntu·命令行
唐青枫2 天前
别再只会用 cron:Linux systemd Timer 定时任务实战详解
linux
AlfredZhao3 天前
生产环境里,为什么不建议把普通端口直接暴露到公网?
linux·https·443·80
戴为沐5 天前
Linux内存扩容指南
linux
zylyehuo5 天前
Linux 彻底且安全地删除文件
linux
用户805533698036 天前
主线 U-Boot 上 RK3506:和闭源 rkbin 拔河的三个隐性契约
linux·嵌入式