hwc.cpp revision cdd61b35ae02e1fe761815ad9bd166db4098ece2
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 <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 "ump.h" 44#include "ion.h" 45#include "gralloc_priv.h" 46#include "exynos_gscaler.h" 47 48struct hwc_callback_entry 49{ 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 = 2; 56const size_t NO_FB_NEEDED = NUM_HW_WINDOWS + 1; 57 58struct exynos5_hwc_composer_device_1_t; 59 60struct exynos5_hwc_post_data_t { 61 exynos5_hwc_composer_device_1_t *pdev; 62 int overlay_map[NUM_HW_WINDOWS]; 63 hwc_layer_1_t overlays[NUM_HW_WINDOWS]; 64 int num_overlays; 65 size_t fb_window; 66 int fence; 67 pthread_mutex_t completion_lock; 68 pthread_cond_t completion; 69}; 70 71struct exynos5_hwc_composer_device_1_t { 72 hwc_composer_device_1_t base; 73 74 int 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, bpp = %u, stride = %u", 105 h->format, h->width, h->height, h->bpp, 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; } 126 127static bool is_scaled(const hwc_layer_1_t &layer) 128{ 129 return WIDTH(layer.displayFrame) != WIDTH(layer.sourceCrop) || 130 HEIGHT(layer.displayFrame) != HEIGHT(layer.sourceCrop); 131} 132 133static enum s3c_fb_pixel_format exynos5_format_to_s3c_format(int format) 134{ 135 switch (format) { 136 case HAL_PIXEL_FORMAT_RGBA_8888: 137 return S3C_FB_PIXEL_FORMAT_RGBA_8888; 138 case HAL_PIXEL_FORMAT_RGBX_8888: 139 return S3C_FB_PIXEL_FORMAT_RGBX_8888; 140 case HAL_PIXEL_FORMAT_RGBA_5551: 141 return S3C_FB_PIXEL_FORMAT_RGBA_5551; 142 case HAL_PIXEL_FORMAT_RGBA_4444: 143 return S3C_FB_PIXEL_FORMAT_RGBA_4444; 144 145 default: 146 return S3C_FB_PIXEL_FORMAT_MAX; 147 } 148} 149 150static bool exynos5_format_is_supported(int format) 151{ 152 return exynos5_format_to_s3c_format(format) < S3C_FB_PIXEL_FORMAT_MAX; 153} 154 155static bool exynos5_format_is_supported_by_gscaler(int format) 156{ 157 switch(format) { 158 case HAL_PIXEL_FORMAT_RGBA_8888: 159 case HAL_PIXEL_FORMAT_RGBX_8888: 160 case HAL_PIXEL_FORMAT_RGB_565: 161 case HAL_PIXEL_FORMAT_YV12: 162 return true; 163 164 default: 165 return false; 166 } 167} 168 169static uint8_t exynos5_format_to_bpp(int format) 170{ 171 switch (format) { 172 case HAL_PIXEL_FORMAT_RGBA_8888: 173 case HAL_PIXEL_FORMAT_RGBX_8888: 174 return 32; 175 176 case HAL_PIXEL_FORMAT_RGBA_5551: 177 case HAL_PIXEL_FORMAT_RGBA_4444: 178 return 16; 179 180 default: 181 ALOGW("unrecognized pixel format %u", format); 182 return 0; 183 } 184} 185 186static int hdmi_enable(struct exynos5_hwc_composer_device_1_t *dev) 187{ 188 if (dev->hdmi_mirroring) 189 return 0; 190 191 exynos_gsc_img src_info; 192 exynos_gsc_img dst_info; 193 194 // TODO: Don't hardcode 195 int src_w = 2560; 196 int src_h = 1600; 197 int dst_w = 1920; 198 int dst_h = 1080; 199 200 dev->hdmi_gsc = exynos_gsc_create_exclusive(3, GSC_OUTPUT_MODE, GSC_OUT_TV); 201 if (!dev->hdmi_gsc) { 202 ALOGE("%s: exynos_gsc_create_exclusive failed", __func__); 203 return -ENODEV; 204 } 205 206 memset(&src_info, 0, sizeof(src_info)); 207 memset(&dst_info, 0, sizeof(dst_info)); 208 209 src_info.w = src_w; 210 src_info.h = src_h; 211 src_info.fw = src_w; 212 src_info.fh = src_h; 213 src_info.format = HAL_PIXEL_FORMAT_BGRA_8888; 214 215 dst_info.w = dst_w; 216 dst_info.h = dst_h; 217 dst_info.fw = dst_w; 218 dst_info.fh = dst_h; 219 dst_info.format = HAL_PIXEL_FORMAT_RGBA_8888; 220 221 int ret = exynos_gsc_config_exclusive(dev->hdmi_gsc, &src_info, &dst_info); 222 if (ret < 0) { 223 ALOGE("%s: exynos_gsc_config_exclusive failed %d", __func__, ret); 224 exynos_gsc_destroy(dev->hdmi_gsc); 225 dev->hdmi_gsc = NULL; 226 return ret; 227 } 228 229 dev->hdmi_mirroring = true; 230 return 0; 231} 232 233static void hdmi_disable(struct exynos5_hwc_composer_device_1_t *dev) 234{ 235 if (!dev->hdmi_mirroring) 236 return; 237 exynos_gsc_destroy(dev->hdmi_gsc); 238 dev->hdmi_gsc = NULL; 239 dev->hdmi_mirroring = false; 240} 241 242static int hdmi_output(struct exynos5_hwc_composer_device_1_t *dev, private_handle_t *fb) 243{ 244 exynos_gsc_img src_info; 245 exynos_gsc_img dst_info; 246 247 memset(&src_info, 0, sizeof(src_info)); 248 memset(&dst_info, 0, sizeof(dst_info)); 249 250 src_info.yaddr = fb->fd; 251 252 int ret = exynos_gsc_run_exclusive(dev->hdmi_gsc, &src_info, &dst_info); 253 if (ret < 0) { 254 ALOGE("%s: exynos_gsc_run_exclusive failed %d", __func__, ret); 255 return ret; 256 } 257 258 return 0; 259} 260 261bool exynos5_supports_overlay(hwc_layer_1_t &layer, size_t i) { 262 private_handle_t *handle = private_handle_t::dynamicCast(layer.handle); 263 264 if (!handle) { 265 ALOGV("\tlayer %u: handle is NULL", i); 266 return false; 267 } 268 if (!exynos5_format_is_supported(handle->format)) { 269 ALOGV("\tlayer %u: pixel format %u not supported", i, 270 handle->format); 271 return false; 272 } 273 if (is_scaled(layer)) { 274 // TODO: this can be made into an overlay if a gscaler 275 // unit is available. Also some size and pixel format 276 // limitations (see 46-3 of datasheet) 277 ALOGV("\tlayer %u: scaling and transforming not supported", i); 278 return false; 279 } 280 if (layer.blending != HWC_BLENDING_NONE) { 281 // TODO: support this 282 ALOGV("\tlayer %u: blending not supported", i); 283 return false; 284 } 285 286 return true; 287} 288 289static int exynos5_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list) 290{ 291 if (!list) 292 return 0; 293 294 ALOGV("preparing %u layers", list->numHwLayers); 295 296 exynos5_hwc_composer_device_1_t *pdev = 297 (exynos5_hwc_composer_device_1_t *)dev; 298 memset(pdev->bufs.overlays, 0, sizeof(pdev->bufs.overlays)); 299 300 bool force_fb = false; 301 if (pdev->hdmi_hpd) { 302 hdmi_enable(pdev); 303 force_fb = true; 304 } else { 305 hdmi_disable(pdev); 306 } 307 308 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) 309 pdev->bufs.overlay_map[i] = -1; 310 311 bool fb_needed = false; 312 size_t first_fb = 0, last_fb; 313 314 // find unsupported overlays 315 for (size_t i = 0; i < list->numHwLayers; i++) { 316 hwc_layer_1_t &layer = list->hwLayers[i]; 317 318 if (layer.compositionType == HWC_BACKGROUND && !force_fb) { 319 ALOGV("\tlayer %u: background supported", i); 320 continue; 321 } 322 323 if (exynos5_supports_overlay(list->hwLayers[i], i) && !force_fb) { 324 ALOGV("\tlayer %u: overlay supported", i); 325 layer.compositionType = HWC_OVERLAY; 326 continue; 327 } 328 329 if (!fb_needed) { 330 first_fb = i; 331 fb_needed = true; 332 } 333 last_fb = i; 334 layer.compositionType = HWC_FRAMEBUFFER; 335 } 336 337 // can't composite overlays sandwiched between framebuffers 338 if (fb_needed) 339 for (size_t i = first_fb; i < last_fb; i++) 340 list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; 341 342 // if we need a framebuffer but can't fit it in, reserve the last 343 // window as a framebuffer 344 if ((fb_needed && first_fb >= NUM_HW_WINDOWS) || 345 (!fb_needed && list->numHwLayers > NUM_HW_WINDOWS)) { 346 fb_needed = true; 347 first_fb = NUM_HW_WINDOWS - 1; 348 for (size_t i = first_fb; i < list->numHwLayers; i++) 349 list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; 350 } 351 352 unsigned int nextWindow = 0; 353 354 // assign as many overlays as possible to windows 355 for (size_t i = 0; i < list->numHwLayers; i++) { 356 hwc_layer_1_t &layer = list->hwLayers[i]; 357 358 if (nextWindow == NUM_HW_WINDOWS) { 359 ALOGV("not enough windows to assign layer %u", i); 360 layer.compositionType = HWC_FRAMEBUFFER; 361 continue; 362 } 363 364 if (fb_needed && i == first_fb) { 365 ALOGV("assigning framebuffer to window %u\n", 366 nextWindow); 367 nextWindow++; 368 continue; 369 } 370 371 if (layer.compositionType != HWC_FRAMEBUFFER) { 372 ALOGV("assigning layer %u to window %u", i, nextWindow); 373 pdev->bufs.overlay_map[nextWindow] = i; 374 nextWindow++; 375 } 376 } 377 378 if (fb_needed) 379 pdev->bufs.fb_window = first_fb; 380 else 381 pdev->bufs.fb_window = NO_FB_NEEDED; 382 383 for (size_t i = 0; i < list->numHwLayers; i++) { 384 dump_layer(&list->hwLayers[i]); 385 if(list->hwLayers[i].handle) 386 dump_handle(private_handle_t::dynamicCast( 387 list->hwLayers[i].handle)); 388 } 389 390 return 0; 391} 392 393static void exynos5_config_handle(private_handle_t *handle, 394 hwc_rect_t &sourceCrop, hwc_rect_t &displayFrame, 395 s3c_fb_win_config &cfg) { 396 cfg.state = cfg.S3C_FB_WIN_STATE_BUFFER; 397 cfg.fd = handle->fd; 398 cfg.x = displayFrame.left; 399 cfg.y = displayFrame.top; 400 cfg.w = WIDTH(displayFrame); 401 cfg.h = HEIGHT(displayFrame); 402 cfg.format = exynos5_format_to_s3c_format(handle->format); 403 uint8_t bpp = exynos5_format_to_bpp(handle->format); 404 cfg.offset = (sourceCrop.top * handle->stride + sourceCrop.left) * 405 bpp / 8; 406 cfg.stride = handle->stride * bpp / 8; 407} 408 409static void exynos5_config_overlay(hwc_layer_1_t *layer, s3c_fb_win_config &cfg, 410 const private_module_t *gralloc_module) 411{ 412 if (layer->compositionType == HWC_BACKGROUND) { 413 hwc_color_t color = layer->backgroundColor; 414 cfg.state = cfg.S3C_FB_WIN_STATE_COLOR; 415 cfg.color = (color.r << 16) | (color.g << 8) | color.b; 416 cfg.x = 0; 417 cfg.y = 0; 418 cfg.w = gralloc_module->xres; 419 cfg.h = gralloc_module->yres; 420 return; 421 } 422 423 private_handle_t *handle = private_handle_t::dynamicCast(layer->handle); 424 exynos5_config_handle(handle, layer->sourceCrop, layer->displayFrame, 425 cfg); 426} 427 428static void exynos5_post_callback(void *data, private_handle_t *fb) 429{ 430 exynos5_hwc_post_data_t *pdata = 431 (exynos5_hwc_post_data_t *)data; 432 433 struct s3c_fb_win_config_data win_data; 434 struct s3c_fb_win_config *config = win_data.config; 435 memset(config, 0, sizeof(win_data.config)); 436 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { 437 if (i == pdata->fb_window) { 438 hwc_rect_t rect = { 0, 0, fb->width, fb->height }; 439 exynos5_config_handle(fb, rect, rect, config[i]); 440 } else if ( pdata->overlay_map[i] != -1) { 441 exynos5_config_overlay(&pdata->overlays[i], config[i], 442 pdata->pdev->gralloc_module); 443 if (pdata->overlays[i].acquireFenceFd != -1) { 444 int err = sync_wait(pdata->overlays[i].acquireFenceFd, 100); 445 if (err != 0) 446 ALOGW("fence for layer %zu didn't signal in 100 ms: %s", 447 i, strerror(errno)); 448 close(pdata->overlays[i].acquireFenceFd); 449 } 450 } 451 dump_config(config[i]); 452 } 453 454 int ret = ioctl(pdata->pdev->fd, S3CFB_WIN_CONFIG, &win_data); 455 if (ret < 0) 456 ALOGE("ioctl S3CFB_WIN_CONFIG failed: %d", errno); 457 458 if (pdata->pdev->hdmi_mirroring) 459 hdmi_output(pdata->pdev, fb); 460 461 pthread_mutex_lock(&pdata->completion_lock); 462 pdata->fence = win_data.fence; 463 pthread_cond_signal(&pdata->completion); 464 pthread_mutex_unlock(&pdata->completion_lock); 465} 466 467static int exynos5_set(struct hwc_composer_device_1 *dev, hwc_display_t dpy, 468 hwc_surface_t sur, hwc_layer_list_1_t* list) 469{ 470 exynos5_hwc_composer_device_1_t *pdev = 471 (exynos5_hwc_composer_device_1_t *)dev; 472 473 if (!dpy || !sur) 474 return 0; 475 476 hwc_callback_queue_t *queue = NULL; 477 pthread_mutex_t *lock = NULL; 478 exynos5_hwc_post_data_t *data = NULL; 479 480 if (list) { 481 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { 482 if (pdev->bufs.overlay_map[i] != -1) { 483 pdev->bufs.overlays[i] = 484 list->hwLayers[pdev->bufs.overlay_map[i]]; 485 } 486 } 487 488 data = (exynos5_hwc_post_data_t *) 489 malloc(sizeof(exynos5_hwc_post_data_t)); 490 memcpy(data, &pdev->bufs, sizeof(pdev->bufs)); 491 492 data->fence = -1; 493 pthread_mutex_init(&data->completion_lock, NULL); 494 pthread_cond_init(&data->completion, NULL); 495 496 if (pdev->bufs.fb_window == NO_FB_NEEDED) { 497 exynos5_post_callback(data, NULL); 498 } else { 499 500 struct hwc_callback_entry entry; 501 entry.callback = exynos5_post_callback; 502 entry.data = data; 503 504 queue = reinterpret_cast<hwc_callback_queue_t *>( 505 pdev->gralloc_module->queue); 506 lock = const_cast<pthread_mutex_t *>( 507 &pdev->gralloc_module->queue_lock); 508 509 pthread_mutex_lock(lock); 510 queue->push_front(entry); 511 pthread_mutex_unlock(lock); 512 513 EGLBoolean success = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); 514 if (!success) { 515 ALOGE("HWC_EGL_ERROR"); 516 if (list) { 517 pthread_mutex_lock(lock); 518 queue->removeAt(0); 519 pthread_mutex_unlock(lock); 520 free(data); 521 } 522 return HWC_EGL_ERROR; 523 } 524 } 525 } 526 527 528 pthread_mutex_lock(&data->completion_lock); 529 while (data->fence == -1) 530 pthread_cond_wait(&data->completion, &data->completion_lock); 531 pthread_mutex_unlock(&data->completion_lock); 532 533 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { 534 if (pdev->bufs.overlay_map[i] != -1) { 535 int dup_fd = dup(data->fence); 536 if (dup_fd < 0) 537 ALOGW("release fence dup failed: %s", strerror(errno)); 538 list->hwLayers[pdev->bufs.overlay_map[i]].releaseFenceFd = dup_fd; 539 } 540 } 541 close(data->fence); 542 free(data); 543 return 0; 544} 545 546static void exynos5_registerProcs(struct hwc_composer_device_1* dev, 547 hwc_procs_t const* procs) 548{ 549 struct exynos5_hwc_composer_device_1_t* pdev = 550 (struct exynos5_hwc_composer_device_1_t*)dev; 551 pdev->procs = const_cast<hwc_procs_t *>(procs); 552} 553 554static int exynos5_query(struct hwc_composer_device_1* dev, int what, int *value) 555{ 556 struct exynos5_hwc_composer_device_1_t *pdev = 557 (struct exynos5_hwc_composer_device_1_t *)dev; 558 559 switch (what) { 560 case HWC_BACKGROUND_LAYER_SUPPORTED: 561 // we support the background layer 562 value[0] = 1; 563 break; 564 case HWC_VSYNC_PERIOD: 565 // vsync period in nanosecond 566 value[0] = 1000000000.0 / pdev->gralloc_module->fps; 567 break; 568 default: 569 // unsupported query 570 return -EINVAL; 571 } 572 return 0; 573} 574 575static int exynos5_eventControl(struct hwc_composer_device_1 *dev, int event, 576 int enabled) 577{ 578 struct exynos5_hwc_composer_device_1_t *pdev = 579 (struct exynos5_hwc_composer_device_1_t *)dev; 580 581 switch (event) { 582 case HWC_EVENT_VSYNC: 583 __u32 val = !!enabled; 584 int err = ioctl(pdev->fd, S3CFB_SET_VSYNC_INT, &val); 585 if (err < 0) { 586 ALOGE("vsync ioctl failed"); 587 return -errno; 588 } 589 590 return 0; 591 } 592 593 return -EINVAL; 594} 595 596static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t *pdev, 597 const char *buff, int len) 598{ 599 const char *s = buff; 600 s += strlen(s) + 1; 601 602 while (*s) { 603 if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE="))) 604 pdev->hdmi_hpd = atoi(s + strlen("SWITCH_STATE=")) == 1; 605 606 s += strlen(s) + 1; 607 if (s - buff >= len) 608 break; 609 } 610 611 ALOGV("HDMI HPD changed to %s", pdev->hdmi_hpd ? "enabled" : "disabled"); 612 613 if (pdev->procs && pdev->procs->invalidate) 614 pdev->procs->invalidate(pdev->procs); 615} 616 617static void handle_vsync_uevent(struct exynos5_hwc_composer_device_1_t *pdev, 618 const char *buff, int len) 619{ 620 uint64_t timestamp = 0; 621 const char *s = buff; 622 623 if (!pdev->procs || !pdev->procs->vsync) 624 return; 625 626 s += strlen(s) + 1; 627 628 while (*s) { 629 if (!strncmp(s, "VSYNC=", strlen("VSYNC="))) 630 timestamp = strtoull(s + strlen("VSYNC="), NULL, 0); 631 632 s += strlen(s) + 1; 633 if (s - buff >= len) 634 break; 635 } 636 637 pdev->procs->vsync(pdev->procs, 0, timestamp); 638} 639 640static void *hwc_vsync_thread(void *data) 641{ 642 struct exynos5_hwc_composer_device_1_t *pdev = 643 (struct exynos5_hwc_composer_device_1_t *)data; 644 char uevent_desc[4096]; 645 memset(uevent_desc, 0, sizeof(uevent_desc)); 646 647 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); 648 649 uevent_init(); 650 while (true) { 651 int len = uevent_next_event(uevent_desc, 652 sizeof(uevent_desc) - 2); 653 654 bool vsync = !strcmp(uevent_desc, 655 "change@/devices/platform/exynos5-fb.1"); 656 if (vsync) 657 handle_vsync_uevent(pdev, uevent_desc, len); 658 659 bool hdmi = !strcmp(uevent_desc, 660 "change@/devices/virtual/switch/hdmi"); 661 if (hdmi) 662 handle_hdmi_uevent(pdev, uevent_desc, len); 663 } 664 665 return NULL; 666} 667 668struct hwc_methods_1 exynos5_methods = { 669 eventControl: exynos5_eventControl, 670}; 671 672static int exynos5_close(hw_device_t* device); 673 674static int exynos5_open(const struct hw_module_t *module, const char *name, 675 struct hw_device_t **device) 676{ 677 int ret; 678 int sw_fd; 679 680 if (strcmp(name, HWC_HARDWARE_COMPOSER)) { 681 return -EINVAL; 682 } 683 684 struct exynos5_hwc_composer_device_1_t *dev; 685 dev = (struct exynos5_hwc_composer_device_1_t *)malloc(sizeof(*dev)); 686 memset(dev, 0, sizeof(*dev)); 687 688 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, 689 (const struct hw_module_t **)&dev->gralloc_module)) { 690 ALOGE("failed to get gralloc hw module"); 691 ret = -EINVAL; 692 goto err_get_module; 693 } 694 695 dev->fd = open("/dev/graphics/fb0", O_RDWR); 696 if (dev->fd < 0) { 697 ALOGE("failed to open framebuffer"); 698 ret = dev->fd; 699 goto err_get_module; 700 } 701 702 sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY); 703 if (sw_fd) { 704 char val; 705 if (read(sw_fd, &val, 1) == 1 && val == '1') 706 dev->hdmi_hpd = true; 707 } 708 709 dev->base.common.tag = HARDWARE_DEVICE_TAG; 710 dev->base.common.version = HWC_DEVICE_API_VERSION_1_0; 711 dev->base.common.module = const_cast<hw_module_t *>(module); 712 dev->base.common.close = exynos5_close; 713 714 dev->base.prepare = exynos5_prepare; 715 dev->base.set = exynos5_set; 716 dev->base.registerProcs = exynos5_registerProcs; 717 dev->base.query = exynos5_query; 718 dev->base.methods = &exynos5_methods; 719 720 dev->bufs.pdev = dev; 721 722 *device = &dev->base.common; 723 724 ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev); 725 if (ret) { 726 ALOGE("failed to start vsync thread: %s", strerror(ret)); 727 ret = -ret; 728 goto err_ioctl; 729 } 730 731 return 0; 732 733err_ioctl: 734 close(dev->fd); 735err_get_module: 736 free(dev); 737 return ret; 738} 739 740static int exynos5_close(hw_device_t *device) 741{ 742 struct exynos5_hwc_composer_device_1_t *dev = 743 (struct exynos5_hwc_composer_device_1_t *)device; 744 close(dev->fd); 745 return 0; 746} 747 748static struct hw_module_methods_t exynos5_hwc_module_methods = { 749 open: exynos5_open, 750}; 751 752hwc_module_t HAL_MODULE_INFO_SYM = { 753 common: { 754 tag: HARDWARE_MODULE_TAG, 755 module_api_version: HWC_MODULE_API_VERSION_0_1, 756 hal_api_version: HARDWARE_HAL_API_VERSION, 757 id: HWC_HARDWARE_MODULE_ID, 758 name: "Samsung exynos5 hwcomposer module", 759 author: "Google", 760 methods: &exynos5_hwc_module_methods, 761 } 762}; 763