Home | History | Annotate | Download | only in libadfhwc
      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 <malloc.h>
     19 #include <poll.h>
     20 #include <pthread.h>
     21 #include <sys/resource.h>
     22 
     23 #include <log/log.h>
     24 #include <utils/Vector.h>
     25 
     26 #include <adf/adf.h>
     27 #include <adfhwc/adfhwc.h>
     28 
     29 struct adf_hwc_helper {
     30     adf_hwc_event_callbacks const *event_cb;
     31     void *event_cb_data;
     32 
     33     pthread_t event_thread;
     34 
     35     android::Vector<int> intf_fds;
     36     android::Vector<drm_mode_modeinfo> display_configs;
     37 };
     38 
     39 template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
     40 
     41 int adf_eventControl(struct adf_hwc_helper *dev, int disp, int event,
     42         int enabled)
     43 {
     44     if (enabled != !!enabled)
     45         return -EINVAL;
     46 
     47     if ((size_t)disp >= dev->intf_fds.size())
     48         return -EINVAL;
     49 
     50     switch (event) {
     51     case HWC_EVENT_VSYNC:
     52         return adf_set_event(dev->intf_fds[disp], ADF_EVENT_VSYNC, enabled);
     53     }
     54 
     55     return -EINVAL;
     56 }
     57 
     58 static inline int32_t dpi(uint16_t res, uint16_t size_mm)
     59 {
     60     if (size_mm)
     61         return 1000 * (res * 25.4f) / size_mm;
     62     return 0;
     63 }
     64 
     65 int adf_blank(struct adf_hwc_helper *dev, int disp, int blank)
     66 {
     67     if ((size_t)disp >= dev->intf_fds.size())
     68         return -EINVAL;
     69 
     70     uint8_t dpms_mode = blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON;
     71     return adf_interface_blank(dev->intf_fds[disp], dpms_mode);
     72 }
     73 
     74 int adf_query_display_types_supported(struct adf_hwc_helper *dev, int *value)
     75 {
     76     *value = 0;
     77     if (dev->intf_fds.size() > 0)
     78         *value |= HWC_DISPLAY_PRIMARY_BIT;
     79     if (dev->intf_fds.size() > 1)
     80         *value |= HWC_DISPLAY_EXTERNAL_BIT;
     81 
     82     return 0;
     83 }
     84 
     85 int adf_getDisplayConfigs(struct adf_hwc_helper *dev, int disp,
     86         uint32_t *configs, size_t *numConfigs)
     87 {
     88     if ((size_t)disp >= dev->intf_fds.size())
     89         return -EINVAL;
     90 
     91     adf_interface_data data;
     92     int err = adf_get_interface_data(dev->intf_fds[disp], &data);
     93     if (err < 0) {
     94         ALOGE("failed to get ADF interface data: %s", strerror(err));
     95         return err;
     96     }
     97 
     98     if (!data.hotplug_detect)
     99         return -ENODEV;
    100 
    101     android::Vector<drm_mode_modeinfo *> unique_configs;
    102     unique_configs.push_back(&data.current_mode);
    103     for (size_t i = 0; i < data.n_available_modes; i++)
    104         if (memcmp(&data.available_modes[i], &data.current_mode,
    105                 sizeof(data.current_mode)))
    106             unique_configs.push_back(&data.available_modes[i]);
    107 
    108     for (size_t i = 0; i < min(*numConfigs, unique_configs.size()); i++) {
    109         configs[i] = dev->display_configs.size();
    110         dev->display_configs.push_back(*unique_configs[i]);
    111     }
    112     *numConfigs = unique_configs.size();
    113 
    114     adf_free_interface_data(&data);
    115     return 0;
    116 }
    117 
    118 static int32_t adf_display_attribute(const adf_interface_data &data,
    119         const drm_mode_modeinfo &mode, const uint32_t attribute)
    120 {
    121     switch (attribute) {
    122     case HWC_DISPLAY_VSYNC_PERIOD:
    123         if (mode.vrefresh)
    124             return 1000000000 / mode.vrefresh;
    125         return 0;
    126 
    127     case HWC_DISPLAY_WIDTH:
    128         return mode.hdisplay;
    129 
    130     case HWC_DISPLAY_HEIGHT:
    131         return mode.vdisplay;
    132 
    133     case HWC_DISPLAY_DPI_X:
    134         return dpi(mode.hdisplay, data.width_mm);
    135 
    136     case HWC_DISPLAY_DPI_Y:
    137         return dpi(mode.vdisplay, data.height_mm);
    138 
    139     default:
    140         ALOGE("unknown display attribute %u", attribute);
    141         return -EINVAL;
    142     }
    143 }
    144 
    145 int adf_getDisplayAttributes(struct adf_hwc_helper *dev, int disp,
    146         uint32_t config, const uint32_t *attributes, int32_t *values)
    147 {
    148     if ((size_t)disp >= dev->intf_fds.size())
    149         return -EINVAL;
    150 
    151     if (config >= dev->display_configs.size())
    152         return -EINVAL;
    153 
    154     adf_interface_data data;
    155     int err = adf_get_interface_data(dev->intf_fds[disp], &data);
    156     if (err < 0) {
    157         ALOGE("failed to get ADF interface data: %s", strerror(err));
    158         return err;
    159     }
    160 
    161     for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++)
    162         values[i] = adf_display_attribute(data, dev->display_configs[config],
    163                 attributes[i]);
    164 
    165     adf_free_interface_data(&data);
    166     return 0;
    167 }
    168 
    169 static int32_t adf_display_attribute_hwc2(const adf_interface_data &data,
    170         const drm_mode_modeinfo &mode, const uint32_t attribute)
    171 {
    172     switch (attribute) {
    173     case HWC2_ATTRIBUTE_VSYNC_PERIOD:
    174         if (mode.vrefresh)
    175             return 1000000000 / mode.vrefresh;
    176         return 0;
    177 
    178     case HWC2_ATTRIBUTE_WIDTH:
    179         return mode.hdisplay;
    180 
    181     case HWC2_ATTRIBUTE_HEIGHT:
    182         return mode.vdisplay;
    183 
    184     case HWC2_ATTRIBUTE_DPI_X:
    185         return dpi(mode.hdisplay, data.width_mm);
    186 
    187     case HWC2_ATTRIBUTE_DPI_Y:
    188         return dpi(mode.vdisplay, data.height_mm);
    189 
    190     default:
    191         ALOGE("unknown display attribute %u", attribute);
    192         return -EINVAL;
    193     }
    194 }
    195 
    196 int adf_getDisplayAttributes_hwc2(struct adf_hwc_helper *dev, int disp,
    197         uint32_t config, const uint32_t *attributes, int32_t *values)
    198 {
    199     if ((size_t)disp >= dev->intf_fds.size())
    200         return -EINVAL;
    201 
    202     if (config >= dev->display_configs.size())
    203         return -EINVAL;
    204 
    205     adf_interface_data data;
    206     int err = adf_get_interface_data(dev->intf_fds[disp], &data);
    207     if (err < 0) {
    208         ALOGE("failed to get ADF interface data: %s", strerror(err));
    209         return err;
    210     }
    211 
    212     for (int i = 0; attributes[i] != HWC2_ATTRIBUTE_INVALID; i++)
    213         values[i] = adf_display_attribute_hwc2(data,
    214                 dev->display_configs[config], attributes[i]);
    215 
    216     adf_free_interface_data(&data);
    217     return 0;
    218 }
    219 
    220 int adf_set_active_config_hwc2(struct adf_hwc_helper *dev, int disp,
    221         uint32_t config)
    222 {
    223     if ((size_t)disp >= dev->intf_fds.size())
    224         return -EINVAL;
    225 
    226     if (config >= dev->display_configs.size())
    227         return -EINVAL;
    228 
    229     struct drm_mode_modeinfo mode = dev->display_configs[config];
    230 
    231     return adf_interface_set_mode(dev->intf_fds[disp], &mode);
    232 }
    233 
    234 static void handle_adf_event(struct adf_hwc_helper *dev, int disp)
    235 {
    236     adf_event *event;
    237     int err = adf_read_event(dev->intf_fds[disp], &event);
    238     if (err < 0) {
    239         ALOGE("error reading event from display %d: %s", disp, strerror(err));
    240         return;
    241     }
    242 
    243     void *vsync_temp;
    244     adf_vsync_event *vsync;
    245     adf_hotplug_event *hotplug;
    246 
    247     switch (event->type) {
    248     case ADF_EVENT_VSYNC:
    249         vsync_temp = event;
    250         vsync = static_cast<adf_vsync_event *>(vsync_temp);
    251         // casting directly to adf_vsync_event * makes g++ warn about
    252         // potential alignment issues that don't apply here
    253         dev->event_cb->vsync(dev->event_cb_data, disp, vsync->timestamp);
    254         break;
    255     case ADF_EVENT_HOTPLUG:
    256         hotplug = reinterpret_cast<adf_hotplug_event *>(event);
    257         dev->event_cb->hotplug(dev->event_cb_data, disp, hotplug->connected);
    258         break;
    259     default:
    260         if (event->type < ADF_EVENT_DEVICE_CUSTOM)
    261             ALOGW("unrecognized event type %u", event->type);
    262         else if (!dev->event_cb || !dev->event_cb->custom_event)
    263             ALOGW("unhandled event type %u", event->type);
    264         else
    265             dev->event_cb->custom_event(dev->event_cb_data, disp, event);
    266     }
    267     free(event);
    268 }
    269 
    270 static void *adf_event_thread(void *data)
    271 {
    272     adf_hwc_helper *dev = static_cast<adf_hwc_helper *>(data);
    273 
    274     setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
    275 
    276     struct sigaction action = { };
    277     sigemptyset(&action.sa_mask);
    278     action.sa_flags = 0;
    279     action.sa_handler = [](int) { pthread_exit(0); };
    280 
    281     if (sigaction(SIGUSR2, &action, NULL) < 0) {
    282         ALOGE("failed to set thread exit action %s", strerror(errno));
    283         return NULL;
    284     }
    285 
    286     sigset_t signal_set;
    287     sigemptyset(&signal_set);
    288     sigaddset(&signal_set, SIGUSR2);
    289 
    290     pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
    291 
    292     pollfd fds[dev->intf_fds.size()];
    293     for (size_t i = 0; i < dev->intf_fds.size(); i++) {
    294         fds[i].fd = dev->intf_fds[i];
    295         fds[i].events = POLLIN | POLLPRI;
    296     }
    297 
    298     while (true) {
    299         if (TEMP_FAILURE_RETRY(poll(fds, dev->intf_fds.size(), -1)) < 0) {
    300             ALOGE("error in event thread: %s", strerror(errno));
    301             break;
    302         }
    303 
    304         for (size_t i = 0; i < dev->intf_fds.size(); i++)
    305             if (fds[i].revents & (POLLIN | POLLPRI))
    306                 handle_adf_event(dev, i);
    307     }
    308 
    309     return NULL;
    310 }
    311 
    312 int adf_hwc_open(int *intf_fds, size_t n_intfs,
    313         const struct adf_hwc_event_callbacks *event_cb, void *event_cb_data,
    314         struct adf_hwc_helper **dev)
    315 {
    316     if (!n_intfs)
    317         return -EINVAL;
    318 
    319     adf_hwc_helper *dev_ret = new adf_hwc_helper;
    320     dev_ret->event_cb = event_cb;
    321     dev_ret->event_cb_data = event_cb_data;
    322 
    323     int ret;
    324 
    325     for (size_t i = 0; i < n_intfs; i++) {
    326         int dup_intf_fd = dup(intf_fds[i]);
    327         if (dup_intf_fd < 0) {
    328             ALOGE("failed to dup interface fd: %s", strerror(errno));
    329             ret = -errno;
    330             goto err;
    331         }
    332 
    333         dev_ret->intf_fds.push_back(dup_intf_fd);
    334 
    335         ret = adf_set_event(dup_intf_fd, ADF_EVENT_HOTPLUG, 1);
    336         if (ret < 0 && ret != -EINVAL) {
    337             ALOGE("failed to enable hotplug event on display %zu: %s",
    338                     i, strerror(errno));
    339             goto err;
    340         }
    341     }
    342 
    343     sigset_t signal_set;
    344     sigemptyset(&signal_set);
    345     sigaddset(&signal_set, SIGUSR2);
    346 
    347     pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
    348 
    349     ret = pthread_create(&dev_ret->event_thread, NULL, adf_event_thread,
    350             dev_ret);
    351     if (ret) {
    352         ALOGE("failed to create event thread: %s", strerror(ret));
    353         goto err;
    354     }
    355 
    356     *dev = dev_ret;
    357     return 0;
    358 
    359 err:
    360     for (size_t i = 0; i < dev_ret->intf_fds.size(); i++)
    361         close(dev_ret->intf_fds[i]);
    362 
    363     delete dev_ret;
    364     return ret;
    365 }
    366 
    367 void adf_hwc_close(struct adf_hwc_helper *dev)
    368 {
    369     pthread_kill(dev->event_thread, SIGUSR2);
    370     pthread_join(dev->event_thread, NULL);
    371 
    372     for (size_t i = 0; i < dev->intf_fds.size(); i++)
    373         close(dev->intf_fds[i]);
    374 
    375     delete dev;
    376 }
    377