云计算百科
云计算领域专业知识百科平台

用户态接口(Userland interfaces)

用户态接口(Userland interfaces)

DRM 核心向应用程序导出了若干接口,通常通过相应的 libdrm 封装函数来使用。此外,驱动还通过 ioctl 和 sysfs 文件导出设备特定的接口,供用户态驱动和设备感知的应用程序使用。外部接口包括:内存映射、上下文管理、DMA 操作、AGP 管理、vblank 控制、fence 管理、内存管理和输出管理。此处涵盖通用 ioctl 和 sysfs 布局。我们只需要高层信息,因为手册页会涵盖其余内容。


libdrm 设备查找(libdrm Device Lookup)

当心陷阱!注意暗坑!

为了警告其他试图搞清楚这里到底怎么回事的人,我来总结一下这个故事。

首先,让我们理清命名,因为内核内部实现、libdrm 和 ioctl 的命名各不相同:

  • GET_UNIQUE ioctl,由 drm_getunique 实现,在 libdrm 中通过 drmGetBusid 函数封装。
  • libdrm 的 drmSetBusid 函数由 SET_UNIQUE ioctl 支撑。
  • 所有这些代码在内核中已被 drm_invalid_op() 废弃。
  • 内部的 set_busid 内核函数和驱动回调仅供 SET_VERSION ioctl 使用,因为只有 drm 1.0(已废弃)才允许用户态通过上述 ioctl 设置 busid。

其他涉及的 ioctl 和函数命名是一致的。

对于想知道 drm 1.1 和 1.4 之间有什么区别的人:正确处理 ppc 上 busid 中的 PCI 域。这一点直到 2010 年才在 libdrm 中正确实现,因此还不能废弃。没人知道 drm 1.2 和 1.3 有什么特别之处。

现在讲讲 DRM 中设备查找的实际"恐怖故事"。大体上有两种方式:按 busid 查找,或按设备驱动名称查找。

