hwc: Listen fb0 event for panel status

Listen fb0 status change event for panel status. fb0 will receive
"PANEL_ALIVE=0" when panel is not responding to status call.
Call blank and unblank to reset the panel in next hwc_prepare
call.

Change-Id: I941a501a82d9f3b725660ad09631c1d8602b7325
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 5038025..e9f2b31 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -54,6 +54,8 @@
     open: hwc_device_open
 };
 
+static void reset_panel(struct hwc_composer_device_1* dev);
+
 hwc_module_t HAL_MODULE_INFO_SYM = {
     common: {
         tag: HARDWARE_MODULE_TAG,
@@ -263,6 +265,12 @@
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+    if (ctx->mPanelResetStatus) {
+        ALOGW("%s: panel is in bad state. reset the panel", __FUNCTION__);
+        reset_panel(dev);
+    }
+
     //Will be unlocked at the end of set
     ctx->mDrawLock.lock();
     reset(ctx, numDisplays, displays);
@@ -430,6 +438,33 @@
     return ret;
 }
 
+static void reset_panel(struct hwc_composer_device_1* dev)
+{
+    int ret = 0;
+    hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+    if (!ctx->mPanelResetStatus)
+        return;
+
+    ALOGD("%s: calling BLANK DISPLAY", __FUNCTION__);
+    ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 1);
+    if (ret < 0) {
+        ALOGE("%s: FBIOBLANK failed to BLANK:  %s", __FUNCTION__,
+                                                            strerror(errno));
+    }
+
+    ALOGD("%s: calling UNBLANK DISPLAY and enabling vsync", __FUNCTION__);
+    ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 0);
+    if (ret < 0) {
+        ALOGE("%s: FBIOBLANK failed to UNBLANK : %s", __FUNCTION__,
+                                                            strerror(errno));
+    }
+    hwc_vsync_control(ctx, HWC_DISPLAY_PRIMARY, 1);
+
+    ctx->mPanelResetStatus = false;
+}
+
+
 static int hwc_query(struct hwc_composer_device_1* dev,
                      int param, int* value)
 {
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 8906216..926f425 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -85,6 +85,24 @@
     return -1;
 }
 
+static bool getPanelResetStatus(hwc_context_t* ctx, const char* strUdata, int len)
+{
+    const char* iter_str = strUdata;
+    if (strcasestr("change@/devices/virtual/graphics/fb0", strUdata)) {
+        while(((iter_str - strUdata) <= len) && (*iter_str)) {
+            char* pstr = strstr(iter_str, "PANEL_ALIVE=0");
+            if (pstr != NULL) {
+                ALOGE("%s: got change event in fb0 with PANEL_ALIVE=0",
+                                                           __FUNCTION__);
+                ctx->mPanelResetStatus = true;
+                return true;
+            }
+            iter_str += strlen(iter_str)+1;
+        }
+    }
+    return false;
+}
+
 /* Parse uevent data for action requested for the display */
 static int getConnectedState(const char* strUdata, int len)
 {
@@ -101,6 +119,11 @@
 
 static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
 {
+    bool bpanelReset = getPanelResetStatus(ctx, udata, len);
+    if (bpanelReset) {
+        return;
+    }
+
     int dpy = getConnectedDisplay(udata);
     if(dpy < 0) {
         ALOGD_IF(UEVENT_DEBUG, "%s: Not disp Event ", __FUNCTION__);
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index d281fb0..1f1953b 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -427,6 +427,9 @@
     bool mBufferMirrorMode;
 
     qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES];
+
+    // Panel reset flag will be set if BTA check fails
+    bool mPanelResetStatus;
 };
 
 namespace qhwc {