1 /* 2 * Copyright (c) 2015 - 2017, 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 <errno.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <math.h> 34 #include <fcntl.h> 35 #include <sys/types.h> 36 #include <sys/resource.h> 37 #include <sys/prctl.h> 38 #include <utils/debug.h> 39 #include <utils/sys.h> 40 #include <pthread.h> 41 #include <algorithm> 42 #include <vector> 43 #include <map> 44 #include <utility> 45 46 #include "hw_events.h" 47 48 #define __CLASS__ "HWEvents" 49 50 namespace sdm { 51 52 pollfd HWEvents::InitializePollFd(HWEventData *event_data) { 53 char node_path[kMaxStringLength] = {0}; 54 char data[kMaxStringLength] = {0}; 55 pollfd poll_fd = {0}; 56 poll_fd.fd = -1; 57 58 if (event_data->event_type == HWEvent::EXIT) { 59 // Create an eventfd to be used to unblock the poll system call when 60 // a thread is exiting. 61 poll_fd.fd = Sys::eventfd_(0, 0); 62 poll_fd.events |= POLLIN; 63 exit_fd_ = poll_fd.fd; 64 } else { 65 snprintf(node_path, sizeof(node_path), "%s%d/%s", fb_path_, fb_num_, 66 map_event_to_node_[event_data->event_type]); 67 poll_fd.fd = Sys::open_(node_path, O_RDONLY); 68 poll_fd.events |= POLLPRI | POLLERR; 69 } 70 71 if (poll_fd.fd < 0) { 72 DLOGW("open failed for display=%d event=%s, error=%s", fb_num_, 73 map_event_to_node_[event_data->event_type], strerror(errno)); 74 return poll_fd; 75 } 76 77 // Read once on all fds to clear data on all fds. 78 Sys::pread_(poll_fd.fd, data , kMaxStringLength, 0); 79 80 return poll_fd; 81 } 82 83 DisplayError HWEvents::SetEventParser(HWEvent event_type, HWEventData *event_data) { 84 DisplayError error = kErrorNone; 85 switch (event_type) { 86 case HWEvent::VSYNC: 87 event_data->event_parser = &HWEvents::HandleVSync; 88 break; 89 case HWEvent::IDLE_NOTIFY: 90 event_data->event_parser = &HWEvents::HandleIdleTimeout; 91 break; 92 case HWEvent::CEC_READ_MESSAGE: 93 event_data->event_parser = &HWEvents::HandleCECMessage; 94 break; 95 case HWEvent::EXIT: 96 event_data->event_parser = &HWEvents::HandleThreadExit; 97 break; 98 case HWEvent::SHOW_BLANK_EVENT: 99 event_data->event_parser = &HWEvents::HandleBlank; 100 break; 101 case HWEvent::THERMAL_LEVEL: 102 event_data->event_parser = &HWEvents::HandleThermal; 103 break; 104 case HWEvent::IDLE_POWER_COLLAPSE: 105 event_data->event_parser = &HWEvents::HandleIdlePowerCollapse; 106 break; 107 case HWEvent::PINGPONG_TIMEOUT: 108 event_data->event_parser = &HWEvents::HandlePingPongTimeout; 109 break; 110 default: 111 error = kErrorParameters; 112 break; 113 } 114 115 return error; 116 } 117 118 void HWEvents::PopulateHWEventData() { 119 for (uint32_t i = 0; i < event_list_.size(); i++) { 120 HWEventData event_data; 121 event_data.event_type = event_list_[i]; 122 SetEventParser(event_list_[i], &event_data); 123 poll_fds_[i] = InitializePollFd(&event_data); 124 event_data_list_.push_back(event_data); 125 } 126 } 127 128 DisplayError HWEvents::Init(int fb_num, HWEventHandler *event_handler, 129 const vector<HWEvent> &event_list) { 130 if (!event_handler) 131 return kErrorParameters; 132 133 event_handler_ = event_handler; 134 fb_num_ = fb_num; 135 event_list_ = event_list; 136 poll_fds_.resize(event_list_.size()); 137 event_thread_name_ += " - " + std::to_string(fb_num_); 138 map_event_to_node_ = {{HWEvent::VSYNC, "vsync_event"}, 139 {HWEvent::EXIT, "thread_exit"}, 140 {HWEvent::IDLE_NOTIFY, "idle_notify"}, 141 {HWEvent::SHOW_BLANK_EVENT, "show_blank_event"}, 142 {HWEvent::CEC_READ_MESSAGE, "cec/rd_msg"}, 143 {HWEvent::THERMAL_LEVEL, "msm_fb_thermal_level"}, 144 {HWEvent::IDLE_POWER_COLLAPSE, "idle_power_collapse"}, 145 {HWEvent::PINGPONG_TIMEOUT, "pingpong_timeout"}}; 146 147 PopulateHWEventData(); 148 149 if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) { 150 DLOGE("Failed to start %s, error = %s", event_thread_name_.c_str()); 151 return kErrorResources; 152 } 153 154 return kErrorNone; 155 } 156 157 DisplayError HWEvents::Deinit() { 158 exit_threads_ = true; 159 Sys::pthread_cancel_(event_thread_); 160 161 uint64_t exit_value = 1; 162 ssize_t write_size = Sys::write_(exit_fd_, &exit_value, sizeof(uint64_t)); 163 if (write_size != sizeof(uint64_t)) 164 DLOGW("Error triggering exit_fd_ (%d). write size = %d, error = %s", exit_fd_, write_size, 165 strerror(errno)); 166 167 pthread_join(event_thread_, NULL); 168 169 for (uint32_t i = 0; i < event_list_.size(); i++) { 170 Sys::close_(poll_fds_[i].fd); 171 poll_fds_[i].fd = -1; 172 } 173 174 return kErrorNone; 175 } 176 177 void* HWEvents::DisplayEventThread(void *context) { 178 if (context) { 179 return reinterpret_cast<HWEvents *>(context)->DisplayEventHandler(); 180 } 181 182 return NULL; 183 } 184 185 void* HWEvents::DisplayEventHandler() { 186 char data[kMaxStringLength] = {0}; 187 188 prctl(PR_SET_NAME, event_thread_name_.c_str(), 0, 0, 0); 189 setpriority(PRIO_PROCESS, 0, kThreadPriorityUrgent); 190 191 while (!exit_threads_) { 192 int error = Sys::poll_(poll_fds_.data(), UINT32(event_list_.size()), -1); 193 194 if (error <= 0) { 195 DLOGW("poll failed. error = %s", strerror(errno)); 196 continue; 197 } 198 199 for (uint32_t event = 0; event < event_list_.size(); event++) { 200 pollfd &poll_fd = poll_fds_[event]; 201 202 if (event_list_.at(event) == HWEvent::EXIT) { 203 if ((poll_fd.revents & POLLIN) && (Sys::read_(poll_fd.fd, data, kMaxStringLength) > 0)) { 204 (this->*(event_data_list_[event]).event_parser)(data); 205 } 206 } else { 207 if ((poll_fd.revents & POLLPRI) && 208 (Sys::pread_(poll_fd.fd, data, kMaxStringLength, 0) > 0)) { 209 (this->*(event_data_list_[event]).event_parser)(data); 210 } 211 } 212 } 213 } 214 215 pthread_exit(0); 216 217 return NULL; 218 } 219 220 void HWEvents::HandleVSync(char *data) { 221 int64_t timestamp = 0; 222 if (!strncmp(data, "VSYNC=", strlen("VSYNC="))) { 223 timestamp = strtoll(data + strlen("VSYNC="), NULL, 0); 224 } 225 226 event_handler_->VSync(timestamp); 227 } 228 229 void HWEvents::HandleIdleTimeout(char *data) { 230 event_handler_->IdleTimeout(); 231 } 232 233 void HWEvents::HandlePingPongTimeout(char *data) { 234 event_handler_->PingPongTimeout(); 235 } 236 237 void HWEvents::HandleThermal(char *data) { 238 int64_t thermal_level = 0; 239 if (!strncmp(data, "thermal_level=", strlen("thermal_level="))) { 240 thermal_level = strtoll(data + strlen("thermal_level="), NULL, 0); 241 } 242 243 DLOGI("Received thermal notification with thermal level = %d", thermal_level); 244 245 event_handler_->ThermalEvent(thermal_level); 246 } 247 248 void HWEvents::HandleCECMessage(char *data) { 249 event_handler_->CECMessage(data); 250 } 251 252 void HWEvents::HandleIdlePowerCollapse(char *data) { 253 event_handler_->IdlePowerCollapse(); 254 } 255 256 } // namespace sdm 257