按 busid 打开相当简单:

  • 首先调用 SET_VERSION 确保 PCI 域被正确处理。副作用是这会在 master 结构体中填入 unique 名称。
  • 调用 GET_UNIQUE 从 master 结构体中读出 unique 名称,由于步骤 1,它与 busid 匹配。
  • 如果不匹配,则继续尝试下一个设备节点。
  • 按名称打开略有不同:

  • 直接调用 VERSION 获取版本,并与该 ioctl 返回的驱动名称进行匹配。注意没有调用 SET_VERSION,这意味着刚打开的 master 节点的 unique 名称没有被填入。尽管当前 DRM 设备节点始终绑定到一个设备,不像 drm 1.0 那样可以在运行时分配。
  • 匹配驱动名称。如果不匹配,则继续下一个设备节点。
  • 调用 GET_UNIQUE,检查 unique 名称长度是否为零(通过检查字符串的第一个字节是否为 0)。如果不是,libdrm 将跳过并继续下一个设备节点。这大概只是从 drm 1.0 时代复制粘贴的遗留代码——当时 unique 名称被设置意味着驱动已被占用,但这只是猜测。
  • 长话短说:为了保持按名称打开的逻辑正常工作,当 SET_VERSION 尚未被调用时,GET_UNIQUE 不能返回 unique 字符串,否则 libdrm 就会崩溃。即使该 unique 字符串永远无法更改,而且与实际打开设备完全无关——因为运行时可分配的设备实例仅在 drm 1.0 中支持,而 drm 1.0 早已消亡。但 libdrm 中 drmOpenByName 的代码就是活了下来,因此不能破坏它。


    主节点、DRM Master 和认证(Primary Nodes, DRM Master and Authentication)

    struct drm_master 用于跟踪已打开主设备节点的客户端组。对于每个曾经至少一次成功成为设备 master 的 struct drm_file(无论是通过 SET_MASTER IOCTL,还是在当前没有其他 master 时通过打开主设备节点隐式获得),都存在一个 drm_master。这记录在 drm_file.is_master 中。所有其他客户端仅持有一个指向其关联 drm_master 的指针。

    此外,一个 drm_device 只能有一个 drm_master 作为当前 master。它可以通过 DROP_MASTER 和 SET_MASTER IOCTL 切换,也可以通过关闭/打开主设备节点隐式切换。另见 drm_is_current_master()。

    客户端可以使用 GETMAGIC 和 AUTHMAGIC IOCTL 向当前 master 认证(如果它与自己的 master 匹配)。配合 master 的交换,这使得一组互相信任的客户端可以受控地访问设备。

    bool drm_is_current_master(struct drm_file *fpriv) — 检查 priv 是否为当前 master

    参数

    • struct drm_file *fpriv — DRM 文件私有数据

    描述

    检查 fpriv 是否为其设备上的当前 master。这决定客户端是否被允许执行 DRM_MASTER IOCTL。

    大多数需要 DRM_MASTER 的现代 IOCTL 用于内核模式设置(kernel modesetting)——当前 master 被认为拥有不可共享的显示硬件。

    struct drm_master *drm_master_get(struct drm_master *master) — 引用 master 指针

    参数

    • struct drm_master *master — struct drm_master

    描述

    递增 master 的引用计数并返回指向 master 的指针。

    struct drm_master *drm_file_get_master(struct drm_file *file_priv) — 引用 file_priv 的 drm_file.master

    参数

    • struct drm_file *file_priv — DRM 文件私有数据

    描述

    递增 file_priv 的 drm_file.master 的引用计数并返回 drm_file.master。如果 file_priv 没有 drm_file.master,则返回 NULL。

    从此函数返回的 master 指针应使用 drm_master_put() 解除引用。

    void drm_master_put(struct drm_master **master) — 解除引用并清空 master 指针

    参数

    • struct drm_master **master — 指向 struct drm_master 指针的指针

    描述

    递减 master 背后的 drm_master 的引用计数并将其设置为 NULL。

    struct drm_master — DRM master 结构体

    定义:

    struct drm_master {
    struct kref refcount;
    struct drm_device *dev;
    char *unique;
    int unique_len;
    struct idr magic_map;
    void *driver_priv;
    struct drm_master *lessor;
    int lessee_id;
    struct list_head lessee_list;
    struct list_head lessees;
    struct idr leases;
    struct idr lessee_idr;
    };

    成员

    • refcount — 此 master 对象的引用计数。
    • dev — 回链到 DRM 设备。
    • unique — 唯一标识符:例如 busid。受 drm_device.master_mutex 保护。
    • unique_len — unique 字段的长度。受 drm_device.master_mutex 保护。
    • magic_map — 已使用的认证令牌映射。受 drm_device.master_mutex 保护。
    • driver_priv — 驱动私有信息的指针。
    • lessor — 租约授予者(lease grantor),仅当此 struct drm_master 表示持有来自 lessor 的对象租约的承租人时才设置。设备的完全所有者将此设置为 NULL。
      lessor 一旦在 drm_lease_create() 中设置就不再更改,每个承租人持有对其 lessor 的引用,在 drm_lease_destroy() 中被销毁时释放。
      另见显示资源租约(display resource leasing)一节。
    • lessee_id — 承租人的 ID。所有者(即 lessor 为 NULL)的 ID 始终为 0。受 drm_device.mode_config 的 drm_mode_config.idr_mutex 保护。
    • lessee_list — lessor 的承租人列表条目,链接到 lessees。所有者不使用。受 drm_device.mode_config 的 drm_mode_config.idr_mutex 保护。
    • lessees — 从此 master 租赁的 drm_masters 列表。受 drm_device.mode_config 的 drm_mode_config.idr_mutex 保护。
      如果未授予任何租约,或所有承租人都已销毁,则此列表为空。由于 lessor 被其所有承租人引用,此 master 无法被销毁,除非列表为空。
    • leases — 租赁给此 drm_master 的对象。受 drm_device.mode_config 的 drm_mode_config.idr_mutex 保护。
      对象在 drm_lease_create() 中一次性全部租赁,在租约被撤销时一次性全部移除。
    • lessee_idr — 此所有者下的所有承租人(仅在 lessor 为 NULL 时使用)。受 drm_device.mode_config 的 drm_mode_config.idr_mutex 保护。

    描述

    注意 master 结构体仅与传统/主设备节点相关,因此每个设备只能有一个,而不是每个 drm_minor 一个。


    DRM 显示资源租约(DRM Display Resource Leasing)

    DRM 租约(leases)提供了有关 DRM master 是否可以控制 DRM 模式设置对象的信息。这使得可以创建多个 DRM master 来管理显示资源的子集。

    设备的原始 DRM master "拥有"可用的 drm 资源。它可以创建额外的 DRM master,并将其控制的资源"租赁"给新的 DRM master。这使新的 DRM master 获得对被租赁资源的控制权,直到所有者撤销租约或新的 DRM master 被关闭。

    一些有用的术语:

    • ‘所有者’(owner) 是不从另一个 struct drm_master 租赁对象的 struct drm_master,因此"拥有"这些对象。所有者可以被识别为 drm_master.lessor 为 NULL 的 struct drm_master。
    • ‘出租者’(lessor) 是将对象租赁给一个或多个其他 struct drm_master 的 struct drm_master。目前,承租人不允许创建子租约,因此出租者与所有者相同。
    • ‘承租人’(lessee) 是从某个其他 struct drm_master 租赁对象的 struct drm_master。每个承租人仅从一个记录在 drm_master.lessor 中的出租者租赁资源,并将其租赁的对象集合保存在 drm_master.leases 中。
    • ‘租约’(lease) 是出租者和承租人之间的合同,标识承租人可以控制哪些资源。所有被租赁的资源必须由出租者拥有或租赁给出租者,且出租者不允许将同一对象租赁给多个承租人。

    任何 struct drm_master “控制"的对象集合仅限于其租赁的对象集(对于承租人)或所有对象(对于所有者)。未被 struct drm_master 控制的对象不能通过各种状态操作 ioctl 进行修改,报告给用户态的任何状态都将被编辑以使其看起来空闲和/或不可用。例如,连接器(connector)始终报告"已断开”,而编码器(encoder)报告没有可能的 crtc 或克隆。

    由于每个承租人仅从一个出租者租赁对象,显示资源租约形成一个 struct drm_master 树。由于承租人目前不允许创建子租约,树深度限制为 1。当顶级设备所有者通过 SETMASTER 或 DROPMASTER IOCTL 变更时,所有这些将同时激活,因此 drm_device.master 指向租约树顶部的所有者(即 drm_master.lessor 为 NULL 的 struct drm_master)。从所有者租赁对象的承租人完整列表可以通过所有者的 drm_master.lessee_idr 搜索。


    开源用户态要求(Open-Source Userspace Requirements)

    DRM 子系统对新 uAPI 的用户态侧有比大多数其他内核子系统更严格的要求。本节解释这些要求的具体内容以及它们存在的原因。

    简而言之:任何 DRM uAPI 的添加都需要相应的开源用户态补丁,且这些补丁必须经过审查并准备好合并到合适的、规范的上游项目中。

    GFX 设备(包括显示和渲染/GPU 侧)是非常复杂的硬件,用户态和内核必须非常紧密地协作。渲染和模式设置的接口必须极其宽泛和灵活,因此几乎不可能为每个可能的边缘情况精确定义它们。这反过来使得在实践中几乎不可能区分用户态所需的行为(不能更改以避免回归)和仅是当前实现的偶然产物的行为。

    如果没有所有用户态使用者的完整源代码访问权,就无法更改实现细节,因为用户态可能在细微之处依赖当前实现的偶然行为。而在没有源代码的情况下调试这种回归几乎是不可能的。

    因此这意味着:

    • Linux 内核的"无回归"策略实际上仅适用于 DRM 子系统的开源用户态。 DRM 开发者完全可以接受闭源 blob 驱动在用户态使用与开源驱动相同的 uAPI,但它们必须以与开源驱动完全相同的方式使用。创造性地(滥用)使用接口将会导致破坏——过去也经常如此。
    • 任何新的用户态接口都必须有开源实现作为示范载体。

    要求开源用户态的另一个原因是 uAPI 审查。由于 GFX 栈的内核和用户态部分必须如此紧密地协作,代码审查只有在同时查看两侧的情况下才能评估新接口是否达到其目标。

    为确保接口确实完整覆盖用例,还需要满足以下附加要求:

    • 开源用户态不能是玩具/测试应用程序,而必须是真实的东西。具体来说,它需要处理所有常见的错误和边缘情况。这些往往是新 uAPI 出问题的地方,因此对于评估所提议接口的适用性至关重要。
    • 用户态侧必须完全按照该用户态项目的标准进行审查和测试。例如 mesa 这意味着 piglit 测试用例和邮件列表上的审查。这同样是为了确保新接口确实能完成任务。
    • 用户态侧的审查者也应在内核 uAPI 补丁上提供 Acked-by,表明他们认为所提议的 uAPI 是合理的,并且有充分的文档和验证供用户态使用。
    • 用户态补丁必须针对规范的上游项目,而非某个厂商的分支。这是为了确保没有人通过快速分支来规避审查和测试要求。
    • 内核补丁只能在满足所有上述要求后合并,但必须在用户态补丁落地之前合并到 drm-next 或 drm-misc-next。uAPI 始终从内核流出,反其道而行之有 uAPI 定义和头文件发散的风险。

    这些是相当高的要求,但它们源于多年来的共同痛苦和经验——仓促添加的 uAPI 几乎总是很快就被后悔。GFX 设备变化非常快,至少每隔几年就需要一次范式转变和全新的 uAPI 接口集合。再加上 Linux 内核保证现有用户态运行 10 年以上的承诺,这对 DRM 子系统来说已经相当痛苦了——同一功能有多个不同的 uAPI 并存。如果我们每年再往里面添几个彻底的错误,那将完全无法管理。


    渲染节点(Render nodes)

    DRM 核心为用户态提供多个字符设备。根据打开的设备不同,用户态可以执行不同的操作集合(主要是 ioctl)。

    主节点(primary node)始终创建,名为 card。此外,还会创建一个当前未使用的控制节点,名为 controlD。主节点提供所有传统操作,历史上是用户态使用的唯一接口。随着 KMS 的引入,控制节点被创建。然而,计划中的 KMS 控制接口从未被编写,因此控制节点至今仍未被使用。

    随着离屏渲染器和 GPGPU 应用的日益增多,客户端不再需要运行合成器或图形服务器就能使用 GPU。但 DRM API 要求非特权客户端先向 DRM-Master 认证才能获得 GPU 访问权。为避免此步骤并在不认证的情况下授予客户端 GPU 访问权,渲染节点(render nodes)被引入。

    渲染节点仅服务于渲染客户端,即不能在渲染节点上发出模式设置或特权 ioctl。只允许非全局渲染命令。

    如果驱动支持渲染节点,它必须通过 DRIVER_RENDER DRM 驱动能力进行声明。如果不支持,则主节点必须与传统 drmAuth 认证流程一起用于渲染客户端。

    如果驱动声明支持渲染节点,DRM 核心将创建一个名为 renderD 的独立渲染节点。每个设备有一个渲染节点。该节点上除了与 PRIME 相关的 ioctl 外不允许任何 ioctl。特别是 GEM_OPEN 将被明确禁止。有关可在渲染节点上使用的驱动无关 ioctl 的完整列表,请参见 drm_ioctl.c 中标记为 DRM_RENDER_ALLOW 的 ioctl。

    渲染节点的设计目的是避免缓冲区泄漏——如果客户端猜测 flink 名称或传统接口上的 mmap 偏移量,就会发生缓冲区泄漏。除了这个基本接口外,驱动还必须将其驱动相关的纯渲染 ioctl 标记为 DRM_RENDER_ALLOW,以便渲染客户端可以使用它们。驱动作者必须小心不要在渲染节点上允许任何特权 ioctl。

    有了渲染节点,用户态现在可以通过基本的文件系统访问模式来控制渲染节点的访问。不再需要在特权主/传统节点上认证客户端的运行中的图形服务器。相反,客户端可以打开渲染节点并立即获得 GPU 访问权。客户端(或服务器)之间的通信通过 PRIME 完成。从渲染节点到传统节点的 FLINK 不受支持。新客户端不应使用不安全的 FLINK 接口。

    除了丢弃所有模式设置/全局 ioctl 外,渲染节点还丢弃了 DRM-Master 概念。没有理由将渲染客户端与 DRM-Master 关联,因为它们独立于任何图形服务器。而且,它们无论如何都必须在没有任何运行中的 master 的情况下工作。如果驱动支持渲染节点,它们必须能够在没有 master 对象的情况下运行。另一方面,如果驱动需要在客户端之间共享对用户态可见且可跨打开文件边界访问的状态,则它们不能支持渲染节点。


    设备热拔插(Device Hot-Unplug)

    注意
    以下是计划。实现尚未完成(2020 年 5 月)。

    图形设备(显示和/或渲染)可能通过 USB(例如显示适配器或扩展坞)或 Thunderbolt(例如 eGPU)连接。最终用户可以在这些设备使用过程中热拔插它们,并期望至少机器不会崩溃。热拔插 DRM 设备造成的任何损害需要尽可能限制,并且必须给用户态机会来处理(如果它愿意的话)。

    理想情况下,拔掉 DRM 设备仍能让桌面继续运行,但这需要整个图形栈的显式支持:从内核和用户态驱动,到显示服务器,通过窗口系统协议,再到应用程序和库。

    其他应导致相同结果的场景包括:不可恢复的 GPU 崩溃、PCI 设备从总线上消失,或强制从物理设备解绑驱动。

    换言之,从用户态的角度来看,一切都需要继续或多或少正常工作,直到用户态停止使用消失的 DRM 设备并完全关闭它。

    用户态将从设备移除 uevent、ioctl 返回 ENODEV(或驱动特定的 ioctl 返回驱动特定的值),或 open() 返回 ENXIO 得知设备消失。只有在用户态关闭了所有相关的 DRM 设备和 dmabuf 文件描述符并移除了所有 mmap 之后,DRM 驱动才能拆除其不再存在的设备实例。如果同一物理设备在此期间以某种方式重新出现,它应作为一个新的 DRM 设备。与 PID 类似,字符设备次设备号不会立即回收。新的 DRM 设备总是选择比之前分配的下一个空闲次设备号,并在次设备号耗尽时回绕。

    该目标至少对内核和驱动提出以下要求:

    KMS UAPI 的要求

    • KMS 连接器必须将其状态更改为已断开(disconnected)。
    • 传统模式设置和页面翻转(pageflip),以及原子提交(atomic commit),包括真实的和 TEST_ONLY 的,以及其他所有 ioctl 要么以 ENODEV 失败,要么伪装成功。
    • 挂起的非阻塞 KMS 操作应传递用户态期望的 DRM 事件。这也适用于伪装成功的 ioctl。
    • 对底层设备已消失的设备节点调用 open() 将以 ENXIO 失败。
    • 尝试在已消失的 DRM 设备上创建 DRM 租约将以 ENODEV 失败。现有的 DRM 租约继续存在并按上述方式工作。

    渲染和跨设备 UAPI 的要求

    • 所有无法再运行的 GPU 作业必须强制信号化(force-signal)其 fence,以避免给用户态造成挂起。相关错误码为 ENODEV。
    • 一些用户态 API 已经定义了设备消失时应发生的行为(OpenGL、GL ES:GL_KHR_robustness;Vulkan:VK_ERROR_DEVICE_LOST 等)。DRM 驱动可以自由实现此行为,例如在驱动特定的 ioctl 中返回失败并在用户态驱动中处理,或依赖 uevent 等。
    • 指向已消失内存的 dmabuf 要么以 ENODEV 导入失败,要么如果在消失前导入会成功则继续成功导入。关于已导入 dmabuf 的内存映射另见下文。
    • 尝试将 dmabuf 导入到已消失的设备将要么以 ENODEV 失败,要么如果在没有消失的情况下会成功则成功。
    • 对底层设备已消失的设备节点调用 open() 将以 ENXIO 失败。

    内存映射的要求

    内存映射有进一步的要求,适用于现有映射和设备消失后创建的映射。

    • 如果底层内存消失,映射被创建或修改为读写仍能成功完成但结果未定义。这适用于用户态 mmap 的内存和指向 dmabuf 的内存(可能被映射到其他设备——跨设备 dmabuf 导入)。
    • 引发 SIGBUS 不是一个选项,因为用户态实际上无法处理它。信号处理器是全局的,这使得从 Mesa 等库中正确使用它们极其困难。信号处理器不可组合,你不能为来自不同厂商的 GPU1 和 GPU2 设置不同的处理器,再为 mmap 的常规文件设置第三个处理器。线程也会给信号处理带来额外的痛苦。

    设备重置(Device reset)

    GPU 栈非常复杂,容易出错——从硬件 bug、有缺陷的应用程序到众多层之间的一切。某些错误需要重置设备才能使设备重新可用。本节描述设备重置时 DRM 和用户态驱动的期望,以及如何传播重置状态。

    设备重置不能在不污染(tainting)内核的情况下被禁用,这可能导致通过 shrinker/mmu_notifier 挂起整个内核。用户态在设备重置中的角色是将消息传播给应用程序,并应用任何阻止有责任的应用程序的特殊策略(如果有的话)。推论是,调试挂起的 GPU 上下文需要硬件支持,以便能够抢占已停止的 GPU 上下文。

    内核模式驱动(Kernel Mode Driver)

    KMD 负责检查设备是否需要重置,并根据需要执行重置。通常在作业执行卡住时检测到挂起。KMD 应跟踪重置,因为用户态可以随时查询特定上下文的重置状态。这对于向栈的其余部分传播已发生重置是必要的。目前,这由每个驱动单独实现,没有通用的 DRM 接口。理想情况下,这应该在 DRM 调度器中适当集成,为所有驱动提供共同基础。重置后,KMD 应拒绝受影响上下文的新命令提交。

    用户模式驱动(User Mode Driver)

    命令提交后,UMD 应检查提交是被接受还是被拒绝。重置后,KMD 应拒绝提交,UMD 可以向 KMD 发出 ioctl 检查重置状态,如果 UMD 需要可以更频繁地检查。检测到重置后,UMD 将使用适当的 API 错误码将其报告给应用程序,如下文关于健壮性(robustness)的章节所述。

    健壮性(Robustness)

    重置后尝试保持图形 API 上下文工作的唯一方法是它遵守所使用的图形 API 的健壮性方面。图形 API 为应用程序提供了处理设备重置的方法。然而,不能保证应用会正确使用这些功能,而一个不支持健壮性接口的用户态(如非健壮性 OpenGL 上下文或没有健壮性支持的 API 如 libva)将健壮性处理完全交给用户态驱动。关于用户态驱动在这种情况下应该做什么,社区没有强烈的共识,因为所有合理的方法都有一些明显的缺点。

    OpenGL:使用 OpenGL 的应用应使用可用的健壮性接口,如扩展 GL_ARB_robustness(或 OpenGL ES 的 GL_EXT_robustness)。此接口告知是否发生了重置,如果是,则所有上下文状态都被视为丢失,应用程序通过创建新的状态继续。如果没有使用健壮性,则应做什么没有共识。

    Vulkan:使用 Vulkan 的应用应检查提交的 VK_ERROR_DEVICE_LOST。此错误码除其他含义外,表示发生了设备重置,需要重新创建上下文以继续运行。

    报告重置原因

    除了通过栈传播重置以便应用可以恢复外,驱动开发者了解最初是什么导致了重置也非常有用。DRM 设备应使用 devcoredump 存储有关重置的相关信息,以便此信息可以添加到用户错误报告中。


    设备节点上的 IOCTL 支持(IOCTL Support on Device Nodes)

    首先,驱动私有 IOCTL 仅应由支持渲染的驱动使用。内核模式设置已全部标准化,并通过属性进行扩展。一些现有驱动中有一些例外,它们定义了供显示 DRM master 使用的 IOCTL,但它们都早于属性机制。

    现在如果你有一个渲染驱动,你始终必须通过驱动私有属性来支持它。有几步需要完成来将所有东西串联起来。

    首先,你需要在驱动私有 UAPI 头文件 include/uapi/drm/my_driver_drm.h 中为你的 IOCTL 定义结构体:

    struct my_driver_operation {
    u32 some_thing;
    u32 another_thing;
    };

    请确保遵循 Documentation/process/botching-up-ioctls.rst 中的所有最佳实践。注意 drm_ioctl() 会自动对结构体进行零扩展,因此确保你可以在末尾添加更多内容,即不要在那里放置可变大小的数组。

    然后,你需要使用 DRM_IO()、DRM_IOR()、DRM_IOW() 或 DRM_IOWR() 之一定义你的 IOCTL 编号。它必须以 DRM_IOCTL_ 前缀开头:

    #define DRM_IOCTL_MY_DRIVER_OPERATION \\
    DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation)

    DRM 驱动私有 IOCTL 必须在 DRM_COMMAND_BASE 到 DRM_COMMAND_END 的范围内。

    最后,你需要一个 struct drm_ioctl_desc 数组来连接处理程序并设置访问权限:

    static const struct drm_ioctl_desc my_driver_ioctls[] = {
    DRM_IOCTL_DEF_DRV(MY_DRIVER_OPERATION, my_driver_operation,
    DRM_AUTH|DRM_RENDER_ALLOW),
    };

    然后将其赋值给驱动结构体中的 drm_driver.ioctls 字段。有关驱动特定 IOCTL 如何连接的详情,请参见关于文件操作的单独章节。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 用户态接口(Userland interfaces)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!