mutex_lock(&dev->struct_mutex);
- if (event && !dev_priv->pageflip_event) {
+ if (event) {
+ /*
+ * the pipe from user always is 0 so we can set pipe number
+ * of current owner to event.
+ */
+ event->pipe = exynos_crtc->pipe;
+
list_add_tail(&event->base.link,
&dev_priv->pageflip_event_list);
ret = drm_vblank_get(dev, exynos_crtc->pipe);
if (ret) {
DRM_DEBUG("failed to acquire vblank counter\n");
+ list_del(&event->base.link);
+
goto out;
}
if (ret) {
crtc->fb = old_fb;
drm_vblank_put(dev, exynos_crtc->pipe);
- dev_priv->pageflip_event = false;
+ list_del(&event->base.link);
goto out;
}
/*
* the values related to a buffer of the drm framebuffer
* to be applied should be set at here. because these values
- * first, is set to shadow registers and then to
+ * first, are set to shadow registers and then to
* real registers at vsync front porch period.
*/
exynos_drm_crtc_apply(crtc);
-
- dev_priv->pageflip_event = true;
}
out:
mutex_unlock(&dev->struct_mutex);
return 0;
}
+static void exynos_drm_preclose(struct drm_device *dev,
+ struct drm_file *file_priv)
+{
+ struct exynos_drm_private *dev_priv = dev->dev_private;
+
+ /*
+ * drm framework frees all events at release time,
+ * so private event list should be cleared.
+ */
+ if (!list_empty(&dev_priv->pageflip_event_list))
+ INIT_LIST_HEAD(&dev_priv->pageflip_event_list);
+}
+
static void exynos_drm_lastclose(struct drm_device *dev)
{
DRM_DEBUG_DRIVER("%s\n", __FILE__);
DRIVER_MODESET | DRIVER_GEM,
.load = exynos_drm_load,
.unload = exynos_drm_unload,
+ .preclose = exynos_drm_preclose,
.lastclose = exynos_drm_lastclose,
.get_vblank_counter = drm_vblank_count,
.enable_vblank = exynos_drm_crtc_enable_vblank,
struct exynos_drm_private {
struct drm_fb_helper *fb_helper;
- /* for pageflip */
+ /* list head for new event to be added. */
struct list_head pageflip_event_list;
- bool pageflip_event;
/*
* created crtc object would be contained at this array and
.disable = fimd_win_disable,
};
-/* for pageflip event */
static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
{
struct exynos_drm_private *dev_priv = drm_dev->dev_private;
struct drm_pending_vblank_event *e, *t;
struct timeval now;
unsigned long flags;
-
- if (!dev_priv->pageflip_event)
- return;
+ bool is_checked = false;
spin_lock_irqsave(&drm_dev->event_lock, flags);
list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
base.link) {
+ /* if event's pipe isn't same as crtc then ignor it. */
+ if (crtc != e->pipe)
+ continue;
+
+ is_checked = true;
+
do_gettimeofday(&now);
e->event.sequence = 0;
e->event.tv_sec = now.tv_sec;
wake_up_interruptible(&e->base.file_priv->event_wait);
}
- drm_vblank_put(drm_dev, crtc);
- dev_priv->pageflip_event = false;
+ if (is_checked)
+ drm_vblank_put(drm_dev, crtc);
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
}