Merge "sde: Add support for HDMI"
diff --git a/displayengine/libs/core/comp_manager.cpp b/displayengine/libs/core/comp_manager.cpp
old mode 100755
new mode 100644
index 916d558..e7c52fc
--- a/displayengine/libs/core/comp_manager.cpp
+++ b/displayengine/libs/core/comp_manager.cpp
@@ -140,6 +140,11 @@
StrategyConstraints *constraints = &display_comp_ctx->constraints;
constraints->safe_mode = safe_mode_;
+
+ // TODO(user): Need to enable SDE Comp on HDMI
+ if (display_comp_ctx->display_type == kHDMI) {
+ constraints->max_layers = 1;
+ }
// If validation for the best available composition strategy with driver has failed, just
// fallback to safe mode composition e.g. GPU or video only.
if (UNLIKELY(hw_layers->info.flags)) {
diff --git a/displayengine/libs/core/display_base.cpp b/displayengine/libs/core/display_base.cpp
old mode 100755
new mode 100644
index 6099231..1d032bf
--- a/displayengine/libs/core/display_base.cpp
+++ b/displayengine/libs/core/display_base.cpp
@@ -45,12 +45,12 @@
DisplayError error = kErrorNone;
error = hw_intf_->Open(hw_device_type_, &hw_device_, this);
- if (UNLIKELY(error != kErrorNone)) {
+ if (error != kErrorNone) {
return error;
}
error = hw_intf_->GetNumDisplayAttributes(hw_device_, &num_modes_);
- if (UNLIKELY(error != kErrorNone)) {
+ if (error != kErrorNone) {
goto CleanupOnError;
}
@@ -62,16 +62,21 @@
for (uint32_t i = 0; i < num_modes_; i++) {
error = hw_intf_->GetDisplayAttributes(hw_device_, &display_attributes_[i], i);
- if (UNLIKELY(error != kErrorNone)) {
+ if (error != kErrorNone) {
goto CleanupOnError;
}
}
- active_mode_index_ = 0;
+ active_mode_index_ = GetBestConfig();
+
+ error = hw_intf_->SetDisplayAttributes(hw_device_, active_mode_index_);
+ if (error != kErrorNone) {
+ goto CleanupOnError;
+ }
error = comp_manager_->RegisterDisplay(display_type_, display_attributes_[active_mode_index_],
&display_comp_ctx_);
- if (UNLIKELY(error != kErrorNone)) {
+ if (error != kErrorNone) {
goto CleanupOnError;
}
@@ -104,25 +109,25 @@
DisplayError error = kErrorNone;
- if (UNLIKELY(!layer_stack)) {
+ if (!layer_stack) {
return kErrorParameters;
}
pending_commit_ = false;
- if (LIKELY(state_ == kStateOn)) {
+ if ((state_ == kStateOn)) {
// Clean hw layers for reuse.
hw_layers_.info.Reset();
hw_layers_.info.stack = layer_stack;
while (true) {
error = comp_manager_->Prepare(display_comp_ctx_, &hw_layers_);
- if (UNLIKELY(error != kErrorNone)) {
+ if (error != kErrorNone) {
break;
}
error = hw_intf_->Validate(hw_device_, &hw_layers_);
- if (LIKELY(error == kErrorNone)) {
+ if (error == kErrorNone) {
// Strategy is successful now, wait for Commit().
comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_);
pending_commit_ = true;
@@ -139,18 +144,18 @@
DisplayError error = kErrorNone;
- if (UNLIKELY(!layer_stack)) {
+ if (!layer_stack) {
return kErrorParameters;
}
- if (UNLIKELY(!pending_commit_)) {
+ if (!pending_commit_) {
DLOGE("Commit: Corresponding Prepare() is not called.");
return kErrorUndefined;
}
- if (LIKELY(state_ == kStateOn)) {
+ if (state_ == kStateOn) {
error = hw_intf_->Commit(hw_device_, &hw_layers_);
- if (LIKELY(error == kErrorNone)) {
+ if (error == kErrorNone) {
comp_manager_->PostCommit(display_comp_ctx_, &hw_layers_);
} else {
DLOGE("Unexpected error. Commit failed on driver.");
@@ -165,7 +170,7 @@
DisplayError DisplayBase::GetDisplayState(DisplayState *state) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!state)) {
+ if (!state) {
return kErrorParameters;
}
@@ -176,7 +181,7 @@
DisplayError DisplayBase::GetNumVariableInfoConfigs(uint32_t *count) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!count)) {
+ if (!count) {
return kErrorParameters;
}
@@ -188,7 +193,7 @@
DisplayError DisplayBase::GetConfig(DisplayConfigFixedInfo *fixed_info) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!fixed_info)) {
+ if (!fixed_info) {
return kErrorParameters;
}
@@ -198,7 +203,7 @@
DisplayError DisplayBase::GetConfig(DisplayConfigVariableInfo *variable_info, uint32_t mode) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!variable_info || mode >= num_modes_)) {
+ if (!variable_info || mode >= num_modes_) {
return kErrorParameters;
}
@@ -210,7 +215,7 @@
DisplayError DisplayBase::GetVSyncState(bool *enabled) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!enabled)) {
+ if (!enabled) {
return kErrorParameters;
}
@@ -224,7 +229,7 @@
DLOGI("Set state = %d", state);
- if (UNLIKELY(state == state_)) {
+ if (state == state_) {
DLOGI("Same state transition is requested.");
return kErrorNone;
}
@@ -253,7 +258,7 @@
break;
}
- if (UNLIKELY(error == kErrorNone)) {
+ if (error == kErrorNone) {
state_ = state;
}
@@ -262,8 +267,14 @@
DisplayError DisplayBase::SetConfig(uint32_t mode) {
SCOPE_LOCK(locker_);
+ DisplayError error = kErrorNone;
- return kErrorNone;
+ if (mode >= num_modes_) {
+ return kErrorParameters;
+ }
+ error = hw_intf_->SetDisplayAttributes(hw_device_, mode);
+
+ return error;
}
DisplayError DisplayBase::SetVSyncState(bool enable) {
@@ -349,5 +360,9 @@
rect_name, rect->left, rect->top, rect->right, rect->bottom);
}
+int DisplayBase::GetBestConfig() {
+ return (num_modes_ == 1) ? 0 : -1;
+}
+
} // namespace sde
diff --git a/displayengine/libs/core/display_base.h b/displayengine/libs/core/display_base.h
index 7eaa044..2a33988 100644
--- a/displayengine/libs/core/display_base.h
+++ b/displayengine/libs/core/display_base.h
@@ -61,6 +61,8 @@
void AppendRect(char *buffer, uint32_t length, const char *rect_name, LayerRect *rect);
protected:
+ virtual int GetBestConfig();
+
Locker locker_;
DisplayType display_type_;
DisplayEventHandler *event_handler_;
diff --git a/displayengine/libs/core/display_hdmi.cpp b/displayengine/libs/core/display_hdmi.cpp
old mode 100755
new mode 100644
index 48208bf..f7c42f4
--- a/displayengine/libs/core/display_hdmi.cpp
+++ b/displayengine/libs/core/display_hdmi.cpp
@@ -36,5 +36,36 @@
: DisplayBase(kHDMI, event_handler, kDeviceHDMI, hw_intf, comp_manager) {
}
+int DisplayHDMI::GetBestConfig() {
+ uint32_t best_config_mode = 0;
+ HWDisplayAttributes *best = &display_attributes_[0];
+ if (num_modes_ == 1) {
+ return best_config_mode;
+ }
+
+ // From the available configs, select the best
+ // Ex: 1920x1080@60Hz is better than 1920x1080@30 and 1920x1080@30 is better than 1280x720@60
+ for (uint32_t index = 1; index < num_modes_; index++) {
+ HWDisplayAttributes *current = &display_attributes_[index];
+ // compare the two modes: in the order of Resolution followed by refreshrate
+ if (current->y_pixels > best->y_pixels) {
+ best_config_mode = index;
+ } else if (current->y_pixels == best->y_pixels) {
+ if (current->x_pixels > best->x_pixels) {
+ best_config_mode = index;
+ } else if (current->x_pixels == best->x_pixels) {
+ if (current->vsync_period_ns < best->vsync_period_ns) {
+ best_config_mode = index;
+ }
+ }
+ }
+ if (best_config_mode == index) {
+ best = &display_attributes_[index];
+ }
+ }
+
+ return best_config_mode;
+}
+
} // namespace sde
diff --git a/displayengine/libs/core/display_hdmi.h b/displayengine/libs/core/display_hdmi.h
index 85f53fc..0bb9dc8 100644
--- a/displayengine/libs/core/display_hdmi.h
+++ b/displayengine/libs/core/display_hdmi.h
@@ -32,6 +32,7 @@
class DisplayHDMI : public DisplayBase {
public:
DisplayHDMI(DisplayEventHandler *event_handler, HWInterface *hw_intf, CompManager *comp_manager);
+ virtual int GetBestConfig();
};
} // namespace sde
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
old mode 100755
new mode 100644
index 69b4a58..1c2ea1e
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -23,7 +23,7 @@
*/
#define __STDC_FORMAT_MACROS
-
+#include <ctype.h>
#include <math.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -41,7 +41,8 @@
#define __CLASS__ "HWFrameBuffer"
-#define IOCTL_LOGE(ioctl) DLOGE("ioctl %s, errno = %d, desc = %s", #ioctl, errno, strerror(errno))
+#define IOCTL_LOGE(ioctl, type) DLOGE("ioctl %s, display = %d errno = %d, desc = %s", #ioctl, \
+ type, errno, strerror(errno))
#ifdef DISPLAY_CORE_VIRTUAL_DRIVER
extern int virtual_ioctl(int fd, int cmd, ...);
@@ -52,12 +53,16 @@
extern FILE* virtual_fopen(const char *fname, const char *mode);
extern int virtual_fclose(FILE* fileptr);
extern ssize_t virtual_getline(char **lineptr, size_t *linelen, FILE *stream);
+extern ssize_t virtual_read(int fd, void *buf, size_t count);
+extern ssize_t virtual_write(int fd, const void *buf, size_t count);
+
#endif
namespace sde {
HWFrameBuffer::HWFrameBuffer() : event_thread_name_("SDE_EventThread"), fake_vsync_(false),
- exit_threads_(false), fb_path_("/sys/class/graphics/fb") {
+ exit_threads_(false), fb_path_("/sys/devices/virtual/graphics/fb"),
+ hotplug_enabled_(false) {
// Pointer to actual driver interfaces.
ioctl_ = ::ioctl;
open_ = ::open;
@@ -67,6 +72,8 @@
fopen_ = ::fopen;
fclose_ = ::fclose;
getline_ = ::getline;
+ read_ = ::read;
+ write_ = ::write;
#ifdef DISPLAY_CORE_VIRTUAL_DRIVER
// If debug property to use virtual driver is set, point to virtual driver interfaces.
@@ -79,6 +86,8 @@
fopen_ = virtual_fopen;
fclose_ = virtual_fclose;
getline_ = virtual_getline;
+ read_ = ::virtual_read;
+ write_ = ::virtual_write;
}
#endif
for (int i = 0; i < kDeviceMax; i++) {
@@ -137,6 +146,16 @@
}
}
+ // Mode look-up table for HDMI
+ supported_video_modes_ = new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
+ if (!supported_video_modes_) {
+ error = kErrorMemory;
+ goto CleanupOnError;
+ }
+ // Populate the mode table for supported modes
+ MSM_HDMI_MODES_INIT_TIMINGS(supported_video_modes_);
+ MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_modes_, MSM_HDMI_MODES_ALL);
+
// Start the Event thread
if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) {
DLOGE("Failed to start %s, error = %s", event_thread_name_);
@@ -156,6 +175,9 @@
}
}
}
+ if (supported_video_modes_) {
+ delete supported_video_modes_;
+ }
return error;
}
@@ -169,6 +191,9 @@
close(poll_fds_[display][event].fd);
}
}
+ if (supported_video_modes_) {
+ delete supported_video_modes_;
+ }
return kErrorNone;
}
@@ -183,27 +208,27 @@
DisplayError error = kErrorNone;
HWContext *hw_context = new HWContext();
- if (UNLIKELY(!hw_context)) {
+ if (!hw_context) {
return kErrorMemory;
}
char device_name[64] = {0};
switch (type) {
- case kDevicePrimary:
- case kDeviceHDMI:
- // Store EventHandlers for two Physical displays, i.e., Primary and HDMI
- // TODO(user): Need to revisit for HDMI as Primary usecase
- event_handler_[type] = eventhandler;
- case kDeviceVirtual:
- snprintf(device_name, sizeof(device_name), "%s%d", "/dev/graphics/fb", fb_node_index_[type]);
- break;
- default:
- break;
+ case kDevicePrimary:
+ case kDeviceHDMI:
+ // Store EventHandlers for two Physical displays, i.e., Primary and HDMI
+ // TODO(user): Need to revisit for HDMI as Primary usecase
+ event_handler_[type] = eventhandler;
+ case kDeviceVirtual:
+ snprintf(device_name, sizeof(device_name), "%s%d", "/dev/graphics/fb", fb_node_index_[type]);
+ break;
+ default:
+ break;
}
hw_context->device_fd = open_(device_name, O_RDWR);
- if (UNLIKELY(hw_context->device_fd < 0)) {
+ if (hw_context->device_fd < 0) {
DLOGE("open %s failed.", device_name);
error = kErrorResources;
delete hw_context;
@@ -218,7 +243,19 @@
DisplayError HWFrameBuffer::Close(Handle device) {
HWContext *hw_context = reinterpret_cast<HWContext *>(device);
- close_(hw_context->device_fd);
+ switch (hw_context->type) {
+ case kDevicePrimary:
+ break;
+ case kDeviceHDMI:
+ hdmi_mode_count_ = 0;
+ break;
+ default:
+ break;
+ }
+
+ if (hw_context->device_fd > 0) {
+ close_(hw_context->device_fd);
+ }
delete hw_context;
return kErrorNone;
@@ -227,8 +264,19 @@
DisplayError HWFrameBuffer::GetNumDisplayAttributes(Handle device, uint32_t *count) {
HWContext *hw_context = reinterpret_cast<HWContext *>(device);
- // TODO(user): Query modes
- *count = 1;
+ switch (hw_context->type) {
+ case kDevicePrimary:
+ *count = 1;
+ break;
+ case kDeviceHDMI:
+ *count = GetHDMIModeCount();
+ if (*count <= 0) {
+ return kErrorHardware;
+ }
+ break;
+ default:
+ return kErrorParameters;
+ }
return kErrorNone;
}
@@ -238,63 +286,160 @@
uint32_t mode) {
HWContext *hw_context = reinterpret_cast<HWContext *>(device);
int &device_fd = hw_context->device_fd;
-
- // TODO(user): Query for respective mode index.
-
// Variable screen info
STRUCT_VAR(fb_var_screeninfo, var_screeninfo);
- if (UNLIKELY(ioctl_(device_fd, FBIOGET_VSCREENINFO, &var_screeninfo) == -1)) {
- IOCTL_LOGE(FBIOGET_VSCREENINFO);
- return kErrorHardware;
- }
- // Frame rate
- STRUCT_VAR(msmfb_metadata, meta_data);
- meta_data.op = metadata_op_frame_rate;
- if (UNLIKELY(ioctl_(device_fd, MSMFB_METADATA_GET, &meta_data) == -1)) {
- IOCTL_LOGE(MSMFB_METADATA_GET);
- return kErrorHardware;
- }
+ switch (hw_context->type) {
+ case kDevicePrimary:
+ {
+ if (ioctl_(device_fd, FBIOGET_VSCREENINFO, &var_screeninfo) == -1) {
+ IOCTL_LOGE(FBIOGET_VSCREENINFO, hw_context->type);
+ return kErrorHardware;
+ }
- // If driver doesn't return width/height information, default to 160 dpi
- if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
- var_screeninfo.width = INT((FLOAT(var_screeninfo.xres) * 25.4f)/160.0f + 0.5f);
- var_screeninfo.height = INT((FLOAT(var_screeninfo.yres) * 25.4f)/160.0f + 0.5f);
- }
+ // Frame rate
+ STRUCT_VAR(msmfb_metadata, meta_data);
+ meta_data.op = metadata_op_frame_rate;
+ if (ioctl_(device_fd, MSMFB_METADATA_GET, &meta_data) == -1) {
+ IOCTL_LOGE(MSMFB_METADATA_GET, hw_context->type);
+ return kErrorHardware;
+ }
- display_attributes->x_pixels = var_screeninfo.xres;
- display_attributes->y_pixels = var_screeninfo.yres;
- display_attributes->x_dpi = (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width);
- display_attributes->y_dpi = (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height);
- display_attributes->vsync_period_ns =
- UINT32(1000000000L / FLOAT(meta_data.data.panel_frame_rate));
+ // If driver doesn't return width/height information, default to 160 dpi
+ if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
+ var_screeninfo.width = INT(((FLOAT(var_screeninfo.xres) * 25.4f)/160.0f) + 0.5f);
+ var_screeninfo.height = INT(((FLOAT(var_screeninfo.yres) * 25.4f)/160.0f) + 0.5f);
+ }
- display_attributes->is_device_split = ((var_screeninfo.xres > hw_resource_.max_mixer_width) ||
- (hw_resource_.split_info.right_split)) ? true : false;
- if (display_attributes->is_device_split) {
- display_attributes->split_left = hw_resource_.split_info.left_split ?
- hw_resource_.split_info.left_split : display_attributes->x_pixels / 2;
+ display_attributes->x_pixels = var_screeninfo.xres;
+ display_attributes->y_pixels = var_screeninfo.yres;
+ display_attributes->x_dpi =
+ (FLOAT(var_screeninfo.xres) * 25.4f) / FLOAT(var_screeninfo.width);
+ display_attributes->y_dpi =
+ (FLOAT(var_screeninfo.yres) * 25.4f) / FLOAT(var_screeninfo.height);
+ display_attributes->vsync_period_ns =
+ UINT32(1000000000L / FLOAT(meta_data.data.panel_frame_rate));
+ display_attributes->is_device_split = (hw_resource_.split_info.left_split ||
+ (var_screeninfo.xres > hw_resource_.max_mixer_width)) ? true : false;
+ display_attributes->split_left = hw_resource_.split_info.left_split ?
+ hw_resource_.split_info.left_split : display_attributes->x_pixels / 2;
+ }
+ break;
+
+ case kDeviceHDMI:
+ {
+ // Get the resolution info from the look up table
+ msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
+ for (int i = 0; i < HDMI_VFRMT_MAX; i++) {
+ msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
+ if (cur->video_format == hdmi_modes_[mode]) {
+ timing_mode = cur;
+ break;
+ }
+ }
+ display_attributes->x_pixels = timing_mode->active_h;
+ display_attributes->y_pixels = timing_mode->active_v;
+ display_attributes->x_dpi = 0;
+ display_attributes->y_dpi = 0;
+ display_attributes->vsync_period_ns =
+ UINT32(1000000000L / FLOAT(timing_mode->refresh_rate));
+ display_attributes->split_left = display_attributes->x_pixels;
+ if (display_attributes->x_pixels > hw_resource_.max_mixer_width) {
+ display_attributes->is_device_split = true;
+ display_attributes->split_left = display_attributes->x_pixels / 2;
+ }
+ }
+ break;
+
+ default:
+ return kErrorParameters;
}
return kErrorNone;
}
+DisplayError HWFrameBuffer::SetDisplayAttributes(Handle device, uint32_t mode) {
+ HWContext *hw_context = reinterpret_cast<HWContext *>(device);
+ DisplayError error = kErrorNone;
+
+ switch (hw_context->type) {
+ case kDevicePrimary:
+ break;
+
+ case kDeviceHDMI:
+ {
+ // Variable screen info
+ STRUCT_VAR(fb_var_screeninfo, vscreeninfo);
+ if (ioctl_(hw_context->device_fd, FBIOGET_VSCREENINFO, &vscreeninfo) == -1) {
+ IOCTL_LOGE(FBIOGET_VSCREENINFO, hw_context->type);
+ return kErrorHardware;
+ }
+
+ DLOGI("GetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3],
+ vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
+ vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
+ vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
+
+ msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[0];
+ for (int i = 0; i < HDMI_VFRMT_MAX; i++) {
+ msm_hdmi_mode_timing_info *cur = &supported_video_modes_[i];
+ if (cur->video_format == hdmi_modes_[mode]) {
+ timing_mode = cur;
+ break;
+ }
+ }
+ if (MapHDMIDisplayTiming(timing_mode, &vscreeninfo) == false) {
+ return kErrorParameters;
+ }
+ STRUCT_VAR(msmfb_metadata, metadata);
+ memset(&metadata, 0 , sizeof(metadata));
+ metadata.op = metadata_op_vic;
+ metadata.data.video_info_code = timing_mode->video_format;
+ if (ioctl(hw_context->device_fd, MSMFB_METADATA_SET, &metadata) == -1) {
+ IOCTL_LOGE(MSMFB_METADATA_SET, hw_context->type);
+ return kErrorHardware;
+ }
+ DLOGI("SetInfo<Mode=%d %dx%d (%d,%d,%d),(%d,%d,%d) %dMHz>", vscreeninfo.reserved[3] & 0xFF00,
+ vscreeninfo.xres, vscreeninfo.yres, vscreeninfo.right_margin, vscreeninfo.hsync_len,
+ vscreeninfo.left_margin, vscreeninfo.lower_margin, vscreeninfo.vsync_len,
+ vscreeninfo.upper_margin, vscreeninfo.pixclock/1000000);
+
+ vscreeninfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
+ if (ioctl_(hw_context->device_fd, FBIOPUT_VSCREENINFO, &vscreeninfo) == -1) {
+ IOCTL_LOGE(FBIOGET_VSCREENINFO, hw_context->type);
+ return kErrorHardware;
+ }
+ }
+ break;
+
+ default:
+ return kErrorParameters;
+ }
+
+ return error;
+}
+
DisplayError HWFrameBuffer::PowerOn(Handle device) {
HWContext *hw_context = reinterpret_cast<HWContext *>(device);
- if (UNLIKELY(ioctl_(hw_context->device_fd, FBIOBLANK, FB_BLANK_UNBLANK) == -1)) {
- IOCTL_LOGE(FB_BLANK_UNBLANK);
+ if (ioctl_(hw_context->device_fd, FBIOBLANK, FB_BLANK_UNBLANK) == -1) {
+ IOCTL_LOGE(FB_BLANK_UNBLANK, hw_context->type);
return kErrorHardware;
}
+ // Need to turn on HPD
+ if (!hotplug_enabled_) {
+ hotplug_enabled_ = EnableHotPlugDetection(1);
+ }
+
return kErrorNone;
}
DisplayError HWFrameBuffer::PowerOff(Handle device) {
HWContext *hw_context = reinterpret_cast<HWContext *>(device);
- if (UNLIKELY(ioctl_(hw_context->device_fd, FBIOBLANK, FB_BLANK_POWERDOWN) == -1)) {
- IOCTL_LOGE(FB_BLANK_POWERDOWN);
+ if (ioctl_(hw_context->device_fd, FBIOBLANK, FB_BLANK_POWERDOWN) == -1) {
+ IOCTL_LOGE(FB_BLANK_POWERDOWN, hw_context->type);
return kErrorHardware;
}
@@ -317,7 +462,7 @@
HWContext *hw_context = reinterpret_cast<HWContext *>(device);
int vsync_on = enable ? 1 : 0;
if (ioctl_(hw_context->device_fd, MSMFB_OVERLAY_VSYNC_CTRL, &vsync_on) == -1) {
- IOCTL_LOGE(MSMFB_OVERLAY_VSYNC_CTRL);
+ IOCTL_LOGE(MSMFB_OVERLAY_VSYNC_CTRL, hw_context->type);
return kErrorHardware;
}
@@ -342,47 +487,35 @@
Layer &layer = stack->layers[layer_index];
LayerBuffer *input_buffer = layer.input_buffer;
HWLayerConfig &config = hw_layers->config[i];
- HWPipeInfo &left_pipe = config.left_pipe;
- // Configure left pipe
- mdp_input_layer &mdp_layer_left = mdp_layers[mdp_layer_count];
- mdp_layer_left.alpha = layer.plane_alpha;
- mdp_layer_left.z_order = static_cast<uint16_t>(i);
- mdp_layer_left.transp_mask = 0xffffffff;
- SetBlending(layer.blending, &mdp_layer_left.blend_op);
- SetRect(left_pipe.src_roi, &mdp_layer_left.src_rect);
- SetRect(left_pipe.dst_roi, &mdp_layer_left.dst_rect);
- mdp_layer_left.pipe_ndx = left_pipe.pipe_id;
+ uint32_t split_count = hw_layers->config[i].is_right_pipe ? 2 : 1;
+ for (uint32_t j = 0; j < split_count; j++) {
+ HWPipeInfo &pipe = (j == 0) ? config.left_pipe : config.right_pipe;
+ mdp_input_layer &mdp_layer = mdp_layers[mdp_layer_count];
+ mdp_layer.alpha = layer.plane_alpha;
+ mdp_layer.z_order = static_cast<uint16_t>(i);
+ mdp_layer.transp_mask = 0xffffffff;
+ SetBlending(layer.blending, &mdp_layer.blend_op);
+ SetRect(pipe.src_roi, &mdp_layer.src_rect);
+ SetRect(pipe.dst_roi, &mdp_layer.dst_rect);
- mdp_layer_buffer &mdp_buffer_left = mdp_layer_left.buffer;
- mdp_buffer_left.width = input_buffer->width;
- mdp_buffer_left.height = input_buffer->height;
+ mdp_layer.pipe_ndx = pipe.pipe_id;
- error = SetFormat(layer.input_buffer->format, &mdp_buffer_left.format);
- if (error != kErrorNone) {
- return error;
- }
+ mdp_layer_buffer &mdp_buffer_left = mdp_layer.buffer;
+ mdp_buffer_left.width = input_buffer->width;
+ mdp_buffer_left.height = input_buffer->height;
- mdp_layer_count++;
-
- // Configure right pipe
- if (config.is_right_pipe) {
- HWPipeInfo &right_pipe = config.right_pipe;
- mdp_input_layer &mdp_layer_right = mdp_layers[mdp_layer_count];
-
- mdp_layer_right = mdp_layer_left;
-
- mdp_layer_right.pipe_ndx = right_pipe.pipe_id;
- SetRect(right_pipe.src_roi, &mdp_layer_right.src_rect);
- SetRect(right_pipe.dst_roi, &mdp_layer_right.dst_rect);
-
+ error = SetFormat(layer.input_buffer->format, &mdp_buffer_left.format);
+ if (error != kErrorNone) {
+ return error;
+ }
mdp_layer_count++;
}
}
mdp_commit.flags |= MDP_VALIDATE_LAYER;
if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_context->mdp_commit) == -1) {
- IOCTL_LOGE(MSMFB_ATOMIC_COMMIT);
+ IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
return kErrorHardware;
}
@@ -424,7 +557,7 @@
mdp_commit.flags |= MDP_COMMIT_RETIRE_FENCE;
mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_context->mdp_commit) == -1) {
- IOCTL_LOGE(MSMFB_ATOMIC_COMMIT);
+ IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
return kErrorHardware;
}
@@ -619,8 +752,8 @@
ssize_t read;
char *line = stringbuffer;
while ((read = getline_(&line, &len, fileptr)) != -1) {
- int token_count = 0;
- const int max_count = 10;
+ uint32_t token_count = 0;
+ const uint32_t max_count = 10;
char *tokens[max_count] = { NULL };
if (!ParseLine(line, tokens, max_count, &token_count)) {
if (!strncmp(tokens[0], "pu_en", strlen("pu_en"))) {
@@ -656,8 +789,8 @@
DisplayError error = kErrorNone;
FILE *fileptr = NULL;
char stringbuffer[kMaxStringLength];
- int token_count = 0;
- const int max_count = 10;
+ uint32_t token_count = 0;
+ const uint32_t max_count = 10;
char *tokens[max_count] = { NULL };
snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/mdp/caps", fb_path_,
fb_node_index_[kHWPrimary]);
@@ -698,7 +831,7 @@
} else if (!strncmp(tokens[0], "max_mixer_width", strlen("max_mixer_width"))) {
hw_resource_.max_mixer_width = atoi(tokens[1]);
} else if (!strncmp(tokens[0], "features", strlen("features"))) {
- for (int i = 0; i < token_count; i++) {
+ for (uint32_t i = 0; i < token_count; i++) {
if (!strncmp(tokens[i], "bwc", strlen("bwc"))) {
hw_resource_.has_bwc = true;
} else if (!strncmp(tokens[i], "decimation", strlen("decimation"))) {
@@ -767,10 +900,11 @@
return error;
}
-int HWFrameBuffer::ParseLine(char *input, char *tokens[], int max_token, int *count) {
+int HWFrameBuffer::ParseLine(char *input, char *tokens[], const uint32_t max_token,
+ uint32_t *count) {
char *tmp_token = NULL;
char *temp_ptr;
- int index = 0;
+ uint32_t index = 0;
const char *delim = ", =\n";
if (!input) {
return -1;
@@ -785,4 +919,87 @@
return 0;
}
+bool HWFrameBuffer::EnableHotPlugDetection(int enable) {
+ bool ret_value = true;
+ char hpdpath[kMaxStringLength];
+ snprintf(hpdpath , sizeof(hpdpath), "%s%d/hpd", fb_path_, fb_node_index_[kDeviceHDMI]);
+ int hpdfd = open_(hpdpath, O_RDWR, 0);
+ if (hpdfd < 0) {
+ DLOGE("Open failed = %s", hpdpath);
+ return kErrorHardware;
+ }
+ char value = enable ? '1' : '0';
+ ssize_t length = write_(hpdfd, &value, 1);
+ if (length <= 0) {
+ DLOGE("Write failed 'hpd' = %d", enable);
+ ret_value = false;
+ }
+ close_(hpdfd);
+
+ return ret_value;
+}
+
+int HWFrameBuffer::GetHDMIModeCount() {
+ ssize_t length = -1;
+ char edid_str[256] = {'\0'};
+ char edid_path[kMaxStringLength] = {'\0'};
+ snprintf(edid_path, sizeof(edid_path), "%s%d/edid_modes", fb_path_, fb_node_index_[kHWHDMI]);
+ int edid_file = open_(edid_path, O_RDONLY);
+ if (edid_file < 0) {
+ DLOGE("EDID file open failed.");
+ return -1;
+ }
+
+ length = read_(edid_file, edid_str, sizeof(edid_str)-1);
+ if (length <= 0) {
+ DLOGE("%s: edid_modes file empty");
+ edid_str[0] = '\0';
+ } else {
+ DLOGI("EDID mode string: %s", edid_str);
+ while (length > 1 && isspace(edid_str[length-1])) {
+ --length;
+ }
+ edid_str[length] = '\0';
+ }
+ close_(edid_file);
+
+ if (length > 0) {
+ // Get EDID modes from the EDID string
+ char *ptr = edid_str;
+ const uint32_t edid_count_max = 128;
+ char *tokens[edid_count_max] = { NULL };
+ ParseLine(ptr, tokens, edid_count_max, &hdmi_mode_count_);
+ for (uint32_t i = 0; i < hdmi_mode_count_; i++) {
+ hdmi_modes_[i] = atoi(tokens[i]);
+ }
+ }
+ return (hdmi_mode_count_ > 0) ? hdmi_mode_count_ : 0;
+}
+
+bool HWFrameBuffer::MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode,
+ fb_var_screeninfo *info) {
+ if (!mode || !info) {
+ return false;
+ }
+
+ info->reserved[0] = 0;
+ info->reserved[1] = 0;
+ info->reserved[2] = 0;
+ info->reserved[3] = (info->reserved[3] & 0xFFFF) | (mode->video_format << 16);
+ info->xoffset = 0;
+ info->yoffset = 0;
+ info->xres = mode->active_h;
+ info->yres = mode->active_v;
+ info->pixclock = (mode->pixel_freq) * 1000;
+ info->vmode = mode->interlaced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
+ info->right_margin = mode->front_porch_h;
+ info->hsync_len = mode->pulse_width_h;
+ info->left_margin = mode->back_porch_h;
+ info->lower_margin = mode->front_porch_v;
+ info->vsync_len = mode->pulse_width_v;
+ info->upper_margin = mode->back_porch_v;
+
+ return true;
+}
+
} // namespace sde
diff --git a/displayengine/libs/core/hw_framebuffer.h b/displayengine/libs/core/hw_framebuffer.h
index b70b5be..568f2b1 100644
--- a/displayengine/libs/core/hw_framebuffer.h
+++ b/displayengine/libs/core/hw_framebuffer.h
@@ -28,6 +28,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <linux/msm_mdp_ext.h>
+#include <video/msm_hdmi_modes.h>
+
#include <poll.h>
#include <pthread.h>
@@ -46,6 +48,7 @@
virtual DisplayError GetNumDisplayAttributes(Handle device, uint32_t *count);
virtual DisplayError GetDisplayAttributes(Handle device, HWDisplayAttributes *display_attributes,
uint32_t mode);
+ virtual DisplayError SetDisplayAttributes(Handle device, uint32_t mode);
virtual DisplayError PowerOn(Handle device);
virtual DisplayError PowerOff(Handle device);
virtual DisplayError Doze(Handle device);
@@ -130,7 +133,13 @@
void PopulatePanelInfo(int fb_index);
// Populates HW Capabilities
DisplayError PopulateHWCapabilities();
- int ParseLine(char *input, char *token[], int max_token, int *count);
+ int ParseLine(char *input, char *token[], const uint32_t max_token, uint32_t *count);
+
+ // HDMI Related Functions
+ bool EnableHotPlugDetection(int enable);
+ int GetHDMIModeCount();
+ bool MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode, fb_var_screeninfo *info);
+ void ResetHDMIModes();
// Pointers to system calls which are either mapped to actual system call or virtual driver.
int (*ioctl_)(int, int, ...);
@@ -138,9 +147,12 @@
int (*close_)(int);
int (*poll_)(struct pollfd *, nfds_t, int);
ssize_t (*pread_)(int, void *, size_t, off_t);
- FILE* (*fopen_)( const char *fname, const char *mode );;
+ FILE* (*fopen_)( const char *fname, const char *mode);
int (*fclose_)(FILE* fileptr);
ssize_t (*getline_)(char **lineptr, size_t *linelen, FILE *stream);
+ ssize_t (*read_)(int fd, void *buf, size_t count);
+ ssize_t (*write_)(int fd, const void *buf, size_t count);
+
// Store the Device EventHandlers - used for callback
HWEventHandler *event_handler_[kNumPhysicalDisplays];
@@ -153,6 +165,11 @@
int fb_node_index_[kDeviceMax];
const char* fb_path_;
PanelInfo pri_panel_info_;
+ bool hotplug_enabled_;
+ uint32_t hdmi_mode_count_;
+ uint32_t hdmi_modes_[256];
+ // Holds the hdmi timing information. Ex: resolution, fps etc.,
+ msm_hdmi_mode_timing_info *supported_video_modes_;
};
} // namespace sde
diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h
index 6748538..1c0c765 100644
--- a/displayengine/libs/core/hw_interface.h
+++ b/displayengine/libs/core/hw_interface.h
@@ -136,6 +136,7 @@
virtual DisplayError GetNumDisplayAttributes(Handle device, uint32_t *count) = 0;
virtual DisplayError GetDisplayAttributes(Handle device,
HWDisplayAttributes *display_attributes, uint32_t mode) = 0;
+ virtual DisplayError SetDisplayAttributes(Handle device, uint32_t mode) = 0;
virtual DisplayError PowerOn(Handle device) = 0;
virtual DisplayError PowerOff(Handle device) = 0;
virtual DisplayError Doze(Handle device) = 0;
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index ee1b25f..164e7f3 100755
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -237,6 +237,8 @@
// assign single pipe
hw_layers->config[i].left_pipe.pipe_id = src_pipes_[left_index].mdss_pipe_id;
src_pipes_[left_index].at_right = false;
+ hw_layers->config[i].is_right_pipe = false;
+ src_pipes_[left_index].at_right = false;
continue;
}
diff --git a/displayengine/libs/hwc/hwc_display.cpp b/displayengine/libs/hwc/hwc_display.cpp
index 801c0da..5e7a637 100644
--- a/displayengine/libs/hwc/hwc_display.cpp
+++ b/displayengine/libs/hwc/hwc_display.cpp
@@ -103,7 +103,7 @@
DisplayError error = kErrorNone;
DisplayConfigVariableInfo variable_config;
- error = display_intf_->GetConfig(&variable_config, 0);
+ error = display_intf_->GetConfig(&variable_config, config);
if (UNLIKELY(error != kErrorNone)) {
DLOGE("GetConfig variable info failed. Error = %d", error);
return -EINVAL;
@@ -127,7 +127,7 @@
values[i] = INT32(variable_config.y_dpi * 1000.0f);
break;
case HWC_DISPLAY_SECURE:
- values[i] = INT32(true); // For backward compatibility. All Physical displays are secure
+ values[i] = INT32(true); // For backward compatibility. All Physical displays are secure
break;
default:
DLOGW("Spurious attribute type = %d", attributes[i]);
@@ -165,6 +165,11 @@
}
int HWCDisplay::AllocateLayerStack(hwc_display_contents_1_t *content_list) {
+ if (!content_list || !content_list->numHwLayers) {
+ DLOGW("Invalid content list");
+ return -EINVAL;
+ }
+
size_t num_hw_layers = content_list->numHwLayers;
// Allocate memory for a) total number of layers b) buffer handle for each layer c) number of
@@ -233,6 +238,11 @@
}
int HWCDisplay::PrepareLayerStack(hwc_display_contents_1_t *content_list) {
+ if (!content_list || !content_list->numHwLayers) {
+ DLOGW("Invalid content list");
+ return -EINVAL;
+ }
+
size_t num_hw_layers = content_list->numHwLayers;
if (num_hw_layers <= 1) {
return 0;
@@ -317,6 +327,11 @@
}
int HWCDisplay::CommitLayerStack(hwc_display_contents_1_t *content_list) {
+ if (!content_list || !content_list->numHwLayers) {
+ DLOGW("Invalid content list");
+ return -EINVAL;
+ }
+
size_t num_hw_layers = content_list->numHwLayers;
if (num_hw_layers <= 1) {
if (!num_hw_layers) {
diff --git a/displayengine/libs/hwc/hwc_display_external.cpp b/displayengine/libs/hwc/hwc_display_external.cpp
old mode 100755
new mode 100644
index 386e713..894374c
--- a/displayengine/libs/hwc/hwc_display_external.cpp
+++ b/displayengine/libs/hwc/hwc_display_external.cpp
@@ -35,26 +35,18 @@
: HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL) {
}
-int HWCDisplayExternal::Init() {
- return 0;
-}
-
-int HWCDisplayExternal::Deinit() {
- return 0;
-}
-
int HWCDisplayExternal::Prepare(hwc_display_contents_1_t *content_list) {
int status = 0;
status = AllocateLayerStack(content_list);
- if (UNLIKELY(status)) {
+ if (status) {
return status;
}
layer_stack_.retire_fence_fd = -1;
status = PrepareLayerStack(content_list);
- if (UNLIKELY(status)) {
+ if (status) {
return status;
}
@@ -65,7 +57,7 @@
int status = 0;
status = HWCDisplay::CommitLayerStack(content_list);
- if (UNLIKELY(status)) {
+ if (status) {
return status;
}
@@ -82,5 +74,24 @@
return 0;
}
+int HWCDisplayExternal::GetDisplayConfigs(uint32_t *configs, size_t *num_configs) {
+ uint32_t config_count = 0;
+ if (*num_configs <= 0) {
+ return -EINVAL;
+ }
+
+ display_intf_->GetNumVariableInfoConfigs(&config_count);
+ *num_configs = static_cast<size_t>(config_count);
+ if (*num_configs <= 0) {
+ return -EINVAL;
+ }
+
+ for (uint32_t i = 0; i < config_count; i++) {
+ configs[i] = i;
+ }
+
+ return 0;
+}
+
} // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display_external.h b/displayengine/libs/hwc/hwc_display_external.h
index 012c653..c8d26fa 100644
--- a/displayengine/libs/hwc/hwc_display_external.h
+++ b/displayengine/libs/hwc/hwc_display_external.h
@@ -32,12 +32,11 @@
class HWCDisplayExternal : public HWCDisplay {
public:
explicit HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
- virtual int Init();
- virtual int Deinit();
virtual int Prepare(hwc_display_contents_1_t *content_list);
virtual int Commit(hwc_display_contents_1_t *content_list);
virtual int PowerOn();
virtual int PowerOff();
+ virtual int GetDisplayConfigs(uint32_t *configs, size_t *num_configs);
};
} // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display_primary.cpp b/displayengine/libs/hwc/hwc_display_primary.cpp
old mode 100755
new mode 100644
index 95dc97e..41e657e
--- a/displayengine/libs/hwc/hwc_display_primary.cpp
+++ b/displayengine/libs/hwc/hwc_display_primary.cpp
@@ -35,26 +35,18 @@
: HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY) {
}
-int HWCDisplayPrimary::Init() {
- return HWCDisplay::Init();
-}
-
-int HWCDisplayPrimary::Deinit() {
- return HWCDisplay::Deinit();
-}
-
int HWCDisplayPrimary::Prepare(hwc_display_contents_1_t *content_list) {
int status = 0;
status = AllocateLayerStack(content_list);
- if (UNLIKELY(status)) {
+ if (status) {
return status;
}
layer_stack_.retire_fence_fd = -1;
status = PrepareLayerStack(content_list);
- if (UNLIKELY(status)) {
+ if (status) {
return status;
}
@@ -65,7 +57,7 @@
int status = 0;
status = HWCDisplay::CommitLayerStack(content_list);
- if (UNLIKELY(status)) {
+ if (status) {
return status;
}
diff --git a/displayengine/libs/hwc/hwc_display_primary.h b/displayengine/libs/hwc/hwc_display_primary.h
index cd8ae0f..df5cbd3 100644
--- a/displayengine/libs/hwc/hwc_display_primary.h
+++ b/displayengine/libs/hwc/hwc_display_primary.h
@@ -32,8 +32,6 @@
class HWCDisplayPrimary : public HWCDisplay {
public:
explicit HWCDisplayPrimary(CoreInterface *core_intf, hwc_procs_t const **hwc_procs);
- virtual int Init();
- virtual int Deinit();
virtual int Prepare(hwc_display_contents_1_t *content_list);
virtual int Commit(hwc_display_contents_1_t *content_list);
virtual int PowerOn();
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
old mode 100755
new mode 100644
index 64cd7e1..a9603d1
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -25,6 +25,9 @@
#include <core/dump_interface.h>
#include <utils/constants.h>
#include <utils/String16.h>
+#include <hardware_legacy/uevent.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
#include <binder/Parcel.h>
#include <QService.h>
@@ -53,7 +56,9 @@
Locker HWCSession::locker_;
-HWCSession::HWCSession(const hw_module_t *module) : core_intf_(NULL), hwc_procs_(NULL) {
+HWCSession::HWCSession(const hw_module_t *module) : core_intf_(NULL), hwc_procs_(NULL),
+ display_primary_(NULL), display_external_(NULL), hotplug_thread_exit_(false),
+ hotplug_thread_name_("HWC_HotPlugThread") {
hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG;
hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_3;
hwc_composer_device_1_t::common.module = const_cast<hw_module_t*>(module);
@@ -86,33 +91,41 @@
}
DisplayError error = CoreInterface::CreateCore(this, HWCLogHandler::Get(), &core_intf_);
- if (UNLIKELY(error != kErrorNone)) {
+ if (error != kErrorNone) {
DLOGE("Display core initialization failed. Error = %d", error);
return -EINVAL;
}
// Create and power on primary display
display_primary_ = new HWCDisplayPrimary(core_intf_, &hwc_procs_);
- if (UNLIKELY(!display_primary_)) {
+ if (!display_primary_) {
CoreInterface::DestroyCore();
return -ENOMEM;
}
status = display_primary_->Init();
- if (UNLIKELY(status)) {
+ if (status) {
CoreInterface::DestroyCore();
delete display_primary_;
return status;
}
status = display_primary_->PowerOn();
- if (UNLIKELY(status)) {
- CoreInterface::DestroyCore();
+ if (status) {
display_primary_->Deinit();
delete display_primary_;
+ CoreInterface::DestroyCore();
return status;
}
+ if (pthread_create(&hotplug_thread_, NULL, &HWCHotPlugThread, this) < 0) {
+ DLOGE("Failed to start = %s, error = %s HDMI display Not supported", hotplug_thread_name_);
+ display_primary_->Deinit();
+ delete display_primary_;
+ CoreInterface::DestroyCore();
+ return -errno;
+ }
+
return 0;
}
@@ -120,6 +133,8 @@
display_primary_->PowerOff();
display_primary_->Deinit();
delete display_primary_;
+ hotplug_thread_exit_ = true;
+ pthread_join(hotplug_thread_, NULL);
DisplayError error = CoreInterface::DestroyCore();
if (error != kErrorNone) {
@@ -130,19 +145,19 @@
}
int HWCSession::Open(const hw_module_t *module, const char *name, hw_device_t **device) {
- if (UNLIKELY(!module || !name || !device)) {
+ if (!module || !name || !device) {
DLOGE("Invalid parameters.");
return -EINVAL;
}
- if (LIKELY(!strcmp(name, HWC_HARDWARE_COMPOSER))) {
+ if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
HWCSession *hwc_session = new HWCSession(module);
- if (UNLIKELY(!hwc_session)) {
+ if (!hwc_session) {
return -ENOMEM;
}
int status = hwc_session->Init();
- if (UNLIKELY(status != 0)) {
+ if (status != 0) {
delete hwc_session;
return status;
}
@@ -155,7 +170,7 @@
}
int HWCSession::Close(hw_device_t *device) {
- if (UNLIKELY(!device)) {
+ if (!device) {
return -EINVAL;
}
@@ -172,74 +187,72 @@
hwc_display_contents_1_t **displays) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!device || !displays)) {
+ if (!device || !displays) {
return -EINVAL;
}
HWCSession *hwc_session = static_cast<HWCSession *>(device);
- int status = -EINVAL;
- for (size_t i = 0; i < num_displays; i++) {
+ for (ssize_t i = (num_displays-1); i >= 0; i--) {
hwc_display_contents_1_t *content_list = displays[i];
- if (UNLIKELY(!content_list || !content_list->numHwLayers)) {
- DLOGW("Invalid content list.");
- return -EINVAL;
- }
switch (i) {
case HWC_DISPLAY_PRIMARY:
- status = hwc_session->display_primary_->Prepare(content_list);
+ hwc_session->display_primary_->Prepare(content_list);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ hwc_session->display_external_->Prepare(content_list);
+ }
+ break;
+ case HWC_DISPLAY_VIRTUAL:
break;
default:
- status = -EINVAL;
- }
-
- if (UNLIKELY(!status)) {
break;
}
}
- return status;
+ // Return 0, else client will go into bad state
+ return 0;
}
int HWCSession::Set(hwc_composer_device_1 *device, size_t num_displays,
hwc_display_contents_1_t **displays) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!device || !displays)) {
+ if (!device || !displays) {
return -EINVAL;
}
HWCSession *hwc_session = static_cast<HWCSession *>(device);
- int status = -EINVAL;
for (size_t i = 0; i < num_displays; i++) {
hwc_display_contents_1_t *content_list = displays[i];
- if (UNLIKELY(!content_list || !content_list->numHwLayers)) {
- DLOGW("Invalid content list.");
- return -EINVAL;
- }
switch (i) {
case HWC_DISPLAY_PRIMARY:
- status = hwc_session->display_primary_->Commit(content_list);
+ hwc_session->display_primary_->Commit(content_list);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ hwc_session->display_external_->Commit(content_list);
+ }
+ break;
+ case HWC_DISPLAY_VIRTUAL:
break;
default:
- status = -EINVAL;
- }
-
- if (UNLIKELY(!status)) {
break;
}
}
- return status;
+ // Return 0, else client will go into bad state
+ return 0;
}
int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!device)) {
+ if (!device) {
return -EINVAL;
}
@@ -250,17 +263,22 @@
case HWC_DISPLAY_PRIMARY:
status = hwc_session->display_primary_->EventControl(event, enable);
break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ status = hwc_session->display_external_->EventControl(event, enable);
+ }
+ break;
default:
status = -EINVAL;
}
- return 0;
+ return status;
}
int HWCSession::Blank(hwc_composer_device_1 *device, int disp, int blank) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!device)) {
+ if (!device) {
return -EINVAL;
}
@@ -271,6 +289,11 @@
case HWC_DISPLAY_PRIMARY:
status = hwc_session->display_primary_->Blank(blank);
break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ status = hwc_session->display_external_->Blank(blank);
+ }
+ break;
default:
status = -EINVAL;
}
@@ -279,7 +302,7 @@
}
int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
- if (UNLIKELY(!device || !value)) {
+ if (!device || !value) {
return -EINVAL;
}
@@ -287,7 +310,7 @@
}
void HWCSession::RegisterProcs(hwc_composer_device_1 *device, hwc_procs_t const *procs) {
- if (UNLIKELY(!device || !procs)) {
+ if (!device || !procs) {
return;
}
@@ -298,7 +321,7 @@
void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
SCOPE_LOCK(locker_);
- if (UNLIKELY(!device || !buffer || !length)) {
+ if (!device || !buffer || !length) {
return;
}
@@ -307,7 +330,7 @@
int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
size_t *num_configs) {
- if (UNLIKELY(!device || !configs || !num_configs)) {
+ if (!device || !configs || !num_configs) {
return -EINVAL;
}
@@ -318,6 +341,11 @@
case HWC_DISPLAY_PRIMARY:
status = hwc_session->display_primary_->GetDisplayConfigs(configs, num_configs);
break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ status = hwc_session->display_external_->GetDisplayConfigs(configs, num_configs);
+ }
+ break;
default:
status = -EINVAL;
}
@@ -327,7 +355,7 @@
int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
const uint32_t *attributes, int32_t *values) {
- if (UNLIKELY(!device || !attributes || !values)) {
+ if (!device || !attributes || !values) {
return -EINVAL;
}
@@ -338,6 +366,11 @@
case HWC_DISPLAY_PRIMARY:
status = hwc_session->display_primary_->GetDisplayAttributes(config, attributes, values);
break;
+ case HWC_DISPLAY_EXTERNAL:
+ if (hwc_session->display_external_) {
+ status = hwc_session->display_external_->GetDisplayAttributes(config, attributes, values);
+ }
+ break;
default:
status = -EINVAL;
}
@@ -390,6 +423,100 @@
DLOGW("type = %d is not supported", type);
}
}
+void* HWCSession::HWCHotPlugThread(void *context) {
+ if (context) {
+ return reinterpret_cast<HWCSession *>(context)->HWCHotPlugThreadHandler();
+ }
+
+ return NULL;
+}
+
+void* HWCSession::HWCHotPlugThreadHandler() {
+ static char uevent_data[PAGE_SIZE];
+ int length = 0;
+ prctl(PR_SET_NAME, hotplug_thread_name_, 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+ if (!uevent_init()) {
+ DLOGE("Failed to init uevent");
+ pthread_exit(0);
+ return NULL;
+ }
+
+ while (!hotplug_thread_exit_) {
+ // keep last 2 zeroes to ensure double 0 termination
+ length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
+
+ if (!strcasestr("change@/devices/virtual/switch/hdmi", uevent_data)) {
+ continue;
+ }
+ DLOGI("Uevent HDMI = %s", uevent_data);
+ int connected = GetHDMIConnectedState(uevent_data, length);
+ if (connected >= 0) {
+ DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
+ if (HotPlugHandler(connected) == -1) {
+ DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
+ }
+ }
+ }
+ pthread_exit(0);
+
+ return NULL;
+}
+
+int HWCSession::GetHDMIConnectedState(const char *uevent_data, int length) {
+ const char* iterator_str = uevent_data;
+ while (((iterator_str - uevent_data) <= length) && (*iterator_str)) {
+ char* pstr = strstr(iterator_str, "SWITCH_STATE=");
+ if (pstr != NULL) {
+ return (atoi(iterator_str + strlen("SWITCH_STATE=")));
+ }
+ iterator_str += strlen(iterator_str) + 1;
+ }
+ return -1;
+}
+
+
+int HWCSession::HotPlugHandler(bool connected) {
+ if (!hwc_procs_) {
+ DLOGW("Ignore hotplug - hwc_proc not registered");
+ return -1;
+ }
+
+ if (connected) {
+ SCOPE_LOCK(locker_);
+ if (display_external_) {
+ DLOGE("HDMI already connected");
+ return -1;
+ }
+ // Create hdmi display
+ display_external_ = new HWCDisplayExternal(core_intf_, &hwc_procs_);
+ if (!display_external_) {
+ return -1;
+ }
+ int status = display_external_->Init();
+ if (status) {
+ delete display_external_;
+ display_external_ = NULL;
+ return -1;
+ }
+ } else {
+ SCOPE_LOCK(locker_);
+ if (!display_external_) {
+ DLOGE("HDMI not connected");
+ return -1;
+ }
+ display_external_->PowerOff();
+ display_external_->Deinit();
+ delete display_external_;
+ display_external_ = NULL;
+ }
+
+ // notify client and trigger a screen refresh
+ hwc_procs_->hotplug(hwc_procs_, HWC_DISPLAY_EXTERNAL, connected);
+ hwc_procs_->invalidate(hwc_procs_);
+
+ return 0;
+}
} // namespace sde
diff --git a/displayengine/libs/hwc/hwc_session.h b/displayengine/libs/hwc/hwc_session.h
index 9e37eed..380c98f 100644
--- a/displayengine/libs/hwc/hwc_session.h
+++ b/displayengine/libs/hwc/hwc_session.h
@@ -31,6 +31,7 @@
#include <IQClient.h>
#include "hwc_display_primary.h"
+#include "hwc_display_external.h"
namespace sde {
@@ -64,6 +65,12 @@
static int GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
const uint32_t *attributes, int32_t *values);
+ // Hotplug thread for HDMI connect/disconnect
+ static void* HWCHotPlugThread(void *context);
+ void* HWCHotPlugThreadHandler();
+ int GetHDMIConnectedState(const char *uevent_data, int length);
+ int HotPlugHandler(bool connected);
+
// CoreEventHandler methods
virtual DisplayError Hotplug(const CoreEventHotplug &hotplug);
@@ -76,6 +83,10 @@
CoreInterface *core_intf_;
hwc_procs_t const *hwc_procs_;
HWCDisplayPrimary *display_primary_;
+ HWCDisplayExternal *display_external_;
+ pthread_t hotplug_thread_;
+ bool hotplug_thread_exit_;
+ const char *hotplug_thread_name_;
};
} // namespace sde