summaryrefslogtreecommitdiffstats
path: root/liboverlay/overlay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'liboverlay/overlay.cpp')
-rw-r--r--liboverlay/overlay.cpp1490
1 files changed, 1490 insertions, 0 deletions
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
new file mode 100644
index 0000000..d0a4289
--- /dev/null
+++ b/liboverlay/overlay.cpp
@@ -0,0 +1,1490 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*#define LOG_NDEBUG 0*/
+#define LOG_TAG "SEC_Overlay"
+
+#include <hardware/hardware.h>
+#include <hardware/overlay.h>
+
+extern "C" {
+#include "v4l2_utils.h"
+}
+
+#include <pthread.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <linux/videodev.h>
+
+#include <cutils/log.h>
+#include <cutils/ashmem.h>
+#include <cutils/atomic.h>
+
+#include "linux/fb.h"
+
+/*****************************************************************************/
+
+#define LOG_FUNCTION_NAME LOGV(" %s %s", __FILE__, __func__)
+
+#define NUM_OVERLAY_BUFFERS_REQUESTED (3)
+/* OVRLYSHM on phone keypad*/
+#define SHARED_DATA_MARKER (0x68759746)
+
+/* These values should come from Surface Flinger */
+unsigned int g_lcd_width = 480;
+unsigned int g_lcd_height = 800;
+unsigned int g_lcd_bpp = 32;
+
+#define CACHEABLE_BUFFERS 0x1
+
+/* shared with Camera/Video Playback HAL */
+#define ALL_BUFFERS_FLUSHED -66
+
+uint32_t phyAddr;
+s5p_fimc_t g_s5p_fimc;
+
+typedef struct
+{
+ uint32_t posX;
+ uint32_t posY;
+ uint32_t posW;
+ uint32_t posH;
+ uint32_t rotation;
+ uint32_t flip;
+
+ uint32_t posX_org;
+ uint32_t posY_org;
+ uint32_t posW_org;
+ uint32_t posH_org;
+
+} overlay_ctrl_t;
+
+typedef struct
+{
+ uint32_t cropX;
+ uint32_t cropY;
+ uint32_t cropW;
+ uint32_t cropH;
+} overlay_data_t;
+
+typedef struct
+{
+ uint32_t marker;
+ uint32_t size;
+
+ volatile int32_t refCnt;
+
+ uint32_t controlReady; /* Only updated by the control side */
+ uint32_t dataReady; /* Only updated by the data side */
+
+ pthread_mutex_t lock;
+ pthread_mutexattr_t attr;
+
+ uint32_t streamEn;
+ uint32_t streamingReset;
+
+ uint32_t dispW;
+ uint32_t dispH;
+
+} overlay_shared_t;
+
+/* Only one instance is created per platform */
+struct overlay_control_context_t {
+ struct overlay_control_device_t device;
+ /* our private state goes below here */
+ struct overlay_t* overlay_video1;
+ struct overlay_t* overlay_video2;
+};
+
+/* A separate instance is created per overlay data side user*/
+struct overlay_data_context_t {
+ struct overlay_data_device_t device;
+ /* our private state goes below here */
+ int ctl_fd;
+ int shared_fd;
+ int shared_size;
+ int width;
+ int height;
+ int format;
+ int num_buffers;
+ size_t *buffers_len;
+ void **buffers;
+
+ overlay_data_t data;
+ overlay_shared_t *shared;
+ struct mapping_data *mapping_data;
+ /* Need to count Qd buffers
+ to be sure we don't block DQ'ing when exiting */
+ int qd_buf_count;
+ int cacheable_buffers;
+
+ bool zerocopy;
+};
+
+static int create_shared_data(overlay_shared_t **shared);
+static void destroy_shared_data(int shared_fd, overlay_shared_t *shared,
+ bool closefd);
+static int open_shared_data(overlay_data_context_t *ctx);
+static void close_shared_data(overlay_data_context_t *ctx);
+enum { LOCK_REQUIRED = 1, NO_LOCK_NEEDED = 0 };
+static int enable_streaming(overlay_shared_t *shared, int ovly_fd,
+ int lock_required );
+
+static int overlay_device_open(const struct hw_module_t* module,
+ const char* name, struct hw_device_t** device);
+
+static int check_fimc_dst_constraints(s5p_fimc_t *s5p_fimc,
+ unsigned int rotation);
+static int check_fimc_src_constraints(s5p_fimc_t *s5p_fimc);
+
+static struct hw_module_methods_t overlay_module_methods = {
+open: overlay_device_open
+};
+
+struct overlay_module_t HAL_MODULE_INFO_SYM = {
+common: {
+tag: HARDWARE_MODULE_TAG,
+ version_major: 1,
+ version_minor: 0,
+ id: OVERLAY_HARDWARE_MODULE_ID,
+ name: "SEC Overlay module",
+ author: "The Android Open Source Project",
+ methods: &overlay_module_methods,
+ }
+};
+
+/*****************************************************************************/
+
+/*
+ * This is the overlay_t object, it is returned to the user and represents
+ * an overlay. here we use a subclass, where we can store our own state.
+ * This handles will be passed across processes and possibly given to other
+ * HAL modules (for instance video decode modules).
+ */
+struct handle_t : public native_handle {
+ /* add the data fields we need here, for instance: */
+ int ctl_fd;
+ int shared_fd;
+ int width;
+ int height;
+ int format;
+ int num_buffers;
+ int shared_size;
+};
+
+static int handle_format(const overlay_handle_t overlay) {
+ return static_cast<const struct handle_t *>(overlay)->format;
+}
+
+static int handle_ctl_fd(const overlay_handle_t overlay) {
+ return static_cast<const struct handle_t *>(overlay)->ctl_fd;
+}
+
+static int handle_shared_fd(const overlay_handle_t overlay) {
+ return static_cast<const struct handle_t *>(overlay)->shared_fd;
+}
+
+static int handle_num_buffers(const overlay_handle_t overlay) {
+ return static_cast<const struct handle_t *>(overlay)->num_buffers;
+}
+
+static int handle_width(const overlay_handle_t overlay) {
+ return static_cast<const struct handle_t *>(overlay)->width;
+}
+
+static int handle_height(const overlay_handle_t overlay) {
+ return static_cast<const struct handle_t *>(overlay)->height;
+}
+
+static int handle_shared_size(const overlay_handle_t overlay) {
+ return static_cast<const struct handle_t *>(overlay)->shared_size;
+}
+
+/* A separate instance of this class is created per overlay */
+class overlay_object : public overlay_t
+{
+ handle_t mHandle;
+
+ overlay_ctrl_t mCtl;
+ overlay_ctrl_t mCtlStage;
+ overlay_shared_t *mShared;
+
+ static overlay_handle_t getHandleRef(struct overlay_t* overlay) {
+ /* returns a reference to the handle, caller doesn't take ownership */
+ return &(static_cast<overlay_object *>(overlay)->mHandle);
+ }
+
+ public:
+ overlay_object(int ctl_fd, int shared_fd, int shared_size, int w, int h,
+ int format, int num_buffers) {
+ this->overlay_t::getHandleRef = getHandleRef;
+ mHandle.version = sizeof(native_handle);
+ mHandle.numFds = 2;
+ mHandle.numInts = 5; /* extra ints we have in our handle */
+ mHandle.ctl_fd = ctl_fd;
+ mHandle.shared_fd = shared_fd;
+ mHandle.width = w;
+ mHandle.height = h;
+ mHandle.format = format;
+ mHandle.num_buffers = num_buffers;
+ mHandle.shared_size = shared_size;
+ this->w = w;
+ this->h = h;
+ this->format = format;
+
+ memset( &mCtl, 0, sizeof( mCtl ) );
+ memset( &mCtlStage, 0, sizeof( mCtlStage ) );
+ }
+
+ int ctl_fd() { return mHandle.ctl_fd; }
+ int shared_fd() { return mHandle.shared_fd; }
+ overlay_ctrl_t* data() { return &mCtl; }
+ overlay_ctrl_t* staging() { return &mCtlStage; }
+ overlay_shared_t* getShared() { return mShared; }
+ void setShared( overlay_shared_t *p ) { mShared = p; }
+};
+
+/*****************************************************************************
+ * Local Functions
+ *****************************************************************************/
+
+static int create_shared_data(overlay_shared_t **shared)
+{
+ int fd;
+ /* assuming sizeof(overlay_shared_t) < a single page */
+ int size = getpagesize();
+ overlay_shared_t *p;
+
+ if ((fd = ashmem_create_region("overlay_data", size)) < 0) {
+ LOGE("Failed to Create Overlay Shared Data!\n");
+ return fd;
+ }
+
+ p = (overlay_shared_t*)mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (p == MAP_FAILED) {
+ LOGE("Failed to Map Overlay Shared Data!\n");
+ close(fd);
+ return -1;
+ }
+
+ memset(p, 0, size);
+ p->marker = SHARED_DATA_MARKER;
+ p->size = size;
+ p->refCnt = 1;
+ if (pthread_mutexattr_init(&p->attr) != 0) {
+ LOGE("Failed to initialize overlay mutex attr");
+ goto MutexAttrErr;
+ }
+ if (pthread_mutexattr_setpshared(&p->attr, PTHREAD_PROCESS_SHARED) != 0) {
+ LOGE("Failed to set the overlay mutex attr to be shared across-processes");
+ goto MutexAttrSetErr;
+ }
+ if (pthread_mutex_init(&p->lock, &p->attr) != 0) {
+ LOGE("Failed to initialize overlay mutex\n");
+ goto MutexErr;
+ }
+
+ *shared = p;
+ return fd;
+
+MutexErr:
+MutexAttrSetErr:
+ pthread_mutexattr_destroy(&p->attr);
+MutexAttrErr:
+ munmap(p, size);
+ close(fd);
+ return -1;
+}
+
+static void destroy_shared_data(int shared_fd, overlay_shared_t *shared,
+ bool closefd )
+{
+ if (shared == NULL)
+ return;
+
+ /* Last side deallocated releases the mutex, otherwise the remaining */
+ /* side will deadlock trying to use an already released mutex */
+ if (android_atomic_dec(&shared->refCnt) == 1) {
+ if (pthread_mutex_destroy(&shared->lock)) {
+ LOGE("Failed to uninitialize overlay mutex!\n");
+ }
+
+ if (pthread_mutexattr_destroy(&shared->attr)) {
+ LOGE("Failed to uninitialize the overlay mutex attr!\n");
+ }
+ shared->marker = 0;
+ }
+
+ if (munmap(shared, shared->size)) {
+ LOGE("Failed to Unmap Overlay Shared Data!\n");
+ }
+
+ if (closefd && close(shared_fd)) {
+ LOGE("Failed to Close Overlay Shared Data!\n");
+ }
+}
+
+static int open_shared_data( overlay_data_context_t *ctx )
+{
+ int rc = -1;
+ int mode = PROT_READ | PROT_WRITE;
+ int fd = ctx->shared_fd;
+ int size = ctx->shared_size;
+
+ if (ctx->shared != NULL) {
+ /* Already open, return success */
+ LOGI("Overlay Shared Data Already Open\n");
+ return 0;
+ }
+ ctx->shared = (overlay_shared_t*)mmap(0, size, mode, MAP_SHARED, fd, 0);
+
+ if (ctx->shared == MAP_FAILED) {
+ LOGE("Failed to Map Overlay Shared Data!\n");
+ } else if ( ctx->shared->marker != SHARED_DATA_MARKER ) {
+ LOGE("Invalid Overlay Shared Marker!\n");
+ munmap( ctx->shared, size);
+ } else if ( (int)ctx->shared->size != size ) {
+ LOGE("Invalid Overlay Shared Size!\n");
+ munmap(ctx->shared, size);
+ } else {
+ android_atomic_inc(&ctx->shared->refCnt);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+static void close_shared_data(overlay_data_context_t *ctx)
+{
+ destroy_shared_data(ctx->shared_fd, ctx->shared, false);
+ ctx->shared = NULL;
+}
+
+static int enable_streaming_locked(overlay_shared_t *shared, int ovly_fd)
+{
+ int rc = 0;
+
+ if (!shared->controlReady || !shared->dataReady) {
+ LOGI("Postponing Stream Enable/%d/%d\n", shared->controlReady,
+ shared->dataReady);
+ } else {
+ shared->streamEn = 1;
+ rc = v4l2_overlay_stream_on(ovly_fd);
+ if (rc) {
+ LOGE("Stream Enable Failed!/%d\n", rc);
+ shared->streamEn = 0;
+ }
+ }
+
+ return rc;
+}
+
+static int enable_streaming(overlay_shared_t *shared, int ovly_fd)
+{
+ int ret;
+
+ pthread_mutex_lock(&shared->lock);
+ ret = enable_streaming_locked(shared, ovly_fd);
+ pthread_mutex_unlock(&shared->lock);
+ return ret;
+}
+
+static int disable_streaming_locked(overlay_shared_t *shared, int ovly_fd)
+{
+ int ret = 0;
+
+ if (shared->streamEn) {
+ ret = v4l2_overlay_stream_off( ovly_fd );
+ if (ret) {
+ LOGE("Stream Off Failed!/%d\n", ret);
+ } else {
+ shared->streamingReset = 1;
+ shared->streamEn = 0;
+ }
+ }
+
+ return ret;
+}
+
+static void set_color_space(unsigned int overlay_color_format, unsigned int *v4l2_color_format)
+{
+ switch (overlay_color_format) {
+ case OVERLAY_FORMAT_RGB_565:
+ *v4l2_color_format = V4L2_PIX_FMT_RGB565;
+ break;
+
+ case OVERLAY_FORMAT_YCbYCr_422_I:
+ case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_I:
+ *v4l2_color_format = V4L2_PIX_FMT_YUYV;
+ break;
+
+ case OVERLAY_FORMAT_CbYCrY_422_I:
+ case HAL_PIXEL_FORMAT_CUSTOM_CbYCrY_422_I:
+ *v4l2_color_format = V4L2_PIX_FMT_UYVY;
+ break;
+
+ case HAL_PIXEL_FORMAT_YCbCr_420_P:
+ *v4l2_color_format = V4L2_PIX_FMT_YUV420;
+ break;
+
+ case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP:
+ *v4l2_color_format = V4L2_PIX_FMT_NV12T;
+ break;
+
+ case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP:
+ *v4l2_color_format = V4L2_PIX_FMT_NV21;
+ break;
+
+ default :
+ LOGE("unsupported pixel format (0x%x)", overlay_color_format);
+ *v4l2_color_format = -1;
+ }
+}
+
+/****************************************************************************
+ * Control module
+ *****************************************************************************/
+
+static int overlay_get(struct overlay_control_device_t *dev, int name)
+{
+ int result = -1;
+
+ switch (name) {
+ /* 0 = no limit */
+ case OVERLAY_MINIFICATION_LIMIT: result = 0; break;
+ /* 0 = no limit */
+ case OVERLAY_MAGNIFICATION_LIMIT: result = 0; break;
+ /* 0 = infinite */
+ case OVERLAY_SCALING_FRAC_BITS: result = 0; break;
+ /* 90 rotation steps (for instance) */
+ case OVERLAY_ROTATION_STEP_DEG: result = 90; break;
+ /* 1-pixel alignment */
+ case OVERLAY_HORIZONTAL_ALIGNMENT: result = 1; break;
+ /* 1-pixel alignment */
+ case OVERLAY_VERTICAL_ALIGNMENT: result = 1; break;
+ /* 1-pixel alignment */
+ case OVERLAY_WIDTH_ALIGNMENT: result = 1; break;
+ case OVERLAY_HEIGHT_ALIGNMENT: break;
+ }
+
+ return result;
+}
+
+static int get_fb_var_screeninfo( struct fb_var_screeninfo *info )
+{
+ int fd = -1;
+ int i=0;
+ char name[64];
+ int ret = 0;
+
+ char const * const device_template[] = {
+ "/dev/graphics/fb%u",
+ "/dev/fb%u",
+ 0 };
+
+ while ((fd==-1) && device_template[i]) {
+ snprintf(name, 64, device_template[i], 0);
+ fd = open(name, O_RDWR, 0);
+ i++;
+ }
+
+ if (fd < 0)
+ ret = -EINVAL;
+
+ if (ioctl(fd, FBIOGET_VSCREENINFO, info) == -1)
+ ret = -EINVAL;
+
+ if (fd > 0)
+ close(fd);
+
+ return 0;
+}
+static overlay_t* overlay_createOverlay(struct overlay_control_device_t *dev,
+ uint32_t w, uint32_t h, int32_t format)
+{
+ LOGD("overlay_createOverlay:IN w=%d h=%d format=%d\n", w, h, format);
+ LOG_FUNCTION_NAME;
+
+ overlay_object *overlay;
+ overlay_control_context_t *ctx = (overlay_control_context_t *)dev;
+ overlay_shared_t *shared;
+
+ int ret;
+ uint32_t num = NUM_OVERLAY_BUFFERS_REQUESTED;
+ int fd;
+ int shared_fd;
+ struct fb_var_screeninfo info;
+ bool zerocopy = false;
+
+ phyAddr = 0;
+
+ if (format == OVERLAY_FORMAT_DEFAULT) {
+ LOGD("format == OVERLAY_FORMAT_DEFAULT\n");
+ LOGD("set to HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP\n");
+ format = HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP;
+ }
+
+ if (ctx->overlay_video1) {
+ LOGE("Error - overlays already in use\n");
+ return NULL;
+ }
+
+ shared_fd = create_shared_data(&shared);
+ if (shared_fd < 0) {
+ LOGE("Failed to create shared data");
+ return NULL;
+ }
+
+ fd = v4l2_overlay_open(V4L2_OVERLAY_PLANE_VIDEO1);
+ if (fd < 0) {
+ LOGE("Failed to open overlay device : %s\n", strerror(errno));
+ goto error;
+ }
+
+ g_s5p_fimc.params.src.full_width = w;
+ g_s5p_fimc.params.src.full_height = h;
+ g_s5p_fimc.params.src.width = w;
+ g_s5p_fimc.params.src.height = h;
+ set_color_space(format, &g_s5p_fimc.params.src.color_space);
+ ret = check_fimc_src_constraints(&g_s5p_fimc);
+ if(ret != 0) {
+ if(ret < 0) {
+ LOGE("Not supported source image size");
+ goto error1;
+ } else {
+ LOGD("src width, height are changed [w= %d, h= %d]->[w=%d, h= %d]"
+ , w, h, g_s5p_fimc.params.src.width
+ , g_s5p_fimc.params.src.height);
+ w = g_s5p_fimc.params.src.width;
+ h = g_s5p_fimc.params.src.height;
+ }
+ }
+
+ if (v4l2_overlay_init(fd, w, h, format, phyAddr)) {
+ LOGE("Failed initializing overlays\n");
+ goto error1;
+ }
+
+ if (v4l2_overlay_set_crop(fd, 0, 0, w, h)) {
+ LOGE("Failed defaulting crop window\n");
+ goto error1;
+ }
+
+ if (v4l2_overlay_set_flip(fd, 0)) {
+ LOGE("Failed defaulting flip\n");
+ goto error1;
+ }
+
+ if (v4l2_overlay_set_rotation(fd, 0, 0)) {
+ LOGE("Failed defaulting rotation\n");
+ goto error1;
+ }
+
+ if (format >= HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP
+ && format < HAL_PIXEL_FORMAT_CUSTOM_MAX)
+ zerocopy = true;
+
+ if (v4l2_overlay_req_buf(fd, &num, 0, (int)zerocopy)) {
+ LOGE("Failed requesting buffers\n");
+ goto error1;
+ }
+
+ v4l2_overlay_init_fimc(fd, &g_s5p_fimc);
+
+ overlay = new overlay_object(fd, shared_fd, shared->size,
+ w, h, format, num);
+ if (overlay == NULL) {
+ LOGE("Failed to create overlay object\n");
+ goto error1;
+ }
+ ctx->overlay_video1 = overlay;
+
+ overlay->setShared(shared);
+
+ shared->controlReady = 0;
+ shared->streamEn = 0;
+ shared->streamingReset = 0;
+
+ /* get lcd size from kernel framebuffer */
+ if(get_fb_var_screeninfo(&info) == 0) {
+ shared->dispW = info.xres;
+ shared->dispH = info.yres;
+ g_lcd_width = info.xres;
+ g_lcd_height = info.yres;
+ g_lcd_bpp = info.bits_per_pixel;
+ } else {
+ shared->dispW = g_lcd_width; /* Need to determine this properly */
+ shared->dispH = g_lcd_height; /* Need to determine this properly */
+ }
+
+ LOGI("Opened video1/fd=%d/obj=%08lx/shm=%d/size=%d", fd,
+ (unsigned long)overlay, shared_fd, shared->size);
+
+ return overlay;
+
+error1:
+ close(fd);
+error:
+ destroy_shared_data(shared_fd, shared, true);
+ return NULL;
+}
+
+static void overlay_destroyOverlay(struct overlay_control_device_t *dev,
+ overlay_t* overlay)
+{
+ LOGD("overlay_destroyOverlay:IN dev (%p) and overlay (%p)", dev, overlay);
+ LOG_FUNCTION_NAME;
+
+ overlay_control_context_t *ctx = (overlay_control_context_t *)dev;
+ overlay_object *obj = static_cast<overlay_object *>(overlay);
+
+ int rc;
+ int fd = obj->ctl_fd();
+ uint32_t num = 0;
+
+ overlay_shared_t *shared = obj->getShared();
+
+ if (shared == NULL) {
+ LOGE("Overlay was already destroyed - nothing needs to be done\n");
+ return;
+ }
+
+ pthread_mutex_lock(&shared->lock);
+
+ disable_streaming_locked(shared, fd);
+
+ pthread_mutex_unlock(&shared->lock);
+
+ destroy_shared_data(obj->shared_fd(), shared, true);
+ obj->setShared(NULL);
+
+ if (v4l2_overlay_req_buf(fd, &num, 0, 0)) {
+ LOGE("Failed requesting buffers\n");
+ }
+
+ LOGI("Destroying overlay/fd=%d/obj=%08lx", fd, (unsigned long)overlay);
+
+ if (close(fd)) {
+ LOGE( "Error closing overly fd/%d\n", errno);
+ }
+
+ if (overlay) {
+ if (ctx->overlay_video1 == overlay)
+ ctx->overlay_video1 = NULL;
+ delete overlay;
+ overlay = NULL;
+ }
+ LOGD("overlay_destroyOverlay:OUT");
+}
+
+static int overlay_setPosition(struct overlay_control_device_t *dev,
+ overlay_t* overlay, int x, int y, uint32_t w,
+ uint32_t h)
+{
+ LOG_FUNCTION_NAME;
+
+ overlay_object *obj = static_cast<overlay_object *>(overlay);
+
+ overlay_ctrl_t *stage = obj->staging();
+ overlay_shared_t *shared = obj->getShared();
+
+ int rc = 0;
+ int temp_x = x, temp_y = y, temp_w = w, temp_h = h;
+
+ /*
+ * This logic here is to return an error if the rectangle is not fully
+ * within the display, unless we have not received a valid position yet,
+ * in which case we will do our best to adjust the rectangle to be within
+ * the display.
+ */
+
+ /* Require a minimum size */
+ if (temp_w < 16)
+ temp_w = 16;
+ if (temp_h < 8)
+ temp_h = 8;
+
+ if (!shared->controlReady) {
+ if ( temp_x < 0 ) temp_x = 0;
+ if ( temp_y < 0 ) temp_y = 0;
+ if ( temp_w > shared->dispW ) temp_w = shared->dispW;
+ if ( temp_h > shared->dispH ) temp_h = shared->dispH;
+ if ( (temp_x + temp_w) > shared->dispW ) temp_w = shared->dispW - temp_x;
+ if ( (temp_y + temp_h) > shared->dispH ) temp_h = shared->dispH - temp_y;
+ } else if (temp_x < 0 || temp_y < 0 || (temp_x + temp_w) > shared->dispW ||
+ (temp_y + temp_h) > shared->dispH) {
+ /* Return an error */
+ rc = -1;
+ }
+
+ if (rc == 0) {
+ stage->posX = temp_x;
+ stage->posY = temp_y;
+ stage->posW = temp_w;
+ stage->posH = temp_h;
+
+ stage->posX_org = x;
+ stage->posY_org = y;
+ stage->posW_org = w;
+ stage->posH_org = h;
+ }
+
+ return rc;
+}
+
+static int overlay_getPosition(struct overlay_control_device_t *dev,
+ overlay_t* overlay, int* x, int* y, uint32_t* w,
+ uint32_t* h)
+{
+ LOG_FUNCTION_NAME;
+
+ overlay_object *obj = static_cast<overlay_object *>(overlay);
+ overlay_ctrl_t *stage = obj->staging();
+
+ *x = stage->posX_org;
+ *y = stage->posY_org;
+ *w = stage->posW_org;
+ *h = stage->posH_org;
+
+ return 0;
+}
+
+static int overlay_setParameter(struct overlay_control_device_t *dev,
+ overlay_t* overlay, int param, int value)
+{
+ LOG_FUNCTION_NAME;
+
+ overlay_ctrl_t *stage = static_cast<overlay_object *>(overlay)->staging();
+ int rc = 0;
+
+ switch (param) {
+ case OVERLAY_DITHER:
+ break;
+
+ case OVERLAY_TRANSFORM:
+ switch ( value )
+ {
+ case 0:
+ stage->rotation = 0;
+ stage->flip = 0;
+ break;
+ case OVERLAY_TRANSFORM_ROT_90:
+ stage->rotation = 90;
+ stage->flip = 0;
+ break;
+ case OVERLAY_TRANSFORM_ROT_180:
+ stage->rotation = 180;
+ stage->flip = 0;
+ break;
+ case OVERLAY_TRANSFORM_ROT_270:
+ stage->rotation = 270;
+ stage->flip = 0;
+ break;
+ // FIMC VFLIP = android overlay FLIP_H.
+ case OVERLAY_TRANSFORM_FLIP_H:
+ stage->rotation = 0;
+ stage->flip = V4L2_CID_VFLIP;
+ break;
+ case OVERLAY_TRANSFORM_FLIP_V:
+ stage->rotation = 0;
+ stage->flip = V4L2_CID_HFLIP;
+ break;
+ // FIMC rotates first but android flips first.
+ case OVERLAY_TRANSFORM_ROT_90+OVERLAY_TRANSFORM_FLIP_H:
+ stage->rotation = 90;
+ stage->flip = V4L2_CID_HFLIP;
+ break;
+ case OVERLAY_TRANSFORM_ROT_90+OVERLAY_TRANSFORM_FLIP_V:
+ stage->rotation = 90;
+ stage->flip = V4L2_CID_VFLIP;
+ break;
+
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ break;
+ }
+
+ return rc;
+}
+
+static int overlay_stage(struct overlay_control_device_t *dev,
+ overlay_t* overlay) {
+ return 0;
+}
+
+static int overlay_commit(struct overlay_control_device_t *dev,
+ overlay_t* overlay) {
+ LOG_FUNCTION_NAME;
+
+ overlay_object *obj = static_cast<overlay_object *>(overlay);
+
+ overlay_ctrl_t *data = obj->data();
+ overlay_ctrl_t *stage = obj->staging();
+ overlay_shared_t *shared = obj->getShared();
+
+ int ret = 0;
+ int fd = obj->ctl_fd();
+
+ if (shared == NULL) {
+ LOGI("Shared Data Not Init'd!\n");
+ return -1;
+ }
+
+ pthread_mutex_lock(&shared->lock);
+
+ if (!shared->controlReady) {
+ shared->controlReady = 1;
+ }
+
+ g_s5p_fimc.params.dst.full_width = g_lcd_width;
+ g_s5p_fimc.params.dst.full_height = g_lcd_height;
+ g_s5p_fimc.params.dst.width = stage->posW;
+ g_s5p_fimc.params.dst.height = stage->posH;
+ if (g_lcd_bpp == 32)
+ g_s5p_fimc.params.dst.color_space = V4L2_PIX_FMT_RGB32;
+ else
+ g_s5p_fimc.params.dst.color_space = V4L2_PIX_FMT_RGB565;
+ ret = check_fimc_dst_constraints(&g_s5p_fimc, stage->rotation);
+ if (ret != 0) {
+ if (ret < 0) {
+ LOGE("Unsupported destination image size");
+ goto end;
+ } else {
+ LOGD("dst width, height have changed [w= %d, h= %d] -> [w=%d, h= %d]",
+ stage->posW, stage->posH, g_s5p_fimc.params.dst.width,
+ g_s5p_fimc.params.dst.height);
+ stage->posW = g_s5p_fimc.params.dst.width;
+ stage->posH = g_s5p_fimc.params.dst.height;
+ }
+ }
+
+ if (data->posX == stage->posX && data->posY == stage->posY &&
+ data->posW == stage->posW && data->posH == stage->posH &&
+ data->rotation == stage->rotation &&
+ data->flip == stage->flip) {
+ LOGI("Nothing to do!\n");
+ goto end;
+ }
+
+ LOGD("Position/X%d/Y%d/W%d/H%d\n", data->posX, data->posY, data->posW,
+ data->posH);
+ LOGD("Adjusted Position/X%d/Y%d/W%d/H%d\n", stage->posX, stage->posY,
+ stage->posW, stage->posH);
+ LOGD("Rotation/%d\n", stage->rotation );
+
+ if ((ret = disable_streaming_locked(shared, fd)))
+ goto end;
+
+ if (stage->flip != data->flip) {
+ ret = v4l2_overlay_set_flip(fd, stage->flip);
+ if (ret) {
+ LOGE("Set Flip Failed!/%d\n", ret);
+ goto end;
+ }
+ }
+
+ if (stage->rotation != data->rotation) {
+ ret = v4l2_overlay_set_rotation(fd, stage->rotation, 0);
+ if (ret) {
+ LOGE("Set Rotation Failed!/%d\n", ret);
+ goto end;
+ }
+ v4l2_overlay_s_fbuf(fd, stage->rotation);
+ }
+
+ ret = v4l2_overlay_set_position(fd, stage->posX, stage->posY,
+ stage->posW, stage->posH, stage->rotation);
+ if (ret) {
+ LOGE("Set Position Failed!/%d\n", ret);
+ goto end;
+ }
+
+ data->posX = stage->posX;
+ data->posY = stage->posY;
+ data->posW = stage->posW;
+ data->posH = stage->posH;
+ data->rotation = stage->rotation;
+ data->flip = stage->flip;
+
+ ret = enable_streaming_locked(shared, fd);
+
+end:
+ pthread_mutex_unlock(&shared->lock);
+
+ return ret;
+}
+
+static int overlay_control_close(struct hw_device_t *dev)
+{
+ LOG_FUNCTION_NAME;
+
+ struct overlay_control_context_t* ctx =
+ (struct overlay_control_context_t*)dev;
+ overlay_object *overlay_v1;
+
+ if (ctx) {
+ overlay_v1 = static_cast<overlay_object *>(ctx->overlay_video1);
+
+ overlay_destroyOverlay((struct overlay_control_device_t *)ctx,
+ overlay_v1);
+
+ free(ctx);
+ }
+ return 0;
+}
+
+static int get_pixel_format_type(unsigned int pixelformat)
+{
+ switch(pixelformat) {
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_RGB565:
+ return PFT_RGB;
+
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV12T:
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_YUV420:
+ return PFT_YUV420;
+
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_YUV422P:
+ return PFT_YUV422;
+
+ default:
+ return PFT_YUV444;
+ }
+}
+
+/* check the constraints of destination image size */
+static int check_fimc_dst_constraints(s5p_fimc_t *s5p_fimc,
+ unsigned int rotation)
+{
+ int tmp = 0;
+
+ if((s5p_fimc->params.dst.height > 0) && (s5p_fimc->params.dst.height < 16))
+ s5p_fimc->params.dst.height = 16;
+
+ if(s5p_fimc->params.dst.width%8 != 0) {
+ tmp = s5p_fimc->params.dst.width - (s5p_fimc->params.dst.width%8);
+ if(tmp <= 0)
+ return -1;
+ else
+ s5p_fimc->params.dst.width = tmp;
+ }
+
+ return 1;
+}
+/* check the constraints of source image size */
+static int check_fimc_src_constraints(s5p_fimc_t *s5p_fimc)
+{
+ int format_type = 0;
+
+ if(s5p_fimc->params.src.full_width < 16 ||
+ s5p_fimc->params.src.full_height < 8 )
+ return -1;
+
+ if(s5p_fimc->hw_ver == 0x50) {
+ format_type = get_pixel_format_type(s5p_fimc->params.src.color_space);
+ switch (format_type) {
+ case PFT_YUV420:
+ if (s5p_fimc->params.src.height%2 != 0)
+ s5p_fimc->params.src.height = s5p_fimc->params.src.height
+ - (s5p_fimc->params.src.height)%2;
+
+ if (s5p_fimc->params.src.width%2 != 0)
+ s5p_fimc->params.src.width = s5p_fimc->params.src.width
+ - (s5p_fimc->params.src.width)%2;
+ break;
+
+ case PFT_YUV422:
+ if (s5p_fimc->params.src.width%2 != 0)
+ s5p_fimc->params.src.width = s5p_fimc->params.src.width
+ - (s5p_fimc->params.src.width)%2;
+ }
+ } else {
+ if (s5p_fimc->params.src.height < 8) {
+ s5p_fimc->params.src.height = 8;
+ }
+
+ if (s5p_fimc->params.src.width%16 != 0) {
+ s5p_fimc->params.src.width = s5p_fimc->params.src.width
+ - (s5p_fimc->params.src.width)%16;
+ }
+ }
+
+ return 1;
+}
+
+/****************************************************************************
+ * Data module
+ *****************************************************************************/
+
+int overlay_initialize(struct overlay_data_device_t *dev,
+ overlay_handle_t handle)
+{
+ LOG_FUNCTION_NAME;
+
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+ struct stat stat;
+
+ int i;
+ int rc = -1;
+
+ ctx->num_buffers = handle_num_buffers(handle);
+ ctx->width = handle_width(handle);
+ ctx->height = handle_height(handle);
+ ctx->format = handle_format(handle);
+ ctx->ctl_fd = handle_ctl_fd(handle);
+ ctx->shared_fd = handle_shared_fd(handle);
+ ctx->shared_size = handle_shared_size(handle);
+ ctx->shared = NULL;
+ ctx->qd_buf_count = 0;
+ ctx->cacheable_buffers = 0;
+
+ if (ctx->format >= HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP
+ && ctx->format < HAL_PIXEL_FORMAT_CUSTOM_MAX)
+ ctx->zerocopy = true;
+ else
+ ctx->zerocopy = false;
+
+ if (fstat(ctx->ctl_fd, &stat)) {
+ LOGE("Error = %s from %s\n", strerror(errno), "overlay initialize");
+ return -1;
+ }
+
+ if (open_shared_data(ctx)) {
+ return -1;
+ }
+
+ ctx->shared->dataReady = 0;
+
+ ctx->mapping_data = new struct mapping_data;
+ ctx->buffers = new void* [ctx->num_buffers];
+ ctx->buffers_len = new size_t[ctx->num_buffers];
+
+ if (!ctx->buffers || !ctx->buffers_len || !ctx->mapping_data) {
+ LOGE("Failed alloc'ing buffer arrays\n");
+ goto error;
+ } else {
+
+ /*
+ * in the zero copy case,
+ * don't need to mmap buffer for source
+ */
+ if (ctx->zerocopy)
+ rc = 0;
+ else {
+ for (i = 0; i < ctx->num_buffers; i++) {
+ rc = v4l2_overlay_map_buf(ctx->ctl_fd, i, &ctx->buffers[i],
+ &ctx->buffers_len[i]);
+ if (rc) {
+ LOGE("Failed mapping buffers\n");
+ goto error;
+ }
+ }
+ }
+ }
+
+ v4l2_overlay_init_fimc(ctx->ctl_fd, &g_s5p_fimc);
+
+ return ( rc );
+
+error:
+
+ if(ctx->mapping_data)
+ delete (ctx->mapping_data);
+ if(ctx->buffers)
+ delete [] ctx->buffers;
+ if(ctx->buffers_len)
+ delete [] ctx->buffers_len;
+
+ close_shared_data( ctx );
+
+ return -1;
+}
+
+static int overlay_resizeInput(struct overlay_data_device_t *dev, uint32_t w,
+ uint32_t h)
+{
+ int rc = -1;
+ int ret = 0;
+
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+
+ if ((ctx->width == (int)w) && (ctx->width == (int)h)) {
+ LOGV("same as current width and height. so do nothing");
+ return 0;
+ }
+
+ if (!ctx->shared) {
+ LOGI("Shared Data Not Init'd!\n");
+ return -1;
+ }
+
+ if (ctx->shared->dataReady) {
+ LOGV("Either setCrop() or queueBuffer() was called prior to this!"
+ "Therefore failing this call.\n");
+ return -1;
+ }
+
+ pthread_mutex_lock(&ctx->shared->lock);
+
+ if ((rc = disable_streaming_locked(ctx->shared, ctx->ctl_fd)))
+ goto end;
+
+ if (!ctx->zerocopy) {
+ for (int i = 0; i < ctx->num_buffers; i++) {
+ v4l2_overlay_unmap_buf(ctx->buffers[i], ctx->buffers_len[i]);
+ }
+ }
+
+ g_s5p_fimc.params.src.full_width = w;
+ g_s5p_fimc.params.src.full_height = h;
+ g_s5p_fimc.params.src.width = w;
+ g_s5p_fimc.params.src.height = h;
+ set_color_space(ctx->format, &g_s5p_fimc.params.src.color_space);
+ ret = check_fimc_src_constraints(&g_s5p_fimc);
+
+ if(ret != 0) {
+ if(ret < 0) {
+ LOGE("Not supported source image size");
+ goto end;
+ } else {
+ LOGD("src width, height are changed [w= %d, h= %d] -> [w=%d, h= %d]"
+ , w, h, g_s5p_fimc.params.src.width
+ , g_s5p_fimc.params.src.height);
+ w = g_s5p_fimc.params.src.width;
+ h = g_s5p_fimc.params.src.height;
+ }
+ }
+
+ rc = v4l2_overlay_init(ctx->ctl_fd, w, h, ctx->format, phyAddr);
+ if (rc) {
+ LOGE("Error initializing overlay");
+ goto end;
+ }
+ rc = v4l2_overlay_set_crop(ctx->ctl_fd, 0, 0, w, h);
+ if (rc) {
+ LOGE("Error setting crop window\n");
+ goto end;
+ }
+ rc = v4l2_overlay_req_buf(ctx->ctl_fd, (uint32_t *)(&ctx->num_buffers),
+ ctx->cacheable_buffers, (int)ctx->zerocopy);
+ if (rc) {
+ LOGE("Error creating buffers");
+ goto end;
+ }
+
+ if (!ctx->zerocopy) {
+ for (int i = 0; i < ctx->num_buffers; i++)
+ v4l2_overlay_map_buf(ctx->ctl_fd, i, &ctx->buffers[i],
+ &ctx->buffers_len[i]);
+ }
+
+ rc = enable_streaming_locked(ctx->shared, ctx->ctl_fd);
+
+end:
+ pthread_mutex_unlock(&ctx->shared->lock);
+
+ return rc;
+}
+
+
+static int overlay_data_setParameter(struct overlay_data_device_t *dev,
+ int param, int value)
+{
+ int ret = 0;
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+
+ if (ctx->shared == NULL) {
+ LOGI("Shared Data Not Init'd!\n");
+ return -1;
+ }
+
+ if (ctx->shared->dataReady) {
+ LOGI("Too late. Cant set it now!\n");
+ return -1;
+ }
+
+ if (param == CACHEABLE_BUFFERS)
+ ctx->cacheable_buffers = value;
+
+ return ( ret );
+}
+
+
+static int overlay_setCrop(struct overlay_data_device_t *dev, uint32_t x,
+ uint32_t y, uint32_t w, uint32_t h) {
+ LOG_FUNCTION_NAME;
+
+ int rc = 0;
+ int cnt = 0;
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+
+ if (ctx->shared == NULL) {
+ LOGI("Shared Data Not Init'd!\n");
+ return -1;
+ }
+
+ pthread_mutex_lock(&ctx->shared->lock);
+
+ ctx->shared->dataReady = 1;
+
+ if (ctx->data.cropX == x && ctx->data.cropY == y && ctx->data.cropW == w
+ && ctx->data.cropH == h) {
+ goto end;
+ }
+
+ ctx->data.cropX = x;
+ ctx->data.cropY = y;
+ ctx->data.cropW = w;
+ ctx->data.cropH = h;
+
+ LOGD("Crop Win/X%d/Y%d/W%d/H%d\n", x, y, w, h );
+
+ if ((rc = disable_streaming_locked(ctx->shared, ctx->ctl_fd)))
+ goto end;
+
+ rc = v4l2_overlay_set_crop(ctx->ctl_fd, x, y, w, h);
+ if (rc) {
+ LOGE("Set Crop Window Failed!/%d\n", rc);
+ }
+
+ rc = enable_streaming_locked(ctx->shared, ctx->ctl_fd);
+
+end:
+ pthread_mutex_unlock(&ctx->shared->lock);
+ return rc;
+}
+
+static int overlay_getCrop(struct overlay_data_device_t *dev , uint32_t* x,
+ uint32_t* y, uint32_t* w, uint32_t* h) {
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+
+ return v4l2_overlay_get_crop(ctx->ctl_fd, x, y, w, h);
+}
+
+int overlay_dequeueBuffer(struct overlay_data_device_t *dev,
+ overlay_buffer_t *buffer) {
+ /* blocks until a buffer is available and return an opaque structure
+ * representing this buffer.
+ */
+
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+
+ int rc=0;
+ int i = -1;
+ uint32_t num = 0;
+ int cnt = 0;
+
+ pthread_mutex_lock(&ctx->shared->lock);
+ if ( ctx->shared->streamingReset ) {
+ ctx->shared->streamingReset = 0;
+ pthread_mutex_unlock(&ctx->shared->lock);
+ return ALL_BUFFERS_FLUSHED;
+ }
+ pthread_mutex_unlock(&ctx->shared->lock);
+
+ /* If we are not streaming dequeue will fail,
+ skip to prevent error printouts */
+ if (ctx->shared->streamEn && ctx->qd_buf_count) {
+ if ((rc = v4l2_overlay_dq_buf( ctx->ctl_fd, &i ,ctx->zerocopy)) != 0) {
+ LOGE("Failed to DQ/%d\n", rc);
+ }
+ else if (i < 0 || i > ctx->num_buffers) {
+ rc = -EINVAL;
+ } else {
+ *((int *)buffer) = i;
+ ctx->qd_buf_count --;
+ }
+ } else {
+ rc = -1;
+ }
+
+ return rc;
+}
+
+int overlay_queueBuffer(struct overlay_data_device_t *dev,
+ overlay_buffer_t buffer) {
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+
+ int cnt = 0;
+
+ pthread_mutex_lock(&ctx->shared->lock);
+ if ( ctx->shared->streamingReset ) {
+ ctx->shared->streamingReset = 0;
+ pthread_mutex_unlock(&ctx->shared->lock);
+ return ALL_BUFFERS_FLUSHED;
+ }
+ pthread_mutex_unlock(&ctx->shared->lock);
+
+ /* Catch the case where the data side had no need to set the crop window */
+ if (!ctx->shared->dataReady) {
+ ctx->shared->dataReady = 1;
+ enable_streaming(ctx->shared, ctx->ctl_fd);
+ }
+
+ if (!ctx->shared->controlReady) return -1;
+ int rc = v4l2_overlay_q_buf( ctx->ctl_fd, (int)buffer, (int) ctx->zerocopy );
+ if (rc == 0 && ctx->qd_buf_count < ctx->num_buffers) {
+ ctx->qd_buf_count ++;
+ }
+
+ return rc;
+}
+
+void *overlay_getBufferAddress(struct overlay_data_device_t *dev,
+ overlay_buffer_t buffer)
+{
+ LOG_FUNCTION_NAME;
+
+ /* this may fail (NULL) if this feature is not supported. In that case,
+ * presumably, there is some other HAL module that can fill the buffer,
+ * using a DSP for instance
+ */
+ int ret;
+ struct v4l2_buffer buf;
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+
+ if (ctx->zerocopy)
+ return NULL;
+
+ if ((int)buffer >= 0 && (int)buffer < ctx->num_buffers)
+ return (void*) ctx->buffers[(int)buffer];
+ else
+ return NULL;
+}
+
+int overlay_getBufferCount(struct overlay_data_device_t *dev)
+{
+ LOG_FUNCTION_NAME;
+
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+
+ return (ctx->num_buffers);
+}
+
+static int overlay_data_close(struct hw_device_t *dev) {
+
+ LOG_FUNCTION_NAME;
+
+ struct overlay_data_context_t* ctx = (struct overlay_data_context_t*)dev;
+ int rc;
+
+ if (ctx) {
+ overlay_data_device_t *overlay_dev = &ctx->device;
+ int buf;
+ int i;
+
+ pthread_mutex_lock(&ctx->shared->lock);
+
+ if (!ctx->zerocopy)
+ for (i = 0; i < ctx->num_buffers; i++) {
+ LOGV("Unmap Buffer/%d/%08lx/%d", i, (unsigned long)ctx->buffers[i],
+ ctx->buffers_len[i] );
+ rc = v4l2_overlay_unmap_buf(ctx->buffers[i], ctx->buffers_len[i]);
+ if (rc != 0) {
+ LOGE("Error unmapping the buffer/%d/%d", i, rc);
+ }
+ }
+
+ delete (ctx->mapping_data);
+ delete [] ctx->buffers;
+ delete [] ctx->buffers_len;
+
+ pthread_mutex_unlock(&ctx->shared->lock);
+
+ ctx->shared->dataReady = 0;
+ close_shared_data( ctx );
+
+ free(ctx);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+static int overlay_device_open(const struct hw_module_t* module,
+ const char* name, struct hw_device_t** device)
+{
+ LOG_FUNCTION_NAME;
+ int status = -EINVAL;
+
+ if (!strcmp(name, OVERLAY_HARDWARE_CONTROL)) {
+ struct overlay_control_context_t *dev;
+ dev = (overlay_control_context_t*)malloc(sizeof(*dev));
+
+ /* initialize our state here */
+ memset(dev, 0, sizeof(*dev));
+
+ /* initialize the procs */
+ dev->device.common.tag = HARDWARE_DEVICE_TAG;
+ dev->device.common.version = 0;
+ dev->device.common.module = const_cast<hw_module_t*>(module);
+ dev->device.common.close = overlay_control_close;
+
+ dev->device.get = overlay_get;
+ dev->device.createOverlay = overlay_createOverlay;
+ dev->device.destroyOverlay = overlay_destroyOverlay;
+ dev->device.setPosition = overlay_setPosition;
+ dev->device.getPosition = overlay_getPosition;
+ dev->device.setParameter = overlay_setParameter;
+ dev->device.stage = overlay_stage;
+ dev->device.commit = overlay_commit;
+
+ *device = &dev->device.common;
+ status = 0;
+ } else if (!strcmp(name, OVERLAY_HARDWARE_DATA)) {
+ struct overlay_data_context_t *dev;
+ dev = (overlay_data_context_t*)malloc(sizeof(*dev));
+
+ /* initialize our state here */
+ memset(dev, 0, sizeof(*dev));
+
+ /* initialize the procs */
+ dev->device.common.tag = HARDWARE_DEVICE_TAG;
+ dev->device.common.version = 0;
+ dev->device.common.module = const_cast<hw_module_t*>(module);
+ dev->device.common.close = overlay_data_close;
+
+ dev->device.initialize = overlay_initialize;
+ dev->device.resizeInput = overlay_resizeInput;
+ dev->device.setCrop = overlay_setCrop;
+ dev->device.getCrop = overlay_getCrop;
+ dev->device.setParameter = overlay_data_setParameter;
+ dev->device.dequeueBuffer = overlay_dequeueBuffer;
+ dev->device.queueBuffer = overlay_queueBuffer;
+ dev->device.getBufferAddress = overlay_getBufferAddress;
+ dev->device.getBufferCount = overlay_getBufferCount;
+
+ *device = &dev->device.common;
+ status = 0;
+ }
+ return status;
+}