|
@@ -5398,15 +5398,23 @@ out:
|
|
|
int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|
|
void *data, struct drm_file *file_priv)
|
|
|
{
|
|
|
- struct drm_mode_crtc_page_flip *page_flip = data;
|
|
|
+ struct drm_mode_crtc_page_flip_target *page_flip = data;
|
|
|
struct drm_crtc *crtc;
|
|
|
struct drm_framebuffer *fb = NULL;
|
|
|
struct drm_pending_vblank_event *e = NULL;
|
|
|
- u32 target_vblank = 0;
|
|
|
+ u32 target_vblank = page_flip->sequence;
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
- if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
|
|
|
- page_flip->reserved != 0)
|
|
|
+ if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags
|
|
|
+ * can be specified
|
|
|
+ */
|
|
|
+ if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
|
|
|
return -EINVAL;
|
|
|
|
|
|
if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
|
|
@@ -5417,15 +5425,41 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
|
|
return -ENOENT;
|
|
|
|
|
|
if (crtc->funcs->page_flip_target) {
|
|
|
+ u32 current_vblank;
|
|
|
int r;
|
|
|
|
|
|
r = drm_crtc_vblank_get(crtc);
|
|
|
if (r)
|
|
|
return r;
|
|
|
|
|
|
- target_vblank = drm_crtc_vblank_count(crtc) +
|
|
|
- !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
|
|
|
- } else if (crtc->funcs->page_flip == NULL) {
|
|
|
+ current_vblank = drm_crtc_vblank_count(crtc);
|
|
|
+
|
|
|
+ switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
|
|
|
+ case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
|
|
|
+ if ((int)(target_vblank - current_vblank) > 1) {
|
|
|
+ DRM_DEBUG("Invalid absolute flip target %u, "
|
|
|
+ "must be <= %u\n", target_vblank,
|
|
|
+ current_vblank + 1);
|
|
|
+ drm_crtc_vblank_put(crtc);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
|
|
|
+ if (target_vblank != 0 && target_vblank != 1) {
|
|
|
+ DRM_DEBUG("Invalid relative flip target %u, "
|
|
|
+ "must be 0 or 1\n", target_vblank);
|
|
|
+ drm_crtc_vblank_put(crtc);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ target_vblank += current_vblank;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ target_vblank = current_vblank +
|
|
|
+ !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else if (crtc->funcs->page_flip == NULL ||
|
|
|
+ (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|