exynos camera -- at this point, preview works but no output tweaks yet
authorPaul Kocialkowski <contact@paulk.fr>
Sat, 19 Jan 2013 15:05:52 +0000 (16:05 +0100)
committerPaul Kocialkowski <contact@paulk.fr>
Sat, 19 Jan 2013 15:05:52 +0000 (16:05 +0100)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Android.mk [new file with mode: 0644]
exynos_camera.c [new file with mode: 0644]
exynos_camera.h [new file with mode: 0644]
exynos_param.c [new file with mode: 0644]
exynos_v4l2.c [new file with mode: 0644]

diff --git a/Android.mk b/Android.mk
new file mode 100644 (file)
index 0000000..674d63c
--- /dev/null
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_SRC_FILES:= \
+       exynos_camera.c \
+       exynos_param.c \
+       exynos_v4l2.c
+
+LOCAL_SHARED_LIBRARIES:= libutils libcutils libbinder liblog libcamera_client libhardware
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include
+LOCAL_MODULE := camera.exynos4
+
+LOCAL_MODULE_TAGS := optional
+
+#include $(BUILD_EXECUTABLE)
+include $(BUILD_SHARED_LIBRARY)
diff --git a/exynos_camera.c b/exynos_camera.c
new file mode 100644 (file)
index 0000000..2b9ae40
--- /dev/null
@@ -0,0 +1,972 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <asm/types.h>
+#include <linux/videodev2.h>
+#include <videodev2_samsung.h>
+
+#define LOG_TAG "exynos_camera"
+#include <utils/Log.h>
+
+#include "exynos_camera.h"
+
+/*
+ * Devices configurations
+ */
+
+struct exynos_camera_preset exynos_camera_presets_galaxys2[] = {
+       {
+               .name = "M5MO",
+               .facing = CAMERA_FACING_FRONT,
+               .orientation = 90,
+       },
+       {
+               .name = "S5K5BAFX",
+               .facing = CAMERA_FACING_BACK,
+               .orientation = 90,
+       },
+};
+
+struct exynos_v4l2_node exynos_v4l2_nodes_galaxys2[] = {
+       {
+               .id = 0,
+               .node = "/dev/video0",
+       },
+       {
+               .id = 1,
+               .node = "/dev/video1",
+       },
+       {
+               .id = 2,
+               .node = "/dev/video2",
+       },
+};
+
+struct exynox_camera_config exynos_camera_config_galaxys2 = {
+       .presets = (struct exynos_camera_preset *) &exynos_camera_presets_galaxys2,
+       .presets_count = 2,
+       .v4l2_nodes = (struct exynos_v4l2_node *) &exynos_v4l2_nodes_galaxys2,
+       .v4l2_nodes_count = 3,
+};
+
+/*
+ * Exynos Params
+ */
+
+/*
+-> always alloc params string (strdup)
+-> register internally with set (but with a _register function)
+-> unregister it all at the same time (but with a _unregister function)
+-> at set, look if there is already one, if not, add to the end of the list and alloc
+-> if there is one, just free the value (if string) and replace it
+
+
+set value for a key
+get value for a key
+set all the values
+get all the values
+-> pas oublier les negatifs
+
+*/
+
+
+
+/*
+ * Exynos Camera
+ */
+
+struct exynox_camera_config *exynos_camera_config =
+       &exynos_camera_config_galaxys2;
+
+int exynos_camera_params_init(struct exynos_camera *exynos_camera, int id)
+{
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       exynos_param_string_set(exynos_camera, "picture-format", "jpeg");
+       exynos_param_string_set(exynos_camera, "picture-format-values", "jpeg");
+
+       exynos_param_string_set(exynos_camera, "picture-size", "2560x1920");
+       exynos_param_string_set(exynos_camera, "picture-size-values",
+               "2560x1920,2048x1536,1600x1200,1280x960,640x480");
+
+       exynos_param_string_set(exynos_camera, "preview-format", "rgb565");
+       exynos_param_string_set(exynos_camera, "preview-format-values", "rgb565");
+       exynos_param_string_set(exynos_camera, "preview-fps-range", "15000,30000");
+       exynos_param_string_set(exynos_camera, "preview-fps-range-values", "(15000,30000)");
+       exynos_param_int_set(exynos_camera, "preview-frame-rate", 15);
+       exynos_param_int_set(exynos_camera, "preview-frame-rate-values", 15);
+       exynos_param_string_set(exynos_camera, "preview-size", "640x480");
+       exynos_param_string_set(exynos_camera, "preview-size-values",
+               "720x480,640x480,352x288,176x144");
+
+       exynos_param_string_set(exynos_camera, "focus-mode", "auto");
+       exynos_param_string_set(exynos_camera, "focus-mode-values", "auto");
+
+       return 0;
+}
+
+int exynos_camera_init(struct exynos_camera *exynos_camera, int id)
+{
+       char firmware_version[7] = { 0 };
+       struct exynos_v4l2_ext_control control;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       // Init FIMC1
+       rc = exynos_v4l2_open(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("Unable to open v4l2 device");
+               return -1;
+       }
+
+       rc = exynos_v4l2_querycap_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: querycap failed", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_enum_input(exynos_camera, 0, id);
+       if (rc < 0) {
+               LOGE("%s: enum input failed", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_input(exynos_camera, 0, id);
+       if (rc < 0) {
+               LOGE("%s: s input failed", __func__);
+               return -1;
+       }
+
+       // Init FIMC2
+       rc = exynos_v4l2_open(exynos_camera, 2);
+       if (rc < 0) {
+               LOGE("Unable to open v4l2 device");
+               return -1;
+       }
+
+       rc = exynos_v4l2_querycap_cap(exynos_camera, 2);
+       if (rc < 0) {
+               LOGE("%s: querycap failed", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_enum_input(exynos_camera, 2, id);
+       if (rc < 0) {
+               LOGE("%s: enum input failed", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_input(exynos_camera, 2, id);
+       if (rc < 0) {
+               LOGE("%s: s input failed", __func__);
+               return -1;
+       }
+
+       // Get firmware information
+       memset(&control, 0, sizeof(control));
+       control.id = V4L2_CID_CAM_SENSOR_FW_VER;
+       control.data.string = firmware_version;
+
+       rc = exynos_v4l2_g_ext_ctrls(exynos_camera, 0, (struct v4l2_ext_control *) &control, 1);
+       if (rc < 0) {
+               LOGE("%s: g ext ctrls failed", __func__);
+       } else {
+               LOGD("Firmware version: %s", firmware_version);
+       }
+
+       // Params
+       rc = exynos_camera_params_init(exynos_camera, id);
+       if (rc < 0)
+               LOGE("%s: Unable to init params", __func__);
+
+       // Gralloc
+       rc = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const struct hw_module_t **) &exynos_camera->gralloc);
+       if (rc)
+               LOGE("%s: Unable to get gralloc module", __func__);
+
+       return 0;
+}
+
+void exynos_camera_deinit(struct exynos_camera *exynos_camera)
+{
+       int i;
+       int id;
+
+       if (exynos_camera == NULL || exynos_camera->config == NULL)
+               return;
+
+       for (i=0 ; i < exynos_camera->config->v4l2_nodes_count ; i++) {
+               id = exynos_camera->config->v4l2_nodes[i].id;
+               exynos_v4l2_close(exynos_camera, id);
+       }
+}
+
+
+int exynos_camera_preview(struct exynos_camera *exynos_camera)
+{
+       buffer_handle_t *buffer;
+       int stride;
+       void *addr = NULL;
+       int offset;
+
+       int index;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       // FIMC1 V4L2
+
+       
+
+       // FIMC0 V4L2
+
+       rc = exynos_v4l2_poll(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: poll failed!", __func__);
+               return -1;
+       } else if (rc == 0) {
+               LOGE("%s: poll timeout!", __func__);
+               // TODO: it's probably a good idea to restart everything
+               return -1;
+       }
+
+       index = exynos_v4l2_dqbuf_cap(exynos_camera, 0);
+       if (index < 0 || index >= exynos_camera->preview_buffers_count) {
+               LOGE("%s: dqbuf failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, index);
+       if (rc < 0) {
+               LOGE("%s: qbuf failed!", __func__);
+               return -1;
+       }
+
+       // Preview window
+
+       exynos_camera->preview_window->dequeue_buffer(exynos_camera->preview_window,
+               &buffer, &stride);
+       exynos_camera->gralloc->lock(exynos_camera->gralloc, *buffer, GRALLOC_USAGE_SW_WRITE_OFTEN,
+               0, 0, 640, 480, &addr);
+
+       if (addr == NULL) {
+               LOGE("Unable to get addr");
+               return -1;
+       }
+       offset = index*640*480*1.5;
+
+       void *frame = (void *) ((int) exynos_camera->preview_memory->data + offset);
+
+int width= 640;
+int height=480;
+/*
+            // the code below assumes YUV, not RGB
+            {
+                int h;
+                char *src = frame;
+                char *ptr = (char *)addr;
+
+                // Copy the Y plane, while observing the stride
+                for (h = 0; h < height; h++) {
+                    memcpy(ptr, src, width);
+                    ptr += stride;
+                    src += width;
+                }
+
+                {
+                    // U
+                    char *v = ptr;
+                    ptr += stride * height / 4;
+                    for (h = 0; h < height / 2; h++) {
+                        memcpy(ptr, src, width / 2);
+                        ptr += stride / 2;
+                        src += width / 2;
+                    }
+                    // V
+                    ptr = v;
+                    for (h = 0; h < height / 2; h++) {
+                        memcpy(ptr, src, width / 2);
+                        ptr += stride / 2;
+                        src += width / 2;
+                    }
+                }
+            }
+*/
+       memcpy(addr, frame, 640*480*1.5);
+
+       exynos_camera->gralloc->unlock(exynos_camera->gralloc, *buffer);
+
+       exynos_camera->preview_window->enqueue_buffer(exynos_camera->preview_window,
+               buffer);
+
+       return 0;
+}
+
+void *exynos_camera_preview_thread(void *data)
+{
+       struct exynos_camera *exynos_camera;
+       int rc;
+
+       if (data == NULL)
+               return NULL;
+
+       exynos_camera = (struct exynos_camera *) data;
+
+       LOGE("%s: Starting thread", __func__);
+       exynos_camera->preview_thread_running = 1;
+
+       // Lock preview lock mutex
+       pthread_mutex_lock(&exynos_camera->preview_lock_mutex);
+
+       while (exynos_camera->preview_enabled == 1) {
+               pthread_mutex_lock(&exynos_camera->preview_mutex);
+
+               rc = exynos_camera_preview(exynos_camera);
+               if (rc < 0)
+                       LOGE("%s: preview failed!", __func__);
+
+               pthread_mutex_unlock(&exynos_camera->preview_mutex);
+       }
+
+       exynos_camera->preview_thread_running = 0;
+       LOGE("%s: Exiting thread", __func__);
+
+       return NULL;
+}
+
+
+/*
+ * Exynos Camera OPS
+ */
+
+int exynos_camera_set_preview_window(struct camera_device *dev,
+       struct preview_stream_ops *w)
+{
+       struct exynos_camera *exynos_camera;
+       buffer_handle_t *buffer;
+       int stride;
+       void *addr = NULL;
+
+       int rc;
+
+       LOGD("%s(%p, %p)", __func__, dev, w);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       if (w == NULL)
+               return 0;
+
+       pthread_mutex_lock(&exynos_camera->preview_mutex);
+
+       exynos_camera->preview_window = w;
+
+       if (w->set_buffer_count == NULL || w->set_usage == NULL || w->set_buffers_geometry == NULL)
+               return -EINVAL;
+
+       if (exynos_camera->preview_buffers_count <= 0) {
+               LOGE("%s: Invalid preview buffers count", __func__);
+               goto error;
+       }
+
+       rc = w->set_buffer_count(w, exynos_camera->preview_buffers_count);
+       if (rc) {
+               LOGE("%s: Unable to set buffer count (%d)", __func__,
+                       exynos_camera->preview_buffers_count);
+               goto error;
+       }
+
+       rc = w->set_usage(w, GRALLOC_USAGE_SW_WRITE_OFTEN);
+       if (rc) {
+               LOGE("%s: Unable to set usage", __func__);
+               goto error;
+       }
+
+       // TODO: Get this from params
+       rc = w->set_buffers_geometry(w, 640, 480, HAL_PIXEL_FORMAT_YCrCb_420_SP);
+       if (rc) {
+               LOGE("%s: Unable to set buffers geometry", __func__);
+               goto error;
+       }
+
+       pthread_mutex_unlock(&exynos_camera->preview_mutex);
+
+       // Unlock preview lock
+       pthread_mutex_unlock(&exynos_camera->preview_lock_mutex);
+
+       return 0;
+
+error:
+       pthread_mutex_unlock(&exynos_camera->preview_mutex);
+
+       return -1;
+}
+
+void exynos_camera_set_callbacks(struct camera_device *dev,
+       camera_notify_callback notify_cb,
+       camera_data_callback data_cb,
+       camera_data_timestamp_callback data_cb_timestamp,
+       camera_request_memory get_memory,
+       void *user)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p, %p)", __func__, dev, user);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera->callbacks.notify = notify_cb;
+       exynos_camera->callbacks.data = data_cb;
+       exynos_camera->callbacks.data_timestamp = data_cb_timestamp;
+       exynos_camera->callbacks.request_memory = get_memory;
+       exynos_camera->callbacks.user = user;
+}
+
+void exynos_camera_enable_msg_type(struct camera_device *dev, int32_t msg_type)
+{
+       LOGD("%s(%p, %d)", __func__, dev, msg_type);
+}
+
+void exynos_camera_disable_msg_type(struct camera_device *dev, int32_t msg_type)
+{
+       LOGD("%s(%p, %d)", __func__, dev, msg_type);
+}
+
+int exynos_camera_msg_type_enabled(struct camera_device *dev, int32_t msg_type)
+{
+       LOGD("%s(%p, %d)", __func__, dev, msg_type);
+
+       return 0;
+}
+
+int exynos_camera_start_preview(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+       struct v4l2_streamparm streamparm;
+       unsigned int fmt;
+       int width, height, fps, frame_size;
+       int fd;
+
+       pthread_attr_t thread_attr;
+
+       int rc;
+       int i;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       // V4L2
+
+       fmt = V4L2_PIX_FMT_NV21;
+
+       rc = exynos_v4l2_enum_fmt_cap(exynos_camera, 0, fmt);
+       if (rc < 0) {
+               LOGE("%s: enum fmt failed!", __func__);
+               return -1;
+       }
+
+       width = 640;
+       height = 480;
+
+       rc = exynos_v4l2_s_fmt_cap(exynos_camera, 0, width, height, fmt);
+       if (rc < 0) {
+               LOGE("%s: s fmt failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CACHEABLE, 1);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_reqbufs_cap(exynos_camera, 0, 8);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               return -1;
+       }
+
+       exynos_camera->preview_buffers_count = rc;
+       LOGD("Found %d buffers available!", exynos_camera->preview_buffers_count);
+
+       fps = 0;
+       memset(&streamparm, 0, sizeof(streamparm));
+       streamparm.parm.capture.timeperframe.numerator = 1;
+       streamparm.parm.capture.timeperframe.denominator = fps;
+
+       rc = exynos_v4l2_s_parm_cap(exynos_camera, 0, &streamparm);
+       if (rc < 0) {
+               LOGE("%s: s parm failed!", __func__);
+               return -1;
+       }
+
+       for (i=0 ; i < exynos_camera->preview_buffers_count ; i++) {
+               rc = exynos_v4l2_querybuf_cap(exynos_camera, 0, i);
+               if (rc < 0) {
+                       LOGE("%s: querybuf failed!", __func__);
+                       return -1;
+               }
+       }
+
+       frame_size = 640 * 480 * 1.5;
+
+       if (exynos_camera->callbacks.request_memory != NULL) {
+               fd = exynos_v4l2_find_fd(exynos_camera, 0);
+               if (fd < 0) {
+                       LOGE("%s: Unable to find v4l2 fd", __func__);
+                       return -1;
+               }
+
+               if (exynos_camera->preview_memory != NULL && exynos_camera->preview_memory->release != NULL)
+                       exynos_camera->preview_memory->release(exynos_camera->preview_memory);
+
+               exynos_camera->preview_memory =
+                       exynos_camera->callbacks.request_memory(fd, 
+                               frame_size, exynos_camera->preview_buffers_count, 0);
+               if (exynos_camera->preview_memory == NULL) {
+                       LOGE("%s: memory request failed!", __func__);
+                       return -1;
+               }
+       } else {
+               LOGE("%s: No memory request function!", __func__);
+               return -1;
+       }
+
+       for (i=0 ; i < exynos_camera->preview_buffers_count ; i++) {
+               rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, i);
+               if (rc < 0) {
+                       LOGE("%s: qbuf failed!", __func__);
+                       return -1;
+               }
+       }
+
+       rc = exynos_v4l2_streamon_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: streamon failed!", __func__);
+               return -1;
+       }
+
+       // Init FIMC1
+       rc = exynos_v4l2_open(exynos_camera, 2);
+       if (rc < 0) {
+               LOGE("Unable to open v4l2 device");
+               return -1;
+       }
+
+       // Thread
+
+       pthread_mutex_init(&exynos_camera->preview_mutex, NULL);
+       pthread_mutex_init(&exynos_camera->preview_lock_mutex, NULL);
+
+       // Lock preview lock
+       pthread_mutex_lock(&exynos_camera->preview_lock_mutex);
+
+       pthread_attr_init(&thread_attr);
+       pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+
+       exynos_camera->preview_enabled = 1;
+
+       rc = pthread_create(&exynos_camera->preview_thread, &thread_attr,
+               exynos_camera_preview_thread, (void *) exynos_camera);
+       if (rc < 0) {
+               LOGE("%s: Unable to create thread", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+void exynos_camera_stop_preview(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+       int rc;
+       int i;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       if (!exynos_camera->preview_enabled)
+               return;
+
+       exynos_camera->preview_enabled = 0;
+
+       // Unlock preview lock
+       pthread_mutex_unlock(&exynos_camera->preview_lock_mutex);
+
+       pthread_mutex_lock(&exynos_camera->preview_mutex);
+
+       // Wait for the thread to end
+       for (i=0 ; i < 10 ; i++) {
+               if (!exynos_camera->preview_thread_running)
+                       break;
+
+               usleep(1000);
+       }
+
+       rc = exynos_v4l2_streamoff_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: streamoff failed!", __func__);
+       }
+
+       if (exynos_camera->preview_memory != NULL && exynos_camera->preview_memory->release != NULL) {
+               exynos_camera->preview_memory->release(exynos_camera->preview_memory);
+               exynos_camera->preview_memory = NULL;
+       }
+
+       pthread_mutex_unlock(&exynos_camera->preview_mutex);
+}
+
+int exynos_camera_preview_enabled(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera->preview_enabled;
+}
+
+int exynos_camera_store_meta_data_in_buffers(struct camera_device *dev,
+       int enable)
+{
+       LOGD("%s(%p, %d)", __func__, dev, enable);
+
+       return 0;
+}
+
+int exynos_camera_start_recording(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       return 0;
+}
+
+void exynos_camera_stop_recording(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+}
+
+int exynos_camera_recording_enabled(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       return 0;
+}
+
+void exynos_camera_release_recording_frame(struct camera_device *dev,
+       const void *opaque)
+{
+       LOGD("%s(%p, %p)", __func__, dev, opaque);
+}
+
+int exynos_camera_auto_focus(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       return 0;
+}
+
+int exynos_camera_cancel_auto_focus(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       return 0;
+}
+
+int exynos_camera_take_picture(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       return 0;
+}
+
+int exynos_camera_cancel_picture(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       return 0;
+}
+
+int exynos_camera_set_parameters(struct camera_device *dev,
+       const char *params)
+{
+       struct exynos_camera *exynos_camera;
+       int rc;
+
+       LOGD("%s(%p, %s)", __func__, dev, params);
+
+       if (dev == NULL || dev->priv == NULL || params == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       rc = exynos_params_string_set(exynos_camera, (char *) params);
+       if (rc < 0) {
+               LOGE("%s: Unable to set params string", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+char *exynos_camera_get_parameters(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+       char *params;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return NULL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       params = exynos_params_string_get(exynos_camera);
+       if (params == NULL) {
+               LOGE("%s: Couldn't find any param", __func__);
+               return strdup("");
+       }
+
+       return params;
+}
+
+void exynos_camera_put_parameters(struct camera_device *dev, char *params)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       if (params != NULL)
+               free(params);
+}
+
+int exynos_camera_send_command(struct camera_device *dev,
+       int32_t cmd, int32_t arg1, int32_t arg2)
+{
+       LOGD("%s(%p, %d, %d, %d)", __func__, dev, cmd, arg1, arg2);
+
+       return 0;
+}
+
+void exynos_camera_release(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+}
+
+int exynos_camera_dump(struct camera_device *dev, int fd)
+{
+       LOGD("%s(%p, %d)", __func__, dev, fd);
+
+       return 0;
+}
+
+/*
+ * Interface
+ */
+
+struct camera_device_ops exynos_camera_ops = {
+       .set_preview_window = exynos_camera_set_preview_window,
+       .set_callbacks = exynos_camera_set_callbacks,
+       .enable_msg_type = exynos_camera_enable_msg_type,
+       .disable_msg_type = exynos_camera_disable_msg_type,
+       .msg_type_enabled = exynos_camera_msg_type_enabled,
+       .start_preview = exynos_camera_start_preview,
+       .stop_preview = exynos_camera_stop_preview,
+       .preview_enabled = exynos_camera_preview_enabled,
+       .store_meta_data_in_buffers = exynos_camera_store_meta_data_in_buffers,
+       .start_recording = exynos_camera_start_recording,
+       .stop_recording = exynos_camera_stop_recording,
+       .recording_enabled = exynos_camera_recording_enabled,
+       .release_recording_frame = exynos_camera_release_recording_frame,
+       .auto_focus = exynos_camera_auto_focus,
+       .cancel_auto_focus = exynos_camera_cancel_auto_focus,
+       .take_picture = exynos_camera_take_picture,
+       .cancel_picture = exynos_camera_cancel_picture,
+       .set_parameters = exynos_camera_set_parameters,
+       .get_parameters = exynos_camera_get_parameters,
+       .put_parameters = exynos_camera_put_parameters,
+       .send_command = exynos_camera_send_command,
+       .release = exynos_camera_release,
+       .dump = exynos_camera_dump,
+};
+
+int exynos_camera_close(hw_device_t *device)
+{
+       struct camera_device *camera_device;
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, device);
+
+       if (device == NULL)
+               return -EINVAL;
+
+       camera_device = (struct camera_device *) device;
+
+       if (camera_device->priv != NULL) {
+               exynos_camera = (struct exynos_camera *) camera_device->priv;
+               exynos_camera_deinit(exynos_camera);
+
+               free(exynos_camera);
+       }
+
+       free(camera_device);
+
+       return 0;
+}
+
+int exynos_camera_open(const struct hw_module_t* module, const char *camera_id,
+       struct hw_device_t** device)
+{
+       struct camera_device *camera_device = NULL;
+       struct exynos_camera *exynos_camera = NULL;
+       int id;
+       int rc;
+
+       LOGD("%s(%p, %s, %p)", __func__, module, camera_id, device);
+
+       if (module == NULL || camera_id == NULL || device == NULL)
+               return -EINVAL;
+
+       id = atoi(camera_id);
+       if (id < 0)
+               return -EINVAL;
+
+       exynos_camera = calloc(1, sizeof(struct exynos_camera));
+       exynos_camera->config = exynos_camera_config;
+
+       if (exynos_camera->config->presets_count > EXYNOS_CAMERA_MAX_PRESETS_COUNT ||
+               exynos_camera->config->v4l2_nodes_count > EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT)
+               goto error_preset;
+
+       if (id >= exynos_camera->config->presets_count)
+               goto error_preset;
+
+       rc = exynos_camera_init(exynos_camera, id);
+       if (rc < 0) {
+               LOGE("%s: Unable to init camera", __func__);
+               goto error;
+       }
+
+       camera_device = calloc(1, sizeof(struct camera_device));
+       camera_device->common.tag = HARDWARE_DEVICE_TAG;
+       camera_device->common.version = 0;
+       camera_device->common.module = (struct hw_module_t *) module;
+       camera_device->common.close = exynos_camera_close;
+
+       camera_device->ops = &exynos_camera_ops;
+       camera_device->priv = exynos_camera;
+
+       *device = (struct hw_device_t *) &(camera_device->common);
+
+       return 0;
+
+error:
+       exynos_camera_deinit(exynos_camera);
+
+error_device:
+       if (camera_device != NULL)
+               free(camera_device);
+
+error_preset:
+       if (exynos_camera != NULL)
+               free(exynos_camera);
+
+       return -1;
+}
+
+int exynos_camera_get_number_of_cameras(void)
+{
+       LOGD("%s()", __func__);
+
+       if (exynos_camera_config == NULL || exynos_camera_config->presets == NULL) {
+               LOGE("%s: Unable to find proper camera config", __func__);
+               return -1;
+       }
+
+       return exynos_camera_config->presets_count;
+}
+
+int exynos_camera_get_camera_info(int id, struct camera_info *info)
+{
+       LOGD("%s(%d, %p)", __func__, id, info);
+
+       if (id < 0 || info == NULL)
+               return -EINVAL;
+
+       if (exynos_camera_config == NULL || exynos_camera_config->presets == NULL) {
+               LOGE("%s: Unable to find proper camera config", __func__);
+               return -1;
+       }
+
+       if (id >= exynos_camera_config->presets_count)
+               return -EINVAL;
+
+       LOGD("Selected camera: %s", exynos_camera_config->presets[id].name);
+
+       info->facing = exynos_camera_config->presets[id].facing;
+       info->orientation = exynos_camera_config->presets[id].orientation;
+
+       return 0;
+}
+
+struct hw_module_methods_t exynos_camera_module_methods = {
+       .open = exynos_camera_open,
+};
+
+struct camera_module HAL_MODULE_INFO_SYM = {
+       .common = {
+               .tag = HARDWARE_MODULE_TAG,
+               .version_major = 1,
+               .version_minor = 0,
+               .id = CAMERA_HARDWARE_MODULE_ID,
+               .name = "Exynos Camera",
+               .author = "Paul Kocialkowski",
+               .methods = &exynos_camera_module_methods,
+       },
+       .get_number_of_cameras = exynos_camera_get_number_of_cameras,
+       .get_camera_info = exynos_camera_get_camera_info,
+};
diff --git a/exynos_camera.h b/exynos_camera.h
new file mode 100644 (file)
index 0000000..c795302
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+
+#include <linux/videodev2.h>
+
+#include <hardware/hardware.h>
+#include <hardware/camera.h>
+
+#ifndef _EXYNOS_CAMERA_H_
+#define _EXYNOS_CAMERA_H_
+
+#define EXYNOS_CAMERA_MAX_PRESETS_COUNT                2
+#define EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT     4
+
+/*
+ * Structures
+ */
+
+struct list_head {
+       struct list_head *next;
+       struct list_head *prev;
+};
+
+enum exynos_param_type {
+       EXYNOS_PARAM_INT,
+       EXYNOS_PARAM_FLOAT,
+       EXYNOS_PARAM_STRING,
+};
+
+union exynos_param_data {
+       int integer;
+       float floating;
+       char *string;
+};
+
+struct exynos_param {
+       struct list_head list;
+
+       char *key;
+       union exynos_param_data data;
+       enum exynos_param_type type;
+};
+
+struct exynos_camera_preset {
+       char *name;
+       int facing;
+       int orientation;
+       char *preview_sizes;
+       char *picture_sizes;
+};
+
+struct exynos_v4l2_node {
+       int id;
+       char *node;
+};
+
+struct exynox_camera_config {
+       struct exynos_camera_preset *presets;
+       int presets_count;
+
+       struct exynos_v4l2_node *v4l2_nodes;
+       int v4l2_nodes_count;
+};
+
+struct exynos_camera_callbacks {
+       camera_notify_callback notify;
+       camera_data_callback data;
+       camera_data_timestamp_callback data_timestamp;
+       camera_request_memory request_memory;
+       void *user;
+};
+
+struct exynos_camera {
+       int v4l2_fds[EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT];
+
+       struct exynox_camera_config *config;
+       struct exynos_param *params;
+
+       struct exynos_camera_callbacks callbacks;
+
+       gralloc_module_t *gralloc;
+
+       pthread_t preview_thread;
+       pthread_mutex_t preview_mutex;
+       pthread_mutex_t preview_lock_mutex;
+       int preview_thread_running;
+       int preview_enabled;
+       struct preview_stream_ops *preview_window;
+       camera_memory_t *preview_memory;
+       int preview_buffers_count;
+};
+
+// This is because the linux header uses anonymous union
+struct exynos_v4l2_ext_control {
+       __u32 id;
+       __u32 size;
+       __u32 reserved2[1];
+       union {
+               __s32 value;
+               __s64 value64;
+               char *string;
+       } data;
+} __attribute__ ((packed));
+
+/*
+ * Param
+ */
+
+int exynos_param_int_get(struct exynos_camera *exynos_camera,
+       char *key);
+float exynos_param_float_get(struct exynos_camera *exynos_camera,
+       char *key);
+char *exynos_param_string_get(struct exynos_camera *exynos_camera,
+       char *key);
+
+int exynos_param_int_set(struct exynos_camera *exynos_camera,
+       char *key, int integer);
+int exynos_param_float_set(struct exynos_camera *exynos_camera,
+       char *key, float floating);
+int exynos_param_string_set(struct exynos_camera *exynos_camera,
+       char *key, char *string);
+
+char *exynos_params_string_get(struct exynos_camera *exynos_camera);
+int exynos_params_string_set(struct exynos_camera *exynos_camera, char *string);
+
+/*
+ * V4L2
+ */
+
+// Utils
+int exynos_v4l2_find_index(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_find_fd(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+
+// File ops
+int exynos_v4l2_open(struct exynos_camera *exynos_camera, int id);
+void exynos_v4l2_close(struct exynos_camera *exynos_camera, int id);
+int exynos_v4l2_ioctl(struct exynos_camera *exynos_camera, int id, int request, void *data);
+int exynos_v4l2_poll(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+
+// VIDIOC
+int exynos_v4l2_qbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int index);
+int exynos_v4l2_qbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index);
+int exynos_v4l2_qbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index);
+int exynos_v4l2_dqbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type);
+int exynos_v4l2_dqbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_dqbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_reqbufs(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int count);
+int exynos_v4l2_reqbufs_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int count);
+int exynos_v4l2_reqbufs_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int count);
+int exynos_v4l2_querybuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int index);
+int exynos_v4l2_querybuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index);
+int exynos_v4l2_querybuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index);
+int exynos_v4l2_querycap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int flags);
+int exynos_v4l2_querycap_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_querycap_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamon(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type);
+int exynos_v4l2_streamon_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamon_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamoff(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type);
+int exynos_v4l2_streamoff_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_streamoff_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id);
+int exynos_v4l2_g_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int *width, int *height, int *fmt);
+int exynos_v4l2_g_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int *width, int *height, int *fmt);
+int exynos_v4l2_g_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int *width, int *height, int *fmt);
+int exynos_v4l2_s_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int width, int height, int fmt);
+int exynos_v4l2_s_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int width, int height, int fmt);
+int exynos_v4l2_s_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int width, int height, int fmt);
+int exynos_v4l2_enum_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int fmt);
+int exynos_v4l2_enum_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int fmt);
+int exynos_v4l2_enum_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int fmt);
+int exynos_v4l2_enum_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id);
+int exynos_v4l2_s_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id);
+int exynos_v4l2_g_ext_ctrls(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_ext_control *control, int count);
+int exynos_v4l2_s_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id, int value);
+int exynos_v4l2_s_parm(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, struct v4l2_streamparm *streamparm);
+int exynos_v4l2_s_parm_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_streamparm *streamparm);
+int exynos_v4l2_s_parm_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_streamparm *streamparm);
+
+#endif
diff --git a/exynos_param.c b/exynos_param.c
new file mode 100644 (file)
index 0000000..91da359
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <malloc.h>
+#include <ctype.h>
+
+#define LOG_TAG "exynos_param"
+#include <utils/Log.h>
+
+#include "exynos_camera.h"
+
+int list_head_insert(struct list_head *list, struct list_head *prev,
+       struct list_head *next)
+{
+       if (list == NULL)
+               return -EINVAL;
+
+       list->prev = prev;
+       list->next = next;
+
+       if(prev != NULL)
+               prev->next = list;
+       if(next != NULL)
+               next->prev = list;
+
+       return 0;
+}
+
+void list_head_remove(struct list_head *list)
+{
+       if(list == NULL)
+               return;
+
+       if(list->next != NULL)
+               list->next->prev = list->prev;
+       if(list->prev != NULL)
+               list->prev->next = list->next;
+}
+
+int exynos_param_register(struct exynos_camera *exynos_camera, char *key,
+       union exynos_param_data data, enum exynos_param_type type)
+{
+       struct list_head *list_end;
+       struct list_head *list;
+       struct exynos_param *param;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       param = (struct exynos_param *) calloc(1, sizeof(struct exynos_param));
+       if (param == NULL)
+               return -ENOMEM;
+
+       param->key = strdup(key);
+       switch (type) {
+               case EXYNOS_PARAM_INT:
+                       param->data.integer = data.integer;
+                       break;
+               case EXYNOS_PARAM_FLOAT:
+                       param->data.floating = data.floating;
+                       break;
+               case EXYNOS_PARAM_STRING:
+                       param->data.string = strdup(data.string);
+                       break;
+               default:
+                       LOGE("%s: Invalid type", __func__);
+                       goto error;
+       }
+       param->type = type;
+
+       list_end = (struct list_head *) exynos_camera->params;
+       while (list_end != NULL && list_end->next != NULL)
+               list_end = list_end->next;
+
+       list = (struct list_head *) param;
+       list_head_insert(list, list_end, NULL);
+
+       if (exynos_camera->params == NULL)
+               exynos_camera->params = param;
+
+       return 0;
+
+error:
+       if (param != NULL) {
+               if (param->key != NULL)
+                       free(param->key);
+
+               free(param);
+       }
+
+       return -1;
+}
+
+void exynos_param_unregister(struct exynos_camera *exynos_camera,
+       struct exynos_param *param)
+{
+       struct list_head *list;
+
+       if (exynos_camera == NULL || param == NULL)
+               return;
+
+       list = (struct list_head *) exynos_camera->params;
+       while (list != NULL) {
+               if ((void *) list == (void *) param) {
+                       list_head_remove(list);
+
+                       if ((void *) list == (void *) exynos_camera->params)
+                               exynos_camera->params = (struct exynos_param *) list->next;
+
+                       if (param->type == EXYNOS_PARAM_STRING && param->data.string != NULL)
+                               free(param->data.string);
+
+                       memset(param, 0, sizeof(struct exynos_param));
+                       free(param);
+
+                       break;
+               }
+
+list_continue:
+               list = list->next;
+       }
+}
+
+struct exynos_param *exynos_param_find_key(struct exynos_camera *exynos_camera,
+       char *key)
+{
+       struct exynos_param *param;
+       struct list_head *list;
+
+       if (exynos_camera == NULL || key == NULL)
+               return NULL;
+
+       list = (struct list_head *) exynos_camera->params;
+       while (list != NULL) {
+               param = (struct exynos_param *) list;
+               if (param->key == NULL)
+                       goto list_continue;
+
+               if (strcmp(param->key, key) == 0)
+                       return param;
+
+list_continue:
+               list = list->next;
+       }
+
+       return NULL;
+}
+
+int exynos_param_data_set(struct exynos_camera *exynos_camera, char *key,
+       union exynos_param_data data, enum exynos_param_type type)
+{
+       struct exynos_param *param;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+
+       if (strchr(key, '=') || strchr(key, ';'))
+               return -EINVAL;
+
+       if (type == EXYNOS_PARAM_STRING && data.string != NULL &&
+               (strchr(data.string, '=') || strchr(data.string, ';')))
+               return -EINVAL;
+
+       param = exynos_param_find_key(exynos_camera, key);
+       if (param == NULL) {
+               // The key isn't in the list yet
+               exynos_param_register(exynos_camera, key, data, type);
+               return 0;
+       }
+
+       if (param->type != type)
+               LOGE("%s: Mismatching types for key %s", __func__, key);
+
+       if (param->type == EXYNOS_PARAM_STRING && param->data.string != NULL)
+               free(param->data.string);
+
+       switch (type) {
+               case EXYNOS_PARAM_INT:
+                       param->data.integer = data.integer;
+                       break;
+               case EXYNOS_PARAM_FLOAT:
+                       param->data.floating = data.floating;
+                       break;
+               case EXYNOS_PARAM_STRING:
+                       param->data.string = strdup(data.string);
+                       break;
+               default:
+                       LOGE("%s: Invalid type", __func__);
+                       return -1;
+       }
+       param->type = type;
+
+       return 0;
+}
+
+int exynos_param_data_get(struct exynos_camera *exynos_camera, char *key,
+       union exynos_param_data *data, enum exynos_param_type type)
+{
+       struct exynos_param *param;
+
+       if (exynos_camera == NULL || key == NULL || data == NULL)
+               return -EINVAL;
+
+       param = exynos_param_find_key(exynos_camera, key);
+       if (param == NULL || param->type != type)
+               return -1;
+
+       memcpy(data, &param->data, sizeof(param->data));
+
+       return 0;
+}
+
+int exynos_param_int_get(struct exynos_camera *exynos_camera,
+       char *key)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       rc = exynos_param_data_get(exynos_camera, key, &data, EXYNOS_PARAM_INT);
+       if (rc < 0) {
+               LOGE("%s: Unable to get data for key %s", __func__, key);
+               return -1;
+       }
+
+       return data.integer;
+}
+
+float exynos_param_float_get(struct exynos_camera *exynos_camera,
+       char *key)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       rc = exynos_param_data_get(exynos_camera, key, &data, EXYNOS_PARAM_FLOAT);
+       if (rc < 0) {
+               LOGE("%s: Unable to get data for key %s", __func__, key);
+               return -1;
+       }
+
+       return data.floating;
+}
+
+char *exynos_param_string_get(struct exynos_camera *exynos_camera,
+       char *key)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return NULL;
+
+       rc = exynos_param_data_get(exynos_camera, key, &data, EXYNOS_PARAM_STRING);
+       if (rc < 0) {
+               LOGE("%s: Unable to get data for key %s", __func__, key);
+               return NULL;
+       }
+
+       return data.string;
+}
+
+int exynos_param_int_set(struct exynos_camera *exynos_camera,
+       char *key, int integer)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       data.integer = integer;
+
+       rc = exynos_param_data_set(exynos_camera, key, data, EXYNOS_PARAM_INT);
+       if (rc < 0) {
+               LOGE("%s: Unable to set data for key %s", __func__, key);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_param_float_set(struct exynos_camera *exynos_camera,
+       char *key, float floating)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL)
+               return -EINVAL;
+
+       data.floating = floating;
+
+       rc = exynos_param_data_set(exynos_camera, key, data, EXYNOS_PARAM_FLOAT);
+       if (rc < 0) {
+               LOGE("%s: Unable to set data for key %s", __func__, key);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_param_string_set(struct exynos_camera *exynos_camera,
+       char *key, char *string)
+{
+       union exynos_param_data data;
+       int rc;
+
+       if (exynos_camera == NULL || key == NULL || string == NULL)
+               return -EINVAL;
+
+       data.string = string;
+
+       rc = exynos_param_data_set(exynos_camera, key, data, EXYNOS_PARAM_STRING);
+       if (rc < 0) {
+               LOGE("%s: Unable to set data for key %s", __func__, key);
+               return -1;
+       }
+
+       return 0;
+}
+
+char *exynos_params_string_get(struct exynos_camera *exynos_camera)
+{
+       struct exynos_param *param;
+       struct list_head *list;
+       char *string = NULL;
+       char *s = NULL;
+       int length = 0;
+       int l = 0;
+
+       if (exynos_camera == NULL)
+               return NULL;
+
+       list = (struct list_head *) exynos_camera->params;
+       while (list != NULL) {
+               param = (struct exynos_param *) list;
+               if (param->key == NULL)
+                       goto list_continue_length;
+
+               length += strlen(param->key);
+               length++;
+
+               switch (param->type) {
+                       case EXYNOS_PARAM_INT:
+                       case EXYNOS_PARAM_FLOAT:
+                               length += 16;
+                               break;
+                       case EXYNOS_PARAM_STRING:
+                               length += strlen(param->data.string);
+                               break;
+                       default:
+                               LOGE("%s: Invalid type", __func__);
+                               return NULL;
+               }
+
+               length++;
+
+list_continue_length:
+               list = list->next;
+       }
+
+       if (length == 0)
+               return NULL;
+
+       string = calloc(1, length);
+       s = string;
+
+       list = (struct list_head *) exynos_camera->params;
+       while (list != NULL) {
+               param = (struct exynos_param *) list;
+               if (param->key == NULL)
+                       goto list_continue;
+
+               l = sprintf(s, "%s=", param->key);
+               s += l;
+
+               switch (param->type) {
+                       case EXYNOS_PARAM_INT:
+                               l = snprintf(s, 16, "%d", param->data.integer);
+                               s += l;
+                               break;
+                       case EXYNOS_PARAM_FLOAT:
+                               l = snprintf(s, 16, "%g", param->data.floating);
+                               s += l;
+                               break;
+                       case EXYNOS_PARAM_STRING:
+                               l = sprintf(s, "%s", param->data.string);
+                               s += l;
+                               break;
+                       default:
+                               LOGE("%s: Invalid type", __func__);
+                               return NULL;
+               }
+
+               if (list->next != NULL) {
+                       *s = ';';
+                       s++;
+               } else {
+                       *s = '\0';
+                       break;
+               }
+
+list_continue:
+               list = list->next;
+       }
+
+       return string;
+}
+
+int exynos_params_string_set(struct exynos_camera *exynos_camera, char *string)
+{
+       union exynos_param_data data;
+       enum exynos_param_type type;
+
+       char *d = NULL;
+       char *s = NULL;
+       char *k = NULL;
+       char *v = NULL;
+
+       char *key;
+       char *value;
+
+       int rc;
+       int i;
+
+       if (exynos_camera == NULL || string == NULL)
+               return -1;
+
+       d = strdup(string);
+       s = d;
+
+       while (1) {
+               k = strchr(s, '=');
+               if (k == NULL)
+                       break;
+               *k = '\0';
+               key = s;
+
+               v = strchr(k+1, ';');
+               if (v != NULL)
+                       *v = '\0';
+               value = k+1;
+
+               k = value;
+               if (isdigit(k[0]) || k[0] == '-') {
+                       type = EXYNOS_PARAM_INT;
+
+                       for (i=0 ; k[i] != '\0' ; i++) {
+                               if (k[i] == '.') {
+                                       type = EXYNOS_PARAM_FLOAT;
+                               } else if (!isdigit(k[i])) {
+                                       type = EXYNOS_PARAM_STRING;
+                                       break;
+                               }
+                       }
+               } else {
+                       type = EXYNOS_PARAM_STRING;
+               }
+
+               switch (type) {
+                       case EXYNOS_PARAM_INT:
+                               data.integer = atoi(value);
+                               break;
+                       case EXYNOS_PARAM_FLOAT:
+                               data.floating = atof(value);
+                               break;
+                       case EXYNOS_PARAM_STRING:
+                               data.string = value;
+                               break;
+                       default:
+                               LOGE("%s: Invalid type", __func__);
+                               goto error;
+               }
+
+               rc = exynos_param_data_set(exynos_camera, key, data, type);
+               if (rc < 0) {
+                       LOGE("%s: Unable to set data for key %s", __func__, key);
+                       goto error;
+               }
+
+               if (v == NULL)
+                       break;
+
+               s = v+1;
+       }
+
+       if (d != NULL)
+               free(d);
+
+       return 0;
+
+error:
+       if (d != NULL)
+               free(d);
+
+       return -1;
+}
diff --git a/exynos_v4l2.c b/exynos_v4l2.c
new file mode 100644 (file)
index 0000000..e69835c
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+#include <poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <asm/types.h>
+#include <linux/videodev2.h>
+
+#define LOG_TAG "exynos_v4l2"
+#include <utils/Log.h>
+
+#include "exynos_camera.h"
+
+/*
+ * Utils
+ */
+
+int exynos_v4l2_find_index(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       int index;
+       int i;
+
+       if (exynos_camera == NULL || exynos_camera->config == NULL ||
+               exynos_camera->config->v4l2_nodes == NULL)
+               return -EINVAL;
+
+       if (exynos_v4l2_id > exynos_camera->config->v4l2_nodes_count)
+               return -1;
+
+       index = -1;
+       for (i=0 ; i < exynos_camera->config->v4l2_nodes_count ; i++) {
+               if (exynos_camera->config->v4l2_nodes[i].id == exynos_v4l2_id &&
+                       exynos_camera->config->v4l2_nodes[i].node != NULL) {
+                       index = i;
+               }
+       }
+
+       return index;
+}
+
+int exynos_v4l2_find_fd(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       int index;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       index = exynos_v4l2_find_index(exynos_camera, exynos_v4l2_id);
+       if (index < 0)
+               return -1;
+
+       return exynos_camera->v4l2_fds[index];
+}
+
+/*
+ * File ops
+ */
+
+int exynos_v4l2_open(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       char *node;
+       int index;
+       int fd;
+
+       if (exynos_camera == NULL || exynos_camera->config == NULL ||
+               exynos_camera->config->v4l2_nodes == NULL)
+               return -EINVAL;
+
+       index = exynos_v4l2_find_index(exynos_camera, exynos_v4l2_id);
+       if (index < 0) {
+               LOGE("%s: Unable to find v4l2 node #%d", __func__, exynos_v4l2_id);
+               return -1;
+       }
+
+       node = exynos_camera->config->v4l2_nodes[index].node;
+       fd = open(node, O_RDWR);
+       if (fd < 0) {
+               LOGE("%s: Unable to open v4l2 node #%d", __func__, exynos_v4l2_id);
+               return -1;
+       }
+
+       exynos_camera->v4l2_fds[index] = fd;
+
+       return 0;
+}
+
+void exynos_v4l2_close(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       int index;
+
+       if (exynos_camera == NULL || exynos_camera->config == NULL ||
+               exynos_camera->config->v4l2_nodes == NULL)
+               return;
+
+       index = exynos_v4l2_find_index(exynos_camera, exynos_v4l2_id);
+       if (index < 0) {
+               LOGE("%s: Unable to find v4l2 node #%d", __func__, exynos_v4l2_id);
+               return;
+       }
+
+       if (exynos_camera->v4l2_fds[index] > 0)
+               close(exynos_camera->v4l2_fds[index]);
+
+       exynos_camera->v4l2_fds[index] = -1;
+}
+
+int exynos_v4l2_ioctl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int request, void *data)
+{
+       int fd;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       fd = exynos_v4l2_find_fd(exynos_camera, exynos_v4l2_id);
+       if (fd < 0) {
+               LOGE("%s: Unable to find v4l2 fd #%d", __func__, exynos_v4l2_id);
+               return -1;
+       }
+
+       return ioctl(fd, request, data);
+}
+
+int exynos_v4l2_poll(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       struct pollfd events;
+       int fd;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       fd = exynos_v4l2_find_fd(exynos_camera, exynos_v4l2_id);
+       if (fd < 0) {
+               LOGE("%s: Unable to find v4l2 fd #%d", __func__, exynos_v4l2_id);
+               return -1;
+       }
+
+       memset(&events, 0, sizeof(events));
+       events.fd = fd;
+       events.events = POLLIN | POLLERR;
+
+       rc = poll(&events, 1, 1000);
+       if (rc < 0 || events.revents & POLLERR) {
+               LOGE("%s: poll failed", __func__);
+               return -1;
+       }
+
+       return rc;
+}
+
+/*
+ * VIDIOC
+ */
+
+int exynos_v4l2_qbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int index)
+{
+       struct v4l2_buffer buffer;
+       int rc;
+
+       if (exynos_camera == NULL || index < 0)
+               return -EINVAL;
+
+       buffer.type = type;
+       buffer.memory = V4L2_MEMORY_MMAP;
+       buffer.index = index;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_QBUF, &buffer);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_qbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index)
+{
+       return exynos_v4l2_qbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE, index);
+}
+
+int exynos_v4l2_qbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index)
+{
+       return exynos_v4l2_qbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT, index);
+}
+
+int exynos_v4l2_dqbuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type)
+{
+       struct v4l2_buffer buffer;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       memset(&buffer, 0, sizeof(buffer));
+       buffer.type = type;
+       buffer.memory = V4L2_MEMORY_MMAP;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_DQBUF, &buffer);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return buffer.index;
+}
+
+int exynos_v4l2_dqbuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_dqbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_dqbuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_dqbuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_reqbufs(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int count)
+{
+       struct v4l2_requestbuffers requestbuffers;
+       int rc;
+
+       if (exynos_camera == NULL || count < 0)
+               return -EINVAL;
+
+       requestbuffers.count = count;
+       requestbuffers.type = type;
+       requestbuffers.memory = V4L2_MEMORY_MMAP;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_REQBUFS, &requestbuffers);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return requestbuffers.count;
+}
+
+int exynos_v4l2_reqbufs_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int count)
+{
+       return exynos_v4l2_reqbufs(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               count);
+}
+
+int exynos_v4l2_reqbufs_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int count)
+{
+       return exynos_v4l2_reqbufs(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               count);
+}
+
+int exynos_v4l2_querybuf(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int index)
+{
+       struct v4l2_buffer buffer;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       memset(&buffer, 0, sizeof(buffer));
+       buffer.type = type;
+       buffer.memory = V4L2_MEMORY_MMAP;
+       buffer.index = index;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_QUERYBUF, &buffer);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return buffer.length;
+}
+
+int exynos_v4l2_querybuf_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index)
+{
+       return exynos_v4l2_querybuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               index);
+}
+
+int exynos_v4l2_querybuf_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int index)
+{
+       return exynos_v4l2_querybuf(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               index);
+}
+
+int exynos_v4l2_querycap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int flags)
+{
+       struct v4l2_capability cap;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_QUERYCAP, &cap);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       if (!(cap.capabilities & flags))
+               return -1;
+
+       return 0;
+}
+
+int exynos_v4l2_querycap_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_querycap(exynos_camera, exynos_v4l2_id, V4L2_CAP_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_querycap_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_querycap(exynos_camera, exynos_v4l2_id, V4L2_CAP_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_streamon(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type)
+{
+       enum v4l2_buf_type buf_type;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       buf_type = type;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_STREAMON, &buf_type);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_streamon_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_streamon(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_streamon_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_streamon(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_streamoff(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type)
+{
+       enum v4l2_buf_type buf_type;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       buf_type = type;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_STREAMOFF, &buf_type);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_streamoff_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_streamoff(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+}
+
+int exynos_v4l2_streamoff_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id)
+{
+       return exynos_v4l2_streamoff(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+}
+
+int exynos_v4l2_g_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int *width, int *height, int *fmt)
+{
+       struct v4l2_format format;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       format.type = type;
+       format.fmt.pix.field = V4L2_FIELD_NONE;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_G_FMT, &format);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       if (width != NULL)
+               *width = format.fmt.pix.width;
+       if (height != NULL)
+               *height = format.fmt.pix.height;
+       if (fmt != NULL)
+               *fmt = format.fmt.pix.pixelformat;
+
+       return 0;
+}
+
+int exynos_v4l2_g_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int *width, int *height, int *fmt)
+{
+       return exynos_v4l2_g_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               width, height, fmt);
+}
+
+int exynos_v4l2_g_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int *width, int *height, int *fmt)
+{
+       return exynos_v4l2_g_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               width, height, fmt);
+}
+
+int exynos_v4l2_s_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int width, int height, int fmt)
+{
+       struct v4l2_format format;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       memset(&format, 0, sizeof(format));
+       format.type = type;
+       format.fmt.pix.width = width;
+       format.fmt.pix.height = height;
+       format.fmt.pix.pixelformat = fmt;
+       format.fmt.pix.field = V4L2_FIELD_NONE;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_FMT, &format);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_s_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int width, int height, int fmt)
+{
+       return exynos_v4l2_s_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               width, height, fmt);
+}
+
+int exynos_v4l2_s_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int width, int height, int fmt)
+{
+       return exynos_v4l2_s_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               width, height, fmt);
+}
+
+int exynos_v4l2_enum_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, int fmt)
+{
+       struct v4l2_fmtdesc fmtdesc;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       fmtdesc.type = type;
+       fmtdesc.index = 0;
+
+       do {
+               rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_ENUM_FMT, &fmtdesc);
+               if (rc < 0) {
+                       LOGE("%s: ioctl failed", __func__);
+                       return -1;
+               }
+
+               if (fmtdesc.pixelformat == (unsigned int) fmt)
+                       return 0;
+
+               fmtdesc.index++;
+       } while (rc >= 0);
+
+       return -1;
+}
+
+int exynos_v4l2_enum_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int fmt)
+{
+       return exynos_v4l2_enum_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               fmt);
+}
+
+int exynos_v4l2_enum_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int fmt)
+{
+       return exynos_v4l2_enum_fmt(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               fmt);
+}
+
+int exynos_v4l2_enum_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id)
+{
+       struct v4l2_input input;
+       int rc;
+
+       if (exynos_camera == NULL || id < 0)
+               return -EINVAL;
+
+       input.index = id;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_ENUMINPUT, &input);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       if (input.name[0] == '\0')
+               return -1;
+
+       return 0;
+}
+
+int exynos_v4l2_s_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id)
+{
+       struct v4l2_input input;
+       int rc;
+
+       if (exynos_camera == NULL || id < 0)
+               return -EINVAL;
+
+       input.index = id;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_INPUT, &input);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_g_ext_ctrls(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_ext_control *control, int count)
+{
+       struct v4l2_ext_controls controls;
+       int rc;
+
+       if (exynos_camera == NULL || control == NULL)
+               return -EINVAL;
+
+       memset(&controls, 0, sizeof(controls));
+       controls.ctrl_class = V4L2_CTRL_CLASS_CAMERA;
+       controls.count = count;
+       controls.controls = control;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_G_EXT_CTRLS, &controls);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_s_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id, int value)
+{
+       struct v4l2_control control;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       control.id = id;
+       control.value = value;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_CTRL, &control);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return control.value;
+}
+
+int exynos_v4l2_s_parm(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int type, struct v4l2_streamparm *streamparm)
+{
+       int rc;
+
+       if (exynos_camera == NULL || streamparm == NULL)
+               return -EINVAL;
+
+       streamparm->type = type;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_PARM, streamparm);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_v4l2_s_parm_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_streamparm *streamparm)
+{
+       return exynos_v4l2_s_parm(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+               streamparm);
+}
+
+int exynos_v4l2_s_parm_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       struct v4l2_streamparm *streamparm)
+{
+       return exynos_v4l2_s_parm(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
+               streamparm);
+}