hwc: Add support for panel resolution switch

Add support for panel resolution switch. This feature makes use of
the Linux modedb feature that lists available modes in
/sys/class/graphics/fb0/modes and accepts a mode change when written
to /sys/class/graphics/fb0/mode

Clients can link to APIs exposed in display_config.h, these
internally resolve to binder calls into HWC. For debugging, mode
changes can be made over binder using shell commands.
adb shell service call display.qservice CODE ARGS
ARGS can include config index and display (only primary supported)

setActiveConfig():
adb shell service call display.qservice 25 i32 INDEX i32 0
getActiveConfig():
adb shell service call display.qservice 26 i32 0
getConfigCount():
adb shell service call display.qservice 27 i32 0
getDisplayAttributes():
adb shell service call display.qservice 28 i32 INDEX i32 0

Change-Id: I97d34cc9c0e521a3bd5c948eeea6d1e07db7b7ff
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 487ec77..9b1f81d 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -121,13 +121,8 @@
         Parcel* outParcel) {
     int dpy = inParcel->readInt32();
     outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
-    if (ctx->dpyAttr[dpy].customFBSize) {
-        outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new);
-        outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new);
-    } else {
-        outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
-        outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
-    }
+    outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
+    outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
     outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
     outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
     //XXX: Need to check what to return for HDMI
@@ -355,6 +350,121 @@
     }
 }
 
+static status_t setActiveConfig(hwc_context_t* ctx, const Parcel *inParcel,
+        Parcel *outParcel) {
+    uint32_t index = inParcel->readInt32();
+    int dpy = inParcel->readInt32();
+    //Currently only primary supported
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        return BAD_VALUE;
+    }
+
+    Configs *configs = Configs::getInstance();
+    if(configs == NULL) {
+        ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    if(configs->getActiveConfig() == index) {
+        ALOGI("%s(): Config %u is already set", __FUNCTION__, index);
+        return ALREADY_EXISTS;
+    }
+
+    ctx->mDrawLock.lock();
+    //Updates the necessary sysfs nodes and reads split info again which is
+    //needed to reinitialize composition resources.
+    if(configs->setActiveConfig(index) == false) {
+        ALOGE("%s(): Failed to set config %u", __FUNCTION__, index);
+        ctx->mDrawLock.unlock();
+        return UNKNOWN_ERROR;
+    }
+
+    qdutils::DisplayAttributes attr = configs->getAttributes(index);
+
+    ctx->dpyAttr[dpy].xres = attr.xres;
+    ctx->dpyAttr[dpy].yres = attr.yres;
+
+    ctx->dpyAttr[dpy].fbScaling = ((ctx->dpyAttr[dpy].xres !=
+            ctx->dpyAttr[dpy].xresFB) || (ctx->dpyAttr[dpy].yres !=
+            ctx->dpyAttr[dpy].yresFB));
+
+    destroyCompositionResources(ctx, dpy);
+    initCompositionResources(ctx, dpy);
+    ctx->dpyAttr[dpy].configSwitched = true;
+    ctx->mDrawLock.unlock();
+    ctx->proc->invalidate(ctx->proc);
+    return NO_ERROR;
+}
+
+static status_t getActiveConfig(hwc_context_t* ctx, const Parcel *inParcel,
+        Parcel *outParcel) {
+    Locker::Autolock _sl(ctx->mDrawLock);
+    int dpy = inParcel->readInt32();
+    //Currently only primary supported
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        return BAD_VALUE;
+    }
+
+    Configs *configs = Configs::getInstance();
+    if(configs == NULL) {
+        ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    outParcel->writeInt32(configs->getActiveConfig());
+    return NO_ERROR;
+}
+
+static status_t getConfigCount(hwc_context_t* ctx, const Parcel *inParcel,
+        Parcel *outParcel) {
+    Locker::Autolock _sl(ctx->mDrawLock);
+    int dpy = inParcel->readInt32();
+    //Currently only primary supported
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        return BAD_VALUE;
+    }
+
+    Configs *configs = Configs::getInstance();
+    if(configs == NULL) {
+        ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    outParcel->writeInt32(configs->getConfigCount());
+    return NO_ERROR;
+}
+
+static status_t getDisplayAttributesForConfig(hwc_context_t* ctx,
+        const Parcel *inParcel, Parcel *outParcel) {
+    Locker::Autolock _sl(ctx->mDrawLock);
+    uint32_t index = inParcel->readInt32();
+    int dpy = inParcel->readInt32();
+    //Currently only primary supported
+    if(dpy > HWC_DISPLAY_PRIMARY) {
+        return BAD_VALUE;
+    }
+
+    Configs *configs = Configs::getInstance();
+    if(configs == NULL) {
+        ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    //xres, yres are used from the Config class, we assume for now that the
+    //other params are the same. This might change in the future.
+    outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
+
+    qdutils::DisplayAttributes attr = configs->getAttributes(index);
+    outParcel->writeInt32(attr.xres);
+    outParcel->writeInt32(attr.yres);
+
+    outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
+    outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
+    outParcel->writeInt32(ctx->mMDP.panel);
+
+    return NO_ERROR;
+}
+
 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t ret = NO_ERROR;
@@ -418,6 +528,19 @@
         case IQService::SET_S3D_MODE:
             setS3DMode(mHwcContext, inParcel->readInt32());
             break;
+        case IQService::SET_ACTIVE_CONFIG:
+            ret = setActiveConfig(mHwcContext, inParcel, outParcel);
+            break;
+        case IQService::GET_ACTIVE_CONFIG:
+            ret = getActiveConfig(mHwcContext, inParcel, outParcel);
+            break;
+        case IQService::GET_CONFIG_COUNT:
+            ret = getConfigCount(mHwcContext, inParcel, outParcel);
+            break;
+        case IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
+            ret = getDisplayAttributesForConfig(mHwcContext, inParcel,
+                    outParcel);
+            break;
         default:
             ret = NO_ERROR;
     }