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