aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdrivers/video/samsung/s3cfb.c47
-rw-r--r--drivers/video/samsung/s3cfb.h5
2 files changed, 52 insertions, 0 deletions
diff --git a/drivers/video/samsung/s3cfb.c b/drivers/video/samsung/s3cfb.c
index c45acfd..77e8420 100755
--- a/drivers/video/samsung/s3cfb.c
+++ b/drivers/video/samsung/s3cfb.c
@@ -29,6 +29,7 @@
#include <linux/io.h>
#include <linux/memory.h>
#include <linux/cpufreq.h>
+#include <linux/kthread.h>
#include <plat/clock.h>
#include <plat/cpu-freq.h>
#include <plat/media.h>
@@ -679,6 +680,16 @@ static int s3cfb_ioctl(struct fb_info *fb, unsigned int cmd, unsigned long arg)
}
break;
+ case S3CFB_SET_VSYNC_ACTIVE:
+ if (get_user(p.vsync, (int __user *)arg))
+ ret = -EFAULT;
+
+ fbdev->vsync_active = p.vsync;
+ wmb();
+ if (p.vsync)
+ wake_up(&fbdev->vsync_wq);
+ break;
+
case S3CFB_GET_CURR_FB_INFO:
next_fb_info.phy_start_addr = fix->smem_start;
next_fb_info.xres = var->xres;
@@ -918,6 +929,32 @@ static int s3cfb_sysfs_store_win_power(struct device *dev,
return len;
}
+static int s3cfb_wait_for_vsync_thread(void *data)
+{
+ struct s3cfb_global *fbdev = data;
+
+ while (!kthread_should_stop()) {
+ ktime_t prev_timestamp = fbdev->vsync_timestamp;
+ int ret = wait_event_interruptible_timeout(fbdev->vsync_wq,
+ s3cfb_vsync_timestamp_changed(fbdev,
+ prev_timestamp) &&
+ fbdev->vsync_active,
+ msecs_to_jiffies(100));
+ if (ret > 0) {
+ char *envp[2];
+ char buf[64];
+ snprintf(buf, sizeof(buf), "VSYNC=%llu",
+ ktime_to_ns(fbdev->vsync_timestamp));
+ envp[0] = buf;
+ envp[1] = NULL;
+ kobject_uevent_env(&fbdev->dev->kobj, KOBJ_CHANGE,
+ envp);
+ }
+ }
+
+ return 0;
+}
+
static DEVICE_ATTR(win_power, S_IRUGO | S_IWUSR,
s3cfb_sysfs_show_win_power, s3cfb_sysfs_store_win_power);
@@ -1056,6 +1093,13 @@ static int __devinit s3cfb_probe(struct platform_device *pdev)
register_early_suspend(&fbdev->early_suspend);
#endif
+ fbdev->vsync_thread = kthread_run(s3cfb_wait_for_vsync_thread,
+ fbdev, "s3cfb-vsync");
+ if (fbdev->vsync_thread == ERR_PTR(-ENOMEM)) {
+ dev_err(fbdev->dev, "failed to run vsync thread\n");
+ fbdev->vsync_thread = NULL;
+ }
+
ret = device_create_file(&(pdev->dev), &dev_attr_win_power);
if (ret < 0)
dev_err(fbdev->dev, "failed to add sysfs entries\n");
@@ -1148,6 +1192,9 @@ static int __devexit s3cfb_remove(struct platform_device *pdev)
regulator_disable(fbdev->regulator);
+ if (fbdev->vsync_thread)
+ kthread_stop(fbdev->vsync_thread);
+
kfree(fbdev->fb);
kfree(fbdev);
diff --git a/drivers/video/samsung/s3cfb.h b/drivers/video/samsung/s3cfb.h
index 3fb1956..d8297de 100644
--- a/drivers/video/samsung/s3cfb.h
+++ b/drivers/video/samsung/s3cfb.h
@@ -234,6 +234,10 @@ struct s3cfb_global {
wait_queue_head_t vsync_wq;
ktime_t vsync_timestamp;
+ bool vsync_active;
+
+ int vsync_state;
+ struct task_struct *vsync_thread;
/* fimd */
int enabled;
@@ -304,6 +308,7 @@ struct s3cfb_next_info {
struct s3cfb_user_chroma)
#define S3CFB_SET_VSYNC_INT _IOW('F', 206, u32)
#define S3CFB_GET_VSYNC_INT_STATUS _IOR('F', 207, u32)
+#define S3CFB_SET_VSYNC_ACTIVE _IOW('F', 208, u32)
#define S3CFB_GET_LCD_WIDTH _IOR('F', 302, int)
#define S3CFB_GET_LCD_HEIGHT _IOR('F', 303, int)
#define S3CFB_SET_WRITEBACK _IOW('F', 304, u32)