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