hwc.cpp revision 3777bbf2b00594bbc0823a78666445ddd0e89dc6
1/*
2 * Copyright (C) 2012 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#include <errno.h>
17#include <fcntl.h>
18#include <poll.h>
19#include <pthread.h>
20#include <stdio.h>
21#include <stdlib.h>
22
23#include <sys/ioctl.h>
24#include <sys/mman.h>
25#include <sys/time.h>
26#include <sys/resource.h>
27
28#include <s3c-fb.h>
29
30#include <EGL/egl.h>
31
32#define HWC_REMOVE_DEPRECATED_VERSIONS 1
33
34#include <cutils/log.h>
35#include <hardware/gralloc.h>
36#include <hardware/hardware.h>
37#include <hardware/hwcomposer.h>
38#include <hardware_legacy/uevent.h>
39#include <utils/Vector.h>
40
41#include <sync/sync.h>
42
43#include "ion.h"
44#include "gralloc_priv.h"
45#include "exynos_gscaler.h"
46
47struct hwc_callback_entry {
48    void (*callback)(void *, private_handle_t *);
49    void *data;
50};
51typedef android::Vector<struct hwc_callback_entry> hwc_callback_queue_t;
52
53const size_t NUM_HW_WINDOWS = 5;
54const size_t NO_FB_NEEDED = NUM_HW_WINDOWS + 1;
55const size_t MAX_PIXELS = 2560 * 1600 * 2;
56
57struct exynos5_hwc_composer_device_1_t;
58
59struct exynos5_hwc_post_data_t {
60    exynos5_hwc_composer_device_1_t *pdev;
61    int                             overlay_map[NUM_HW_WINDOWS];
62    hwc_layer_1_t                   overlays[NUM_HW_WINDOWS];
63    int                             num_overlays;
64    size_t                          fb_window;
65    int                             fence;
66    pthread_mutex_t                 completion_lock;
67    pthread_cond_t                  completion;
68};
69
70struct exynos5_hwc_composer_device_1_t {
71    hwc_composer_device_1_t base;
72
73    int                     fd;
74    int                     vsync_fd;
75    exynos5_hwc_post_data_t bufs;
76
77    const private_module_t  *gralloc_module;
78    hwc_procs_t             *procs;
79    pthread_t               vsync_thread;
80
81    bool hdmi_hpd;
82    bool hdmi_mirroring;
83    void *hdmi_gsc;
84};
85
86static void dump_layer(hwc_layer_1_t const *l)
87{
88    ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
89            "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
90            l->compositionType, l->flags, l->handle, l->transform,
91            l->blending,
92            l->sourceCrop.left,
93            l->sourceCrop.top,
94            l->sourceCrop.right,
95            l->sourceCrop.bottom,
96            l->displayFrame.left,
97            l->displayFrame.top,
98            l->displayFrame.right,
99            l->displayFrame.bottom);
100}
101
102static void dump_handle(private_handle_t *h)
103{
104    ALOGV("\t\tformat = %d, width = %u, height = %u, stride = %u",
105            h->format, h->width, h->height, h->stride);
106}
107
108static void dump_config(s3c_fb_win_config &c)
109{
110    ALOGV("\tstate = %u", c.state);
111    if (c.state == c.S3C_FB_WIN_STATE_BUFFER) {
112        ALOGV("\t\tfd = %d, offset = %u, stride = %u, "
113                "x = %d, y = %d, w = %u, h = %u, "
114                "format = %u",
115                c.fd, c.offset, c.stride,
116                c.x, c.y, c.w, c.h,
117                c.format);
118    }
119    else if (c.state == c.S3C_FB_WIN_STATE_COLOR) {
120        ALOGV("\t\tcolor = %u", c.color);
121    }
122}
123
124inline int WIDTH(const hwc_rect &rect) { return rect.right - rect.left; }
125inline int HEIGHT(const hwc_rect &rect) { return rect.bottom - rect.top; }
126template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; }
127template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
128
129static bool is_transformed(const hwc_layer_1_t &layer)
130{
131    return layer.transform != 0;
132}
133
134static bool is_scaled(const hwc_layer_1_t &layer)
135{
136    return WIDTH(layer.displayFrame) != WIDTH(layer.sourceCrop) ||
137            HEIGHT(layer.displayFrame) != HEIGHT(layer.sourceCrop);
138}
139
140static enum s3c_fb_pixel_format exynos5_format_to_s3c_format(int format)
141{
142    switch (format) {
143    case HAL_PIXEL_FORMAT_RGBA_8888:
144        return S3C_FB_PIXEL_FORMAT_RGBA_8888;
145    case HAL_PIXEL_FORMAT_RGBX_8888:
146        return S3C_FB_PIXEL_FORMAT_RGBX_8888;
147    case HAL_PIXEL_FORMAT_RGBA_5551:
148        return S3C_FB_PIXEL_FORMAT_RGBA_5551;
149    case HAL_PIXEL_FORMAT_RGBA_4444:
150        return S3C_FB_PIXEL_FORMAT_RGBA_4444;
151
152    default:
153        return S3C_FB_PIXEL_FORMAT_MAX;
154    }
155}
156
157static bool exynos5_format_is_supported(int format)
158{
159    return exynos5_format_to_s3c_format(format) < S3C_FB_PIXEL_FORMAT_MAX;
160}
161
162static bool exynos5_format_is_supported_by_gscaler(int format)
163{
164    switch(format) {
165    case HAL_PIXEL_FORMAT_RGBA_8888:
166    case HAL_PIXEL_FORMAT_RGBX_8888:
167    case HAL_PIXEL_FORMAT_RGB_565:
168    case HAL_PIXEL_FORMAT_YV12:
169        return true;
170
171    default:
172        return false;
173    }
174}
175
176static uint8_t exynos5_format_to_bpp(int format)
177{
178    switch (format) {
179    case HAL_PIXEL_FORMAT_RGBA_8888:
180    case HAL_PIXEL_FORMAT_RGBX_8888:
181        return 32;
182
183    case HAL_PIXEL_FORMAT_RGBA_5551:
184    case HAL_PIXEL_FORMAT_RGBA_4444:
185        return 16;
186
187    default:
188        ALOGW("unrecognized pixel format %u", format);
189        return 0;
190    }
191}
192
193static int hdmi_enable(struct exynos5_hwc_composer_device_1_t *dev)
194{
195    if (dev->hdmi_mirroring)
196        return 0;
197
198    exynos_gsc_img src_info;
199    exynos_gsc_img dst_info;
200
201    // TODO: Don't hardcode
202    int src_w = 2560;
203    int src_h = 1600;
204    int dst_w = 1920;
205    int dst_h = 1080;
206
207    dev->hdmi_gsc = exynos_gsc_create_exclusive(3, GSC_OUTPUT_MODE, GSC_OUT_TV);
208    if (!dev->hdmi_gsc) {
209        ALOGE("%s: exynos_gsc_create_exclusive failed", __func__);
210        return -ENODEV;
211    }
212
213    memset(&src_info, 0, sizeof(src_info));
214    memset(&dst_info, 0, sizeof(dst_info));
215
216    src_info.w = src_w;
217    src_info.h = src_h;
218    src_info.fw = src_w;
219    src_info.fh = src_h;
220    src_info.format = HAL_PIXEL_FORMAT_BGRA_8888;
221
222    dst_info.w = dst_w;
223    dst_info.h = dst_h;
224    dst_info.fw = dst_w;
225    dst_info.fh = dst_h;
226    dst_info.format = HAL_PIXEL_FORMAT_YV12;
227
228    int ret = exynos_gsc_config_exclusive(dev->hdmi_gsc, &src_info, &dst_info);
229    if (ret < 0) {
230        ALOGE("%s: exynos_gsc_config_exclusive failed %d", __func__, ret);
231        exynos_gsc_destroy(dev->hdmi_gsc);
232        dev->hdmi_gsc = NULL;
233        return ret;
234    }
235
236    dev->hdmi_mirroring = true;
237    return 0;
238}
239
240static void hdmi_disable(struct exynos5_hwc_composer_device_1_t *dev)
241{
242    if (!dev->hdmi_mirroring)
243        return;
244    exynos_gsc_destroy(dev->hdmi_gsc);
245    dev->hdmi_gsc = NULL;
246    dev->hdmi_mirroring = false;
247}
248
249static int hdmi_output(struct exynos5_hwc_composer_device_1_t *dev, private_handle_t *fb)
250{
251    exynos_gsc_img src_info;
252    exynos_gsc_img dst_info;
253
254    memset(&src_info, 0, sizeof(src_info));
255    memset(&dst_info, 0, sizeof(dst_info));
256
257    src_info.yaddr = fb->fd;
258
259    int ret = exynos_gsc_run_exclusive(dev->hdmi_gsc, &src_info, &dst_info);
260    if (ret < 0) {
261        ALOGE("%s: exynos_gsc_run_exclusive failed %d", __func__, ret);
262        return ret;
263    }
264
265    return 0;
266}
267
268bool exynos5_supports_overlay(hwc_layer_1_t &layer, size_t i)
269{
270    private_handle_t *handle = private_handle_t::dynamicCast(layer.handle);
271
272    if (!handle) {
273        ALOGV("\tlayer %u: handle is NULL", i);
274        return false;
275    }
276    if (!exynos5_format_is_supported(handle->format)) {
277        ALOGV("\tlayer %u: pixel format %u not supported", i,
278                handle->format);
279        return false;
280    }
281    if (is_scaled(layer)) {
282        ALOGV("\tlayer %u: scaling not supported", i);
283        return false;
284    }
285    if (is_transformed(layer)) {
286        ALOGV("\tlayer %u: transformations not supported", i);
287        return false;
288    }
289    if (layer.blending != HWC_BLENDING_NONE) {
290        // TODO: support this
291        ALOGV("\tlayer %u: blending not supported", i);
292        return false;
293    }
294
295    return true;
296}
297
298inline bool intersect(const hwc_rect &r1, const hwc_rect &r2)
299{
300    return !(r1.left > r2.right ||
301        r1.right < r2.left ||
302        r1.top > r2.bottom ||
303        r1.bottom < r2.top);
304}
305
306inline hwc_rect intersection(const hwc_rect &r1, const hwc_rect &r2)
307{
308    hwc_rect i;
309    i.top = max(r1.top, r2.top);
310    i.bottom = min(r1.bottom, r2.bottom);
311    i.left = max(r1.left, r2.left);
312    i.right = min(r1.right, r2.right);
313    return i;
314}
315
316static int exynos5_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list)
317{
318    if (!list)
319        return 0;
320
321    ALOGV("preparing %u layers", list->numHwLayers);
322
323    exynos5_hwc_composer_device_1_t *pdev =
324            (exynos5_hwc_composer_device_1_t *)dev;
325    memset(pdev->bufs.overlays, 0, sizeof(pdev->bufs.overlays));
326
327    bool force_fb = false;
328    if (pdev->hdmi_hpd) {
329        hdmi_enable(pdev);
330        force_fb = true;
331    } else {
332        hdmi_disable(pdev);
333    }
334
335    for (size_t i = 0; i < NUM_HW_WINDOWS; i++)
336        pdev->bufs.overlay_map[i] = -1;
337
338    bool fb_needed = false;
339    size_t first_fb = 0, last_fb = 0;
340
341    // find unsupported overlays
342    for (size_t i = 0; i < list->numHwLayers; i++) {
343        hwc_layer_1_t &layer = list->hwLayers[i];
344
345        if (layer.compositionType == HWC_BACKGROUND && !force_fb) {
346            ALOGV("\tlayer %u: background supported", i);
347            continue;
348        }
349
350        if (exynos5_supports_overlay(list->hwLayers[i], i) && !force_fb) {
351            ALOGV("\tlayer %u: overlay supported", i);
352            layer.compositionType = HWC_OVERLAY;
353            continue;
354        }
355
356        if (!fb_needed) {
357            first_fb = i;
358            fb_needed = true;
359        }
360        last_fb = i;
361        layer.compositionType = HWC_FRAMEBUFFER;
362    }
363
364    // can't composite overlays sandwiched between framebuffers
365    if (fb_needed)
366        for (size_t i = first_fb; i < last_fb; i++)
367            list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
368
369    // Incrementally try to add our supported layers to hardware windows.
370    // If adding a layer would violate a hardware constraint, force it
371    // into the framebuffer and try again.  (Revisiting the entire list is
372    // necessary because adding a layer to the framebuffer can cause other
373    // windows to retroactively violate constraints.)
374    bool changed;
375    do {
376        android::Vector<hwc_rect> rects;
377        android::Vector<hwc_rect> overlaps;
378        size_t pixels_left, windows_left;
379
380        if (fb_needed) {
381            hwc_rect_t fb_rect;
382            fb_rect.top = fb_rect.left = 0;
383            fb_rect.right = pdev->gralloc_module->xres - 1;
384            fb_rect.bottom = pdev->gralloc_module->yres - 1;
385            pixels_left = MAX_PIXELS - pdev->gralloc_module->xres *
386                    pdev->gralloc_module->yres;
387            windows_left = NUM_HW_WINDOWS - 1;
388            rects.push_back(fb_rect);
389        }
390        else {
391            pixels_left = MAX_PIXELS;
392            windows_left = NUM_HW_WINDOWS;
393        }
394        changed = false;
395
396        for (size_t i = 0; i < list->numHwLayers; i++) {
397            hwc_layer_1_t &layer = list->hwLayers[i];
398
399            // we've already accounted for the framebuffer above
400            if (layer.compositionType == HWC_FRAMEBUFFER)
401                continue;
402
403            // only layer 0 can be HWC_BACKGROUND, so we can
404            // unconditionally allow it without extra checks
405            if (layer.compositionType == HWC_BACKGROUND) {
406                windows_left--;
407                continue;
408            }
409
410            size_t pixels_needed = WIDTH(layer.displayFrame) *
411                    HEIGHT(layer.displayFrame);
412            bool can_compose = windows_left && pixels_needed <= pixels_left;
413
414            // hwc_rect_t right and bottom values are normally exclusive;
415            // the intersection logic is simpler if we make them inclusive
416            hwc_rect_t visible_rect = layer.displayFrame;
417            visible_rect.right--; visible_rect.bottom--;
418
419            // no more than 2 layers can overlap on a given pixel
420            for (size_t j = 0; can_compose && j < overlaps.size(); j++) {
421                if (intersect(visible_rect, overlaps.itemAt(j)))
422                    can_compose = false;
423            }
424
425            if (!can_compose) {
426                layer.compositionType = HWC_FRAMEBUFFER;
427                if (!fb_needed) {
428                    first_fb = last_fb = i;
429                    fb_needed = true;
430                }
431                else {
432                    first_fb = min(i, first_fb);
433                    last_fb = max(i, last_fb);
434                }
435                changed = true;
436                break;
437            }
438
439            for (size_t j = 0; j < rects.size(); j++) {
440                const hwc_rect_t &other_rect = rects.itemAt(j);
441                if (intersect(visible_rect, other_rect))
442                    overlaps.push_back(intersection(visible_rect, other_rect));
443            }
444            rects.push_back(visible_rect);
445            pixels_left -= pixels_needed;
446            windows_left--;
447        }
448
449        if (changed)
450            for (size_t i = first_fb; i < last_fb; i++)
451                list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
452    } while(changed);
453
454    unsigned int nextWindow = 0;
455
456    for (size_t i = 0; i < list->numHwLayers; i++) {
457        hwc_layer_1_t &layer = list->hwLayers[i];
458
459        if (fb_needed && i == first_fb) {
460            ALOGV("assigning framebuffer to window %u\n",
461                    nextWindow);
462            nextWindow++;
463            continue;
464        }
465
466        if (layer.compositionType != HWC_FRAMEBUFFER) {
467            ALOGV("assigning layer %u to window %u", i, nextWindow);
468            pdev->bufs.overlay_map[nextWindow] = i;
469            nextWindow++;
470        }
471    }
472
473    if (fb_needed)
474        pdev->bufs.fb_window = first_fb;
475    else
476        pdev->bufs.fb_window = NO_FB_NEEDED;
477
478    for (size_t i = 0; i < list->numHwLayers; i++) {
479        dump_layer(&list->hwLayers[i]);
480        if(list->hwLayers[i].handle)
481            dump_handle(private_handle_t::dynamicCast(
482                    list->hwLayers[i].handle));
483    }
484
485    return 0;
486}
487
488static void exynos5_config_handle(private_handle_t *handle,
489        hwc_rect_t &sourceCrop, hwc_rect_t &displayFrame,
490        s3c_fb_win_config &cfg)
491{
492    cfg.state = cfg.S3C_FB_WIN_STATE_BUFFER;
493    cfg.fd = handle->fd;
494    cfg.x = displayFrame.left;
495    cfg.y = displayFrame.top;
496    cfg.w = WIDTH(displayFrame);
497    cfg.h = HEIGHT(displayFrame);
498    cfg.format = exynos5_format_to_s3c_format(handle->format);
499    uint8_t bpp = exynos5_format_to_bpp(handle->format);
500    cfg.offset = (sourceCrop.top * handle->stride + sourceCrop.left) * bpp / 8;
501    cfg.stride = handle->stride * bpp / 8;
502}
503
504static void exynos5_config_overlay(hwc_layer_1_t *layer, s3c_fb_win_config &cfg,
505        const private_module_t *gralloc_module)
506{
507    if (layer->compositionType == HWC_BACKGROUND) {
508        hwc_color_t color = layer->backgroundColor;
509        cfg.state = cfg.S3C_FB_WIN_STATE_COLOR;
510        cfg.color = (color.r << 16) | (color.g << 8) | color.b;
511        cfg.x = 0;
512        cfg.y = 0;
513        cfg.w = gralloc_module->xres;
514        cfg.h = gralloc_module->yres;
515        return;
516    }
517
518    private_handle_t *handle = private_handle_t::dynamicCast(layer->handle);
519    exynos5_config_handle(handle, layer->sourceCrop, layer->displayFrame, cfg);
520}
521
522static void exynos5_post_callback(void *data, private_handle_t *fb)
523{
524    exynos5_hwc_post_data_t *pdata = (exynos5_hwc_post_data_t *)data;
525
526    struct s3c_fb_win_config_data win_data;
527    struct s3c_fb_win_config *config = win_data.config;
528    memset(config, 0, sizeof(win_data.config));
529    for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
530        if (i == pdata->fb_window) {
531            hwc_rect_t rect = { 0, 0, fb->width, fb->height };
532            exynos5_config_handle(fb, rect, rect, config[i]);
533        } else if ( pdata->overlay_map[i] != -1) {
534            exynos5_config_overlay(&pdata->overlays[i], config[i],
535                    pdata->pdev->gralloc_module);
536            if (pdata->overlays[i].acquireFenceFd != -1) {
537                int err = sync_wait(pdata->overlays[i].acquireFenceFd, 100);
538                if (err != 0)
539                    ALOGW("fence for layer %zu didn't signal in 100 ms: %s",
540                          i, strerror(errno));
541                close(pdata->overlays[i].acquireFenceFd);
542            }
543        }
544        dump_config(config[i]);
545    }
546
547    int ret = ioctl(pdata->pdev->fd, S3CFB_WIN_CONFIG, &win_data);
548    if (ret < 0)
549        ALOGE("ioctl S3CFB_WIN_CONFIG failed: %d", errno);
550
551    if (pdata->pdev->hdmi_mirroring)
552        hdmi_output(pdata->pdev, fb);
553
554    pthread_mutex_lock(&pdata->completion_lock);
555    pdata->fence = win_data.fence;
556    pthread_cond_signal(&pdata->completion);
557    pthread_mutex_unlock(&pdata->completion_lock);
558}
559
560static int exynos5_set(struct hwc_composer_device_1 *dev, hwc_display_t dpy,
561        hwc_surface_t sur, hwc_layer_list_1_t* list)
562{
563    exynos5_hwc_composer_device_1_t *pdev =
564            (exynos5_hwc_composer_device_1_t *)dev;
565
566    if (!dpy || !sur)
567        return 0;
568
569    hwc_callback_queue_t *queue = NULL;
570    pthread_mutex_t *lock = NULL;
571    exynos5_hwc_post_data_t *data = NULL;
572
573    if (list) {
574        for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
575            if (pdev->bufs.overlay_map[i] != -1) {
576                pdev->bufs.overlays[i] =
577                    list->hwLayers[pdev->bufs.overlay_map[i]];
578            }
579        }
580
581        data = (exynos5_hwc_post_data_t *)
582                malloc(sizeof(exynos5_hwc_post_data_t));
583        memcpy(data, &pdev->bufs, sizeof(pdev->bufs));
584
585        data->fence = -1;
586        pthread_mutex_init(&data->completion_lock, NULL);
587        pthread_cond_init(&data->completion, NULL);
588
589        if (pdev->bufs.fb_window == NO_FB_NEEDED) {
590            exynos5_post_callback(data, NULL);
591        } else {
592
593            struct hwc_callback_entry entry;
594            entry.callback = exynos5_post_callback;
595            entry.data = data;
596
597            queue = reinterpret_cast<hwc_callback_queue_t *>(
598                pdev->gralloc_module->queue);
599            lock = const_cast<pthread_mutex_t *>(
600                &pdev->gralloc_module->queue_lock);
601
602            pthread_mutex_lock(lock);
603            queue->push_front(entry);
604            pthread_mutex_unlock(lock);
605
606            EGLBoolean success = eglSwapBuffers((EGLDisplay)dpy,
607                    (EGLSurface)sur);
608            if (!success) {
609                ALOGE("HWC_EGL_ERROR");
610                if (list) {
611                    pthread_mutex_lock(lock);
612                    queue->removeAt(0);
613                    pthread_mutex_unlock(lock);
614                    free(data);
615                }
616                return HWC_EGL_ERROR;
617            }
618        }
619    }
620
621
622    pthread_mutex_lock(&data->completion_lock);
623    while (data->fence == -1)
624        pthread_cond_wait(&data->completion, &data->completion_lock);
625    pthread_mutex_unlock(&data->completion_lock);
626
627    for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
628        if (pdev->bufs.overlay_map[i] != -1) {
629            int dup_fd = dup(data->fence);
630            if (dup_fd < 0)
631                ALOGW("release fence dup failed: %s", strerror(errno));
632            list->hwLayers[pdev->bufs.overlay_map[i]].releaseFenceFd = dup_fd;
633        }
634    }
635    close(data->fence);
636    free(data);
637    return 0;
638}
639
640static void exynos5_registerProcs(struct hwc_composer_device_1* dev,
641        hwc_procs_t const* procs)
642{
643    struct exynos5_hwc_composer_device_1_t* pdev =
644            (struct exynos5_hwc_composer_device_1_t*)dev;
645    pdev->procs = const_cast<hwc_procs_t *>(procs);
646}
647
648static int exynos5_query(struct hwc_composer_device_1* dev, int what, int *value)
649{
650    struct exynos5_hwc_composer_device_1_t *pdev =
651            (struct exynos5_hwc_composer_device_1_t *)dev;
652
653    switch (what) {
654    case HWC_BACKGROUND_LAYER_SUPPORTED:
655        // we support the background layer
656        value[0] = 1;
657        break;
658    case HWC_VSYNC_PERIOD:
659        // vsync period in nanosecond
660        value[0] = 1000000000.0 / pdev->gralloc_module->fps;
661        break;
662    default:
663        // unsupported query
664        return -EINVAL;
665    }
666    return 0;
667}
668
669static int exynos5_eventControl(struct hwc_composer_device_1 *dev, int event,
670        int enabled)
671{
672    struct exynos5_hwc_composer_device_1_t *pdev =
673            (struct exynos5_hwc_composer_device_1_t *)dev;
674
675    switch (event) {
676    case HWC_EVENT_VSYNC:
677        __u32 val = !!enabled;
678        int err = ioctl(pdev->fd, S3CFB_SET_VSYNC_INT, &val);
679        if (err < 0) {
680            ALOGE("vsync ioctl failed");
681            return -errno;
682        }
683
684        return 0;
685    }
686
687    return -EINVAL;
688}
689
690static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t *pdev,
691        const char *buff, int len)
692{
693    const char *s = buff;
694    s += strlen(s) + 1;
695
696    while (*s) {
697        if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
698            pdev->hdmi_hpd = atoi(s + strlen("SWITCH_STATE=")) == 1;
699
700        s += strlen(s) + 1;
701        if (s - buff >= len)
702            break;
703    }
704
705    ALOGV("HDMI HPD changed to %s", pdev->hdmi_hpd ? "enabled" : "disabled");
706
707    if (pdev->procs && pdev->procs->invalidate)
708        pdev->procs->invalidate(pdev->procs);
709}
710
711static void handle_vsync_event(struct exynos5_hwc_composer_device_1_t *pdev)
712{
713    if (!pdev->procs || !pdev->procs->vsync)
714        return;
715
716    char buf[4096];
717    int err = read(pdev->vsync_fd, buf, sizeof(buf));
718    if (err < 0) {
719        ALOGE("error reading vsync timestamp: %s", strerror(errno));
720        return;
721    }
722    buf[sizeof(buf) - 1] = '\0';
723
724    errno = 0;
725    uint64_t timestamp = strtoull(buf, NULL, 0);
726    if (!errno)
727        pdev->procs->vsync(pdev->procs, 0, timestamp);
728}
729
730static void *hwc_vsync_thread(void *data)
731{
732    struct exynos5_hwc_composer_device_1_t *pdev =
733            (struct exynos5_hwc_composer_device_1_t *)data;
734    char uevent_desc[4096];
735    memset(uevent_desc, 0, sizeof(uevent_desc));
736
737    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
738
739    uevent_init();
740
741    struct pollfd fds[2];
742    fds[0].fd = pdev->vsync_fd;
743    fds[0].events = POLLPRI;
744    fds[1].fd = uevent_get_fd();
745    fds[1].events = POLLIN;
746
747    while (true) {
748        int err = poll(fds, 2, -1);
749
750        if (err > 0) {
751            if (fds[0].revents & POLLPRI) {
752                handle_vsync_event(pdev);
753            }
754            else if (fds[1].revents & POLLIN) {
755                int len = uevent_next_event(uevent_desc,
756                        sizeof(uevent_desc) - 2);
757
758                bool hdmi = !strcmp(uevent_desc,
759                        "change@/devices/virtual/switch/hdmi");
760                if (hdmi)
761                    handle_hdmi_uevent(pdev, uevent_desc, len);
762            }
763        }
764        else if (err == -1) {
765            if (errno == EINTR)
766                break;
767            ALOGE("error in vsync thread: %s", strerror(errno));
768        }
769    }
770
771    return NULL;
772}
773
774static int exynos5_blank(struct hwc_composer_device_1 *dev, int blank)
775{
776    struct exynos5_hwc_composer_device_1_t *pdev =
777            (struct exynos5_hwc_composer_device_1_t *)dev;
778
779    int fb_blank = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
780    int err = ioctl(pdev->fd, FBIOBLANK, fb_blank);
781    if (err < 0) {
782        ALOGE("%sblank ioctl failed", blank ? "" : "un");
783        return -errno;
784    }
785
786    return 0;
787}
788
789struct hwc_methods_1 exynos5_methods = {
790    eventControl: exynos5_eventControl,
791    blank: exynos5_blank,
792};
793
794static int exynos5_close(hw_device_t* device);
795
796static int exynos5_open(const struct hw_module_t *module, const char *name,
797        struct hw_device_t **device)
798{
799    int ret;
800    int sw_fd;
801
802    if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
803        return -EINVAL;
804    }
805
806    struct exynos5_hwc_composer_device_1_t *dev;
807    dev = (struct exynos5_hwc_composer_device_1_t *)malloc(sizeof(*dev));
808    memset(dev, 0, sizeof(*dev));
809
810    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
811            (const struct hw_module_t **)&dev->gralloc_module)) {
812        ALOGE("failed to get gralloc hw module");
813        ret = -EINVAL;
814        goto err_get_module;
815    }
816
817    dev->fd = open("/dev/graphics/fb0", O_RDWR);
818    if (dev->fd < 0) {
819        ALOGE("failed to open framebuffer");
820        ret = dev->fd;
821        goto err_get_module;
822    }
823
824    dev->vsync_fd = open("/sys/devices/platform/exynos5-fb.1/vsync", O_RDONLY);
825    if (dev->vsync_fd < 0) {
826        ALOGE("failed to open vsync attribute");
827        ret = dev->vsync_fd;
828        goto err_ioctl;
829    }
830
831    sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY);
832    if (sw_fd) {
833        char val;
834        if (read(sw_fd, &val, 1) == 1 && val == '1')
835            dev->hdmi_hpd = true;
836    }
837
838    dev->base.common.tag = HARDWARE_DEVICE_TAG;
839    dev->base.common.version = HWC_DEVICE_API_VERSION_1_0;
840    dev->base.common.module = const_cast<hw_module_t *>(module);
841    dev->base.common.close = exynos5_close;
842
843    dev->base.prepare = exynos5_prepare;
844    dev->base.set = exynos5_set;
845    dev->base.registerProcs = exynos5_registerProcs;
846    dev->base.query = exynos5_query;
847    dev->base.methods = &exynos5_methods;
848
849    dev->bufs.pdev = dev;
850
851    *device = &dev->base.common;
852
853    ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev);
854    if (ret) {
855        ALOGE("failed to start vsync thread: %s", strerror(ret));
856        ret = -ret;
857        goto err_vsync;
858    }
859
860    return 0;
861
862err_vsync:
863    close(dev->vsync_fd);
864err_ioctl:
865    close(dev->fd);
866err_get_module:
867    free(dev);
868    return ret;
869}
870
871static int exynos5_close(hw_device_t *device)
872{
873    struct exynos5_hwc_composer_device_1_t *dev =
874            (struct exynos5_hwc_composer_device_1_t *)device;
875    pthread_kill(dev->vsync_thread, SIGTERM);
876    pthread_join(dev->vsync_thread, NULL);
877    close(dev->vsync_fd);
878    close(dev->fd);
879    return 0;
880}
881
882static struct hw_module_methods_t exynos5_hwc_module_methods = {
883    open: exynos5_open,
884};
885
886hwc_module_t HAL_MODULE_INFO_SYM = {
887    common: {
888        tag: HARDWARE_MODULE_TAG,
889        module_api_version: HWC_MODULE_API_VERSION_0_1,
890        hal_api_version: HARDWARE_HAL_API_VERSION,
891        id: HWC_HARDWARE_MODULE_ID,
892        name: "Samsung exynos5 hwcomposer module",
893        author: "Google",
894        methods: &exynos5_hwc_module_methods,
895    }
896};
897