summaryrefslogtreecommitdiffstats
path: root/livedisplay/impl/SDM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'livedisplay/impl/SDM.cpp')
-rw-r--r--livedisplay/impl/SDM.cpp506
1 files changed, 506 insertions, 0 deletions
diff --git a/livedisplay/impl/SDM.cpp b/livedisplay/impl/SDM.cpp
new file mode 100644
index 0000000..4788281
--- /dev/null
+++ b/livedisplay/impl/SDM.cpp
@@ -0,0 +1,506 @@
+/*
+** Copyright 2016, The CyanogenMod Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cutils/properties.h>
+
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "LiveDisplay-SDM"
+#include <utils/Log.h>
+
+#include "SDM.h"
+#include "Utils.h"
+
+namespace android {
+
+status_t SDM::loadVendorLibrary() {
+ if (mLibHandle != NULL) {
+ return OK;
+ }
+
+ mLibHandle = dlopen(SDM_DISP_LIB, RTLD_NOW);
+ if (mLibHandle == NULL) {
+ ALOGE("DLOPEN failed for %s", SDM_DISP_LIB);
+ return NO_INIT;
+ }
+
+ disp_api_init = (int32_t(*)(int64_t*, uint32_t))dlsym(mLibHandle, "disp_api_init");
+ if (disp_api_init == NULL) {
+ ALOGE("dlsym failed for disp_api_init");
+ goto fail;
+ }
+ disp_api_deinit = (int32_t(*)(int64_t, uint32_t))dlsym(mLibHandle, "disp_api_deinit");
+ if (disp_api_deinit == NULL) {
+ ALOGE("dlsym failed for disp_api_deinit");
+ goto fail;
+ }
+ disp_api_get_global_color_balance_range = (int32_t(*)(int64_t, uint32_t, void*))dlsym(
+ mLibHandle, "disp_api_get_global_color_balance_range");
+ if (disp_api_get_global_color_balance_range == NULL) {
+ ALOGE("dlsym failed for disp_api_get_global_color_balance_range");
+ goto fail;
+ }
+ disp_api_set_global_color_balance = (int32_t(*)(int64_t, uint32_t, int32_t, uint32_t))dlsym(
+ mLibHandle, "disp_api_set_global_color_balance");
+ if (disp_api_set_global_color_balance == NULL) {
+ ALOGE("dlsym failed for disp_api_set_global_color_balance");
+ goto fail;
+ }
+ disp_api_get_global_color_balance = (int32_t(*)(int64_t, uint32_t, int32_t*, uint32_t*))dlsym(
+ mLibHandle, "disp_api_get_global_color_balance");
+ if (disp_api_get_global_color_balance == NULL) {
+ ALOGE("dlsym failed for disp_api_get_global_color_balance");
+ goto fail;
+ }
+ disp_api_get_num_display_modes =
+ (int32_t(*)(int64_t, uint32_t, int32_t, int32_t*, uint32_t*))dlsym(
+ mLibHandle, "disp_api_get_num_display_modes");
+ if (disp_api_get_num_display_modes == NULL) {
+ ALOGE("dlsym failed for disp_api_get_num_display_modes");
+ goto fail;
+ }
+ disp_api_get_display_modes =
+ (int32_t(*)(int64_t, uint32_t, int32_t, void*, int32_t, uint32_t*))dlsym(
+ mLibHandle, "disp_api_get_display_modes");
+ if (disp_api_get_display_modes == NULL) {
+ ALOGE("dlsym failed for disp_api_get_display_modes");
+ goto fail;
+ }
+ disp_api_get_active_display_mode =
+ (int32_t(*)(int64_t, uint32_t, int32_t*, uint32_t*, uint32_t*))dlsym(
+ mLibHandle, "disp_api_get_active_display_mode");
+ if (disp_api_get_active_display_mode == NULL) {
+ ALOGE("dlsym failed for disp_api_get_active_display_mode");
+ goto fail;
+ }
+ disp_api_set_active_display_mode = (int32_t(*)(int64_t, uint32_t, int32_t, uint32_t))dlsym(
+ mLibHandle, "disp_api_set_active_display_mode");
+ if (disp_api_set_active_display_mode == NULL) {
+ ALOGE("dlsym failed for disp_api_set_active_display_mode");
+ goto fail;
+ }
+ disp_api_set_default_display_mode = (int32_t(*)(int64_t, uint32_t, int32_t, uint32_t))dlsym(
+ mLibHandle, "disp_api_set_default_display_mode");
+ if (disp_api_set_default_display_mode == NULL) {
+ ALOGE("dlsym failed for disp_api_set_default_display_mode");
+ goto fail;
+ }
+ disp_api_get_default_display_mode = (int32_t(*)(int64_t, uint32_t, int32_t*, uint32_t*))dlsym(
+ mLibHandle, "disp_api_get_default_display_mode");
+ if (disp_api_get_default_display_mode == NULL) {
+ ALOGE("dlsym failed for disp_api_get_default_display_mode");
+ goto fail;
+ }
+ disp_api_get_global_pa_range =
+ (int32_t(*)(int64_t, uint32_t, void*))dlsym(mLibHandle, "disp_api_get_global_pa_range");
+ if (disp_api_get_global_pa_range == NULL) {
+ ALOGE("dlsym failed for disp_api_get_global_pa_range");
+ goto fail;
+ }
+ disp_api_get_global_pa_config = (int32_t(*)(int64_t, uint32_t, uint32_t*, void*))dlsym(
+ mLibHandle, "disp_api_get_global_pa_config");
+ if (disp_api_get_global_pa_config == NULL) {
+ ALOGE("dlsym failed for disp_api_get_global_pa_config");
+ goto fail;
+ }
+ disp_api_set_global_pa_config = (int32_t(*)(int64_t, uint32_t, uint32_t, void*))dlsym(
+ mLibHandle, "disp_api_set_global_pa_config");
+ if (disp_api_set_global_pa_config == NULL) {
+ ALOGE("dlsym failed for disp_api_set_global_pa_config");
+ goto fail;
+ }
+ disp_api_get_feature_version = (int32_t(*)(int64_t, uint32_t, void*, uint32_t*))dlsym(
+ mLibHandle, "disp_api_get_feature_version");
+ if (disp_api_get_feature_version == NULL) {
+ ALOGE("dlsym failed for disp_api_get_feature_version");
+ goto fail;
+ }
+
+ return OK;
+
+fail:
+ ALOGE("Failed to link vendor library: %s", dlerror());
+ dlclose(mLibHandle);
+ mLibHandle = NULL;
+ return NO_INIT;
+}
+
+status_t SDM::initialize() {
+ status_t rc = loadVendorLibrary();
+ if (rc != OK) {
+ return rc;
+ }
+
+ rc = disp_api_init(&mHandle, 0);
+ if (rc != OK) {
+ return rc;
+ }
+
+ mActiveModeId = -1;
+
+ if (hasFeature(Feature::DISPLAY_MODES)) {
+ sp<DisplayMode> defMode = getDefaultDisplayMode();
+ if (defMode != nullptr) {
+ setDisplayMode(defMode->id, false);
+ }
+ }
+ return OK;
+}
+
+SDM::~SDM() {
+ if (mLibHandle != NULL) {
+ dlclose(mLibHandle);
+ }
+}
+
+status_t SDM::deinitialize() {
+ if (mLibHandle != NULL) {
+ disp_api_deinit(mHandle, 0);
+ mHandle = -1;
+ }
+ return OK;
+}
+
+status_t SDM::setAdaptiveBacklightEnabled(bool enabled) {
+ status_t rc = NO_INIT;
+ if (enabled == mCachedFOSSStatus) {
+ return OK;
+ }
+ char* buf = new char[DPPS_BUF_SIZE];
+ sprintf(buf, "%s", enabled ? FOSS_ON : FOSS_OFF);
+ if (Utils::sendDPPSCommand(buf, DPPS_BUF_SIZE) == OK) {
+ if (strncmp(buf, "Success", 7) == 0) {
+ rc = OK;
+ mCachedFOSSStatus = enabled;
+ }
+ }
+ delete buf;
+ return rc;
+}
+
+bool SDM::isAdaptiveBacklightEnabled() {
+ return mCachedFOSSStatus;
+}
+
+status_t SDM::getColorBalanceRange(Range& range) {
+ status_t rc = disp_api_get_global_color_balance_range(mHandle, 0, &range);
+ ALOGV("getColorBalanceRange: min=%d max=%d step=%d", range.min, range.max, range.step);
+ return rc;
+}
+
+status_t SDM::setColorBalance(int32_t balance) {
+ return disp_api_set_global_color_balance(mHandle, 0, balance, 0);
+}
+
+int32_t SDM::getColorBalance() {
+ int32_t value = -1;
+ uint32_t flags = 0;
+ if (disp_api_get_global_color_balance(mHandle, 0, &value, &flags) != 0) {
+ value = 0;
+ }
+ return value;
+}
+
+uint32_t SDM::getNumDisplayModes() {
+ uint32_t flags = 0;
+ int32_t count = 0;
+ if (disp_api_get_num_display_modes(mHandle, 0, 0, &count, &flags)) {
+ count = 0;
+ }
+ if (getLocalSRGBMode() != nullptr) {
+ count++;
+ }
+ return count;
+}
+
+status_t SDM::getDisplayModes(List<sp<DisplayMode>>& profiles) {
+ status_t rc = OK;
+ uint32_t flags = 0, i = 0;
+
+ uint32_t count = getNumDisplayModes();
+ if (!count) return rc;
+
+ sp<DisplayMode> srgb = getLocalSRGBMode();
+ uint32_t sdm_count = srgb == nullptr ? count : (count - 1);
+
+ struct sdm_mode {
+ int32_t id;
+ int32_t type;
+ int32_t len;
+ char* name;
+ };
+
+ sdm_mode* tmp = new sdm_mode[sdm_count];
+ memset(tmp, 0, sizeof(sdm_mode) * sdm_count);
+ for (i = 0; i < sdm_count; i++) {
+ tmp[i].id = -1;
+ tmp[i].name = new char[128];
+ tmp[i].len = 128;
+ }
+
+ rc = disp_api_get_display_modes(mHandle, 0, 0, tmp, sdm_count, &flags);
+ if (rc == 0) {
+ for (i = 0; i < sdm_count; i++) {
+ const sp<DisplayMode> m = new DisplayMode(tmp[i].id, tmp[i].name, tmp[i].len);
+ m->privFlags = PRIV_MODE_FLAG_SDM;
+ profiles.push_back(m);
+ delete tmp[i].name;
+ }
+ }
+ delete[] tmp;
+
+ if (srgb != nullptr) {
+ profiles.push_back(srgb);
+ }
+
+ return rc;
+}
+
+status_t SDM::setDisplayMode(int32_t modeID, bool makeDefault) {
+ status_t rc = OK;
+
+ if (modeID == mActiveModeId) {
+ return OK;
+ }
+
+ sp<DisplayMode> mode = getDisplayModeById(modeID);
+ if (mode == nullptr) {
+ return BAD_VALUE;
+ }
+
+ ALOGV("setDisplayMode: current mode=%d", mActiveModeId);
+
+ if (mActiveModeId >= 0) {
+ sp<DisplayMode> oldMode = getDisplayModeById(mActiveModeId);
+ ALOGV("setDisplayMode: oldMode=%d flags=%d", oldMode->id, oldMode->privFlags);
+ if (oldMode->privFlags == PRIV_MODE_FLAG_SYSFS ||
+ mode->privFlags == PRIV_MODE_FLAG_SYSFS) {
+ ALOGV("disabling old mode");
+ rc = setModeState(oldMode, false);
+ if (rc != OK) {
+ ALOGE("Failed to disable previous mode! err=%d", rc);
+ return rc;
+ }
+ }
+ }
+
+ rc = setModeState(mode, true);
+ if (rc == OK) {
+ mActiveModeId = mode->id;
+ if (makeDefault) {
+ rc = Utils::writeLocalModeId(mode->id);
+ if (rc != OK) {
+ ALOGE("failed to save mode! %d", rc);
+ return rc;
+ }
+ }
+ HSIC tmp;
+ rc = getPictureAdjustment(tmp);
+ if (rc != OK) {
+ ALOGE("failed to retrieve picture adjustment after mode setting!");
+ } else {
+ ALOGV("new default PA: %d %f %f %f %f", tmp.hue, tmp.saturation,
+ tmp.intensity, tmp.contrast, tmp.saturationThreshold);
+ mDefaultPictureAdjustment.setTo(tmp);
+ }
+ } else {
+ ALOGE("Failed to setModeState! err=%d", rc);
+ return rc;
+ }
+
+ ALOGV("setDisplayMode: %d default: %d flags: %d", modeID, makeDefault, mode->privFlags);
+ return OK;
+}
+
+sp<DisplayMode> SDM::getDisplayModeById(int32_t id) {
+ List<sp<DisplayMode>> profiles;
+ status_t rc = getDisplayModes(profiles);
+ if (rc == OK) {
+ for (List<sp<DisplayMode>>::iterator it = profiles.begin(); it != profiles.end(); ++it) {
+ const sp<DisplayMode> mode = *it;
+ if (id == mode->id) {
+ return mode;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+sp<DisplayMode> SDM::getCurrentDisplayMode() {
+ return getDisplayModeById(mActiveModeId);
+}
+
+sp<DisplayMode> SDM::getDefaultDisplayMode() {
+ int32_t id = 0;
+ if (Utils::readLocalModeId(&id) == OK && id >= 0) {
+ return getDisplayModeById(id);
+ }
+ return nullptr;
+}
+
+status_t SDM::setModeState(sp<DisplayMode> mode, bool state) {
+ uint32_t flags = 0;
+ int32_t id = 0;
+
+ if (mode->privFlags == PRIV_MODE_FLAG_SYSFS) {
+ ALOGV("sysfs node: %s state=%d", mode->privData.string(), state);
+ return Utils::writeInt(mode->privData.string(), state ? 1 : 0);
+ } else if (mode->privFlags == PRIV_MODE_FLAG_SDM) {
+ if (state) {
+ return disp_api_set_active_display_mode(mHandle, 0, mode->id, 0);
+ } else {
+ if (disp_api_get_default_display_mode(mHandle, 0, &id, &flags) == 0) {
+ ALOGV("set sdm mode to default: id=%d", id);
+ return disp_api_set_active_display_mode(mHandle, 0, id, 0);
+ }
+ }
+ }
+ return BAD_VALUE;
+}
+
+sp<DisplayMode> SDM::getLocalSRGBMode() {
+ char path[PATH_MAX];
+ sprintf(path, "%s", SRGB_NODE);
+
+ if (access(path, W_OK) != 0) {
+ return nullptr;
+ }
+ sp<DisplayMode> m = new DisplayMode(SRGB_NODE_ID, "srgb", 4);
+ m->privFlags = PRIV_MODE_FLAG_SYSFS;
+ m->privData.setTo(path);
+ return m;
+}
+
+status_t SDM::getPictureAdjustmentRanges(HSICRanges& ranges) {
+ hsic_ranges r;
+ memset(&r, 0, sizeof(struct hsic_ranges));
+
+ status_t rc = disp_api_get_global_pa_range(mHandle, 0, &r);
+ if (rc == OK) {
+ ranges.hue.min = r.hue.min;
+ ranges.hue.max = r.hue.max;
+ ranges.hue.step - r.hue.step;
+ ranges.saturation.min = r.saturation.min;
+ ranges.saturation.max = r.saturation.max;
+ ranges.saturation.step = r.saturation.step;
+ ranges.intensity.min = r.intensity.min;
+ ranges.intensity.max = r.intensity.max;
+ ranges.intensity.step = r.intensity.step;
+ ranges.contrast.min = r.contrast.min;
+ ranges.contrast.max = r.contrast.max;
+ ranges.contrast.step = r.contrast.step;
+ ranges.saturationThreshold.min = r.saturationThreshold.min;
+ ranges.saturationThreshold.max = r.saturationThreshold.max;
+ ranges.saturationThreshold.step = r.saturationThreshold.step;
+ }
+ return rc;
+}
+
+status_t SDM::getPictureAdjustment(HSIC& hsic) {
+ uint32_t enable = 0;
+ hsic_config config;
+ memset(&config, 0, sizeof(struct hsic_config));
+
+ status_t rc = disp_api_get_global_pa_config(mHandle, 0, &enable, &config);
+ if (rc == OK) {
+ hsic.hue = config.data.hue;
+ hsic.saturation = config.data.saturation;
+ hsic.intensity = config.data.intensity;
+ hsic.contrast = config.data.contrast;
+ hsic.saturationThreshold = config.data.saturationThreshold;
+ }
+ return rc;
+}
+
+status_t SDM::getDefaultPictureAdjustment(HSIC& hsic) {
+ hsic.setTo(mDefaultPictureAdjustment);
+ return OK;
+}
+
+status_t SDM::setPictureAdjustment(HSIC hsic) {
+ hsic_config config;
+ memset(&config, 0, sizeof(struct hsic_config));
+ config.data.hue = hsic.hue;
+ config.data.saturation = hsic.saturation;
+ config.data.intensity = hsic.intensity;
+ config.data.contrast = hsic.contrast;
+ config.data.saturationThreshold = hsic.saturationThreshold;
+
+ return disp_api_set_global_pa_config(mHandle, 0, 1, &config);
+}
+
+bool SDM::hasFeature(Feature feature) {
+ uint32_t id = 0, flags = 0;
+ struct version {
+ uint8_t x, y;
+ uint16_t z;
+ };
+ version v;
+
+ switch (feature) {
+ case Feature::DISPLAY_MODES:
+ id = 4;
+ break;
+ case Feature::COLOR_TEMPERATURE:
+ id = 3;
+ break;
+ case Feature::PICTURE_ADJUSTMENT:
+ id = 1;
+ case Feature::ADAPTIVE_BACKLIGHT:
+ if (property_get_int32("ro.qualcomm.foss", 0) > 0) {
+ return true;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ if (disp_api_get_feature_version(mHandle, id, &v, &flags) == 0) {
+ if (v.x > 0 || v.y > 0 || v.z > 0) {
+
+ // Color balance depends on calibration data in SDM
+ if (feature == Feature::DISPLAY_MODES ||
+ feature == Feature::COLOR_TEMPERATURE) {
+ if (getNumDisplayModes() > 0) {
+ // make sure the range isn't zero
+ if (feature == Feature::COLOR_TEMPERATURE) {
+ Range r;
+ if (getColorBalanceRange(r) == OK && r.isNonZero()) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+ } else if (feature == Feature::PICTURE_ADJUSTMENT) {
+ HSICRanges r;
+ if (getPictureAdjustmentRanges(r) == OK && r.isValid()) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+};