From 211f9f4144d6ec2ab9e7ca16cc15319b01cf53fa Mon Sep 17 00:00:00 2001 From: Amara Venkata Mastan Manoj Kumar Date: Thu, 2 Aug 2012 08:26:21 -0700 Subject: [PATCH] hwc_composer: Support of WFD Display. 1. WFD Event Detection. 2. WFD/HDMI Priority Decision. 3. Configure HWC for WFD Connect/Disconnect. Change-Id: I1c1bbae449ce38d9b32e8e2bd66d14ae98468c49 --- libhwcomposer/hwc.cpp | 3 + libhwcomposer/hwc_external.cpp | 118 ++++++++++++++++++++++++--------- libhwcomposer/hwc_external.h | 26 +++++++- libhwcomposer/hwc_uevents.cpp | 41 +++++------- 4 files changed, 131 insertions(+), 57 deletions(-) diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp index d02f97a..ff4d5a0 100644 --- a/libhwcomposer/hwc.cpp +++ b/libhwcomposer/hwc.cpp @@ -77,6 +77,9 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) hwc_context_t* ctx = (hwc_context_t*)(dev); ctx->overlayInUse = false; + if(ctx->mExtDisplay->getExternalDisplay()) + ovutils::setExtType(ctx->mExtDisplay->getExternalDisplay()); + //Prepare is called after a vsync, so unlock previous buffers here. ctx->qbuf->unlockAllPrevious(); diff --git a/libhwcomposer/hwc_external.cpp b/libhwcomposer/hwc_external.cpp index b5e1e89..e624b20 100644 --- a/libhwcomposer/hwc_external.cpp +++ b/libhwcomposer/hwc_external.cpp @@ -38,20 +38,20 @@ namespace qhwc { - -#define DEVICE_ROOT "/sys/devices/virtual/graphics" -#define DEVICE_NODE "fb1" - -#define SYSFS_EDID_MODES DEVICE_ROOT "/" DEVICE_NODE "/edid_modes" -#define SYSFS_HPD DEVICE_ROOT "/" DEVICE_NODE "/hpd" - +static const char *extPanelName[MAX_DISPLAY_EXTERNAL_DEVICES] = { + HDMI_PANEL, + WFD_PANEL +}; ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1), mCurrentMode(-1), mHwcContext(ctx) { memset(&mVInfo, 0, sizeof(mVInfo)); + //Enable HPD for HDMI - writeHPDOption(1); + if(isHDMIConfigured()) { + writeHPDOption(1); + } } ExternalDisplay::~ExternalDisplay() @@ -197,12 +197,16 @@ bool ExternalDisplay::readResolution() return (strlen(mEDIDs) > 0); } -bool ExternalDisplay::openFramebuffer() +const char* msmFbDevicePath[2] = { "/dev/graphics/fb1", + "/dev/graphics/fb2"}; + + +bool ExternalDisplay::openFrameBuffer(int fbNum) { if (mFd == -1) { - mFd = open("/dev/graphics/fb1", O_RDWR); + mFd = open(msmFbDevicePath[fbNum-1], O_RDWR); if (mFd < 0) - ALOGE("%s: /dev/graphics/fb1 not available", __FUNCTION__); + ALOGE("%s: %s not available", __FUNCTION__, msmFbDevicePath[fbNum-1]); } return (mFd > 0); } @@ -294,7 +298,7 @@ void ExternalDisplay::setResolution(int ID) { struct fb_var_screeninfo info; int ret = 0; - if (!openFramebuffer()) + if (!openFrameBuffer(EXTERN_DISPLAY_FB1)) return; ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); if(ret < 0) { @@ -354,32 +358,85 @@ void ExternalDisplay::setResolution(int ID) } } +/* + * This function queries the msm_fb_type for fb1 and checks whether it is + * HDMI or not + * + * Returns: + * 0 -> WFD device + * 1 -> HDMI device + */ +bool ExternalDisplay::isHDMIConfigured() { + bool configured = false; + FILE *displayDeviceFP = NULL; + char fbType[MAX_FRAME_BUFFER_NAME_SIZE]; -int ExternalDisplay::getExternalDisplay() const -{ - return mExternalDisplay; + displayDeviceFP = fopen("/sys/class/graphics/fb1/msm_fb_type", "r"); + + if(displayDeviceFP) { + fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE, displayDeviceFP); + + if(!strncmp(fbType, extPanelName[0], sizeof(extPanelName[0]))) { + configured = true; + } + fclose(displayDeviceFP); + } + return configured; +} + +void ExternalDisplay::processUEventOffline(const char *str) { + const char *s1 = str + (strlen(str)-strlen(DEVICE_NODE_FB1)); + // check if it is for FB1 + if(strncmp(s1,DEVICE_NODE_FB1, strlen(DEVICE_NODE_FB1))== 0) { + enableHDMIVsync(EXTERN_DISPLAY_NONE); + closeFrameBuffer(); + resetInfo(); + setExternalDisplay(EXTERN_DISPLAY_NONE); + } + else if(strncmp(s1, DEVICE_NODE_FB2, strlen(DEVICE_NODE_FB2)) == 0) { + closeFrameBuffer(); + setExternalDisplay(EXTERN_DISPLAY_NONE); + } +} + + +void ExternalDisplay::processUEventOnline(const char *str) { + const char *s1 = str + (strlen(str)-strlen(DEVICE_NODE_FB1)); + // check if it is for FB1 + if(strncmp(s1,DEVICE_NODE_FB1, strlen(DEVICE_NODE_FB1))== 0) { + if(isHDMIConfigured()) { + // HDMI connect event. + // Tear-down WFD if it is active. + if(mExternalDisplay == EXTERN_DISPLAY_FB2) { + closeFrameBuffer(); + setExternalDisplay(EXTERN_DISPLAY_NONE); + } + } + readResolution(); + //Get the best mode and set + setResolution(getBestMode()); + enableHDMIVsync(EXTERN_DISPLAY_FB1); + setExternalDisplay(EXTERN_DISPLAY_FB1); + } + else if(strncmp(s1, DEVICE_NODE_FB2, strlen(DEVICE_NODE_FB2)) == 0) { + // WFD connect event + if(mExternalDisplay == EXTERN_DISPLAY_FB1) { + // HDMI has higher priority. + // Do Not Override. + }else { + // WFD is connected + openFrameBuffer(EXTERN_DISPLAY_FB2); + setExternalDisplay(EXTERN_DISPLAY_FB2); + } + } } void ExternalDisplay::setExternalDisplay(int connected) { - hwc_context_t* ctx = mHwcContext; if(ctx) { ALOGD_IF(DEBUG, "%s: status = %d", __FUNCTION__, connected); - if(connected) { - readResolution(); - //Get the best mode and set - // TODO: DO NOT call this for WFD - setResolution(getBestMode()); - //enable hdmi vsync - enableHDMIVsync(connected); - } else { - // Disable the hdmi vsync - enableHDMIVsync(connected); - closeFrameBuffer(); - resetInfo(); - } // Store the external display mExternalDisplay = connected; const char* prop = (connected) ? "1" : "0"; @@ -388,8 +445,7 @@ void ExternalDisplay::setExternalDisplay(int connected) //Invalidate hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; if(!proc) { - ALOGE("%s: HWC proc not registered", - __FUNCTION__); + ALOGE("%s: HWC proc not registered", __FUNCTION__); } else { /* Trigger redraw */ ALOGD_IF(DEBUG, "%s: Invalidate !!", __FUNCTION__); diff --git a/libhwcomposer/hwc_external.h b/libhwcomposer/hwc_external.h index 55773c0..dfe93c5 100644 --- a/libhwcomposer/hwc_external.h +++ b/libhwcomposer/hwc_external.h @@ -27,6 +27,25 @@ struct hwc_context_t; namespace qhwc { +#define DEVICE_ROOT "/sys/devices/virtual/graphics" +#define DEVICE_NODE_FB1 "fb1" +#define DEVICE_NODE_FB2 "fb2" +#define HDMI_PANEL "dtv panel" +#define WFD_PANEL "writeback panel" +#define EXTERN_DISPLAY_NONE 0 +#define EXTERN_DISPLAY_FB1 1 +#define EXTERN_DISPLAY_FB2 2 +#define MAX_FRAME_BUFFER_NAME_SIZE 80 +#define MAX_DISPLAY_EXTERNAL_DEVICES 2 +#define HPD_ENABLE 1 +#define HPD_DISABLE 0 +#define DEVICE_ONLINE true +#define DEVICE_OFFLINE false + + +#define SYSFS_EDID_MODES DEVICE_ROOT "/" DEVICE_NODE_FB1 "/edid_modes" +#define SYSFS_HPD DEVICE_ROOT "/" DEVICE_NODE_FB1 "/hpd" + class ExternalDisplay { //Type of external display - OFF, HDMI, WFD @@ -44,16 +63,19 @@ class ExternalDisplay public: ExternalDisplay(hwc_context_t* ctx); ~ExternalDisplay(); - int getExternalDisplay() const; + inline int getExternalDisplay() { return mExternalDisplay; } void setExternalDisplay(int connected); bool commit(); int enableHDMIVsync(int enable); + void processUEventOnline(const char *str); + void processUEventOffline(const char *str); + bool isHDMIConfigured(); private: bool readResolution(); int parseResolution(char* edidStr, int* edidModes); void setResolution(int ID); - bool openFramebuffer(); + bool openFrameBuffer(int fbNum); bool closeFrameBuffer(); bool writeHPDOption(int userOption) const; bool isValidMode(int ID); diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp index 1953c8a..68d01ae 100644 --- a/libhwcomposer/hwc_uevents.cpp +++ b/libhwcomposer/hwc_uevents.cpp @@ -18,8 +18,8 @@ * limitations under the License. */ #define DEBUG 0 -#ifndef HWC_OBSERVER_H -#define HWC_OBSERVER_H +#ifndef HWC_UEVENTS_H +#define HWC_UEVENTS_H #include #include #include @@ -32,12 +32,11 @@ namespace qhwc { const char* MSMFB_DEVICE_FB0 = "change@/devices/virtual/graphics/fb0"; const char* MSMFB_DEVICE_FB1 = "change@/devices/virtual/graphics/fb1"; -const char* MSMFB_HDMI_NODE = "fb1"; +const char* MSMFB_FB_NODE = "fb"; static void handle_uevent(hwc_context_t* ctx, const char* udata, int len) { int vsync = 0; - char* hdmi; int64_t timestamp = 0; const char *str = udata; hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; @@ -48,12 +47,12 @@ static void handle_uevent(hwc_context_t* ctx, const char* udata, int len) return; } - if(hdmiconnected) + if(ctx->mExtDisplay->isHDMIConfigured() && + (hdmiconnected == EXTERN_DISPLAY_FB1)) vsync = !strncmp(str, MSMFB_DEVICE_FB1, strlen(MSMFB_DEVICE_FB1)); else vsync = !strncmp(str, MSMFB_DEVICE_FB0, strlen(MSMFB_DEVICE_FB0)); - hdmi = strcasestr(str, MSMFB_HDMI_NODE); if(vsync) { str += strlen(str) + 1; while(*str) { @@ -68,24 +67,18 @@ static void handle_uevent(hwc_context_t* ctx, const char* udata, int len) return; } - if(hdmi) { - // parse HDMI events - // The event will be of the form: - // change@/devices/virtual/graphics/fb1 ACTION=change - // DEVPATH=/devices/virtual/graphics/fb1 - // SUBSYSTEM=graphics HDCP_STATE=FAIL MAJOR=29 - // for now just parsing onlin/offline info is enough - str = udata; - int connected = 0; - if(!(strncmp(str,"online@",strlen("online@")))) { - connected = 1; - ctx->mExtDisplay->setExternalDisplay(connected); - } else if(!(strncmp(str,"offline@",strlen("offline@")))) { - connected = 0; - ctx->mExtDisplay->setExternalDisplay(connected); - } + // parse HDMI events + // The event will be of the form: + // change@/devices/virtual/graphics/fb1 ACTION=change + // DEVPATH=/devices/virtual/graphics/fb1 + // SUBSYSTEM=graphics HDCP_STATE=FAIL MAJOR=29 + // for now just parsing onlin/offline info is enough + str = udata; + if(!(strncmp(str,"online@",strlen("online@")))) { + ctx->mExtDisplay->processUEventOnline(str); + } else if(!(strncmp(str,"offline@",strlen("offline@")))) { + ctx->mExtDisplay->processUEventOffline(str); } - } static void *uevent_loop(void *param) @@ -113,4 +106,4 @@ void init_uevent_thread(hwc_context_t* ctx) } }; //namespace -#endif //HWC_OBSERVER_H +#endif //HWC_UEVENTS_H