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