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 53namespace sdm { 54 55using drm_utils::DRMMaster; 56 57DisplayError 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 break; 88 } 89 } 90 91 return kErrorNone; 92} 93 94DisplayError HWEventsDRM::SetEventParser() { 95 DisplayError error = kErrorNone; 96 97 for (auto &event_data : event_data_list_) { 98 switch (event_data.event_type) { 99 case HWEvent::VSYNC: 100 event_data.event_parser = &HWEventsDRM::HandleVSync; 101 break; 102 case HWEvent::IDLE_NOTIFY: 103 event_data.event_parser = &HWEventsDRM::HandleIdleTimeout; 104 break; 105 case HWEvent::CEC_READ_MESSAGE: 106 event_data.event_parser = &HWEventsDRM::HandleCECMessage; 107 break; 108 case HWEvent::EXIT: 109 event_data.event_parser = &HWEventsDRM::HandleThreadExit; 110 break; 111 case HWEvent::SHOW_BLANK_EVENT: 112 event_data.event_parser = &HWEventsDRM::HandleBlank; 113 break; 114 case HWEvent::THERMAL_LEVEL: 115 event_data.event_parser = &HWEventsDRM::HandleThermal; 116 break; 117 default: 118 error = kErrorParameters; 119 break; 120 } 121 } 122 123 return error; 124} 125 126void HWEventsDRM::PopulateHWEventData(const vector<HWEvent> &event_list) { 127 for (auto &event : event_list) { 128 HWEventData event_data; 129 event_data.event_type = event; 130 event_data_list_.push_back(std::move(event_data)); 131 } 132 133 SetEventParser(); 134 InitializePollFd(); 135} 136 137DisplayError HWEventsDRM::Init(int display_type, HWEventHandler *event_handler, 138 const vector<HWEvent> &event_list) { 139 if (!event_handler) 140 return kErrorParameters; 141 142 event_handler_ = event_handler; 143 poll_fds_.resize(event_list.size()); 144 event_thread_name_ += " - " + std::to_string(display_type); 145 146 PopulateHWEventData(event_list); 147 148 if (pthread_create(&event_thread_, NULL, &DisplayEventThread, this) < 0) { 149 DLOGE("Failed to start %s, error = %s", event_thread_name_.c_str()); 150 return kErrorResources; 151 } 152 153 return kErrorNone; 154} 155 156DisplayError HWEventsDRM::Deinit() { 157 exit_threads_ = true; 158 Sys::pthread_cancel_(event_thread_); 159 160 for (uint32_t i = 0; i < event_data_list_.size(); i++) { 161 if (event_data_list_[i].event_type == HWEvent::EXIT) { 162 uint64_t exit_value = 1; 163 ssize_t write_size = Sys::write_(poll_fds_[i].fd, &exit_value, sizeof(uint64_t)); 164 if (write_size != sizeof(uint64_t)) { 165 DLOGW("Error triggering exit fd (%d). write size = %d, error = %s", poll_fds_[i].fd, 166 write_size, strerror(errno)); 167 } 168 } 169 } 170 171 pthread_join(event_thread_, NULL); 172 CloseFds(); 173 174 return kErrorNone; 175} 176 177DisplayError HWEventsDRM::CloseFds() { 178 for (uint32_t i = 0; i < event_data_list_.size(); i++) { 179 switch (event_data_list_[i].event_type) { 180 case HWEvent::VSYNC: 181 poll_fds_[i].fd = -1; 182 break; 183 case HWEvent::EXIT: 184 Sys::close_(poll_fds_[i].fd); 185 poll_fds_[i].fd = -1; 186 break; 187 case HWEvent::IDLE_NOTIFY: 188 case HWEvent::CEC_READ_MESSAGE: 189 case HWEvent::SHOW_BLANK_EVENT: 190 case HWEvent::THERMAL_LEVEL: 191 break; 192 default: 193 return kErrorNotSupported; 194 } 195 } 196 197 return kErrorNone; 198} 199 200void *HWEventsDRM::DisplayEventThread(void *context) { 201 if (context) { 202 return reinterpret_cast<HWEventsDRM *>(context)->DisplayEventHandler(); 203 } 204 205 return NULL; 206} 207 208void *HWEventsDRM::DisplayEventHandler() { 209 char data[kMaxStringLength]{}; 210 211 prctl(PR_SET_NAME, event_thread_name_.c_str(), 0, 0, 0); 212 setpriority(PRIO_PROCESS, 0, kThreadPriorityUrgent); 213 214 while (!exit_threads_) { 215 if (RegisterVSync() != kErrorNone) { 216 pthread_exit(0); 217 return nullptr; 218 } 219 220 int error = Sys::poll_(poll_fds_.data(), UINT32(poll_fds_.size()), -1); 221 if (error <= 0) { 222 DLOGW("poll failed. error = %s", strerror(errno)); 223 continue; 224 } 225 226 for (uint32_t i = 0; i < event_data_list_.size(); i++) { 227 pollfd &poll_fd = poll_fds_[i]; 228 switch (event_data_list_[i].event_type) { 229 case HWEvent::VSYNC: 230 (this->*(event_data_list_[i]).event_parser)(nullptr); 231 break; 232 case HWEvent::EXIT: 233 if ((poll_fd.revents & POLLIN) && 234 (Sys::read_(poll_fd.fd, data, kMaxStringLength) > 0)) { 235 (this->*(event_data_list_[i]).event_parser)(data); 236 } 237 break; 238 case HWEvent::IDLE_NOTIFY: 239 case HWEvent::CEC_READ_MESSAGE: 240 case HWEvent::SHOW_BLANK_EVENT: 241 case HWEvent::THERMAL_LEVEL: 242 if (poll_fd.fd >= 0 && (poll_fd.revents & POLLPRI) && 243 (Sys::pread_(poll_fd.fd, data, kMaxStringLength, 0) > 0)) { 244 (this->*(event_data_list_[i]).event_parser)(data); 245 } 246 break; 247 } 248 } 249 } 250 251 pthread_exit(0); 252 253 return nullptr; 254} 255 256DisplayError HWEventsDRM::RegisterVSync() { 257 drmVBlank vblank{}; 258 vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT); 259 vblank.request.sequence = 1; 260 // DRM hack to pass in context to unused field signal. Driver will write this to the node being 261 // polled on, and will be read as part of drm event handling and sent to handler 262 vblank.request.signal = reinterpret_cast<unsigned long>(this); // NOLINT 263 int error = drmWaitVBlank(poll_fds_[vsync_index_].fd, &vblank); 264 if (error < 0) { 265 DLOGE("drmWaitVBlank failed with err %d", errno); 266 return kErrorResources; 267 } 268 269 return kErrorNone; 270} 271 272void HWEventsDRM::HandleVSync(char *data) { 273 if (poll_fds_[vsync_index_].revents & (POLLIN | POLLPRI)) { 274 drmEventContext event = {}; 275 event.version = DRM_EVENT_CONTEXT_VERSION; 276 event.vblank_handler = &HWEventsDRM::VSyncHandlerCallback; 277 int error = drmHandleEvent(poll_fds_[vsync_index_].fd, &event); 278 if (error != 0) { 279 DLOGE("drmHandleEvent failed: %i", error); 280 } 281 } 282} 283 284void HWEventsDRM::VSyncHandlerCallback(int fd, unsigned int sequence, unsigned int tv_sec, 285 unsigned int tv_usec, void *data) { 286 int64_t timestamp = (int64_t)(tv_sec)*1000000000 + (int64_t)(tv_usec)*1000; 287 reinterpret_cast<HWEventsDRM *>(data)->event_handler_->VSync(timestamp); 288} 289 290void HWEventsDRM::HandleIdleTimeout(char *data) { 291 event_handler_->IdleTimeout(); 292} 293 294void HWEventsDRM::HandleCECMessage(char *data) { 295 event_handler_->CECMessage(data); 296} 297 298} // namespace sdm 299