1 /* 2 * Copyright (c) 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 <drm_master.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <math.h> 34 #include <pthread.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <sys/prctl.h> 38 #include <sys/resource.h> 39 #include <sys/types.h> 40 #include <utils/debug.h> 41 #include <utils/sys.h> 42 #include <xf86drm.h> 43 44 #include <algorithm> 45 #include <map> 46 #include <utility> 47 #include <vector> 48 49 #include "hw_events_drm.h" 50 51 #define __CLASS__ "HWEventsDRM" 52 53 namespace sdm { 54 55 using drm_utils::DRMMaster; 56 57 DisplayError HWEventsDRM::InitializePollFd() { 58 for (uint32_t i = 0; i < event_data_list_.size(); i++) { 59 char data[kMaxStringLength]{}; 60 HWEventData &event_data = event_data_list_[i]; 61 poll_fds_[i].fd = -1; 62 63 switch (event_data.event_type) { 64 case HWEvent::VSYNC: { 65 poll_fds_[i].events = POLLIN | POLLPRI | POLLERR; 66 DRMMaster *master = nullptr; 67 int ret = DRMMaster::GetInstance(&master); 68 if (ret < 0) { 69 DLOGE("Failed to acquire DRMMaster instance"); 70 return kErrorNotSupported; 71 } 72 master->GetHandle(&poll_fds_[i].fd); 73 vsync_index_ = i; 74 } break; 75 case HWEvent::EXIT: { 76 // Create an eventfd to be used to unblock the poll system call when 77 // a thread is exiting. 78 poll_fds_[i].fd = Sys::eventfd_(0, 0); 79 poll_fds_[i].events |= POLLIN; 80 // Clear any existing data 81 Sys::pread_(poll_fds_[i].fd, data, kMaxStringLength, 0); 82 } break; 83 case HWEvent::IDLE_NOTIFY: 84 case HWEvent::CEC_READ_MESSAGE: 85 case HWEvent::SHOW_BLANK_EVENT: 86 case HWEvent::THERMAL_LEVEL: 87 case HWEvent::IDLE_POWER_COLLAPSE: 88 break; 89 } 90 } 91 92 return kErrorNone; 93 } 94 95 DisplayError HWEventsDRM::SetEventParser() { 96 DisplayError error = kErrorNone; 97 98 for (auto &event_data : event_data_list_) { 99 switch (event_data.event_type) { 100 case HWEvent::VSYNC: 101 event_data.event_parser = &HWEventsDRM::HandleVSync; 102 break; 103 case HWEvent::IDLE_NOTIFY: 104 event_data.event_parser = &HWEventsDRM::HandleIdleTimeout; 105 break; 106 case HWEvent::CEC_READ_MESSAGE: 107 event_data.event_parser = &HWEventsDRM::HandleCECMessage; 108 break; 109 case HWEvent::EXIT: 110 event_data.event_parser = &HWEventsDRM::HandleThreadExit; 111 break; 112 case HWEvent::SHOW_BLANK_EVENT: 113 event_data.event_parser = &HWEventsDRM::HandleBlank; 114 break; 115 case HWEvent::THERMAL_LEVEL: 116 event_data.event_parser = &HWEventsDRM::HandleThermal; 117 break; 118 case HWEvent::IDLE_POWER_COLLAPSE: 119 event_data.event_parser = &HWEventsDRM::HandleIdlePowerCollapse; 120 break; 121 default: 122 error = kErrorParameters; 123 break; 124 } 125 } 126 127 return error; 128 } 129 130 void HWEventsDRM::PopulateHWEventData(const vector<HWEvent> &event_list) { 131 for (auto &event : event_list) { 132 HWEventData event_data; 133 event_data.event_type = event; 134 event_data_list_.push_back(std::move(event_data)); 135 } 136 137 SetEventParser(); 138 InitializePollFd(); 139 } 140 141 DisplayError HWEventsDRM::Init(int display_type, HWEventHandler *event_handler, 142 const vector<HWEvent> &event_list) { 143 if (!event_handler) 144 return kErrorParameters; 145 146 event_handler_ = event_handler; 147 poll_fds_.resize(event_list.size()); 148 event_thread_name_ += " - " + std::to_string(display_type); 149 150 PopulateHWEventData(event_list); 151 152 if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) { 153 DLOGE("Failed to start %s, error = %s", event_thread_name_.c_str()); 154 return kErrorResources; 155 } 156 157 return kErrorNone; 158 } 159 160 DisplayError HWEventsDRM::Deinit() { 161 exit_threads_ = true; 162 Sys::pthread_cancel_(event_thread_); 163 WakeUpEventThread(); 164 pthread_join(event_thread_, NULL); 165 CloseFds(); 166 167 return kErrorNone; 168 } 169 170 DisplayError HWEventsDRM::SetEventState(HWEvent event, bool enable, void *arg) { 171 switch (event) { 172 case HWEvent::VSYNC: 173 vsync_enabled_ = enable; 174 if (enable) { 175 WakeUpEventThread(); 176 } 177 break; 178 default: 179 DLOGE("Event not supported"); 180 return kErrorNotSupported; 181 } 182 183 return kErrorNone; 184 } 185 186 void HWEventsDRM::WakeUpEventThread() { 187 for (uint32_t i = 0; i < event_data_list_.size(); i++) { 188 if (event_data_list_[i].event_type == HWEvent::EXIT) { 189 uint64_t exit_value = 1; 190 ssize_t write_size = Sys::write_(poll_fds_[i].fd, &exit_value, sizeof(uint64_t)); 191 if (write_size != sizeof(uint64_t)) { 192 DLOGW("Error triggering exit fd (%d). write size = %d, error = %s", poll_fds_[i].fd, 193 write_size, strerror(errno)); 194 } 195 break; 196 } 197 } 198 } 199 200 DisplayError HWEventsDRM::CloseFds() { 201 for (uint32_t i = 0; i < event_data_list_.size(); i++) { 202 switch (event_data_list_[i].event_type) { 203 case HWEvent::VSYNC: 204 poll_fds_[i].fd = -1; 205 break; 206 case HWEvent::EXIT: 207 Sys::close_(poll_fds_[i].fd); 208 poll_fds_[i].fd = -1; 209 break; 210 case HWEvent::IDLE_NOTIFY: 211 case HWEvent::CEC_READ_MESSAGE: 212 case HWEvent::SHOW_BLANK_EVENT: 213 case HWEvent::THERMAL_LEVEL: 214 case HWEvent::IDLE_POWER_COLLAPSE: 215 break; 216 default: 217 return kErrorNotSupported; 218 } 219 } 220 221 return kErrorNone; 222 } 223 224 void *HWEventsDRM::DisplayEventThread(void *context) { 225 if (context) { 226 return reinterpret_cast<HWEventsDRM *>(context)->DisplayEventHandler(); 227 } 228 229 return NULL; 230 } 231 232 void *HWEventsDRM::DisplayEventHandler() { 233 char data[kMaxStringLength]{}; 234 235 prctl(PR_SET_NAME, event_thread_name_.c_str(), 0, 0, 0); 236 setpriority(PRIO_PROCESS, 0, kThreadPriorityUrgent); 237 238 while (!exit_threads_) { 239 if (vsync_enabled_ && RegisterVSync() != kErrorNone) { 240 pthread_exit(0); 241 return nullptr; 242 } 243 244 int error = Sys::poll_(poll_fds_.data(), UINT32(poll_fds_.size()), -1); 245 if (error <= 0) { 246 DLOGW("poll failed. error = %s", strerror(errno)); 247 continue; 248 } 249 250 for (uint32_t i = 0; i < event_data_list_.size(); i++) { 251 pollfd &poll_fd = poll_fds_[i]; 252 switch (event_data_list_[i].event_type) { 253 case HWEvent::VSYNC: 254 (this->*(event_data_list_[i]).event_parser)(nullptr); 255 break; 256 case HWEvent::EXIT: 257 if ((poll_fd.revents & POLLIN) && 258 (Sys::read_(poll_fd.fd, data, kMaxStringLength) > 0)) { 259 (this->*(event_data_list_[i]).event_parser)(data); 260 } 261 break; 262 case HWEvent::IDLE_NOTIFY: 263 case HWEvent::CEC_READ_MESSAGE: 264 case HWEvent::SHOW_BLANK_EVENT: 265 case HWEvent::THERMAL_LEVEL: 266 case HWEvent::IDLE_POWER_COLLAPSE: 267 if (poll_fd.fd >= 0 && (poll_fd.revents & POLLPRI) && 268 (Sys::pread_(poll_fd.fd, data, kMaxStringLength, 0) > 0)) { 269 (this->*(event_data_list_[i]).event_parser)(data); 270 } 271 break; 272 } 273 } 274 } 275 276 pthread_exit(0); 277 278 return nullptr; 279 } 280 281 DisplayError HWEventsDRM::RegisterVSync() { 282 drmVBlank vblank{}; 283 vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT); 284 vblank.request.sequence = 1; 285 // DRM hack to pass in context to unused field signal. Driver will write this to the node being 286 // polled on, and will be read as part of drm event handling and sent to handler 287 vblank.request.signal = reinterpret_cast<unsigned long>(this); // NOLINT 288 int error = drmWaitVBlank(poll_fds_[vsync_index_].fd, &vblank); 289 if (error < 0) { 290 DLOGE("drmWaitVBlank failed with err %d", errno); 291 return kErrorResources; 292 } 293 294 return kErrorNone; 295 } 296 297 void HWEventsDRM::HandleVSync(char *data) { 298 if (poll_fds_[vsync_index_].revents & (POLLIN | POLLPRI)) { 299 drmEventContext event = {}; 300 event.version = DRM_EVENT_CONTEXT_VERSION; 301 event.vblank_handler = &HWEventsDRM::VSyncHandlerCallback; 302 int error = drmHandleEvent(poll_fds_[vsync_index_].fd, &event); 303 if (error != 0) { 304 DLOGE("drmHandleEvent failed: %i", error); 305 } 306 } 307 } 308 309 void HWEventsDRM::VSyncHandlerCallback(int fd, unsigned int sequence, unsigned int tv_sec, 310 unsigned int tv_usec, void *data) { 311 int64_t timestamp = (int64_t)(tv_sec)*1000000000 + (int64_t)(tv_usec)*1000; 312 reinterpret_cast<HWEventsDRM *>(data)->event_handler_->VSync(timestamp); 313 } 314 315 void HWEventsDRM::HandleIdleTimeout(char *data) { 316 event_handler_->IdleTimeout(); 317 } 318 319 void HWEventsDRM::HandleCECMessage(char *data) { 320 event_handler_->CECMessage(data); 321 } 322 323 void HWEventsDRM::HandleIdlePowerCollapse(char *data) { 324 event_handler_->IdlePowerCollapse(); 325 } 326 327 } // namespace sdm 328