• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Create(int fb_num,HWEventHandler * event_handler,std::vector<const char * > * event_list,HWEventsInterface ** intf)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 
Destroy(HWEventsInterface * intf)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 
InitializePollFd(HWEventData * event_data)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 
SetEventParser(const char * event_name,HWEventData * event_data)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 
PopulateHWEventData()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 
Init(int fb_num,HWEventHandler * event_handler,vector<const char * > * event_list)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 
Deinit()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 
DisplayEventThread(void * context)184 void* HWEvents::DisplayEventThread(void *context) {
185   if (context) {
186     return reinterpret_cast<HWEvents *>(context)->DisplayEventHandler();
187   }
188 
189   return NULL;
190 }
191 
DisplayEventHandler()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 
HandleVSync(char * data)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 
HandleIdleTimeout(char * data)236 void HWEvents::HandleIdleTimeout(char *data) {
237   event_handler_->IdleTimeout();
238 }
239 
HandleThermal(char * data)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 
HandleCECMessage(char * data)251 void HWEvents::HandleCECMessage(char *data) {
252   event_handler_->CECMessage(data);
253 }
254 
255 }  // namespace sdm
256 
257