Home | History | Annotate | Download | only in drm
      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