1 /* 2 * Copyright (c) 2012, The Linux Foundation. All rights reserved. 3 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above 10 * copyright notice, this list of conditions and the following 11 * disclaimer in the documentation and/or other materials provided 12 * with the distribution. 13 * * Neither the name of The Linux Foundation nor the names of its 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "idle_invalidator.h" 31 #include <unistd.h> 32 #include <poll.h> 33 #include <string.h> 34 #include <fcntl.h> 35 #include <cutils/properties.h> 36 37 #define II_DEBUG 0 38 #define IDLE_NOTIFY_PATH "/sys/devices/virtual/graphics/fb0/idle_notify" 39 #define IDLE_TIME_PATH "/sys/devices/virtual/graphics/fb0/idle_time" 40 41 42 static const char *threadName = "IdleInvalidator"; 43 InvalidatorHandler IdleInvalidator::mHandler = NULL; 44 android::sp<IdleInvalidator> IdleInvalidator::sInstance(0); 45 46 IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0), 47 mTimeoutEventFd(-1) { 48 ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); 49 } 50 51 IdleInvalidator::~IdleInvalidator() { 52 if(mTimeoutEventFd >= 0) { 53 close(mTimeoutEventFd); 54 } 55 } 56 57 int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data) { 58 mHandler = reg_handler; 59 mHwcContext = user_data; 60 61 // Open a sysfs node to receive the timeout notification from driver. 62 mTimeoutEventFd = open(IDLE_NOTIFY_PATH, O_RDONLY); 63 if (mTimeoutEventFd < 0) { 64 ALOGE ("%s:not able to open %s node %s", 65 __FUNCTION__, IDLE_NOTIFY_PATH, strerror(errno)); 66 return -1; 67 } 68 69 int defaultIdleTime = 70; //ms 70 char property[PROPERTY_VALUE_MAX] = {0}; 71 if((property_get("debug.mdpcomp.idletime", property, NULL) > 0)) { 72 defaultIdleTime = atoi(property); 73 } 74 if(not setIdleTimeout(defaultIdleTime)) { 75 close(mTimeoutEventFd); 76 mTimeoutEventFd = -1; 77 return -1; 78 } 79 80 //Triggers the threadLoop to run, if not already running. 81 run(threadName, android::PRIORITY_LOWEST); 82 return 0; 83 } 84 85 bool IdleInvalidator::setIdleTimeout(const uint32_t& timeout) { 86 ALOGD_IF(II_DEBUG, "IdleInvalidator::%s timeout %d", 87 __FUNCTION__, timeout); 88 89 // Open a sysfs node to send the timeout value to driver. 90 int fd = open(IDLE_TIME_PATH, O_WRONLY); 91 92 if (fd < 0) { 93 ALOGE ("%s:Unable to open %s node %s", 94 __FUNCTION__, IDLE_TIME_PATH, strerror(errno)); 95 return false; 96 } 97 98 char strSleepTime[64]; 99 snprintf(strSleepTime, sizeof(strSleepTime), "%d", timeout); 100 101 // Notify driver about the timeout value 102 ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0); 103 if(len < -1) { 104 ALOGE ("%s:Unable to write into %s node %s", 105 __FUNCTION__, IDLE_TIME_PATH, strerror(errno)); 106 close(fd); 107 return false; 108 } 109 110 close(fd); 111 return true; 112 } 113 114 bool IdleInvalidator::threadLoop() { 115 ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); 116 struct pollfd pFd; 117 pFd.fd = mTimeoutEventFd; 118 if (pFd.fd >= 0) 119 pFd.events = POLLPRI | POLLERR; 120 // Poll for an timeout event from driver 121 int err = poll(&pFd, 1, -1); 122 if(err > 0) { 123 if (pFd.revents & POLLPRI) { 124 char data[64]; 125 // Consume the node by reading it 126 ssize_t len = pread(pFd.fd, data, 64, 0); 127 ALOGD_IF(II_DEBUG, "IdleInvalidator::%s Idle Timeout fired len %zd", 128 __FUNCTION__, len); 129 mHandler((void*)mHwcContext); 130 } 131 } 132 return true; 133 } 134 135 int IdleInvalidator::readyToRun() { 136 ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); 137 return 0; /*NO_ERROR*/ 138 } 139 140 void IdleInvalidator::onFirstRef() { 141 ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); 142 } 143 144 IdleInvalidator *IdleInvalidator::getInstance() { 145 ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__); 146 if(sInstance.get() == NULL) 147 sInstance = new IdleInvalidator(); 148 return sInstance.get(); 149 } 150