1054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin/*
2054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * Copyright (c) 2012, The Linux Foundation. All rights reserved.
3054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
4054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * Redistribution and use in source and binary forms, with or without
5054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * modification, are permitted provided that the following conditions are
6054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * met:
7054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *   * Redistributions of source code must retain the above copyright
8054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *     notice, this list of conditions and the following disclaimer.
9054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *   * Redistributions in binary form must reproduce the above
10054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *     copyright notice, this list of conditions and the following
11054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *     disclaimer in the documentation and/or other materials provided
12054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *     with the distribution.
13054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *   * Neither the name of The Linux Foundation nor the names of its
14054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *     contributors may be used to endorse or promote products derived
15054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *     from this software without specific prior written permission.
16054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin *
17054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin */
29054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
30054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include "idle_invalidator.h"
31054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <unistd.h>
32054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <poll.h>
33054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <string.h>
34054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <fcntl.h>
35054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#include <cutils/properties.h>
36054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
37054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#define II_DEBUG 0
38054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#define IDLE_NOTIFY_PATH "/sys/devices/virtual/graphics/fb0/idle_notify"
39054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin#define IDLE_TIME_PATH "/sys/devices/virtual/graphics/fb0/idle_time"
40054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
41054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
42054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinstatic const char *threadName = "IdleInvalidator";
43054df959aef7dce630a7f41d4aba6626c130756bPatrick TjinInvalidatorHandler IdleInvalidator::mHandler = NULL;
44054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinandroid::sp<IdleInvalidator> IdleInvalidator::sInstance(0);
45054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
46054df959aef7dce630a7f41d4aba6626c130756bPatrick TjinIdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0),
47054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    mTimeoutEventFd(-1) {
48054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
49054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin}
50054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
51054df959aef7dce630a7f41d4aba6626c130756bPatrick TjinIdleInvalidator::~IdleInvalidator() {
52054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    if(mTimeoutEventFd >= 0) {
53054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        close(mTimeoutEventFd);
54054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    }
55054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin}
56054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
57054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinint IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data) {
58054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    mHandler = reg_handler;
59054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    mHwcContext = user_data;
60054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
61054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    // Open a sysfs node to receive the timeout notification from driver.
62054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    mTimeoutEventFd = open(IDLE_NOTIFY_PATH, O_RDONLY);
63054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    if (mTimeoutEventFd < 0) {
64054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        ALOGE ("%s:not able to open %s node %s",
65054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin                __FUNCTION__, IDLE_NOTIFY_PATH, strerror(errno));
66054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        return -1;
67054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    }
68054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
69054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    int defaultIdleTime = 70; //ms
70054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    char property[PROPERTY_VALUE_MAX] = {0};
71054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    if((property_get("debug.mdpcomp.idletime", property, NULL) > 0)) {
72054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        defaultIdleTime = atoi(property);
73054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    }
74054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    if(not setIdleTimeout(defaultIdleTime)) {
75054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        close(mTimeoutEventFd);
76054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        mTimeoutEventFd = -1;
77054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        return -1;
78054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    }
79054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
80054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    //Triggers the threadLoop to run, if not already running.
81054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    run(threadName, android::PRIORITY_LOWEST);
82054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    return 0;
83054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin}
84054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
85054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinbool IdleInvalidator::setIdleTimeout(const uint32_t& timeout) {
86054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s timeout %d",
87054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin            __FUNCTION__, timeout);
88054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
89054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    // Open a sysfs node to send the timeout value to driver.
90054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    int fd = open(IDLE_TIME_PATH, O_WRONLY);
91054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
92054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    if (fd < 0) {
93054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        ALOGE ("%s:Unable to open %s node %s",
94054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
95054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        return false;
96054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    }
97054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
98054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    char strSleepTime[64];
99054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    snprintf(strSleepTime, sizeof(strSleepTime), "%d", timeout);
100054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
101054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    // Notify driver about the timeout value
102054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0);
103054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    if(len < -1) {
104054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        ALOGE ("%s:Unable to write into %s node %s",
105054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin                __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
106054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        close(fd);
107054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        return false;
108054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    }
109054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
110054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    close(fd);
111054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    return true;
112054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin}
113054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
114054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinbool IdleInvalidator::threadLoop() {
115054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
116054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    struct pollfd pFd;
117054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    pFd.fd = mTimeoutEventFd;
118054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    if (pFd.fd >= 0)
119054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        pFd.events = POLLPRI | POLLERR;
120054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    // Poll for an timeout event from driver
121054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    int err = poll(&pFd, 1, -1);
122054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    if(err > 0) {
123054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        if (pFd.revents & POLLPRI) {
124054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin            char data[64];
125054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin            // Consume the node by reading it
126054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin            ssize_t len = pread(pFd.fd, data, 64, 0);
127054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin            ALOGD_IF(II_DEBUG, "IdleInvalidator::%s Idle Timeout fired len %zd",
128054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin                __FUNCTION__, len);
129054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin            mHandler((void*)mHwcContext);
130054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        }
131054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    }
132054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    return true;
133054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin}
134054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
135054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinint IdleInvalidator::readyToRun() {
136054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
137054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    return 0; /*NO_ERROR*/
138054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin}
139054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
140054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjinvoid IdleInvalidator::onFirstRef() {
141054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
142054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin}
143054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin
144054df959aef7dce630a7f41d4aba6626c130756bPatrick TjinIdleInvalidator *IdleInvalidator::getInstance() {
145054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
146054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    if(sInstance.get() == NULL)
147054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin        sInstance = new IdleInvalidator();
148054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin    return sInstance.get();
149054df959aef7dce630a7f41d4aba6626c130756bPatrick Tjin}
150