KMS核心结构和函数
struct drm_mode_config_funcs
提供模式设置功能的基本驱动程序
定义
struct drm_mode_config_funcs { struct drm_framebuffer *(*fb_create)(struct drm_device *dev,struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd); const struct drm_format_info *(*get_format_info)(const struct drm_mode_fb_cmd2 *mode_cmd); void (*output_poll_changed)(struct drm_device *dev); enum drm_mode_status (*mode_valid)(struct drm_device *dev, const struct drm_display_mode *mode); int (*atomic_check)(struct drm_device *dev, struct drm_atomic_state *state); int (*atomic_commit)(struct drm_device *dev,struct drm_atomic_state *state, bool nonblock); struct drm_atomic_state *(*atomic_state_alloc)(struct drm_device *dev); void (*atomic_state_clear)(struct drm_atomic_state *state); void (*atomic_state_free)(struct drm_atomic_state *state); };
成员
fb_create
创建一个新的framebuffer对象。核心对请求的元数据进行基本检查,但大部分检查留给驱动程序。详见结构drm_mode_fb_cmd2。
为了验证像素格式和修饰符,驱动程序可以使用drm_any_plane_has_format()来确保至少有一个平面支持请求的值。注意,如果请求没有指定modifier,即当(mode_cmd->flags & DRM_MODE_FB_MODIFIERS) == 0,驱动程序必须首先确定实际使用的修饰符。
重要提示:如果修饰符启用了超出fourcc像素格式代码的额外plane,这些原来用户空间传递给内核的隐含修饰符必须存储在drm_framebuffer结构中,包括所有相关的元数据,如drm_framebuffer.pitches和drm_framebuffer.offsets。这是GETFB2 ioctl所需要的。
如果参数被认为是有效的,并且底层内存管理器中的后备存储对象都存在,那么驱动程序分配一个新的drm_framebuffer结构,子类化以包含驱动程序特定的信息(如内部本地缓冲区对象引用)。它还需要填写所有相关的元数据,这应该通过调用drm_helper_mode_fill_fb_struct()来完成。
初始化通过调用drm_framebuffer_init()来完成,drm_framebuffer_init()注册framebuffer并使其他线程可以访问它。
返回值
一个新的framebuffer,其初始引用计数为1或一个用ERR_PTR()编码的负错误码。
get_format_info
允许驱动程序返回特定fb布局的自定义格式信息(例如带有辅助压缩控制平面的信息)。
返回值
特定于给定fb元数据的格式信息,如果没有找到,则为NULL。
output_poll_changed
helper程序使用回调函数通知驱动程序输出配置已经更改。
通过helper程序实现此函数的驱动程序可以从这个钩子调用drm_fb_helper_hotplug_changed来通知fbdev助手输出配置发生了变化。
FIXME:除了设备级helper回调没有虚表之外,这没有理由是一个核心函数。
mode_valid
具体设备的显示模式验证。可用于拒绝永远不支持的模式。只有设备范围的限制可以在这里检查。对于每个特定的对象,应该在.mode_valid()钩子中检查特定的crtc/encoder/bridge/connector约束。
atomic_check
这是验证原子模式集更新的唯一钩子。该函数必须拒绝硬件或驱动程序不支持的任何模式集和状态更改。这包括但当然不限于:
- 检查模式、帧缓冲区、缩放和放置需求等是否在硬件的限制范围内;
- 检查任何隐藏的共享资源是否超额使用。这可以共享pll,共享通道,总体内存带宽,显示fifo空间(在planes之间共享,甚至crtc);
- 检查导出到用户空间的虚拟化资源是否超额使用。出于各种原因,我们可以导出比实际硬件更多的planes、crtcs或encoders。一个例子是双管道操作(通常应该从用户空间隐藏,和硬件保持一致),plane可能需要1个硬件plane(如果它只是一个管道),2个硬件plane(当它跨越两个管道)甚至和第二平面共享硬件平面(如果有一个其他管道要求的兼容的plane);
- 检查任何过渡状态是否可能,如果有请求,更新确实可以在vblank期间完成,而不会暂时禁用一些功能。
- 检查驱动程序或硬件可能有的任何其他约束;
- 这个回调函数还需要正确地填写这个更新中的drm_crtc_state,以确保drm_atomic_crtc_needs_modeset()反映了可能更新的性质,并且当且仅当在该CRTC上的一个vblank中没有被删除而不能应用更新时返回true。如果用户空间在其请求中不允许更新,核心将使用这些信息来拒绝需要完整模式集的更新(即,屏蔽屏幕,或至少暂停更新相当长的时间);
- 驱动程序也不需要像对相应的遗留入口点那样重复基本的输入验证。core在调用这个钩子之前做这个。
请参阅atomic_commit的文档,了解不需要在这个回调中检查的详尽错误列表。
请参阅结构drm_atomic_state的文档,了解如何准确地描述原子模式集更新。
使用原子帮助程序的驱动程序可以使用drm_atomic_helper_check()或它导出的子函数之一来实现这个钩子函数。
返回值
0表示成功,或者下面的负错误码之一:
- -EINVAL,如果违反上述任何约束。
- 当试图通过drm_modeset_lock()获取额外的drm_modeset_lock时返回-EDEADLK。
- -ENOMEM,如果由于缺乏内存而分配额外的状态子结构失败。
- -EINTR、-EAGAIN或-ERESTARTSYS,如果IOCTL需要重新启动。这可能是由于一个待定的信号,或者因为驱动程序需要完全退出,以从异常情况下恢复,如GPU挂起。从用户空间的角度来看,所有的错误都是平等对待的。
atomic_commit
这是提交原子模式集更新的唯一钩子。核心保证在调用这个函数之前已经成功地调用了atomic_check,并且在此期间没有任何更改。
请参阅结构drm_atomic_state的文档,了解如何准确地描述原子模式集更新。
使用原子帮助程序的驱动程序可以使用drm_atomic_helper_commit()或它导出的子函数之一来实现这个钩子。
非阻塞提交(用nonblock参数表示)必须在回调的上下文中做任何可能导致不成功提交的准备工作。唯一的例外是导致-EIO的硬件错误。但即使在这种情况下,驱动程序也必须确保显示管道至少正在运行,以避免当pageflips不起作用时compositors崩溃。其他任何事情,特别是将更新提交给硬件,都应该在不阻塞调用者的情况下完成。对于不需要修改模式设置的更新操作,必须保证这一点。
在执行flip之前,驱动程序必须等待framebuffer的渲染完成。如果底层缓冲区是共享dma-buf,它还应该等待来自其他驱动程序的未完成的渲染完成。非阻塞提交绝不能在这个回调的上下文中等待渲染。
当原子提交完成时,应用程序可以请求得到通知。这些事件是针对每个CRTC的,可以通过drm_event提供给用户空间的CRTC索引来区分不同的crtc.
drm核心将在每个CRTC的drm_crtc_state.event中提供一个结构drm_event。请参阅drm_crtc_state.event以获取有关此事件的精确语义的更多细节。
驱动程序不允许关闭任何通过原子提交成功启用的显示管道。如果因为管道关闭而突然拒绝page flip,那么这样做可能会导致合成器崩溃。
返回:
0表示成功,或者下面的负错误码之一:
- -EBUSY,如果请求了一个非阻塞更新,并且有一个较早的更新等待处理。允许驱动程序支持一个未完成更新队列,但目前还没有驱动程序支持。注意,如果请求同步更新,驱动程序必须等待之前的更新完成,在这种情况下,它们不允许提交失败。
- -ENOMEM,如果驱动分配内存失败。特别地,当试图固定framebuffer时可能会发生这种情况,而这只能在提交状态时才能完成.
- -ENOSPC,作为更通用的-ENOMEM的一个改进,表明驱动程序已经用完vram, iommu空间或帧缓冲区所需的类似GPU地址空间。
- -EIO,如果硬件完全死机。
- -EINTR、-EAGAIN或-ERESTARTSYS,如果IOCTL需要重新启动。这可能是由于一个待定的信号,或者因为驱动程序需要完全卸载,以从异常情况下恢复,如GPU挂起。从用户空间的角度来看,所有的错误都是平等对待的。
这个列表是详尽无遗的。特别地,这个钩子不允许返回-EINVAL(任何无效的请求都应该被atomic_check捕获)或-EDEADLK(这个函数不能获得额外的modesset锁)。
atomic_state_alloc
这个可选的钩子可以被那些想要继承drm_atomic_state结构的驱动程序使用,以便能够轻松地跟踪它们自己的驱动私有全局状态。如果实现了这个钩子,驱动程序也必须实现atomic_state_clear和atomic_state_free。
不赞成继承drm_atomic_state,而赞成使用drm_private_state和drm_private_obj。
返回值
成功时返回drm_atomic_state,失败时为NULL。
atomic_state_clear
这个钩子必须清除任何复制到传入drm_atomic_state的驱动程序私有状态。这个钩子在调用者遇到drm_modeset_lock死锁时被调用,并且需要删除所有已经获得的锁,作为drm_modeset_backoff()中实现的避免死锁操作的一部分。
任何复制的状态都必须是无效的,因为并发的原子更新可能会更改它,而且当当前状态更改后,drm原子接口总是应用更新。
实现这个的驱动程序必须调用drm_atomic_state_default_clear()来清除公共状态。
不赞成继承drm_atomic_state,而赞成使用drm_private_state和drm_private_obj。
atomic_state_free
这个钩子需要驱动程序私有资源和drm_atomic_state本身。注意,核心首先调用drm_atomic_state_clear()来避免clear和free钩子之间的代码重复。
实现这个的驱动程序必须调用drm_atomic_state_default_release()来释放公共资源。
不赞成继承drm_atomic_state,而赞成使用drm_private_state和drm_private_obj.