libexternal: Add support for changing resolution on HDMI

- set the property hdmi.resolution with the required mode
  (16,4,3,32,34,1)
- If that resolution is not supported by the TV, it will fall
  back to the best mode supported by the TV

Change-Id: I90ceda02319e79e388035ba7b5926bdcf6625595
CRs-fixed: 430055
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index b9abc31..1a41775 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -86,9 +86,16 @@
     if(mFd == -1)
         return -1;
     readResolution();
-    //Get the best mode and set
     // TODO: Move this to activate
-    setResolution(getBestMode());
+    /* Used for changing the resolution
+     * getUserMode will get the preferred
+     * mode set thru adb shell */
+    int mode = getUserMode();
+    if (mode == -1) {
+        //Get the best mode and set
+        mode = getBestMode();
+    }
+    setResolution(mode);
     setDpyHdmiAttr();
     setExternalDisplay(true, mHdmiFbNum);
     return 0;
@@ -385,6 +392,8 @@
 
 int ExternalDisplay::getModeOrder(int mode)
 {
+    // XXX: We dont support interlaced modes but having
+    // it here for for future
     switch (mode) {
         default:
         case m1440x480i60_4_3:
@@ -424,6 +433,20 @@
     }
 }
 
+/// Returns the user mode set(if any) using adb shell
+int ExternalDisplay::getUserMode() {
+    /* Based on the property set the resolution */
+    char property_value[PROPERTY_VALUE_MAX];
+    property_get("hdmi.resolution", property_value, "-1");
+    int mode = atoi(property_value);
+    // We dont support interlaced modes
+    if(isValidMode(mode) && !isInterlacedMode(mode)) {
+        ALOGD_IF("%s: setting the HDMI mode = %d", __FUNCTION__, mode);
+        return mode;
+    }
+    return -1;
+}
+
 // Get the best mode for the current HD TV
 int ExternalDisplay::getBestMode() {
     int bestOrder = 0;
@@ -443,7 +466,30 @@
 
 inline bool ExternalDisplay::isValidMode(int ID)
 {
-    return ((ID >= m640x480p60_4_3) && (ID <= m1920x1080p30_16_9));
+    bool valid = false;
+    for (int i = 0; i < mModeCount; i++) {
+        if(ID == mEDIDModes[i]) {
+            valid = true;
+            break;
+        }
+    }
+    return valid;
+}
+
+// returns true if the mode(ID) is interlaced mode format
+bool ExternalDisplay::isInterlacedMode(int ID) {
+    bool interlaced = false;
+    switch(ID) {
+        case m1440x480i60_4_3:
+        case m1440x480i60_16_9:
+        case m1440x576i50_4_3:
+        case m1440x576i50_16_9:
+        case m1920x1080i60_16_9:
+            interlaced = true;
+        default:
+            interlaced = false;
+    }
+    return interlaced;
 }
 
 void ExternalDisplay::setResolution(int ID)
@@ -462,7 +508,7 @@
             mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
             mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
             mVInfo.pixclock/1000/1000);
-    //If its a valid mode and its a new ID - update var_screeninfo
+    //If its a new ID - update var_screeninfo
     if ((isValidMode(ID)) && mCurrentMode != ID) {
         const struct disp_mode_timing_type *mode =
             &supported_video_mode_lut[0];