Home | History | Annotate | Download | only in libhwcomposer
      1 
      2 /*
      3  * Copyright (C) 2010 The Android Open Source Project
      4  * Copyright (C) 2012-14, The Linux Foundation. All rights reserved.
      5  *
      6  * Not a Contribution, Apache license notifications and license are
      7  * retained for attribution purposes only.
      8 
      9  * Licensed under the Apache License, Version 2.0 (the "License");
     10  * you may not use this file except in compliance with the License.
     11  * You may obtain a copy of the License at
     12  *
     13  *      http://www.apache.org/licenses/LICENSE-2.0
     14  *
     15  * Unless required by applicable law or agreed to in writing, software
     16  * distributed under the License is distributed on an "AS IS" BASIS,
     17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     18  * See the License for the specific language governing permissions and
     19  * limitations under the License.
     20  */
     21 #define UEVENT_DEBUG 0
     22 #include <hardware_legacy/uevent.h>
     23 #include <utils/Log.h>
     24 #include <sys/resource.h>
     25 #include <sys/prctl.h>
     26 #include <string.h>
     27 #include <stdlib.h>
     28 #include "hwc_utils.h"
     29 #include "hwc_fbupdate.h"
     30 #include "hwc_mdpcomp.h"
     31 #include "hwc_copybit.h"
     32 #include "comptype.h"
     33 #include "hdmi.h"
     34 #include "hwc_virtual.h"
     35 #include "mdp_version.h"
     36 using namespace overlay;
     37 namespace qhwc {
     38 #define HWC_UEVENT_SWITCH_STR  "change@/devices/virtual/switch/"
     39 #define HWC_UEVENT_THREAD_NAME "hwcUeventThread"
     40 
     41 /* Parse uevent data for devices which we are interested */
     42 static int getConnectedDisplay(hwc_context_t* ctx, const char* strUdata)
     43 {
     44     int ret = -1;
     45     // Switch node for HDMI as PRIMARY/EXTERNAL
     46     if(strcasestr("change@/devices/virtual/switch/hdmi", strUdata)) {
     47         if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
     48             ret = HWC_DISPLAY_PRIMARY;
     49         } else {
     50             ret = HWC_DISPLAY_EXTERNAL;
     51         }
     52     }
     53     return ret;
     54 }
     55 
     56 static bool getPanelResetStatus(hwc_context_t* ctx, const char* strUdata, int len)
     57 {
     58     const char* iter_str = strUdata;
     59     if (strcasestr("change@/devices/virtual/graphics/fb0", strUdata)) {
     60         while(((iter_str - strUdata) <= len) && (*iter_str)) {
     61             char* pstr = strstr(iter_str, "PANEL_ALIVE=0");
     62             if (pstr != NULL) {
     63                 ALOGI("%s: got change event in fb0 with PANEL_ALIVE=0",
     64                                                            __FUNCTION__);
     65                 ctx->mPanelResetStatus = true;
     66                 return true;
     67             }
     68             iter_str += strlen(iter_str)+1;
     69         }
     70     }
     71     return false;
     72 }
     73 
     74 /* Parse uevent data for action requested for the display */
     75 static int getConnectedState(const char* strUdata, int len)
     76 {
     77     const char* iter_str = strUdata;
     78     while(((iter_str - strUdata) <= len) && (*iter_str)) {
     79         char* pstr = strstr(iter_str, "SWITCH_STATE=");
     80         if (pstr != NULL) {
     81             return (atoi(pstr + strlen("SWITCH_STATE=")));
     82         }
     83         iter_str += strlen(iter_str)+1;
     84     }
     85     return -1;
     86 }
     87 
     88 static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
     89 {
     90     bool bpanelReset = getPanelResetStatus(ctx, udata, len);
     91     if (bpanelReset) {
     92         ctx->proc->invalidate(ctx->proc);
     93         return;
     94     }
     95 
     96     int dpy = getConnectedDisplay(ctx, udata);
     97     if(dpy < 0) {
     98         ALOGD_IF(UEVENT_DEBUG, "%s: Not disp Event ", __FUNCTION__);
     99         return;
    100     }
    101 
    102     int switch_state = getConnectedState(udata, len);
    103 
    104     ALOGE_IF(UEVENT_DEBUG,"%s: uevent received: %s switch state: %d",
    105              __FUNCTION__,udata, switch_state);
    106 
    107     switch(switch_state) {
    108     case EXTERNAL_OFFLINE:
    109         {
    110             /* Display not connected */
    111             if(!ctx->dpyAttr[dpy].connected){
    112                 ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_OFFLINE event"
    113                          "for display: %d", __FUNCTION__, dpy);
    114                 break;
    115             }
    116 
    117             ctx->mDrawLock.lock();
    118             handle_offline(ctx, dpy);
    119             ctx->mDrawLock.unlock();
    120 
    121             /* We need to send hotplug to SF only when we are disconnecting
    122              * HDMI as an external display. */
    123             if(dpy == HWC_DISPLAY_EXTERNAL) {
    124                 ALOGE_IF(UEVENT_DEBUG,"%s:Sending EXTERNAL OFFLINE hotplug"
    125                         "event", __FUNCTION__);
    126                 ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_OFFLINE);
    127             }
    128             break;
    129         }
    130     case EXTERNAL_ONLINE:
    131         {
    132             /* Display already connected */
    133             if(ctx->dpyAttr[dpy].connected) {
    134                 ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_ONLINE event"
    135                          "for display: %d", __FUNCTION__, dpy);
    136                 break;
    137             }
    138 
    139             if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
    140                 ctx->mDrawLock.lock();
    141                 handle_online(ctx, dpy);
    142                 ctx->mDrawLock.unlock();
    143 
    144                 ctx->proc->invalidate(ctx->proc);
    145                 break;
    146             } else {
    147                 ctx->mDrawLock.lock();
    148                 //Force composition to give up resources like pipes and
    149                 //close fb. For example if assertive display is going on,
    150                 //fb2 could be open, thus connecting Layer Mixer#0 to
    151                 //WriteBack module. If HDMI attempts to open fb1, the driver
    152                 //will try to attach Layer Mixer#0 to HDMI INT, which will
    153                 //fail, since Layer Mixer#0 is still connected to WriteBack.
    154                 //This block will force composition to close fb2 in above
    155                 //example.
    156                 ctx->dpyAttr[dpy].isConfiguring = true;
    157                 ctx->mDrawLock.unlock();
    158 
    159                 ctx->proc->invalidate(ctx->proc);
    160             }
    161             //2 cycles for slower content
    162             usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
    163                    * 2 / 1000);
    164 
    165             if(isVDConnected(ctx)) {
    166                 // Do not initiate WFD teardown if WFD architecture is based
    167                 // on VDS mechanism.
    168                 // WFD Stack listens to HDMI intent and initiates virtual
    169                 // display teardown.
    170                 // ToDo: Currently non-WFD Virtual display clients do not
    171                 // involve HWC. If there is a change, we need to come up
    172                 // with mechanism of how to address non-WFD Virtual display
    173                 // clients + HDMI
    174                 ctx->mWfdSyncLock.lock();
    175                 ALOGD_IF(HWC_WFDDISPSYNC_LOG,
    176                         "%s: Waiting for wfd-teardown to be signalled",
    177                         __FUNCTION__);
    178                 ctx->mWfdSyncLock.wait();
    179                 ALOGD_IF(HWC_WFDDISPSYNC_LOG,
    180                         "%s: Teardown signalled. Completed waiting in"
    181                         "uevent thread", __FUNCTION__);
    182                 ctx->mWfdSyncLock.unlock();
    183             }
    184             ctx->mHDMIDisplay->configure();
    185             ctx->mHDMIDisplay->activateDisplay();
    186 
    187             ctx->mDrawLock.lock();
    188             updateDisplayInfo(ctx, dpy);
    189             initCompositionResources(ctx, dpy);
    190             ctx->dpyAttr[dpy].isPause = false;
    191             ctx->dpyAttr[dpy].connected = true;
    192             ctx->dpyAttr[dpy].isConfiguring = true;
    193             ctx->mDrawLock.unlock();
    194 
    195             /* External display is HDMI */
    196             ALOGE_IF(UEVENT_DEBUG, "%s: Sending EXTERNAL ONLINE"
    197                     "hotplug event", __FUNCTION__);
    198             ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_ONLINE);
    199             break;
    200         }
    201     default:
    202         {
    203             ALOGE("%s: Invalid state to swtich:%d", __FUNCTION__, switch_state);
    204             break;
    205         }
    206     }
    207 }
    208 
    209 static void *uevent_loop(void *param)
    210 {
    211     int len = 0;
    212     static char udata[PAGE_SIZE];
    213     hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
    214     char thread_name[64] = HWC_UEVENT_THREAD_NAME;
    215     prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
    216     setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
    217     if(!uevent_init()) {
    218         ALOGE("%s: failed to init uevent ",__FUNCTION__);
    219         return NULL;
    220     }
    221 
    222     while(1) {
    223         len = uevent_next_event(udata, (int)sizeof(udata) - 2);
    224         handle_uevent(ctx, udata, len);
    225     }
    226 
    227     return NULL;
    228 }
    229 
    230 void init_uevent_thread(hwc_context_t* ctx)
    231 {
    232     pthread_t uevent_thread;
    233     int ret;
    234 
    235     ALOGI("Initializing UEVENT Thread");
    236     ret = pthread_create(&uevent_thread, NULL, uevent_loop, (void*) ctx);
    237     if (ret) {
    238         ALOGE("%s: failed to create %s: %s", __FUNCTION__,
    239             HWC_UEVENT_THREAD_NAME, strerror(ret));
    240     }
    241 }
    242 
    243 }; //namespace
    244