.timings.x_res? "3" : "0");
        ext->mirror.rotation = atoi(value) & EXT_ROTATION;
        ext->mirror.hflip = (atoi(value) & EXT_HFLIP) > 0;
        ext->mirror.docking = 0;

        if (ext->force_dock) {
            /* restrict to docking with no transform */
            ext->mirror.enabled = 0;
            ext->dock.rotation = 0;
            ext->dock.hflip = 0;

            if (!dock_image.rowbytes) {
                property_get("persist.hwc.dock_image", value, "/vendor/res/images/dock/dock.png");
                load_png_image(hwc_dev, value, &dock_image);
            }
        }

        /* select best mode for mirroring */
        if (ext->mirror.enabled) {
            ext->current = ext->mirror;
            ext->mirror_mode = 0;
            if (setup_mirroring(hwc_dev) == 0) {
                ext->mirror_mode = ext->last_mode;
                ioctl(hwc_dev->hdmi_fb_fd, FBIOBLANK, FB_BLANK_UNBLANK);
            } else
                ext->mirror.enabled = 0;
        }
        /* Allocate backup buffers for FB rotation
        * This is required only if the FB tranform is different from that
        * of the external display and the FB is not in TILER2D space
        */
        if (ext->mirror.rotation && (limits.fbmem_type!= DSSCOMP_FBMEM_TILER2D))
            allocate_tiler2d_buffers(hwc_dev);

    } else {
        ext->last_mode = 0;
        if (ext->mirror.rotation && (limits.fbmem_type!= DSSCOMP_FBMEM_TILER2D)) {
            /* free tiler 2D buffer on detach */
            free_tiler2d_buffers(hwc_dev);
        }
    }
    ALOGI("external display changed (state=%d, mirror={%s tform=%ddeg%s}, dock={%s tform=%ddeg%s%s}, tv=%d", state,
         ext->mirror.enabled? "enabled" : "disabled",
         ext->mirror.rotation * 90,
         ext->mirror.hflip? "+hflip" : "",
         ext->dock.enabled? "enabled" : "disabled",
         ext->dock.rotation * 90,
         ext->dock.hflip? "+hflip" : "",
         ext->force_dock? " forced" : "",
         ext->on_tv);

    pthread_mutex_unlock(&hwc_dev->lock);

    /* hwc_dev->procs is set right after the device is opened, but there is
     * still a race condition where a hotplug event might occur after the open
     * but before the procs are registered. */
    if (hwc_dev->procs && hwc_dev->procs->invalidate)
            hwc_dev->procs->invalidate(hwc_dev->procs);
}

static void handle_uevents(omap4_hwc_device_t *hwc_dev, const char *buff, int len)
{
    int dock;
    int hdmi;
    int vsync;
    int state = 0;
    uint64_t timestamp = 0;
    const char *s = buff;

    dock =!strcmp(s, "change@/devices/virtual/switch/dock");
    hdmi =!strcmp(s, "change@/devices/virtual/switch/hdmi");
    vsync =!strcmp(s, "change@/devices/platform/omapfb") ||
       !strcmp(s, "change@/devices/virtual/switch/omapfb-vsync");

    if (!dock &&!vsync &&!hdmi)
       return;

    s += strlen(s) + 1;

    while(*s) {
        if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
            state = atoi(s + strlen("SWITCH_STATE="));
        else if (!strncmp(s, "SWITCH_TIME=", strlen("SWITCH_TIME=")))
            timestamp = strtoull(s + strlen("SWITCH_TIME="), NULL, 0);
        else if (!strncmp(s, "VSYNC=", strlen("VSYNC=")))
            timestamp = strtoull(s + strlen("VSYNC="), NULL, 0);

        s += strlen(s) + 1;
        if (s - buff >= len)
            break;
    }

    if (vsync) {
        fire_vsync_event(hwc_dev, timestamp);
    } else {
        if (dock) {
            hwc_dev->ext.force_dock = state == 1;
        } else {
            /* If the primary display is HDMI, VSYNC is enabled, and HDMI's plug
             * state has just gone from 1->0, then we need to be sure to start
             * faking the VSYNC events.
             */
            if (hwc_dev->on_tv) {
                int new_state, state_change;

                pthread_mutex_lock(&hwc_dev->vsync_lock);

                new_state = state == 1;
                state_change = (new_state!= hwc_dev->ext.hdmi_state);
                hwc_dev->ext.hdmi_state = new_state;
                if (state_change &&!new_state)
                    wakeup_hdmi_thread(hwc_dev);

                pthread_mutex_unlock(&hwc_dev->vsync_lock);
            } else {
                hwc_dev->ext.hdmi_state = state == 1;
            }
        }
        handle_hotplug(hwc_dev);
    }
}

static void *omap4_hwc_hdmi_thread(void *data)
{
    omap4_hwc_device_t *hwc_dev = data;
    static char uevent_desc[4096];
    struct pollfd fds[2];
    int invalidate = 0;
    int timeout;
    int err;

    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);

    uevent_init();

    fds[0].fd = uevent_get_fd();
    fds[0].events = POLLIN;
    fds[1].fd = hwc_dev->wakeup_evt;
    fds[1].events = POLLIN;

    timeout = hwc_dev->idle? hwc_dev->idle : -1;

    memset(uevent_desc, 0, sizeof(uevent_desc));

    do {
        uint64_t idle_wakeup  = (uint64_t)(-1);
        uint64_t vsync_wakeup = (uint64_t)(-1);
        uint64_t now = vsync_clock_now();
        uint64_t effective_wakeup;
        int effective_timeout;

        if (timeout >= 0)
            idle_wakeup = now + (((uint64_t)timeout) * 1000000);

        if (hwc_dev->on_tv) {
            pthread_mutex_lock(&hwc_dev->vsync_lock);

            if (!hwc_dev->ext.hdmi_state && hwc_dev->vsync_enabled) {
                vsync_wakeup = hwc_dev->last_vsync_time_valid
                            ? hwc_dev->last_vsync_time
                             : now;

                vsync_wakeup += hwc_dev->fake_vsync_period;

                if (vsync_wakeup < now)
                    vsync_wakeup = now;
            }

            pthread_mutex_unlock(&hwc_dev->vsync_lock);
        }

        effective_wakeup = idle_wakeup < vsync_wakeup
                        ? idle_wakeup
                         : vsync_wakeup;
        if (effective_wakeup == (uint64_t)(-1))
            effective_timeout = -1;
        else if (effective_wakeup <= now)
            effective_timeout = 0;
        else
            