exynos3: Implement custom VSYNC IOCTL

* Replace crespo-based VSYNC uevent mechanism in hwcomposer
  with a custom IOCTL mechanism instead (required kernel
  modifications.

* The VSYNC uevents were spamming the Android UEventObserver
  and causing about 7% of constant CPU load

  c86856efabfa0b2981ceb47898dc5873a4998707

Improve custom VSYNC handler in hwcomposer

* only poll when necessary
* solves suspend/resume instability?

  45bf1dae7fa9057a3415151f7559e7bd2a162ead

Change-Id: Icdb5c60059e71688479d390b7b3a1f09a0315a5f
diff --git a/exynos3/s5pc110/libhwcomposer/SecHWC.cpp b/exynos3/s5pc110/libhwcomposer/SecHWC.cpp
index dda1108..31d25f4 100644
--- a/exynos3/s5pc110/libhwcomposer/SecHWC.cpp
+++ b/exynos3/s5pc110/libhwcomposer/SecHWC.cpp
@@ -453,6 +453,17 @@
     return 0;
 }
 
+#ifdef VSYNC_IOCTL
+// Linux version of a manual reset event to control when
+// and when not to ask the video card for a VSYNC.  This
+// stops the worker thread from asking for a VSYNC when
+// there is nothing useful to do with it and more closely
+// mimicks the original uevent mechanism
+int vsync_enable = 0;
+pthread_mutex_t vsync_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t vsync_condition = PTHREAD_COND_INITIALIZER;
+#endif
+
 static int hwc_eventControl(struct hwc_composer_device* dev,
         int event, int enabled)
 {
@@ -465,6 +476,18 @@
         if (err < 0)
             return -errno;
 
+#if VSYNC_IOCTL
+        // Enable or disable the ability for the worker thread
+        // to ask for VSYNC events from the video driver
+        pthread_mutex_lock(&vsync_mutex);
+        if(enabled) {
+            vsync_enable = 1;
+            pthread_cond_broadcast(&vsync_condition);
+        }
+        else vsync_enable = 0;
+        pthread_mutex_unlock(&vsync_mutex);
+#endif
+
         return 0;
     }
 
@@ -496,18 +519,47 @@
 static void *hwc_vsync_thread(void *data)
 {
     hwc_context_t *ctx = (hwc_context_t *)(data);
+#ifdef VSYNC_IOCTL
+    uint64_t timestamp = 0;
+#else
     char uevent_desc[4096];
     memset(uevent_desc, 0, sizeof(uevent_desc));
+#endif
 
     setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
 
+#ifndef VSYNC_IOCTL
     uevent_init();
+#endif
     while(true) {
+#ifdef VSYNC_IOCTL
+        // Only continue if hwc_eventControl is enabled, otherwise
+        // just sit here and wait until it is.  This stops the code
+        // from constantly looking for the VSYNC event with the screen
+        // turned off.
+        pthread_mutex_lock(&vsync_mutex);
+        if(!vsync_enable) pthread_cond_wait(&vsync_condition, &vsync_mutex);
+        pthread_mutex_unlock(&vsync_mutex);
+
+        timestamp = 0;          // Reset the timestamp value
+
+        // S3CFB_WAIT_FOR_VSYNC is a custom IOCTL I added to wait for
+        // the VSYNC interrupt, and then return the timestamp that was
+        // originally being communicated via a uevent.  The uevent was
+        // spamming the UEventObserver and events/0 process with more
+        // information than this device could really deal with every 18ms
+        int res = ioctl(ctx->global_lcd_win.fd, S3CFB_WAIT_FOR_VSYNC, &timestamp);
+        if(res > 0) {
+            if(!ctx->procs || !ctx->procs->vsync) continue;
+            ctx->procs->vsync(ctx->procs, 0, timestamp);
+        }
+#else
         int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
 
         bool vsync = !strcmp(uevent_desc, "change@/devices/platform/s3cfb");
         if(vsync)
             handle_vsync_uevent(ctx, uevent_desc, len);
+#endif
     }
 
     return NULL;