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 <adf/adf.h>
     24 #include <adfhwc/adfhwc.h>
     25 
     26 #include <cutils/log.h>
     27 #include <utils/Vector.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 void handle_adf_event(struct adf_hwc_helper *dev, int disp)
    170 {
    171     adf_event *event;
    172     int err = adf_read_event(dev->intf_fds[disp], &event);
    173     if (err < 0) {
    174         ALOGE("error reading event from display %d: %s", disp, strerror(err));
    175         return;
    176     }
    177 
    178     void *vsync_temp;
    179     adf_vsync_event *vsync;
    180     adf_hotplug_event *hotplug;
    181 
    182     switch (event->type) {
    183     case ADF_EVENT_VSYNC:
    184         vsync_temp = event;
    185         vsync = static_cast<adf_vsync_event *>(vsync_temp);
    186         // casting directly to adf_vsync_event * makes g++ warn about
    187         // potential alignment issues that don't apply here
    188         dev->event_cb->vsync(dev->event_cb_data, disp, vsync->timestamp);
    189         break;
    190     case ADF_EVENT_HOTPLUG:
    191         hotplug = reinterpret_cast<adf_hotplug_event *>(event);
    192         dev->event_cb->hotplug(dev->event_cb_data, disp, hotplug->connected);
    193         break;
    194     default:
    195         if (event->type < ADF_EVENT_DEVICE_CUSTOM)
    196             ALOGW("unrecognized event type %u", event->type);
    197         else if (!dev->event_cb || !dev->event_cb->custom_event)
    198             ALOGW("unhandled event type %u", event->type);
    199         else
    200             dev->event_cb->custom_event(dev->event_cb_data, disp, event);
    201     }
    202     free(event);
    203 }
    204 
    205 static void *adf_event_thread(void *data)
    206 {
    207     adf_hwc_helper *dev = static_cast<adf_hwc_helper *>(data);
    208 
    209     setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
    210 
    211     pollfd *fds = new pollfd[dev->intf_fds.size()];
    212     for (size_t i = 0; i < dev->intf_fds.size(); i++) {
    213         fds[i].fd = dev->intf_fds[i];
    214         fds[i].events = POLLIN | POLLPRI;
    215     }
    216 
    217     while (true) {
    218         int err = poll(fds, dev->intf_fds.size(), -1);
    219 
    220         if (err > 0) {
    221             for (size_t i = 0; i < dev->intf_fds.size(); i++)
    222                 if (fds[i].revents & (POLLIN | POLLPRI))
    223                     handle_adf_event(dev, i);
    224         }
    225         else if (err == -1) {
    226             if (errno == EINTR)
    227                 break;
    228             ALOGE("error in event thread: %s", strerror(errno));
    229         }
    230     }
    231 
    232     delete [] fds;
    233     return NULL;
    234 }
    235 
    236 int adf_hwc_open(int *intf_fds, size_t n_intfs,
    237         const struct adf_hwc_event_callbacks *event_cb, void *event_cb_data,
    238         struct adf_hwc_helper **dev)
    239 {
    240     if (!n_intfs)
    241         return -EINVAL;
    242 
    243     adf_hwc_helper *dev_ret = new adf_hwc_helper;
    244     dev_ret->event_cb = event_cb;
    245     dev_ret->event_cb_data = event_cb_data;
    246 
    247     int ret;
    248 
    249     for (size_t i = 0; i < n_intfs; i++) {
    250         int dup_intf_fd = dup(intf_fds[i]);
    251         if (dup_intf_fd < 0) {
    252             ALOGE("failed to dup interface fd: %s", strerror(errno));
    253             ret = -errno;
    254             goto err;
    255         }
    256 
    257         dev_ret->intf_fds.push_back(dup_intf_fd);
    258 
    259         ret = adf_set_event(dup_intf_fd, ADF_EVENT_HOTPLUG, 1);
    260         if (ret < 0 && ret != -EINVAL) {
    261             ALOGE("failed to enable hotplug event on display %zu: %s",
    262                     i, strerror(errno));
    263             goto err;
    264         }
    265     }
    266 
    267     ret = pthread_create(&dev_ret->event_thread, NULL, adf_event_thread,
    268             dev_ret);
    269     if (ret) {
    270         ALOGE("failed to create event thread: %s", strerror(ret));
    271         goto err;
    272     }
    273 
    274     *dev = dev_ret;
    275     return 0;
    276 
    277 err:
    278     for (size_t i = 0; i < dev_ret->intf_fds.size(); i++)
    279         close(dev_ret->intf_fds[i]);
    280 
    281     delete dev_ret;
    282     return ret;
    283 }
    284 
    285 void adf_hwc_close(struct adf_hwc_helper *dev)
    286 {
    287     pthread_kill(dev->event_thread, SIGTERM);
    288     pthread_join(dev->event_thread, NULL);
    289 
    290     for (size_t i = 0; i < dev->intf_fds.size(); i++)
    291         close(dev->intf_fds[i]);
    292 
    293     delete dev;
    294 }
    295