diff options
Diffstat (limited to 'livedisplay/impl/SDM.cpp')
| -rw-r--r-- | livedisplay/impl/SDM.cpp | 506 |
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; +} + +}; |
