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

统信UOS设备驱动开发-核心模块

包含linux设备驱动开发的基础知识及统信UOS设备驱动的总体架构,常用的设备驱动开发调试优化手段及在环境搭建和代码编写过程中常见问题处理等。

文章目录

  • 一、UOS驱动开发总体方案
      • 基于DKMS的驱动开发
      • 驱动测试
      • 通用必测项
      • 补丁测试
      • 驱动DEB包签名与分发
      • 驱动升级
      • 内核驱动升级
      • DKMS驱动升级
  • 二、 显示设备驱动开发
      • 注册驱动
      • 注册DRM设备
      • 显卡驱动集成方案
  • 三、无线网络设备驱动开发
      • 总线设备驱动层
      • 网络设备驱动层
      • 网络接口层
      • 设备接口层
      • 设备驱动功能层
      • 网络设备和媒介层
  • 四、蓝牙设备驱动开发
      • 蓝牙协议架构
      • 蓝牙协议的HCI传输层
      • 编程框架
  • 五、打印驱动开发
      • 打印驱动开发
      • 于 PPD 的驱动设计
      • PD 文件格式
      • filter 程序的开发
      • backend 程序的开发
      • filter 与 backend 的通信
      • 打印驱动安装规范
      • 无驱打印
      • 打印管理器与打印驱动

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


一、UOS驱动开发总体方案

基于DKMS的驱动开发

DMKS包是一个可以安装的deb包。用dkpg -i命令安装DKMS驱动后可以保证覆盖内核中原有的驱动。DKMS驱动可以保证升级内核后重新编译和自动加载,降低了维护驱动的成本。

在这里插入图片描述
DKMS状态图

DKMS主要的命令可以参考上图,分别是add、build、install、uninstall和remove,另外,还可以执行"dkms status"查看目前DKMS系统维护的模块的状态。

驱动测试

驱动的测试主要是从安装,卸载,功能性,稳定性四个方面来进行用例的设计。

通用必测项

  • S3-500次待机:
    1、用户态调用 待机操作500次
    2、引导过程中系统无卡死,花屏,裂屏现象
    3、测试完成后, 查看内核日志无Call Trace事件
    执行 sudo dmesg | grep “Call Trace” 命令后无返回信息
  • S4-500次休眠:
    1、用户态调用 休眠操作500次
    2、引导过程中系统无卡死,花屏,裂屏现象
    3、测试完成后, 查看内核日志无Call Trace事件
  • reboot-500次重启:
    1、用户态调用重启操作500次
    2、引导过程中系统无卡死,花屏,裂屏现象
    3、测试完成后, 查看内核日志无 Call Trace事件
    执行 sudo dmesg | grep “Call Trace” 命令后无返回信息
  • LTP 稳定性测:
    按照不同标准,进行LTP 12小时、24小时、48小时测试。
  • 仓库升级测试:
    根据目标系统和线上系统,进行软件升级测试。
  • 安装/卸载测试:
    对软件包的安装、卸载的测试。
    功能测试
    显卡测试:x11perf,3D性能测试(glmark2),HDMI插拔,VGA插拔,驱动识别检查,双屏测试。
    声卡测试:系统音效检查,新增音频设备节点检查,录音和播放测试。
    网卡测试:有线,WIFI和蓝牙的连接,断开,数据传输校验。

补丁测试

  • cpu补丁
    覆盖对应型号的一系列cpu测试设备,至少2种型号设备,覆盖基本功能/必测项。
  • 显卡补丁
    覆盖显卡功能用例,核内驱动可以点亮设备,核外驱动覆盖必测项。
  • 网卡补丁
    覆盖显卡功能用例,覆盖必测项。
  • 声卡补丁
    覆盖声卡功能用例,覆盖必测项。
  • 其他硬件驱动补丁
    覆盖对应硬件设备,覆盖必测项。
  • glibc库补丁
    覆盖unixbench。

驱动DEB包签名与分发

多证书签名系统概述
UOS多证书签名系统包含四个子系统,分别是deepin-deb-sign、deepin-elf-sign、deepin-deb-verify、deepin-elf-verify 四个子系统。牵涉到证书签名的模块有deb归档文件增删模块, ELF节增删模块,以及PKCS7签名模块。见下图 UOS多证书签名子系统功能模块说明。

在这里插入图片描述
驱动包以DEB的格式分发,签名遵循UOS DEB包的签名方案,具体参照elf_verify的方案。

分发
经过系统测试和集成测试后,经过自动化智能平台,由crp打包到线上正式仓库进行发布。

驱动升级

驱动的升级我们可以通过对内核驱动升级和dkms驱动升级两种方式进行。

内核驱动升级

对于核内以模块形式提供的内核,往往通过修改内核驱动代码,编译新的内核来升级驱动。这种方式升级驱动,需要升级内核来达到目的。可以通过dpkg或apt包管理器来升级内核,或者研发提供了测试内核通过本地安装来升级内核。
如果想手动替换驱动可以按照下面的过程来做:
1、在内核中找到较新的驱动程序,不管是通过厂商还是通过一些上游的社区。
2、安装软件包build-essentials和linux-kernel-headers。
3、创建一个Makefile文件如下:

obj-m += drivername.o

MODDESTDIR := /lib/modules/$(shell uname -r)/kernel/path/to/driver/

all:

    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:

    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

install:

    install -p -m 644 drivername.ko 

make之后再sudo make install即可安装到内核中,最后update-initramfs -u -k all,即可手动更新完成驱动(这条命令可以确保重启后驱动是更新过的驱动)。

DKMS驱动升级

对于DKMS的驱动升级,只需要制做更新版本的DKMS驱动包,通过dpkg或apt安装新的驱动包即可。

DKMS新的驱动包的制做需要注意的更多的是包的制做和测试流程的规范,针对不同种类的驱动程序使用不同的测试用例覆盖全面。

二、 显示设备驱动开发

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

下面我们以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)

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

相关文章:

  • 力扣经典题目之219. 存在重复元素 II
  • MATLAB对文件处理
  • Flink概念知识讲解之:Restart重启策略配置
  • 基于 GEE Sentinel-1 数据集提取水体
  • 六祖坛经主要讲什么,现代心理学或哲学,有什么和它对应
  • 桌面运维岗面试三十问
  • uln2003驱动28BYJ-48步进电机
  • 图像识别基础认识
  • 网安学习之信息收集
  • [产品管理-55]:产品设计不仅仅完成功能,即可用性设计,还需要完成可生产性、可装配性、可维护性、可回收性、可服务性设计
  • npm入门教程4:npm基本操作
  • 什么是Web3D交互展示?有什么优势?
  • Linux docker 部署redis详解
  • js,ts控制流程
  • SAP ABAP开发学习——BADI增强操作步骤示例1
  • 《Baichuan-Omni》论文精读:第1个7B全模态模型 | 能够同时处理文本、图像、视频和音频输入
  • 【Python】深度剖析Python中的可迭代对象与迭代器——掌握高级迭代器实现与应用
  • Oracle视频基础1.3.8与1.4.1练习
  • FRIENDLYARM Tiny6410 superboot烧写进sd卡教程
  • C#-值类型、引用类型
  • ctfshow web文件上传 web166-170
  • elementUI table 多级表头隔行变背景颜色
  • 从零开始构建 ChatGPT
  • 2024 Rust现代实用教程 Trait特质
  • 15分钟学 Go 第 27 天:路由和处理请求
  • 实际案例说明用基于FPGA的原型来测试、验证和确认IP——如何做到鱼与熊掌兼得?