14a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh/* 24a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. 34a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* 44a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* Redistribution and use in source and binary forms, with or without 54a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* modification, are permitted provided that the following conditions are 64a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* met: 74a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* * Redistributions of source code must retain the above copyright 84a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* notice, this list of conditions and the following disclaimer. 94a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* * Redistributions in binary form must reproduce the above 104a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* copyright notice, this list of conditions and the following 114a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* disclaimer in the documentation and/or other materials provided 124a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* with the distribution. 134a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* * Neither the name of The Linux Foundation nor the names of its 144a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* contributors may be used to endorse or promote products derived 154a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* from this software without specific prior written permission. 164a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* 174a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 184a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 194a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 204a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 214a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 224a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 234a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 244a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 254a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 264a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 274a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 284a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh*/ 294a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 304a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <ctype.h> 314a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <math.h> 324a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <fcntl.h> 334a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <inttypes.h> 344a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <sys/types.h> 354a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <sys/stat.h> 364a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <sys/resource.h> 374a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <sys/prctl.h> 384a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <linux/msm_mdp.h> 394a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <utils/constants.h> 404a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include <utils/debug.h> 414a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#include "hw_color_manager.h" 424a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 434a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#define __CLASS__ "HWColorManager" 444a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 454a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanhnamespace sdm { 464a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 474a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain VongsouvanhDisplayError (*HWColorManager::SetFeature[])(const PPFeatureInfo &, msmfb_mdp_pp *) = { 484a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh [kGlobalColorFeaturePcc] = &HWColorManager::SetPCC, 494a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh [kGlobalColorFeatureIgc] = &HWColorManager::SetIGC, 504a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh [kGlobalColorFeaturePgc] = &HWColorManager::SetPGC, 514a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh [kMixerColorFeatureGc] = &HWColorManager::SetMixerGC, 524a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh [kGlobalColorFeaturePaV2] = &HWColorManager::SetPAV2, 534a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh [kGlobalColorFeatureDither] = &HWColorManager::SetDither, 544a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh [kGlobalColorFeatureGamut] = &HWColorManager::SetGamut, 554a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh [kGlobalColorFeaturePADither] = &HWColorManager::SetPADither, 564a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh}; 574a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 584a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain VongsouvanhDisplayError HWColorManager::SetPCC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { 594a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DisplayError ret = kErrorNone; 604a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 614a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->op = mdp_op_pcc_cfg; 624a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pcc_cfg_data.version = feature.feature_version_; 634a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pcc_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; 644a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pcc_cfg_data.ops = feature.enable_flags_; 654a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pcc_cfg_data.cfg_payload = feature.GetConfigData(); 664a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DLOGV_IF(kTagQDCM, "kernel params version = %d, block = %d, flags = %d", 674a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pcc_cfg_data.version, kernel_params->data.pcc_cfg_data.block, 684a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pcc_cfg_data.ops); 694a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 704a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh return ret; 714a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh} 724a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 734a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain VongsouvanhDisplayError HWColorManager::SetIGC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { 744a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DisplayError ret = kErrorNone; 754a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 764a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->op = mdp_op_lut_cfg; 774a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.lut_type = mdp_lut_igc; 784a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.igc_lut_data.block = 794a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; 804a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.igc_lut_data.version = feature.feature_version_; 814a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.igc_lut_data.ops = feature.enable_flags_; 824a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.igc_lut_data.cfg_payload = feature.GetConfigData(); 834a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 844a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh return ret; 854a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh} 864a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 874a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain VongsouvanhDisplayError HWColorManager::SetPGC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { 884a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DisplayError ret = kErrorNone; 894a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 904a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->op = mdp_op_lut_cfg; 914a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.lut_type = mdp_lut_pgc; 924a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.pgc_lut_data.version = feature.feature_version_; 934a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.pgc_lut_data.block = 944a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; 954a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.pgc_lut_data.flags = feature.enable_flags_; 964a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.pgc_lut_data.cfg_payload = feature.GetConfigData(); 974a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 984a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh return ret; 994a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh} 1004a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1014a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain VongsouvanhDisplayError HWColorManager::SetMixerGC(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { 1024a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DisplayError ret = kErrorNone; 1034a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1044a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->op = mdp_op_lut_cfg; 1054a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.lut_type = mdp_lut_pgc; 1064a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.pgc_lut_data.version = feature.feature_version_; 1074a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.pgc_lut_data.block = 1084a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh (MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_) | MDSS_PP_LM_CFG; 1094a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.pgc_lut_data.flags = feature.enable_flags_; 1104a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.lut_cfg_data.data.pgc_lut_data.cfg_payload = feature.GetConfigData(); 1114a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh return ret; 1124a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh} 1134a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1144a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain VongsouvanhDisplayError HWColorManager::SetPAV2(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { 1154a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DisplayError ret = kErrorNone; 1164a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1174a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->op = mdp_op_pa_v2_cfg; 1184a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pa_v2_cfg_data.version = feature.feature_version_; 1194a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pa_v2_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; 1204a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pa_v2_cfg_data.flags = feature.enable_flags_; 1214a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pa_v2_cfg_data.cfg_payload = feature.GetConfigData(); 1224a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DLOGV_IF(kTagQDCM, "kernel params version = %d, block = %d, flags = %d", 1234a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pa_v2_cfg_data.version, kernel_params->data.pa_v2_cfg_data.block, 1244a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.pa_v2_cfg_data.flags); 1254a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1264a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh return ret; 1274a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh} 1284a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1294a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain VongsouvanhDisplayError HWColorManager::SetDither(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { 1304a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DisplayError ret = kErrorNone; 1314a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1324a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->op = mdp_op_dither_cfg; 1334a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.dither_cfg_data.version = feature.feature_version_; 1344a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.dither_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; 1354a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.dither_cfg_data.flags = feature.enable_flags_; 1364a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.dither_cfg_data.cfg_payload = feature.GetConfigData(); 1374a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1384a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh return ret; 1394a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh} 1404a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1414a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain VongsouvanhDisplayError HWColorManager::SetGamut(const PPFeatureInfo &feature, msmfb_mdp_pp *kernel_params) { 1424a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DisplayError ret = kErrorNone; 1434a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1444a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->op = mdp_op_gamut_cfg; 1454a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.gamut_cfg_data.version = feature.feature_version_; 1464a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.gamut_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; 1474a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.gamut_cfg_data.flags = feature.enable_flags_; 1484a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.gamut_cfg_data.cfg_payload = feature.GetConfigData(); 1494a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1504a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh return ret; 1514a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh} 1524a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1534a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain VongsouvanhDisplayError HWColorManager::SetPADither(const PPFeatureInfo &feature, 1544a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh msmfb_mdp_pp *kernel_params) { 1554a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh DisplayError ret = kErrorNone; 1564a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#ifdef PA_DITHER 1574a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->op = mdp_op_pa_dither_cfg; 1584a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.dither_cfg_data.version = feature.feature_version_; 1594a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.dither_cfg_data.block = MDP_LOGICAL_BLOCK_DISP_0 + feature.disp_id_; 1604a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.dither_cfg_data.flags = feature.enable_flags_; 1614a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh kernel_params->data.dither_cfg_data.cfg_payload = feature.GetConfigData(); 1624a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh#endif 1634a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh return ret; 1644a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh} 1654a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh 1664a1efd0680d2e9b61739e1eaeffd89174d6d2605Alain Vongsouvanh} // namespace sdm 167