1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <fcntl.h> 18 #include <poll.h> 19 #include <pthread.h> 20 #include <sys/resource.h> 21 22 #include <adf/adf.h> 23 #include <adfhwc/adfhwc.h> 24 25 #include <cutils/log.h> 26 #include <utils/Vector.h> 27 28 struct adf_hwc_helper { 29 adf_hwc_event_callbacks const *event_cb; 30 void *event_cb_data; 31 32 pthread_t event_thread; 33 34 android::Vector<int> intf_fds; 35 android::Vector<drm_mode_modeinfo> display_configs; 36 }; 37 38 template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; } 39 40 int adf_eventControl(struct adf_hwc_helper *dev, int disp, int event, 41 int enabled) 42 { 43 if (enabled != !!enabled) 44 return -EINVAL; 45 46 if ((size_t)disp >= dev->intf_fds.size()) 47 return -EINVAL; 48 49 switch (event) { 50 case HWC_EVENT_VSYNC: 51 return adf_set_event(dev->intf_fds[disp], ADF_EVENT_VSYNC, enabled); 52 } 53 54 return -EINVAL; 55 } 56 57 static inline int32_t dpi(uint16_t res, uint16_t size_mm) 58 { 59 if (size_mm) 60 return 1000 * (res * 25.4f) / size_mm; 61 return 0; 62 } 63 64 int adf_blank(struct adf_hwc_helper *dev, int disp, int blank) 65 { 66 if ((size_t)disp >= dev->intf_fds.size()) 67 return -EINVAL; 68 69 uint8_t dpms_mode = blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON; 70 return adf_interface_blank(dev->intf_fds[disp], dpms_mode); 71 } 72 73 int adf_query_display_types_supported(struct adf_hwc_helper *dev, int *value) 74 { 75 *value = 0; 76 if (dev->intf_fds.size() > 0) 77 *value |= HWC_DISPLAY_PRIMARY_BIT; 78 if (dev->intf_fds.size() > 1) 79 *value |= HWC_DISPLAY_EXTERNAL_BIT; 80 81 return 0; 82 } 83 84 int adf_getDisplayConfigs(struct adf_hwc_helper *dev, int disp, 85 uint32_t *configs, size_t *numConfigs) 86 { 87 if ((size_t)disp >= dev->intf_fds.size()) 88 return -EINVAL; 89 90 adf_interface_data data; 91 int err = adf_get_interface_data(dev->intf_fds[disp], &data); 92 if (err < 0) { 93 ALOGE("failed to get ADF interface data: %s", strerror(err)); 94 return err; 95 } 96 97 if (!data.hotplug_detect) 98 return -ENODEV; 99 100 android::Vector<drm_mode_modeinfo *> unique_configs; 101 unique_configs.push_back(&data.current_mode); 102 for (size_t i = 0; i < data.n_available_modes; i++) 103 if (memcmp(&data.available_modes[i], &data.current_mode, 104 sizeof(data.current_mode))) 105 unique_configs.push_back(&data.available_modes[i]); 106 107 for (size_t i = 0; i < min(*numConfigs, unique_configs.size()); i++) { 108 configs[i] = dev->display_configs.size(); 109 dev->display_configs.push_back(*unique_configs[i]); 110 } 111 *numConfigs = unique_configs.size(); 112 113 adf_free_interface_data(&data); 114 return 0; 115 } 116 117 static int32_t adf_display_attribute(const adf_interface_data &data, 118 const drm_mode_modeinfo &mode, const uint32_t attribute) 119 { 120 switch (attribute) { 121 case HWC_DISPLAY_VSYNC_PERIOD: 122 if (mode.vrefresh) 123 return 1000000000 / mode.vrefresh; 124 return 0; 125 126 case HWC_DISPLAY_WIDTH: 127 return mode.hdisplay; 128 129 case HWC_DISPLAY_HEIGHT: 130 return mode.vdisplay; 131 132 case HWC_DISPLAY_DPI_X: 133 return dpi(mode.hdisplay, data.width_mm); 134 135 case HWC_DISPLAY_DPI_Y: 136 return dpi(mode.vdisplay, data.height_mm); 137 138 default: 139 ALOGE("unknown display attribute %u", attribute); 140 return -EINVAL; 141 } 142 } 143 144 int adf_getDisplayAttributes(struct adf_hwc_helper *dev, int disp, 145 uint32_t config, const uint32_t *attributes, int32_t *values) 146 { 147 if ((size_t)disp >= dev->intf_fds.size()) 148 return -EINVAL; 149 150 if (config >= dev->display_configs.size()) 151 return -EINVAL; 152 153 adf_interface_data data; 154 int err = adf_get_interface_data(dev->intf_fds[disp], &data); 155 if (err < 0) { 156 ALOGE("failed to get ADF interface data: %s", strerror(err)); 157 return err; 158 } 159 160 for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) 161 values[i] = adf_display_attribute(data, dev->display_configs[config], 162 attributes[i]); 163 164 adf_free_interface_data(&data); 165 return 0; 166 } 167 168 static void handle_adf_event(struct adf_hwc_helper *dev, int disp) 169 { 170 adf_event *event; 171 int err = adf_read_event(dev->intf_fds[disp], &event); 172 if (err < 0) { 173 ALOGE("error reading event from display %d: %s", disp, strerror(err)); 174 return; 175 } 176 177 void *vsync_temp; 178 adf_vsync_event *vsync; 179 adf_hotplug_event *hotplug; 180 181 switch (event->type) { 182 case ADF_EVENT_VSYNC: 183 vsync_temp = event; 184 vsync = static_cast<adf_vsync_event *>(vsync_temp); 185 // casting directly to adf_vsync_event * makes g++ warn about 186 // potential alignment issues that don't apply here 187 dev->event_cb->vsync(dev->event_cb_data, disp, vsync->timestamp); 188 break; 189 case ADF_EVENT_HOTPLUG: 190 hotplug = reinterpret_cast<adf_hotplug_event *>(event); 191 dev->event_cb->hotplug(dev->event_cb_data, disp, hotplug->connected); 192 break; 193 default: 194 if (event->type < ADF_EVENT_DEVICE_CUSTOM) 195 ALOGW("unrecognized event type %u", event->type); 196 else if (!dev->event_cb || !dev->event_cb->custom_event) 197 ALOGW("unhandled event type %u", event->type); 198 else 199 dev->event_cb->custom_event(dev->event_cb_data, disp, event); 200 } 201 free(event); 202 } 203 204 static void *adf_event_thread(void *data) 205 { 206 adf_hwc_helper *dev = static_cast<adf_hwc_helper *>(data); 207 208 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); 209 210 pollfd *fds = new pollfd[dev->intf_fds.size()]; 211 for (size_t i = 0; i < dev->intf_fds.size(); i++) { 212 fds[i].fd = dev->intf_fds[i]; 213 fds[i].events = POLLIN | POLLPRI; 214 } 215 216 while (true) { 217 int err = poll(fds, dev->intf_fds.size(), -1); 218 219 if (err > 0) { 220 for (size_t i = 0; i < dev->intf_fds.size(); i++) 221 if (fds[i].revents & (POLLIN | POLLPRI)) 222 handle_adf_event(dev, i); 223 } 224 else if (err == -1) { 225 if (errno == EINTR) 226 break; 227 ALOGE("error in event thread: %s", strerror(errno)); 228 } 229 } 230 231 delete [] fds; 232 return NULL; 233 } 234 235 int adf_hwc_open(int *intf_fds, size_t n_intfs, 236 const struct adf_hwc_event_callbacks *event_cb, void *event_cb_data, 237 struct adf_hwc_helper **dev) 238 { 239 if (!n_intfs) 240 return -EINVAL; 241 242 adf_hwc_helper *dev_ret = new adf_hwc_helper; 243 dev_ret->event_cb = event_cb; 244 dev_ret->event_cb_data = event_cb_data; 245 246 int ret; 247 248 for (size_t i = 0; i < n_intfs; i++) { 249 int dup_intf_fd = dup(intf_fds[i]); 250 if (dup_intf_fd < 0) { 251 ALOGE("failed to dup interface fd: %s", strerror(errno)); 252 ret = -errno; 253 goto err; 254 } 255 256 dev_ret->intf_fds.push_back(dup_intf_fd); 257 258 ret = adf_set_event(dup_intf_fd, ADF_EVENT_HOTPLUG, 1); 259 if (ret < 0 && ret != -EINVAL) { 260 ALOGE("failed to enable hotplug event on display %zu: %s", 261 i, strerror(errno)); 262 goto err; 263 } 264 } 265 266 ret = pthread_create(&dev_ret->event_thread, NULL, adf_event_thread, 267 dev_ret); 268 if (ret) { 269 ALOGE("failed to create event thread: %s", strerror(ret)); 270 goto err; 271 } 272 273 *dev = dev_ret; 274 return 0; 275 276 err: 277 for (size_t i = 0; i < dev_ret->intf_fds.size(); i++) 278 close(dev_ret->intf_fds[i]); 279 280 delete dev_ret; 281 return ret; 282 } 283 284 void adf_hwc_close(struct adf_hwc_helper *dev) 285 { 286 pthread_kill(dev->event_thread, SIGTERM); 287 pthread_join(dev->event_thread, NULL); 288 289 for (size_t i = 0; i < dev->intf_fds.size(); i++) 290 close(dev->intf_fds[i]); 291 292 delete dev; 293 } 294