diff options
-rwxr-xr-x | drivers/video/samsung/s3cfb.c | 47 | ||||
-rw-r--r-- | drivers/video/samsung/s3cfb.h | 5 |
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) |