sdm: Add support for HDMI minimum HDCP encryption level change.
- Enable HDCP libraries to communicate with SDM via a qdutils API to
indicate change in encryption level.
- Write this change on HDMI file node to trigger driver.
Change-Id: I226d4e986081b97243c80ea30c16b05ea34499c4
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 7849d7f..8f77c66 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -280,6 +280,26 @@
return err;
}
+int minHdcpEncryptionLevelChanged(int dpy) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(dpy);
+
+ if(binder != NULL) {
+ err = binder->dispatch(IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED,
+ &inParcel, &outParcel);
+ }
+
+ if(err) {
+ ALOGE("%s: Failed for dpy %d err=%d", __FUNCTION__, dpy, err);
+ } else {
+ err = outParcel.readInt32();
+ }
+
+ return err;
+}
+
}// namespace
// ----------------------------------------------------------------------------
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 768fe6c..c5e7340 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -136,6 +136,11 @@
// Set the primary display mode to command or video mode
int setDisplayMode(int mode);
+// Notify change in minimum encryption level for HDCP
+// Return -1 on error.
+// Only HDMI display is supported as dpy for now
+int minHdcpEncryptionLevelChanged(int dpy);
+
//=============================================================================
// The functions and methods below run in the context of HWC and
// are called in response to binder calls from clients
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 4c0271a..df8e235 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -70,6 +70,7 @@
GET_DISPLAY_ATTRIBUTES_FOR_CONFIG = 28, //Get attr for specified config
SET_DISPLAY_MODE = 29, // Set display mode to command or video mode
SET_CAMERA_STATUS = 30, // To notify display when camera is on and off
+ MIN_HDCP_ENCRYPTION_LEVEL_CHANGED = 31,
COMMAND_LIST_END = 400,
};
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index 0c6f4fd..140ac77 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -373,6 +373,12 @@
*/
virtual DisplayError SetPanelBrightness(int level) = 0;
+ /*! @brief Method to notify display about change in min HDCP encryption level.
+
+ @return \link DisplayError \endlink
+ */
+ virtual DisplayError OnMinHdcpEncryptionLevelChange() = 0;
+
/*! @brief Method to route display API requests to color service.
@param[in] in_payload \link PPDisplayAPIPayload \endlink
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index ca81fdc..118c036 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -471,6 +471,10 @@
return kErrorNotSupported;
}
+DisplayError DisplayBase::OnMinHdcpEncryptionLevelChange() {
+ return kErrorNotSupported;
+}
+
void DisplayBase::AppendDump(char *buffer, uint32_t length) {
DumpImpl::AppendString(buffer, length, "\n-----------------------");
DumpImpl::AppendString(buffer, length, "\ndevice type: %u", display_type_);
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 6f75a27..75c1f8c 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -66,6 +66,7 @@
virtual DisplayError IsScalingValid(const LayerRect &crop, const LayerRect &dst, bool rotate90);
virtual bool IsUnderscanSupported();
virtual DisplayError SetPanelBrightness(int level);
+ virtual DisplayError OnMinHdcpEncryptionLevelChange();
virtual DisplayError ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload,
PPDisplayAPIPayload *out_payload,
PPPendingParams *pending_action);
diff --git a/sdm/libs/core/display_hdmi.cpp b/sdm/libs/core/display_hdmi.cpp
index c1ad8cd..dcabb7b 100644
--- a/sdm/libs/core/display_hdmi.cpp
+++ b/sdm/libs/core/display_hdmi.cpp
@@ -176,6 +176,11 @@
return DisplayBase::SetPanelBrightness(level);
}
+DisplayError DisplayHDMI::OnMinHdcpEncryptionLevelChange() {
+ SCOPE_LOCK(locker_);
+ return hw_hdmi_intf_->OnMinHdcpEncryptionLevelChange();
+}
+
int DisplayHDMI::GetBestConfig() {
uint32_t best_config_mode = 0;
HWDisplayAttributes *best = &display_attributes_[0];
diff --git a/sdm/libs/core/display_hdmi.h b/sdm/libs/core/display_hdmi.h
index f22eca4..8e96828 100644
--- a/sdm/libs/core/display_hdmi.h
+++ b/sdm/libs/core/display_hdmi.h
@@ -59,6 +59,7 @@
virtual DisplayError SetRefreshRate(uint32_t refresh_rate);
virtual bool IsUnderscanSupported();
virtual DisplayError SetPanelBrightness(int level);
+ virtual DisplayError OnMinHdcpEncryptionLevelChange();
virtual void AppendDump(char *buffer, uint32_t length);
virtual DisplayError SetCursorPosition(int x, int y);
diff --git a/sdm/libs/core/fb/hw_hdmi.cpp b/sdm/libs/core/fb/hw_hdmi.cpp
index 6ab3980..56b329a 100644
--- a/sdm/libs/core/fb/hw_hdmi.cpp
+++ b/sdm/libs/core/fb/hw_hdmi.cpp
@@ -376,6 +376,33 @@
return kErrorNone;
}
+DisplayError HWHDMI::OnMinHdcpEncryptionLevelChange() {
+ DisplayError error = kErrorNone;
+ int fd = -1;
+ char data[kMaxStringLength] = {'\0'};
+
+ snprintf(data, sizeof(data), "%s%d/hdcp2p2/min_level_change", fb_path_, fb_node_index_);
+
+ fd = Sys::open_(data, O_WRONLY);
+ if (fd < 0) {
+ DLOGW("File '%s' could not be opened.", data);
+ return kErrorHardware;
+ }
+
+ // write any value (1 here) on this fd to trigger level change.
+ snprintf(data, sizeof(data), "%d", 1);
+
+ ssize_t err = Sys::pwrite_(fd, data, strlen(data), 0);
+ if (err <= 0) {
+ DLOGE("Write failed, Error = %s", strerror(errno));
+ error = kErrorHardware;
+ }
+
+ Sys::close_(fd);
+
+ return error;
+}
+
HWScanSupport HWHDMI::MapHWScanSupport(uint32_t value) {
switch (value) {
// TODO(user): Read the scan type from driver defined values instead of hardcoding
@@ -396,7 +423,7 @@
void HWHDMI::ReadScanInfo() {
int scan_info_file = -1;
ssize_t len = -1;
- char data[4096] = {'\0'};
+ char data[kPageSize] = {'\0'};
snprintf(data, sizeof(data), "%s%d/scan_info", fb_path_, fb_node_index_);
scan_info_file = Sys::open_(data, O_RDONLY);
@@ -406,7 +433,7 @@
}
memset(&data[0], 0, sizeof(data));
- len = read(scan_info_file, data, sizeof(data) - 1);
+ len = Sys::pread_(scan_info_file, data, sizeof(data) - 1, 0);
if (len <= 0) {
Sys::close_(scan_info_file);
DLOGW("File %s%d/scan_info is empty.", fb_path_, fb_node_index_);
@@ -469,7 +496,8 @@
if (err <= 0) {
DLOGE("Write to res_info failed (%s)", strerror(errno));
}
- close(fd);
+
+ Sys::close_(fd);
}
// Reads the contents of res_info node into a buffer if the file is not empty
@@ -484,7 +512,8 @@
if ((bytes_read = Sys::pread_(fd, config_buffer, kPageSize, 0)) != 0) {
is_file_read = true;
}
- close(fd);
+
+ Sys::close_(fd);
DLOGI_IF(kTagDriverConfig, "bytes_read=%d is_file_read=%d", bytes_read, is_file_read);
diff --git a/sdm/libs/core/fb/hw_hdmi.h b/sdm/libs/core/fb/hw_hdmi.h
index 50d793d..2d2d557 100644
--- a/sdm/libs/core/fb/hw_hdmi.h
+++ b/sdm/libs/core/fb/hw_hdmi.h
@@ -45,6 +45,7 @@
virtual DisplayError GetHWScanInfo(HWScanInfo *scan_info);
virtual DisplayError GetVideoFormat(uint32_t config_index, uint32_t *video_format);
virtual DisplayError GetMaxCEAFormat(uint32_t *max_cea_format);
+ virtual DisplayError OnMinHdcpEncryptionLevelChange();
virtual DisplayError SetDisplayAttributes(uint32_t index);
virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index);
virtual DisplayError PowerOn();
diff --git a/sdm/libs/core/hw_hdmi_interface.h b/sdm/libs/core/hw_hdmi_interface.h
index 0d3d800..3b177b4 100644
--- a/sdm/libs/core/hw_hdmi_interface.h
+++ b/sdm/libs/core/hw_hdmi_interface.h
@@ -39,6 +39,7 @@
virtual DisplayError GetHWScanInfo(HWScanInfo *scan_info) = 0;
virtual DisplayError GetVideoFormat(uint32_t config_index, uint32_t *video_format) = 0;
virtual DisplayError GetMaxCEAFormat(uint32_t *max_cea_format) = 0;
+ virtual DisplayError OnMinHdcpEncryptionLevelChange() = 0;
protected:
virtual ~HWHDMIInterface() { }
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
index 14b4f3f..3f73064 100644
--- a/sdm/libs/hwc/hwc_display.cpp
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -1192,6 +1192,15 @@
return 0;
}
+int HWCDisplay::OnMinHdcpEncryptionLevelChange() {
+ DisplayError error = display_intf_->OnMinHdcpEncryptionLevelChange();
+ if (error != kErrorNone) {
+ DLOGE("Failed. Error = %d", error);
+ return -1;
+ }
+
+ return 0;
+}
void HWCDisplay::MarkLayersForGPUBypass(hwc_display_contents_1_t *content_list) {
for (size_t i = 0 ; i < (content_list->numHwLayers - 1); i++) {
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
index b546ee2..a7386a4 100644
--- a/sdm/libs/hwc/hwc_display.h
+++ b/sdm/libs/hwc/hwc_display.h
@@ -55,6 +55,7 @@
virtual void GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels);
virtual void GetPanelResolution(uint32_t *x_pixels, uint32_t *y_pixels);
virtual int SetDisplayStatus(uint32_t display_status);
+ virtual int OnMinHdcpEncryptionLevelChange();
virtual int Perform(uint32_t operation, ...);
virtual int SetCursorPosition(int x, int y);
virtual ~HWCDisplay() { }
diff --git a/sdm/libs/hwc/hwc_session.cpp b/sdm/libs/hwc/hwc_session.cpp
index 38b1eb8..af2d6f1 100644
--- a/sdm/libs/hwc/hwc_session.cpp
+++ b/sdm/libs/hwc/hwc_session.cpp
@@ -541,7 +541,11 @@
break;
case qService::IQService::QDCM_SVC_CMDS:
- status = QdcmCMDHandler(*input_parcel, output_parcel);
+ status = QdcmCMDHandler(input_parcel, output_parcel);
+ break;
+
+ case qService::IQService::MIN_HDCP_ENCRYPTION_LEVEL_CHANGED:
+ status = OnMinHdcpEncryptionLevelChange(input_parcel, output_parcel);
break;
case qService::IQService::CONTROL_PARTIAL_UPDATE:
@@ -784,7 +788,8 @@
}
}
-android::status_t HWCSession::QdcmCMDHandler(const android::Parcel &in, android::Parcel *out) {
+android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
int ret = 0;
int32_t *brightness_value = NULL;
uint32_t display_id(0);
@@ -792,7 +797,7 @@
PPDisplayAPIPayload resp_payload, req_payload;
// Read display_id, payload_size and payload from in_parcel.
- ret = HWCColorManager::CreatePayloadFromParcel(in, &display_id, &req_payload);
+ ret = HWCColorManager::CreatePayloadFromParcel(*input_parcel, &display_id, &req_payload);
if (!ret) {
if (HWC_DISPLAY_PRIMARY == display_id && hwc_display_[HWC_DISPLAY_PRIMARY])
ret = hwc_display_[HWC_DISPLAY_PRIMARY]->ColorSVCRequestRoute(req_payload,
@@ -804,7 +809,7 @@
}
if (ret) {
- out->writeInt32(ret); // first field in out parcel indicates return code.
+ output_parcel->writeInt32(ret); // first field in out parcel indicates return code.
req_payload.DestroyPayload();
resp_payload.DestroyPayload();
return ret;
@@ -847,14 +852,33 @@
}
// for display API getter case, marshall returned params into out_parcel.
- out->writeInt32(ret);
- HWCColorManager::MarshallStructIntoParcel(resp_payload, out);
+ output_parcel->writeInt32(ret);
+ HWCColorManager::MarshallStructIntoParcel(resp_payload, output_parcel);
req_payload.DestroyPayload();
resp_payload.DestroyPayload();
return (ret? -EINVAL : 0);
}
+android::status_t HWCSession::OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel) {
+ int ret = -EINVAL;
+ uint32_t display_id = UINT32(input_parcel->readInt32());
+
+ DLOGI("Display %d", display_id);
+ if (display_id != HWC_DISPLAY_EXTERNAL) {
+ DLOGW("Not supported for display %d", display_id);
+ } else if (!hwc_display_[display_id]) {
+ DLOGE("Display %d is not connected", display_id);
+ } else {
+ ret = hwc_display_[display_id]->OnMinHdcpEncryptionLevelChange();
+ }
+
+ output_parcel->writeInt32(ret);
+
+ return ret;
+}
+
void* HWCSession::HWCUeventThread(void *context) {
if (context) {
return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
diff --git a/sdm/libs/hwc/hwc_session.h b/sdm/libs/hwc/hwc_session.h
index a3ac07c..def7616 100644
--- a/sdm/libs/hwc/hwc_session.h
+++ b/sdm/libs/hwc/hwc_session.h
@@ -91,8 +91,11 @@
android::status_t SetSecondaryDisplayStatus(const android::Parcel *input_parcel);
android::status_t ControlBackLight(const android::Parcel *input_parcel);
android::status_t ConfigureRefreshRate(const android::Parcel *input_parcel);
- android::status_t QdcmCMDHandler(const android::Parcel &in, android::Parcel *out);
+ android::status_t QdcmCMDHandler(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel);
android::status_t ControlPartialUpdate(const android::Parcel *input_parcel, android::Parcel *out);
+ android::status_t OnMinHdcpEncryptionLevelChange(const android::Parcel *input_parcel,
+ android::Parcel *output_parcel);
static Locker locker_;
CoreInterface *core_intf_;