Initial copy from camera-hal-v4l2 52/270352/2 accepted/tizen/unified/20220224.125707 submit/tizen/20220224.052022
authorJeongmo Yang <jm80.yang@samsung.com>
Fri, 28 Jan 2022 11:59:03 +0000 (20:59 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Fri, 28 Jan 2022 12:04:29 +0000 (21:04 +0900)
[Version] 0.0.1
[Issue Type] Initial release

Change-Id: Ibef763c4b2e11f1e64737deadeaf2a8792983dbc
Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
AUTHORS [new file with mode: 0644]
LICENSE.APLv2 [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NOTICE [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
hal-backend-camera-v4l2.manifest [new file with mode: 0644]
packaging/hal-backend-camera-v4l2.spec [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/hal_backend_camera_v4l2.c [new file with mode: 0644]
src/hal_backend_camera_v4l2_private.h [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..7e88032
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Jeongmo Yang <jm80.yang@samsung.com>
diff --git a/LICENSE.APLv2 b/LICENSE.APLv2
new file mode 100644 (file)
index 0000000..6e529a2
--- /dev/null
@@ -0,0 +1,205 @@
+\r
+                                 Apache License\r
+                           Version 2.0, January 2004\r
+                        http://www.apache.org/licenses/\r
+\r
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+   1. Definitions.\r
+\r
+      "License" shall mean the terms and conditions for use, reproduction,\r
+      and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+      "Licensor" shall mean the copyright owner or entity authorized by\r
+      the copyright owner that is granting the License.\r
+\r
+      "Legal Entity" shall mean the union of the acting entity and all\r
+      other entities that control, are controlled by, or are under common\r
+      control with that entity. For the purposes of this definition,\r
+      "control" means (i) the power, direct or indirect, to cause the\r
+      direction or management of such entity, whether by contract or\r
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+      outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+      "You" (or "Your") shall mean an individual or Legal Entity\r
+      exercising permissions granted by this License.\r
+\r
+      "Source" form shall mean the preferred form for making modifications,\r
+      including but not limited to software source code, documentation\r
+      source, and configuration files.\r
+\r
+      "Object" form shall mean any form resulting from mechanical\r
+      transformation or translation of a Source form, including but\r
+      not limited to compiled object code, generated documentation,\r
+      and conversions to other media types.\r
+\r
+      "Work" shall mean the work of authorship, whether in Source or\r
+      Object form, made available under the License, as indicated by a\r
+      copyright notice that is included in or attached to the work\r
+      (an example is provided in the Appendix below).\r
+\r
+      "Derivative Works" shall mean any work, whether in Source or Object\r
+      form, that is based on (or derived from) the Work and for which the\r
+      editorial revisions, annotations, elaborations, or other modifications\r
+      represent, as a whole, an original work of authorship. For the purposes\r
+      of this License, Derivative Works shall not include works that remain\r
+      separable from, or merely link (or bind by name) to the interfaces of,\r
+      the Work and Derivative Works thereof.\r
+\r
+      "Contribution" shall mean any work of authorship, including\r
+      the original version of the Work and any modifications or additions\r
+      to that Work or Derivative Works thereof, that is intentionally\r
+      submitted to Licensor for inclusion in the Work by the copyright owner\r
+      or by an individual or Legal Entity authorized to submit on behalf of\r
+      the copyright owner. For the purposes of this definition, "submitted"\r
+      means any form of electronic, verbal, or written communication sent\r
+      to the Licensor or its representatives, including but not limited to\r
+      communication on electronic mailing lists, source code control systems,\r
+      and issue tracking systems that are managed by, or on behalf of, the\r
+      Licensor for the purpose of discussing and improving the Work, but\r
+      excluding communication that is conspicuously marked or otherwise\r
+      designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+      "Contributor" shall mean Licensor and any individual or Legal Entity\r
+      on behalf of whom a Contribution has been received by Licensor and\r
+      subsequently incorporated within the Work.\r
+\r
+   2. Grant of Copyright License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      copyright license to reproduce, prepare Derivative Works of,\r
+      publicly display, publicly perform, sublicense, and distribute the\r
+      Work and such Derivative Works in Source or Object form.\r
+\r
+   3. Grant of Patent License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      (except as stated in this section) patent license to make, have made,\r
+      use, offer to sell, sell, import, and otherwise transfer the Work,\r
+      where such license applies only to those patent claims licensable\r
+      by such Contributor that are necessarily infringed by their\r
+      Contribution(s) alone or by combination of their Contribution(s)\r
+      with the Work to which such Contribution(s) was submitted. If You\r
+      institute patent litigation against any entity (including a\r
+      cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+      or a Contribution incorporated within the Work constitutes direct\r
+      or contributory patent infringement, then any patent licenses\r
+      granted to You under this License for that Work shall terminate\r
+      as of the date such litigation is filed.\r
+\r
+   4. Redistribution. You may reproduce and distribute copies of the\r
+      Work or Derivative Works thereof in any medium, with or without\r
+      modifications, and in Source or Object form, provided that You\r
+      meet the following conditions:\r
+\r
+      (a) You must give any other recipients of the Work or\r
+          Derivative Works a copy of this License; and\r
+\r
+      (b) You must cause any modified files to carry prominent notices\r
+          stating that You changed the files; and\r
+\r
+      (c) You must retain, in the Source form of any Derivative Works\r
+          that You distribute, all copyright, patent, trademark, and\r
+          attribution notices from the Source form of the Work,\r
+          excluding those notices that do not pertain to any part of\r
+          the Derivative Works; and\r
+\r
+      (d) If the Work includes a "NOTICE" text file as part of its\r
+          distribution, then any Derivative Works that You distribute must\r
+          include a readable copy of the attribution notices contained\r
+          within such NOTICE file, excluding those notices that do not\r
+          pertain to any part of the Derivative Works, in at least one\r
+          of the following places: within a NOTICE text file distributed\r
+          as part of the Derivative Works; within the Source form or\r
+          documentation, if provided along with the Derivative Works; or,\r
+          within a display generated by the Derivative Works, if and\r
+          wherever such third-party notices normally appear. The contents\r
+          of the NOTICE file are for informational purposes only and\r
+          do not modify the License. You may add Your own attribution\r
+          notices within Derivative Works that You distribute, alongside\r
+          or as an addendum to the NOTICE text from the Work, provided\r
+          that such additional attribution notices cannot be construed\r
+          as modifying the License.\r
+\r
+      You may add Your own copyright statement to Your modifications and\r
+      may provide additional or different license terms and conditions\r
+      for use, reproduction, or distribution of Your modifications, or\r
+      for any such Derivative Works as a whole, provided Your use,\r
+      reproduction, and distribution of the Work otherwise complies with\r
+      the conditions stated in this License.\r
+\r
+   5. Submission of Contributions. Unless You explicitly state otherwise,\r
+      any Contribution intentionally submitted for inclusion in the Work\r
+      by You to the Licensor shall be under the terms and conditions of\r
+      this License, without any additional terms or conditions.\r
+      Notwithstanding the above, nothing herein shall supersede or modify\r
+      the terms of any separate license agreement you may have executed\r
+      with Licensor regarding such Contributions.\r
+\r
+   6. Trademarks. This License does not grant permission to use the trade\r
+      names, trademarks, service marks, or product names of the Licensor,\r
+      except as required for reasonable and customary use in describing the\r
+      origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+   7. Disclaimer of Warranty. Unless required by applicable law or\r
+      agreed to in writing, Licensor provides the Work (and each\r
+      Contributor provides its Contributions) on an "AS IS" BASIS,\r
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+      implied, including, without limitation, any warranties or conditions\r
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+      PARTICULAR PURPOSE. You are solely responsible for determining the\r
+      appropriateness of using or redistributing the Work and assume any\r
+      risks associated with Your exercise of permissions under this License.\r
+\r
+   8. Limitation of Liability. In no event and under no legal theory,\r
+      whether in tort (including negligence), contract, or otherwise,\r
+      unless required by applicable law (such as deliberate and grossly\r
+      negligent acts) or agreed to in writing, shall any Contributor be\r
+      liable to You for damages, including any direct, indirect, special,\r
+      incidental, or consequential damages of any character arising as a\r
+      result of this License or out of the use or inability to use the\r
+      Work (including but not limited to damages for loss of goodwill,\r
+      work stoppage, computer failure or malfunction, or any and all\r
+      other commercial damages or losses), even if such Contributor\r
+      has been advised of the possibility of such damages.\r
+\r
+   9. Accepting Warranty or Additional Liability. While redistributing\r
+      the Work or Derivative Works thereof, You may choose to offer,\r
+      and charge a fee for, acceptance of support, warranty, indemnity,\r
+      or other liability obligations and/or rights consistent with this\r
+      License. However, in accepting such obligations, You may act only\r
+      on Your own behalf and on Your sole responsibility, not on behalf\r
+      of any other Contributor, and only if You agree to indemnify,\r
+      defend, and hold each Contributor harmless for any liability\r
+      incurred by, or claims asserted against, such Contributor by reason\r
+      of your accepting any such warranty or additional liability.\r
+\r
+   END OF TERMS AND CONDITIONS\r
+\r
+   APPENDIX: How to apply the Apache License to your work.\r
+\r
+      To apply the Apache License to your work, attach the following\r
+      boilerplate notice, with the fields enclosed by brackets "[]"\r
+      replaced with your own identifying information. (Don't include\r
+      the brackets!)  The text should be enclosed in the appropriate\r
+      comment syntax for the file format. We also recommend that a\r
+      file or class name and description of purpose be included on the\r
+      same "printed page" as the copyright notice for easier\r
+      identification within third-party archives.\r
+\r
+   Copyright [yyyy] [name of copyright owner]\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+\r
+\r
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/NOTICE b/NOTICE
new file mode 100644 (file)
index 0000000..0e0f016
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,3 @@
+Copyright (c) Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the LICENSE.APLv2 file for Apache License terms and conditions.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..f5469d7
--- /dev/null
@@ -0,0 +1,7 @@
+#! /bin/sh
+
+libtoolize --copy --force
+aclocal
+autoheader
+autoconf
+automake -a -c
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..9bdd6e8
--- /dev/null
@@ -0,0 +1,80 @@
+AC_PREREQ(2.52)
+
+AC_INIT([hal-backend-camera-v4l2], [0.0.1])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+AC_CONFIG_HEADERS([config.h:config.hin])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+AC_PROG_CC
+AC_PROG_CXX
+AM_PROG_CC_C_O
+AC_C_CONST
+dnl AC_FUNC_MALLOC
+AC_FUNC_MMAP
+AC_FUNC_REALLOC
+AC_FUNC_SELECT_ARGTYPES
+AC_FUNC_STAT
+AC_FUNC_VPRINTF
+AC_HEADER_STDBOOL
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_PROG_GCC_TRADITIONAL
+AC_PROG_LIBTOOL
+
+PKG_CHECK_MODULES(GLIB, glib-2.0)
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+PKG_CHECK_MODULES(TBM, libtbm)
+AC_SUBST(TBM_CFLAGS)
+AC_SUBST(TBM_LIBS)
+
+PKG_CHECK_MODULES(DLOG, dlog)
+AC_SUBST(DLOG_CFLAGS)
+AC_SUBST(DLOG_LIBS)
+
+PKG_CHECK_MODULES(HAL_API_COMMON, hal-api-common)
+AC_SUBST(HAL_API_COMMON_CFLAGS)
+
+PKG_CHECK_MODULES(HAL_API_CAMERA, hal-api-camera)
+AC_SUBST(HAL_API_CAMERA_CFLAGS)
+
+AC_ARG_ENABLE(libv4l2, AC_HELP_STRING([--enable-libv4l2], [enable libv4l2]),
+[
+  case "${enableval}" in
+    yes) HAVE_LIBV4L2=yes ;;
+    no)  HAVE_LIBV4L2=no ;;
+    *) AC_MSG_ERROR(bad value ${enableval} for --enable-libv4l2) ;;
+  esac
+],[HAVE_LIBV4L2=no])
+if test "x$HAVE_LIBV4L2" = "xyes"; then
+PKG_CHECK_MODULES(LIBV4L2, libv4l2)
+AC_SUBST(LIBV4L2_CFLAGS)
+AC_SUBST(LIBV4L2_LIBS)
+fi
+AM_CONDITIONAL([HAVE_LIBV4L2], [test "x$HAVE_LIBV4L2" = "xyes"])
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([fcntl.h memory.h stdlib.h string.h sys/time.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+AC_FUNC_ALLOCA
+AC_FUNC_FORK
+AC_FUNC_MALLOC
+AC_FUNC_MEMCMP
+AC_FUNC_SELECT_ARGTYPES
+AC_TYPE_SIGNAL
+AC_CHECK_FUNCS([memset select])
+AC_CONFIG_FILES([
+Makefile
+src/Makefile
+])
+AC_OUTPUT
diff --git a/hal-backend-camera-v4l2.manifest b/hal-backend-camera-v4l2.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/packaging/hal-backend-camera-v4l2.spec b/packaging/hal-backend-camera-v4l2.spec
new file mode 100644 (file)
index 0000000..59f2bba
--- /dev/null
@@ -0,0 +1,55 @@
+%define enable_libv4l2 1
+
+Name:       hal-backend-camera-v4l2
+Summary:    Tizen Camera Hal using generic V4L2 interface
+Version:    0.0.1
+Release:    0
+Group:      Multimedia/Libraries
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(libtbm)
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(hal-api-common)
+BuildRequires:  pkgconfig(hal-api-camera)
+%if 0%{?enable_libv4l2}
+BuildRequires:  pkgconfig(libv4l2)
+%endif
+
+%description
+Tizen Camera Hal using generic V4L2 interface.
+
+
+%prep
+%setup -q
+
+
+%build
+./autogen.sh
+%configure \
+%if 0%{?enable_libv4l2}
+       --enable-libv4l2\
+%endif
+       --disable-static\
+       --libdir=%{_hal_libdir}
+make %{?jobs:-j%jobs}
+
+%install
+%make_install
+mkdir -p %{buildroot}%{_hal_licensedir}/%{name}
+cp LICENSE.APLv2 %{buildroot}%{_hal_licensedir}/%{name}
+
+
+%post
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest %{name}.manifest
+%{_hal_licensedir}/%{name}/*
+%defattr(-,root,root,-)
+%{_hal_libdir}/*.so
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..76ed725
--- /dev/null
@@ -0,0 +1,29 @@
+ACLOCAL_AMFLAGS='-I m4'
+
+lib_LTLIBRARIES = libhal-backend-camera.la
+
+noinst_HEADERS = hal_backend_camera_v4l2_private.h
+
+libhal_backend_camera_la_SOURCES = hal_backend_camera_v4l2.c
+
+libhal_backend_camera_la_CFLAGS = \
+       -I$(srcdir)/include \
+       $(GLIB_CFLAGS) \
+       $(DLOG_CFLAGS) \
+       $(HAL_API_COMMON_CFLAGS) \
+       $(HAL_API_CAMERA_CFLAGS) \
+       $(TBM_CFLAGS)
+
+libhal_backend_camera_la_LIBADD = \
+       $(GLIB_LIBS) \
+       $(DLOG_LIBS) \
+       $(TBM_LIBS)
+
+if HAVE_LIBV4L2
+libhal_backend_camera_la_CFLAGS += $(LIBV4L2_CFLAGS) -DHAVE_LIBV4L2
+libhal_backend_camera_la_LIBADD += $(LIBV4L2_LIBS)
+endif
+
+libhal_backend_camera_la_CFLAGS += -fdata-sections -ffunction-sections -Wl,--gc-sections
+libhal_backend_camera_la_LDFLAGS = -Wl,--gc-sections -avoid-version
+
diff --git a/src/hal_backend_camera_v4l2.c b/src/hal_backend_camera_v4l2.c
new file mode 100644 (file)
index 0000000..2d830ec
--- /dev/null
@@ -0,0 +1,2575 @@
+/*
+ * hal_backend_tizen_camera_v4l2.c
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <glob.h>
+#include <dlog.h>
+#include <sched.h>
+#include "hal_backend_camera_v4l2_private.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif /* LOG_TAG */
+#define LOG_TAG "CAMERA_HAL"
+
+#define TEST_JPEG_PATH          "/home/owner/media/Images/test.jpg"
+#define DEVICE_NODE_PATH_MAX    16
+#define DEVICE_NODE_PATH_PREFIX "/dev/video"
+#define FOURCC_FORMAT           "%c%c%c%c"
+#define FOURCC_CONVERT(fourcc)  \
+       fourcc & 0xff,\
+       (fourcc >> 8) & 0xff,\
+       (fourcc >> 16) & 0xff,\
+       (fourcc >> 24) & 0xff
+
+
+static camera_device_info_list_s *g_device_info_list;
+static guint32 g_device_caps;
+static GMutex g_device_info_lock;
+
+
+static void __camera_hal_v4l2_destructor(void) __attribute__((destructor));
+static void __camera_send_message(hal_camera_handle *handle, camera_message_type_e type, int value);
+
+
+static void __camera_hal_v4l2_destructor(void)
+{
+       LOGD("release device info list %p", g_device_info_list);
+
+       g_free(g_device_info_list);
+       g_device_info_list = NULL;
+
+       return;
+}
+
+
+static void __camera_send_message(hal_camera_handle *handle, camera_message_type_e type, int value)
+{
+       camera_message_s *message = NULL;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return;
+       }
+
+       message = g_new0(camera_message_s, 1);
+
+       message->type = type;
+
+       switch (type) {
+       case CAMERA_MESSAGE_TYPE_FOCUS_CHANGED:
+               message->focus_state = (camera_focus_state_e)value;
+               break;
+       case CAMERA_MESSAGE_TYPE_CAPTURED:
+               break;
+       case CAMERA_MESSAGE_TYPE_HDR_PROGRESS:
+               message->hdr_progress = (uint32_t)value;
+               break;
+       case CAMERA_MESSAGE_TYPE_ERROR:
+               message->error_code = (camera_error_e)value;
+               break;
+       default:
+               LOGE("unknown type[%d]", type);
+               g_free(message);
+               return;
+       }
+
+       g_mutex_lock(&handle->msg_cb_lock);
+
+       LOGD("type[%d], value[0x%x]", type, value);
+
+       g_queue_push_tail(handle->msg_list, message);
+       g_cond_signal(&handle->msg_cb_cond);
+
+       g_mutex_unlock(&handle->msg_cb_lock);
+}
+
+
+static int __camera_v4l2_wait_frame(int device_fd, int wait_time)
+{
+       int ret = CAMERA_ERROR_NONE;
+       fd_set fds;
+       struct timeval timeout;
+
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       FD_ZERO(&fds);
+       FD_SET(device_fd, &fds);
+
+       memset(&timeout, 0x0, sizeof(struct timeval));
+
+       timeout.tv_sec = wait_time;
+       timeout.tv_usec = 0;
+
+       /*LOGD("select : %d sec", wait_time);*/
+
+       ret = select(device_fd + 1, &fds, NULL, NULL, &timeout);
+       if (ret == -1) {
+               if (EINTR == errno) {
+                       LOGD("select error : EINTR");
+                       return CAMERA_ERROR_NONE;
+               }
+               LOGE("select failed. errno %d", errno);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       if (ret == 0) {
+               LOGE("select timeout.");
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       /*LOGD("select done");*/
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+static int __camera_v4l2_g_ctrl(int device_fd, int cid, int *value)
+{
+       int ret = 0;
+       struct v4l2_control ctrl;
+
+       if (!value) {
+               LOGE("NULL param");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&ctrl, 0x0, sizeof(struct v4l2_control));
+
+       ctrl.id = cid;
+
+       ret = v4l2_ioctl(device_fd, VIDIOC_G_CTRL, &ctrl);
+
+       *value = ctrl.value;
+
+       LOGD("G_CTRL id 0x%x, value %d, ret %d", cid, *value, ret);
+
+       return ret;
+}
+
+
+static int __camera_v4l2_s_ctrl(int device_fd, int cid, int value)
+{
+       int ret = 0;
+       struct v4l2_control ctrl;
+
+       memset(&ctrl, 0x0, sizeof(struct v4l2_control));
+
+       ctrl.id = cid;
+       ctrl.value = value;
+
+       ret = v4l2_ioctl(device_fd, VIDIOC_S_CTRL, &ctrl);
+
+       LOGD("S_CTRL id 0x%x, value %d, ret %d", cid, value, ret);
+
+       return ret;
+}
+
+
+static int __camera_v4l2_stream(int device_fd, int type, gboolean onoff)
+{
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (v4l2_ioctl(device_fd, onoff ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &type) < 0) {
+               LOGE("stream %d failed. [t:%d] errno %d", onoff, type, errno);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       LOGD("stream %d done [t:%d]", onoff, type);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+static int __camera_v4l2_reqbufs(int device_fd, int type, int memory, uint32_t count, uint32_t *result_count)
+{
+       struct v4l2_requestbuffers v4l2_reqbuf;
+
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!result_count) {
+               LOGE("NULL parameter");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&v4l2_reqbuf, 0x0, sizeof(struct v4l2_requestbuffers));
+
+       v4l2_reqbuf.type = type;
+       v4l2_reqbuf.memory = memory;
+       v4l2_reqbuf.count = count;
+
+       if (v4l2_ioctl(device_fd, VIDIOC_REQBUFS, &v4l2_reqbuf) < 0) {
+               LOGE("REQBUFS[count %d] failed. errno %d", count, errno);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       if (v4l2_reqbuf.count != count)
+               LOGW("different count [req:%d, result:%d]", count, v4l2_reqbuf.count);
+
+       *result_count = v4l2_reqbuf.count;
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+static int __camera_v4l2_qbuf(int device_fd, int type, int memory, int index)
+{
+       struct v4l2_buffer v4l2_buf;
+       struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
+
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+       memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
+
+       v4l2_buf.index = index;
+       v4l2_buf.type = type;
+       v4l2_buf.memory = memory;
+       v4l2_buf.m.planes = v4l2_planes;
+       v4l2_buf.length = 460800;
+       v4l2_buf.bytesused = 460800;
+
+       if (v4l2_ioctl(device_fd, VIDIOC_QBUF, &v4l2_buf) < 0) {
+               LOGE("qbuf failed.  [i: %d, t: %d, m: %d] errno %d",
+                       index, type, memory, errno);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       /*LOGD("QBUF done [i: %d, t: %d, m: %d]", index, type, memory);*/
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+static int __camera_v4l2_dqbuf(int device_fd, int type, int memory, int *index)
+{
+       int ret = CAMERA_ERROR_NONE;
+       struct v4l2_buffer v4l2_buf;
+       struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
+
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!index) {
+               LOGE("NULL parameter");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+       memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
+
+       v4l2_buf.type = type;
+       v4l2_buf.memory = memory;
+       v4l2_buf.m.planes = v4l2_planes;
+
+       ret = v4l2_ioctl(device_fd, VIDIOC_DQBUF, &v4l2_buf);
+       if (ret < 0) {
+               LOGE("dqbuf failed. [t: %d, m: %d] errno %d",
+                       type, memory, errno);
+               return CAMERA_ERROR_DEVICE_READ;
+       }
+
+       *index = v4l2_buf.index;
+
+       /*LOGD("dqbuf index %d", *index);*/
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+static int __camera_get_format(guint32 fourcc, int *pixel_format)
+{
+       if (!pixel_format) {
+               LOGE("NULL parameter");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       switch (fourcc) {
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV12M:
+       case V4L2_PIX_FMT_NV12MT:
+               *pixel_format = CAMERA_PIXEL_FORMAT_NV12;
+               break;
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV21M:
+               *pixel_format = CAMERA_PIXEL_FORMAT_NV21;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+               *pixel_format = CAMERA_PIXEL_FORMAT_I420;
+               break;
+       case V4L2_PIX_FMT_YVU420:
+               *pixel_format = CAMERA_PIXEL_FORMAT_YV12;
+               break;
+       case V4L2_PIX_FMT_YUYV:
+               *pixel_format = CAMERA_PIXEL_FORMAT_YUYV;
+               break;
+       case V4L2_PIX_FMT_UYVY:
+               *pixel_format = CAMERA_PIXEL_FORMAT_UYVY;
+               break;
+       case V4L2_PIX_FMT_JPEG:
+               *pixel_format = CAMERA_PIXEL_FORMAT_JPEG;
+               break;
+       case V4L2_PIX_FMT_H264:
+               *pixel_format = CAMERA_PIXEL_FORMAT_H264;
+               break;
+       case V4L2_PIX_FMT_MJPEG:
+               *pixel_format = CAMERA_PIXEL_FORMAT_MJPEG;
+               break;
+       default:
+               LOGE("unknown fourcc "FOURCC_FORMAT, FOURCC_CONVERT(fourcc));
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       LOGD("fourcc "FOURCC_FORMAT" -> %d",
+               FOURCC_CONVERT(fourcc), *pixel_format);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+static int __camera_get_fourcc_plane_num(int pixel_format, guint32 *fourcc, guint32 *plane_num)
+{
+       if (!fourcc || !plane_num) {
+               LOGE("NULL parameter %p %p", fourcc, plane_num);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       switch (pixel_format) {
+       case CAMERA_PIXEL_FORMAT_NV12:
+               *fourcc = V4L2_PIX_FMT_NV12;
+               *plane_num = 2;
+               break;
+       case CAMERA_PIXEL_FORMAT_NV21:
+               *fourcc = V4L2_PIX_FMT_NV21;
+               *plane_num = 2;
+               break;
+       case CAMERA_PIXEL_FORMAT_I420:
+               *fourcc = V4L2_PIX_FMT_YUV420;
+               *plane_num = 3;
+               break;
+       case CAMERA_PIXEL_FORMAT_YV12:
+               *fourcc = V4L2_PIX_FMT_YVU420;
+               *plane_num = 3;
+               break;
+       case CAMERA_PIXEL_FORMAT_YUYV:
+               *fourcc = V4L2_PIX_FMT_YUYV;
+               *plane_num = 1;
+               break;
+       case CAMERA_PIXEL_FORMAT_UYVY:
+               *fourcc = V4L2_PIX_FMT_UYVY;
+               *plane_num = 1;
+               break;
+       case CAMERA_PIXEL_FORMAT_JPEG:
+               *fourcc = V4L2_PIX_FMT_JPEG;
+               *plane_num = 1;
+               break;
+       case CAMERA_PIXEL_FORMAT_H264:
+               *fourcc = V4L2_PIX_FMT_H264;
+               *plane_num = 1;
+               break;
+       case CAMERA_PIXEL_FORMAT_MJPEG:
+               *fourcc = V4L2_PIX_FMT_MJPEG;
+               *plane_num = 1;
+               break;
+       default:
+               LOGE("unknown format %d", pixel_format);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       LOGD("format %d -> fourcc "FOURCC_FORMAT,
+               pixel_format, FOURCC_CONVERT(*fourcc));
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+static void __camera_get_fps_list(int device_fd, guint32 pixel_format, int width, int height, camera_fps_list_s *fps_list)
+{
+       uint32_t fps_count = 0;
+       struct v4l2_frmivalenum ival;
+
+       if (device_fd < 0 || !fps_list) {
+               LOGE("invalid param %d %p", device_fd, fps_list);
+               return;
+       }
+
+       ival.index = 0;
+       ival.pixel_format = pixel_format;
+       ival.width = width;
+       ival.height = height;
+
+       while (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0) {
+               if (ival.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
+                       LOGE("NOT DISCRETE type[%u] for [%dx%d]", ival.type, width, height);
+                       return;
+               }
+
+               if (ival.index++ >= FPS_COUNT_MAX) {
+                       LOGW("\t\t\t\tFramerate[i:%u][%u/%u] is available, but list is full[max:%d]",
+                               ival.index - 1, ival.discrete.denominator, ival.discrete.numerator, FPS_COUNT_MAX);
+                       continue;
+               }
+
+               LOGI("\t\t\t\tFramerate[%u/%u]", ival.discrete.denominator, ival.discrete.numerator);
+               fps_list->fps[fps_count++] = ival.discrete.denominator;
+       }
+
+
+       fps_list->count = fps_count;
+}
+
+
+static int __camera_get_device_info(int device_index, int device_fd, camera_device_info_s *device_info, char *node_path)
+{
+       int format_index = 0;
+       int format_count = 0;
+       int resolution_index = 0;
+       int resolution_count = 0;
+       int camera_format = 0;
+       struct v4l2_fmtdesc v4l2_format;
+       struct v4l2_frmsizeenum v4l2_frame;
+
+       if (device_fd < 0 || !device_info || !node_path) {
+               LOGE("invalid param %d %p %p", device_fd, device_info, node_path);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("Get Supported format, resolution and fps");
+
+       for (format_index = 0, format_count = 0 ; ; format_index++) {
+               memset(&v4l2_format, 0x0, sizeof(struct v4l2_fmtdesc));
+
+               v4l2_format.index = format_index;
+               v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+               if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FMT, &v4l2_format) < 0) {
+                       LOGW("\tformat : end of enumeration");
+                       break;
+               }
+
+               LOGD("\tTry [%d] format "FOURCC_FORMAT" (emulated:%d)",
+                       format_count, FOURCC_CONVERT(v4l2_format.pixelformat),
+                       ((v4l2_format.flags & V4L2_FMT_FLAG_EMULATED) ? 1 : 0));
+
+               if (__camera_get_format(v4l2_format.pixelformat, &camera_format) != CAMERA_ERROR_NONE)
+                       continue;
+
+               if (format_count + 1 >= CAMERA_PIXEL_FORMAT_MAX) {
+                       LOGW("format list is full[max:%u], skip format[i:%u][%d]",
+                               CAMERA_PIXEL_FORMAT_MAX, v4l2_format.index, camera_format);
+                       continue;
+               }
+
+               device_info->format_list.formats[format_count++] = camera_format;
+
+               for (resolution_index = 0, resolution_count = 0 ; ; resolution_index++) {
+                       memset(&v4l2_frame, 0x0, sizeof(struct v4l2_frmsizeenum));
+
+                       v4l2_frame.index = resolution_index;
+                       v4l2_frame.pixel_format = v4l2_format.pixelformat;
+
+                       if (v4l2_ioctl(device_fd, VIDIOC_ENUM_FRAMESIZES, &v4l2_frame) < 0) {
+                               LOGW("\t\tframesize : end of enumeration");
+                               break;
+                       }
+
+                       if (resolution_count + 1 >= RESOLUTION_COUNT_MAX) {
+                               LOGW("resolution list is full, skip resolution[%ux%u]", v4l2_frame.discrete.width, v4l2_frame.discrete.height);
+                               continue;
+                       }
+
+                       switch (v4l2_frame.type) {
+                       case V4L2_FRMSIZE_TYPE_DISCRETE:
+                               device_info->preview_list.resolutions[resolution_count].width = v4l2_frame.discrete.width;
+                               device_info->preview_list.resolutions[resolution_count].height = v4l2_frame.discrete.height;
+                               device_info->capture_list.resolutions[resolution_count].width = v4l2_frame.discrete.width;
+                               device_info->capture_list.resolutions[resolution_count].height = v4l2_frame.discrete.height;
+                               device_info->video_list.resolutions[resolution_count].width = v4l2_frame.discrete.width;
+                               device_info->video_list.resolutions[resolution_count].height = v4l2_frame.discrete.height;
+
+                               LOGD("\t\tsize[%d] %ux%u", resolution_count,
+                                       v4l2_frame.discrete.width,
+                                       v4l2_frame.discrete.height);
+
+                               __camera_get_fps_list(device_fd,
+                                       v4l2_frame.pixel_format,
+                                       v4l2_frame.discrete.width,
+                                       v4l2_frame.discrete.height,
+                                       &device_info->preview_fps_list[resolution_count]);
+
+                               memcpy(&device_info->video_fps_list[resolution_count], &device_info->preview_fps_list[resolution_count], sizeof(camera_fps_list_s));
+
+                               resolution_count++;
+                               break;
+                       case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+                               LOGW("\t\tsize[%d] %ux%u - %ux%u", resolution_count,
+                                       v4l2_frame.stepwise.min_width,
+                                       v4l2_frame.stepwise.min_height,
+                                       v4l2_frame.stepwise.max_width,
+                                       v4l2_frame.stepwise.max_height);
+                               break;
+                       case V4L2_FRMSIZE_TYPE_STEPWISE:
+                               LOGW("\t\tsize[%d] %ux%u - %ux%u (step %ux%u)", resolution_count,
+                                       v4l2_frame.stepwise.min_width,
+                                       v4l2_frame.stepwise.min_height,
+                                       v4l2_frame.stepwise.max_width,
+                                       v4l2_frame.stepwise.max_height,
+                                       v4l2_frame.stepwise.step_width,
+                                       v4l2_frame.stepwise.step_height);
+                               break;
+                       default:
+                               LOGE("\t\tunknown frame type %d", v4l2_frame.type);
+                               break;
+                       }
+               }
+
+               device_info->preview_list.count = resolution_count;
+               device_info->capture_list.count = resolution_count;
+               device_info->video_list.count = resolution_count;
+
+               LOGD("\t\tresolution count [%d]", resolution_count);
+       }
+
+       device_info->index = device_index;
+       device_info->format_list.count = format_count;
+       device_info->facing_direction = CAMERA_FACING_DIRECTION_EXTERNAL;
+       snprintf(device_info->name, sizeof(device_info->name), "V4L2_CAMERA");
+       snprintf(device_info->node_path, sizeof(device_info->node_path), "%s", node_path);
+
+       LOGD("\tformat count [%d]", format_count);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+static int __camera_get_device_info_list(void)
+{
+       int i = 0;
+       int ret = 0;
+       int device_count = 0;
+       int device_fd = CAMERA_HAL_INITIAL_FD;
+#ifdef HAVE_LIBV4L2
+       int libv4l2_fd = CAMERA_HAL_INITIAL_FD;
+#endif /* HAVE_LIBV4L2 */
+       glob_t glob_buf;
+       struct v4l2_capability v4l2_cap;
+       camera_device_info_list_s *device_info_list = NULL;
+
+       g_mutex_lock(&g_device_info_lock);
+
+       if (g_device_info_list) {
+               LOGD("device info list is already existed");
+               ret = CAMERA_ERROR_NONE;
+               goto _GET_DEVICE_INFO_LIST_DONE;
+       }
+
+       device_info_list = g_new0(camera_device_info_list_s, 1);
+       if (!device_info_list) {
+               LOGE("failed to alloc device info structure");
+               ret = CAMERA_ERROR_OUT_OF_MEMORY;
+               goto _GET_DEVICE_INFO_LIST_DONE;
+       }
+
+       memset(&glob_buf, 0x0, sizeof(glob_t));
+
+       ret = glob(DEVICE_NODE_PATH_PREFIX"*", 0, 0, &glob_buf);
+       if (ret != 0) {
+               switch (ret) {
+               case GLOB_NOSPACE:
+                       LOGE("out of memory");
+                       ret = CAMERA_ERROR_OUT_OF_MEMORY;
+                       goto _GET_DEVICE_INFO_LIST_DONE;
+               case GLOB_ABORTED:
+                       LOGE("read error");
+                       ret = CAMERA_ERROR_INTERNAL;
+                       goto _GET_DEVICE_INFO_LIST_DONE;
+               case GLOB_NOMATCH:
+                       LOGE("match not found");
+                       ret = CAMERA_ERROR_INTERNAL;
+                       goto _GET_DEVICE_INFO_LIST_DONE;
+               default:
+                       LOGE("unknown error : %d", ret);
+                       ret = CAMERA_ERROR_INTERNAL;
+                       goto _GET_DEVICE_INFO_LIST_DONE;
+               }
+       }
+
+       LOGD("device node count : %zu", glob_buf.gl_pathc);
+
+       for (i = 0 ; i < glob_buf.gl_pathc ; i++) {
+               LOGD("[%d] check device [%s]", i, glob_buf.gl_pathv[i]);
+
+               device_fd = open(glob_buf.gl_pathv[i], O_RDWR);
+               if (device_fd < 0) {
+                       LOGE("open failed [%s] errno %d", glob_buf.gl_pathv[i], errno);
+                       continue;
+               }
+
+#ifdef HAVE_LIBV4L2
+               libv4l2_fd = v4l2_fd_open(device_fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
+
+               LOGI("device_fd[%d], libv4l2_fd[%d]", device_fd, libv4l2_fd);
+
+               if (libv4l2_fd != CAMERA_HAL_INITIAL_FD)
+                       device_fd = libv4l2_fd;
+#endif /* HAVE_LIBV4L2 */
+
+               memset(&v4l2_cap, 0x0, sizeof(struct v4l2_capability));
+
+               if (v4l2_ioctl(device_fd, VIDIOC_QUERYCAP, &v4l2_cap) < 0) {
+                       LOGE("querycap failed. errno %d", errno);
+                       v4l2_close(device_fd);
+                       continue;
+               }
+
+               if (v4l2_cap.capabilities & V4L2_CAP_DEVICE_CAPS)
+                       g_device_caps = v4l2_cap.device_caps;
+               else
+                       g_device_caps = v4l2_cap.capabilities;
+
+               if (!(g_device_caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) ||
+                       (g_device_caps & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE))) {
+                       LOGW("[%s] is not a capture device 0x%x", glob_buf.gl_pathv[i], g_device_caps);
+                       v4l2_close(device_fd);
+                       continue;
+               }
+
+               ret = __camera_get_device_info(device_count, device_fd,
+                       &device_info_list->device_info[device_count], glob_buf.gl_pathv[i]);
+
+               v4l2_close(device_fd);
+
+               if (ret == CAMERA_ERROR_NONE)
+                       device_count++;
+       }
+
+       device_info_list->count = device_count;
+       g_device_info_list = device_info_list;
+
+       LOGD("new g_device_info_list %p - device count %d",
+               g_device_info_list, device_count);
+
+_GET_DEVICE_INFO_LIST_DONE:
+       g_mutex_unlock(&g_device_info_lock);
+       LOGD("ret 0x%x", ret);
+
+       if (ret != CAMERA_ERROR_NONE)
+               g_free(device_info_list);
+
+       return ret;
+}
+
+
+static int __camera_stop_stream(hal_camera_handle *handle, uint32_t buffer_count)
+{
+       int i = 0;
+       int ret = CAMERA_ERROR_NONE;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("buffer count[%d]", buffer_count);
+
+       /* stream off */
+       ret = __camera_v4l2_stream(handle->device_fd, handle->buffer_type, FALSE);
+
+       LOGD("stream off : 0x%x", ret);
+
+       /* munmap */
+       for (i = 0 ; i < buffer_count ; i++) {
+               if (handle->camera_buffers[i].planes[0].data != NULL) {
+                       LOGW("munmap %p", handle->camera_buffers[i].planes[0].data);
+
+                       v4l2_munmap(handle->camera_buffers[i].planes[0].data, handle->camera_buffers[i].planes[0].size);
+
+                       handle->camera_buffers[i].planes[0].data = 0;
+                       handle->camera_buffers[i].planes[0].size = 0;
+               } else {
+                       LOGW("NULL data [index %d]", i);
+               }
+       }
+
+       /* reqbufs 0 */
+       ret = __camera_v4l2_reqbufs(handle->device_fd,
+               handle->buffer_type, V4L2_MEMORY_MMAP, 0, &buffer_count);
+
+       LOGD("reqbufs 0 : 0x%x", ret);
+
+       return ret;
+}
+
+
+static int __camera_start_stream(hal_camera_handle *handle, camera_pixel_format_e pixel_format,
+       camera_resolution_s *resolution, uint32_t fps, uint32_t request_buffer_count)
+{
+       int i = 0;
+       int ret = CAMERA_ERROR_NONE;
+       camera_buffer_s *buffer = NULL;
+       struct v4l2_format v4l2_fmt;
+       struct v4l2_streamparm v4l2_parm;
+       struct v4l2_buffer v4l2_buf;
+       struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];;
+       guint32 fourcc = 0;
+       guint32 plane_num = 0;
+
+       if (!handle || !resolution) {
+               LOGE("NULL param %p %p", handle, resolution);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       /* S_FMT */
+       ret = __camera_get_fourcc_plane_num(pixel_format, &fourcc, &plane_num);
+       if (ret != CAMERA_ERROR_NONE) {
+               LOGE("get fourcc failed [format %d]", pixel_format);
+               return ret;
+       }
+
+       memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format));
+
+       v4l2_fmt.type = handle->buffer_type;
+       if (V4L2_TYPE_IS_MULTIPLANAR(handle->buffer_type)) {
+               v4l2_fmt.fmt.pix_mp.width = resolution->width;
+               v4l2_fmt.fmt.pix_mp.height = resolution->height;
+               v4l2_fmt.fmt.pix_mp.pixelformat = fourcc;
+               v4l2_fmt.fmt.pix_mp.num_planes = plane_num;
+       } else {
+               v4l2_fmt.fmt.pix.width = resolution->width;
+               v4l2_fmt.fmt.pix.height = resolution->height;
+               v4l2_fmt.fmt.pix.pixelformat = fourcc;
+               v4l2_fmt.fmt.pix.bytesperline = resolution->width;
+       }
+
+       if (v4l2_ioctl(handle->device_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) {
+               LOGE("S_FMT failed. errno %d", errno);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(handle->buffer_type)) {
+               for (i = 0 ; i < v4l2_fmt.fmt.pix_mp.num_planes ; i++) {
+                       LOGD("plane[%d] stride %u, sizeimage %u", i,
+                               v4l2_fmt.fmt.pix_mp.plane_fmt[i].bytesperline,
+                               v4l2_fmt.fmt.pix_mp.plane_fmt[i].sizeimage);
+               }
+       } else {
+               LOGD("stride %d, sizeimage %d",
+                       v4l2_fmt.fmt.pix.bytesperline,
+                       v4l2_fmt.fmt.pix.sizeimage);
+       }
+
+       /* G_PARM */
+       memset(&v4l2_parm, 0x0, sizeof(struct v4l2_streamparm));
+
+       v4l2_parm.type = handle->buffer_type;
+
+       if (v4l2_ioctl(handle->device_fd, VIDIOC_G_PARM, &v4l2_parm) < 0) {
+               LOGE("G_PARM failed. errno %d", errno);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       /* S_PARM to set fps */
+       v4l2_parm.parm.capture.timeperframe.numerator = 1;
+       v4l2_parm.parm.capture.timeperframe.denominator = fps;
+
+       if (v4l2_ioctl(handle->device_fd, VIDIOC_S_PARM, &v4l2_parm) < 0) {
+               LOGE("S_PARM failed. errno %d", errno);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       /* request buffer */
+       ret = __camera_v4l2_reqbufs(handle->device_fd,
+               handle->buffer_type, V4L2_MEMORY_MMAP, request_buffer_count, &handle->buffer_count);
+       if (ret != CAMERA_ERROR_NONE) {
+               return ret;
+       }
+
+       LOGD("buffer count : request %d -> result %d",
+               request_buffer_count, handle->buffer_count);
+
+       /* query buffer, mmap and qbuf */
+       for (i = 0 ; i < handle->buffer_count ; i++) {
+               memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+               memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
+
+               v4l2_buf.type = handle->buffer_type;
+               v4l2_buf.memory = V4L2_MEMORY_MMAP;
+               v4l2_buf.index = i;
+               v4l2_buf.m.planes = v4l2_planes;
+               v4l2_buf.length = plane_num;
+
+               if (v4l2_ioctl(handle->device_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) {
+                       LOGE("[%d] query buf failed. errno %d", i, errno);
+                       goto _START_STREAM_FAILED;
+               }
+
+               buffer = &handle->camera_buffers[i];
+
+               buffer->index = i;
+               buffer->format = pixel_format;
+               buffer->resolution.width = resolution->width;
+               buffer->resolution.height = resolution->height;
+               buffer->total_size = v4l2_buf.length;
+               buffer->num_planes = plane_num;
+               buffer->planes[0].size = v4l2_buf.length;
+               buffer->planes[0].data = v4l2_mmap(0,
+                       v4l2_buf.length,
+                       PROT_READ | PROT_WRITE,
+                       MAP_SHARED,
+                       handle->device_fd,
+                       v4l2_buf.m.offset);
+
+               if (buffer->planes[0].data == MAP_FAILED) {
+                       LOGE("[%d] mmap failed (errno %d)", i, errno);
+                       goto _START_STREAM_FAILED;
+               }
+
+               if (__camera_v4l2_qbuf(handle->device_fd, handle->buffer_type, V4L2_MEMORY_MMAP, i) != CAMERA_ERROR_NONE) {
+                       LOGE("[%d] qbuf failed (errno %d)", i, errno);
+                       goto _START_STREAM_FAILED;
+               }
+       }
+
+       /* stream on */
+       ret = __camera_v4l2_stream(handle->device_fd, handle->buffer_type, TRUE);
+       if (ret != CAMERA_ERROR_NONE) {
+               LOGE("stream on failed");
+               goto _START_STREAM_FAILED;
+       }
+
+       return CAMERA_ERROR_NONE;
+
+_START_STREAM_FAILED:
+       __camera_stop_stream(handle, handle->buffer_count);
+       return ret;
+}
+
+
+static void __camera_do_capture(hal_camera_handle *handle)
+{
+       int ret = CAMERA_ERROR_NONE;
+       int buffer_index = 0;
+       gint64 current_time = 0;
+       gint64 previous_time = 0;
+       gint64 interval_us = 0;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return;
+       }
+
+       LOGD("start");
+
+       if (handle->capture_count > 1)
+               interval_us = (gint64)handle->capture_interval_ms * 1000;
+
+       /* restart stream for capture */
+       if (handle->capture_restart_stream) {
+               ret = __camera_stop_stream(handle, handle->buffer_count);
+               if (ret != CAMERA_ERROR_NONE) {
+                       LOGE("stop stream failed for capture[0x%x]", ret);
+                       goto _CAPTURE_DONE;
+               }
+
+               ret = __camera_start_stream(handle,
+                       handle->preview_format.capture_format,
+                       &handle->preview_format.capture_resolution,
+                       handle->preview_format.stream_fps,
+                       BUFFER_MAX);
+               if (ret != CAMERA_ERROR_NONE) {
+                       LOGE("start stream failed for capture[0x%x]", ret);
+                       goto _CAPTURE_DONE;
+               }
+       }
+
+       do {
+               /* get capture buffer */
+               ret = __camera_v4l2_wait_frame(handle->device_fd, 5);
+               if (ret != CAMERA_ERROR_NONE) {
+                       LOGE("frame wait failed for capture[0x%x]", ret);
+                       goto _CAPTURE_DONE;
+               }
+
+               ret = __camera_v4l2_dqbuf(handle->device_fd,
+                       handle->buffer_type, V4L2_MEMORY_MMAP, &buffer_index);
+               if (ret != CAMERA_ERROR_NONE) {
+                       LOGE("dqbuf failed for capture[0x%x]", ret);
+                       goto _CAPTURE_DONE;
+               }
+
+               if (handle->captured_count > 0) {
+                       g_mutex_lock(&handle->buffer_lock);
+                       if (handle->state != CAMERA_STATE_CAPTURING) {
+                               LOGW("stop continuous capture");
+                               handle->captured_count = handle->capture_count;
+                               g_mutex_unlock(&handle->buffer_lock);
+                               goto _TRY_NEXT;
+                       }
+                       g_mutex_unlock(&handle->buffer_lock);
+               }
+
+               if (handle->capture_count > 1) {
+                       current_time = g_get_monotonic_time();
+
+                       LOGI("time[prev:%"PRId64", cur:%"PRId64"] interval[%"PRId64" us]",
+                               previous_time, current_time, interval_us);
+
+                       if (current_time < previous_time + interval_us)
+                               goto _TRY_NEXT;
+               }
+
+               g_mutex_lock(&handle->buffer_lock);
+               handle->captured_count++;
+               g_mutex_unlock(&handle->buffer_lock);
+
+               LOGD("capture cb[%p], buffer index[%d],count[%d]",
+                       handle->capture_cb, buffer_index, handle->captured_count);
+
+               if (handle->capture_cb) {
+                       handle->capture_cb(&handle->camera_buffers[buffer_index],
+                               NULL, NULL, handle->capture_cb_data);
+               } else {
+                       LOGW("capture callback is NULL");
+                       /* Need to post error? */
+               }
+
+               previous_time = current_time;
+
+_TRY_NEXT:
+               ret = __camera_v4l2_qbuf(handle->device_fd,
+                       handle->buffer_type, V4L2_MEMORY_MMAP, buffer_index);
+               if (ret != CAMERA_ERROR_NONE)
+                       LOGE("qbuf failed for capture[0x%x]", ret);
+       } while (handle->captured_count < handle->capture_count);
+
+       g_mutex_lock(&handle->buffer_lock);
+
+       if (handle->state == CAMERA_STATE_CAPTURING) {
+               LOGD("wait for capture stop signal");
+               g_cond_wait(&handle->buffer_cond, &handle->buffer_lock);
+               LOGD("signal received");
+       } else {
+               LOGD("The state is already changed.");
+       }
+
+       g_mutex_unlock(&handle->buffer_lock);
+
+_CAPTURE_DONE:
+       /* restart stream for preview */
+       if (handle->capture_restart_stream) {
+               ret = __camera_stop_stream(handle, handle->buffer_count);
+               if (ret != CAMERA_ERROR_NONE)
+                       LOGE("stop stream failed for preview[0x%x]", ret);
+
+               ret = __camera_start_stream(handle,
+                       handle->preview_format.stream_format,
+                       &handle->preview_format.stream_resolution,
+                       handle->preview_format.stream_fps,
+                       BUFFER_MAX);
+               if (ret != CAMERA_ERROR_NONE)
+                       LOGE("start stream failed for preview[0x%x]", ret);
+       }
+
+       LOGD("done");
+}
+
+
+static void *__camera_buffer_handler_func(gpointer data)
+{
+       int error = CAMERA_ERROR_NONE;
+       int index = 0;
+       hal_camera_handle *handle = (hal_camera_handle *)data;
+
+       if (!handle) {
+               LOGE("NULL handle for buffer handler");
+               return NULL;
+       }
+
+       LOGD("enter");
+
+       /* run buffer thread */
+       g_mutex_lock(&handle->buffer_lock);
+
+       while (handle->buffer_thread_run) {
+               g_mutex_unlock(&handle->buffer_lock);
+
+               if (__camera_v4l2_wait_frame(handle->device_fd, 5) != CAMERA_ERROR_NONE) {
+                       LOGE("frame wait failed");
+                       g_mutex_lock(&handle->buffer_lock);
+                       break;
+               }
+
+               g_mutex_lock(&handle->buffer_lock);
+
+               if (handle->buffer_thread_run == FALSE) {
+                       LOGW("stop buffer handler thread");
+                       break;
+               }
+
+               error = __camera_v4l2_dqbuf(handle->device_fd, handle->buffer_type, V4L2_MEMORY_MMAP, &index);
+               if (error != CAMERA_ERROR_NONE) {
+                       LOGE("dqbuf failed[0x%x]", error);
+                       break;
+               }
+
+               handle->buffer_dequeued_count++;
+
+               /*LOGD("dequeued buffer count %d", handle->buffer_dequeued_count);*/
+
+               g_mutex_unlock(&handle->buffer_lock);
+
+               if (handle->preview_cb) {
+                       handle->preview_cb(&handle->camera_buffers[index], NULL, handle->preview_cb_data);
+               } else {
+                       LOGW("preview callback is NULL");
+                       camera_v4l2_release_preview_buffer((void *)handle, index);
+               }
+
+               g_mutex_lock(&handle->extra_preview_lock);
+
+               if (handle->extra_preview_cb) {
+                       handle->extra_preview_cb(&handle->camera_buffers[index], NULL, 0, handle->extra_preview_cb_data);
+                       handle->extra_preview_cb(&handle->camera_buffers[index], NULL, 1, handle->extra_preview_cb_data);
+                       handle->extra_preview_cb(&handle->camera_buffers[index], NULL, 2, handle->extra_preview_cb_data);
+                       handle->extra_preview_cb(&handle->camera_buffers[index], NULL, 3, handle->extra_preview_cb_data);
+               }
+
+               g_mutex_unlock(&handle->extra_preview_lock);
+
+               /* check capture request flag */
+               if (handle->capture_request) {
+                       __camera_do_capture(handle);
+                       handle->capture_request = FALSE;
+               }
+
+               sched_yield();
+
+               g_mutex_lock(&handle->buffer_lock);
+       }
+
+       g_mutex_unlock(&handle->buffer_lock);
+
+       if (error != CAMERA_ERROR_NONE)
+               __camera_send_message(handle, CAMERA_MESSAGE_TYPE_ERROR, error);
+
+       LOGD("leave");
+
+       return NULL;
+}
+
+
+static void __camera_message_release_func(gpointer data)
+{
+       camera_message_s *message = (camera_message_s *)data;
+
+       if (!message) {
+               LOGW("NULL message");
+               return;
+       }
+
+       LOGD("release message %p, type %d", message, message->type);
+
+       g_free(message);
+
+       return;
+}
+
+
+static void *_camera_message_handler_func(gpointer data)
+{
+       int i = 0;
+       camera_message_s *message = NULL;
+       hal_camera_handle *handle = (hal_camera_handle *)data;
+
+       if (!handle) {
+               LOGE("NULL handle for capture thread");
+               return NULL;
+       }
+
+       LOGD("enter - message thread");
+
+       g_mutex_lock(&handle->msg_cb_lock);
+
+       while (handle->msg_cb_run) {
+               if (g_queue_is_empty(handle->msg_list)) {
+                       LOGD("wait for message");
+                       g_cond_wait(&handle->msg_cb_cond, &handle->msg_cb_lock);
+                       LOGD("message signal received");
+               }
+
+               if (!handle->msg_cb_run) {
+                       LOGW("break message thread");
+                       break;
+               }
+
+               message = g_queue_pop_head(handle->msg_list);
+               if (!message) {
+                       LOGW("NULL message");
+                       continue;
+               }
+
+               g_mutex_unlock(&handle->msg_cb_lock);
+
+               for (i = 0 ; i < MESSAGE_CALLBACK_MAX ; i++) {
+                       if (handle->msg_cb[i]) {
+                               LOGD("call message callback[%d] type[%d]", i, message->type);
+                               handle->msg_cb[i](message, handle->msg_cb_data[i]);
+                       }
+               }
+
+               g_free(message);
+               message = NULL;
+
+               g_mutex_lock(&handle->msg_cb_lock);
+       }
+
+       g_mutex_unlock(&handle->msg_cb_lock);
+
+       LOGD("leave - message thread");
+
+       return NULL;
+}
+
+
+static void __camera_release_handle(hal_camera_handle *handle)
+{
+       if (!handle) {
+               LOGW("NULL handle");
+               return;
+       }
+
+       if (handle->msg_thread) {
+               g_mutex_lock(&handle->msg_cb_lock);
+               handle->msg_cb_run = FALSE;
+               g_cond_signal(&handle->msg_cb_cond);
+               g_mutex_unlock(&handle->msg_cb_lock);
+               g_thread_join(handle->msg_thread);
+               g_queue_free_full(handle->msg_list, (GDestroyNotify)__camera_message_release_func);
+               handle->msg_list = NULL;
+       }
+
+       g_mutex_clear(&handle->lock);
+       g_mutex_clear(&handle->buffer_lock);
+       g_mutex_clear(&handle->msg_cb_lock);
+       g_mutex_clear(&handle->extra_preview_lock);
+       g_cond_clear(&handle->buffer_cond);
+       g_cond_clear(&handle->msg_cb_cond);
+
+       if (handle->bufmgr) {
+               tbm_bufmgr_deinit(handle->bufmgr);
+               handle->bufmgr = NULL;
+       }
+
+       LOGD("camera HAL handle %p destroy", handle);
+
+       g_free(handle);
+
+       return;
+}
+
+
+int camera_v4l2_init(void **camera_handle)
+{
+       int ret = CAMERA_ERROR_NONE;
+       hal_camera_handle *new_handle = NULL;
+       tbm_bufmgr bufmgr = NULL;
+
+       LOGD("enter");
+
+       if (!camera_handle) {
+               LOGE("NULL pointer for handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       bufmgr = tbm_bufmgr_init(-1);
+       if (bufmgr == NULL) {
+               LOGE("get tbm bufmgr failed");
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       new_handle = g_new0(hal_camera_handle, 1);
+       if (!new_handle) {
+               LOGE("failed to alloc camera hal handle");
+               tbm_bufmgr_deinit(bufmgr);
+               return CAMERA_ERROR_OUT_OF_MEMORY;
+       }
+
+       new_handle->bufmgr = bufmgr;
+
+       g_mutex_init(&new_handle->lock);
+       g_mutex_init(&new_handle->buffer_lock);
+       g_mutex_init(&new_handle->msg_cb_lock);
+       g_mutex_init(&new_handle->extra_preview_lock);
+       g_cond_init(&new_handle->buffer_cond);
+       g_cond_init(&new_handle->msg_cb_cond);
+
+       /* message thread */
+       new_handle->msg_list = g_queue_new();
+       new_handle->msg_cb_run = TRUE;
+       new_handle->msg_thread = g_thread_try_new("camera_hal_msg_thread",
+               _camera_message_handler_func, (gpointer)new_handle, NULL);
+       if (!new_handle->msg_thread) {
+               LOGE("failed to create message thread");
+               ret = CAMERA_ERROR_INTERNAL;
+               goto _INIT_ERROR;
+       }
+
+       new_handle->device_index = CAMERA_HAL_INITIAL_INDEX;
+       new_handle->device_fd = CAMERA_HAL_INITIAL_FD;
+       new_handle->state = CAMERA_STATE_INITIALIZED;
+
+       ret = __camera_get_device_info_list();
+       if (ret != CAMERA_ERROR_NONE) {
+               LOGE("get device info failed");
+               goto _INIT_ERROR;
+       }
+
+#ifdef HAVE_LIBV4L2
+       LOGI("libv4l2 ENABLED");
+#else /* HAVE_LIBV4L2 */
+       LOGI("libv4l2 DISABLED");
+#endif /* HAVE_LIBV4L2 */
+
+       *camera_handle = new_handle;
+
+       LOGD("camera HAL handle %p", new_handle);
+
+       return CAMERA_ERROR_NONE;
+
+_INIT_ERROR:
+       __camera_release_handle(new_handle);
+
+       return ret;
+}
+
+
+int camera_v4l2_deinit(void *camera_handle)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->state != CAMERA_STATE_INITIALIZED) {
+               LOGE("invalid state %d, can not destroy handle", handle->state);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INVALID_STATE;
+       }
+
+       g_mutex_unlock(&handle->lock);
+
+       __camera_release_handle(handle);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_get_device_info_list(camera_device_info_list_s *device_info_list)
+{
+       int ret = 0;
+
+       if (!device_info_list) {
+               LOGE("NULL pointer for device_info_list");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       ret = __camera_get_device_info_list();
+       if (ret != CAMERA_ERROR_NONE) {
+               LOGE("get device info failed");
+               return ret;
+       }
+
+       memcpy(device_info_list, g_device_info_list, sizeof(camera_device_info_list_s));
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_open_device(void *camera_handle, int device_index)
+{
+       int ret = CAMERA_ERROR_NONE;
+       int device_fd = CAMERA_HAL_INITIAL_FD;
+#ifdef HAVE_LIBV4L2
+       int libv4l2_fd = CAMERA_HAL_INITIAL_FD;
+#endif /* HAVE_LIBV4L2 */
+       char *node_path = NULL;
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->state != CAMERA_STATE_INITIALIZED) {
+               LOGE("invalid state %d", handle->state);
+               ret = CAMERA_ERROR_INVALID_STATE;
+               goto _OPEN_DEVICE_DONE;
+       }
+
+       if (!g_device_info_list) {
+               LOGE("NO DEVICE INFO");
+               ret = CAMERA_ERROR_INTERNAL;
+               goto _OPEN_DEVICE_DONE;
+       }
+
+       if (device_index >= g_device_info_list->count) {
+               LOGE("invalid index %d [info:%d]", device_index, g_device_info_list->count);
+               ret = CAMERA_ERROR_INVALID_PARAMETER;
+               goto _OPEN_DEVICE_DONE;
+       }
+
+       node_path = g_device_info_list->device_info[device_index].node_path;
+
+       device_fd = open(node_path, O_RDWR);
+       if (device_fd < 0) {
+               switch (errno) {
+                       case EACCES:
+                       case EPERM:
+                               ret = CAMERA_ERROR_PERMISSION_DENIED;
+                               break;
+                       case ENOENT:
+                               ret = CAMERA_ERROR_DEVICE_NOT_FOUND;
+                               break;
+                       case EBUSY:
+                               ret = CAMERA_ERROR_DEVICE_BUSY;
+                               break;
+                       default:
+                               ret = CAMERA_ERROR_DEVICE_OPEN;
+                               break;
+               }
+
+               LOGE("open [%s] failed 0x%x [errno %d]",
+                       node_path, ret, errno);
+
+               goto _OPEN_DEVICE_DONE;
+       }
+
+       if (g_device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
+               handle->buffer_type = V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+       else
+               handle->buffer_type = V4L2_CAP_VIDEO_CAPTURE;
+
+#ifdef HAVE_LIBV4L2
+       libv4l2_fd = v4l2_fd_open(device_fd, V4L2_ENABLE_ENUM_FMT_EMULATION);
+
+       LOGI("device_fd[%d], libv4l2_fd[%d]", device_fd, libv4l2_fd);
+
+       if (libv4l2_fd != CAMERA_HAL_INITIAL_FD)
+               device_fd = libv4l2_fd;
+#endif /* HAVE_LIBV4L2 */
+
+       handle->state = CAMERA_STATE_OPENED;
+       handle->device_index = device_index;
+       handle->device_fd = device_fd;
+
+       LOGD("[%d] device[%s] opened [fd %d, type %d]",
+               device_index, node_path, device_fd, handle->buffer_type);
+
+_OPEN_DEVICE_DONE:
+       g_mutex_unlock(&handle->lock);
+
+       return ret;
+}
+
+
+int camera_v4l2_open_device_ext(void *camera_handle, const char *device_name)
+{
+       LOGE("NOT SUPPORTED");
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_v4l2_close_device(void *camera_handle)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->state != CAMERA_STATE_OPENED) {
+               LOGE("invalid state %d", handle->state);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INVALID_STATE;
+       }
+
+       if (handle->device_fd >= 0) {
+               LOGD("close fd %d", handle->device_fd);
+
+               v4l2_close(handle->device_fd);
+               handle->device_fd = CAMERA_HAL_INITIAL_FD;
+       } else {
+               LOGW("invalid fd %d", handle->device_fd);
+       }
+
+       handle->state = CAMERA_STATE_INITIALIZED;
+
+       LOGD("device [%d] closed", handle->device_index);
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_add_message_callback(void *camera_handle, hal_camera_message_cb callback, void *user_data, uint32_t *cb_id)
+{
+       uint32_t i = 0;
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!callback || !cb_id) {
+               LOGE("NULL pointer for callback %p or cb_id %p", callback, cb_id);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       for (i = 0 ; i < MESSAGE_CALLBACK_MAX ; i++) {
+               if (handle->msg_cb[i] == NULL) {
+                       handle->msg_cb[i] = callback;
+                       handle->msg_cb_data[i] = user_data;
+                       *cb_id = i;
+                       LOGD("message cb [%p] added, user data %p - id %u", callback, user_data, i);
+                       g_mutex_unlock(&handle->lock);
+                       return CAMERA_ERROR_NONE;
+               }
+       }
+
+       g_mutex_unlock(&handle->lock);
+
+       LOGE("no available message cb slot");
+
+       return CAMERA_ERROR_INTERNAL;
+}
+
+
+int camera_v4l2_remove_message_callback(void *camera_handle, uint32_t cb_id)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (cb_id >= MESSAGE_CALLBACK_MAX) {
+               LOGE("invalid cb_id %u", cb_id);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->msg_cb[cb_id]) {
+               LOGD("remove message callback %p, user data %p - cb_id %u",
+                       handle->msg_cb[cb_id], handle->msg_cb_data[cb_id], cb_id);
+
+               handle->msg_cb[cb_id] = NULL;
+               handle->msg_cb_data[cb_id] = NULL;
+       } else {
+               LOGE("already removed message cb");
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_set_preview_stream_format(void *camera_handle, camera_format_s *format)
+{
+       int i = 0;
+       int j = 0;
+       int ret = CAMERA_ERROR_NONE;
+       gboolean capability_check = FALSE;
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+       camera_device_info_s *device_info = NULL;
+
+       if (!handle || !format) {
+               LOGE("NULL param %p %p", handle, format);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!g_device_info_list) {
+               LOGE("no device info list");
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->state != CAMERA_STATE_OPENED &&
+               handle->state != CAMERA_STATE_PREVIEWING) {
+               LOGE("invalid state %d", handle->state);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INVALID_STATE;
+       }
+
+       /* check capability */
+       device_info = &g_device_info_list->device_info[handle->device_index];
+
+       /* format */
+       for (i = 0 ; i < device_info->format_list.count ; i++) {
+               if (format->stream_format == device_info->format_list.formats[i]) {
+                       LOGD("format matched %d, check resolution.", format->stream_format);
+
+                       /* resolution */
+                       for (j = 0 ; j < device_info->preview_list.count ; j++) {
+                               if (format->stream_resolution.width == device_info->preview_list.resolutions[j].width &&
+                                       format->stream_resolution.height == device_info->preview_list.resolutions[j].height) {
+                                       LOGD("resolution matched %dx%d",
+                                               format->stream_resolution.width,
+                                               format->stream_resolution.height);
+                                       capability_check = TRUE;
+                                       break;
+                               }
+                       }
+
+                       break;
+               }
+       }
+
+       if (!capability_check) {
+               LOGE("capability failed - %d, %dx%d",
+                       format->stream_format,
+                       format->stream_resolution.width,
+                       format->stream_resolution.height);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       /* compare with current settings */
+       if (handle->state == CAMERA_STATE_PREVIEWING) {
+               if (handle->preview_format.stream_format == format->stream_format &&
+                       handle->preview_format.stream_resolution.width == format->stream_resolution.width &&
+                       handle->preview_format.stream_resolution.height == format->stream_resolution.height &&
+                       handle->preview_format.stream_fps == format->stream_fps &&
+                       handle->preview_format.stream_rotation == format->stream_rotation) {
+                       LOGD("no need to restart preview stream");
+                       goto _SET_PREVIEW_STREAM_FORMAT_DONE;
+               }
+
+               LOGD("Preview setting is changed. Restart preview now.");
+
+               /* stop preview stream to change it */
+               ret = __camera_stop_stream(handle, handle->buffer_count);
+               if (ret != CAMERA_ERROR_NONE) {
+                       LOGE("failed to stop stream");
+                       g_mutex_unlock(&handle->lock);
+                       return ret;
+               }
+
+               /* restart preview stream to change it */
+               ret = __camera_start_stream(handle,
+                       format->stream_format,
+                       &format->stream_resolution,
+                       format->stream_fps,
+                       BUFFER_MAX);
+               if (ret != CAMERA_ERROR_NONE) {
+                       LOGE("failed to start stream");
+                       g_mutex_unlock(&handle->lock);
+                       return ret;
+               }
+       }
+
+_SET_PREVIEW_STREAM_FORMAT_DONE:
+       /* set capture restart flag */
+       if (format->stream_format == format->capture_format &&
+               format->stream_resolution.width == format->capture_resolution.width &&
+               format->stream_resolution.height == format->capture_resolution.height)
+               handle->capture_restart_stream = FALSE;
+       else
+               handle->capture_restart_stream = TRUE;
+
+       memcpy(&handle->preview_format, format, sizeof(camera_format_s));
+
+       LOGD("set format PREVIEW[%d:%dx%d,fps:%d], CAPTURE[%d:%dx%d,restart:%d]",
+               format->stream_format,
+               format->stream_resolution.width,
+               format->stream_resolution.height,
+               format->stream_fps,
+               format->capture_format,
+               format->capture_resolution.width,
+               format->capture_resolution.height,
+               handle->capture_restart_stream);
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_get_preview_stream_format(void *camera_handle, camera_format_s *format)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle || !format) {
+               LOGE("NULL param %p %p", handle, format);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       memcpy(format, &handle->preview_format, sizeof(camera_format_s));
+
+       LOGD("get stream format %d, %dx%d", format->stream_format,
+               format->stream_resolution.width, format->stream_resolution.height);
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_set_user_buffer_fd(void *camera_handle, int *fds, int number)
+{
+       LOGE("NOT SUPPORTED");
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_v4l2_start_preview(void *camera_handle, hal_camera_preview_frame_cb callback, void *user_data)
+{
+       int ret = 0;
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle || !callback) {
+               LOGE("NULL param %p %p", handle, callback);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->state != CAMERA_STATE_OPENED) {
+               LOGE("invalid state %d", handle->state);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INVALID_STATE;
+       }
+
+       ret = __camera_start_stream(handle,
+               handle->preview_format.stream_format,
+               &handle->preview_format.stream_resolution,
+               handle->preview_format.stream_fps,
+               BUFFER_MAX);
+       if (ret != CAMERA_ERROR_NONE) {
+               LOGE("__camera_start_stream failed[0x%x]", ret);
+               g_mutex_unlock(&handle->lock);
+               return ret;
+       }
+
+       g_mutex_lock(&handle->buffer_lock);
+
+       handle->buffer_thread_run = TRUE;
+
+       handle->buffer_thread = g_thread_try_new("camera_hal_buffer_thread",
+               __camera_buffer_handler_func, (gpointer)handle, NULL);
+       if (!handle->buffer_thread) {
+               LOGE("failed to create buffer handler thread");
+               g_mutex_unlock(&handle->buffer_lock);
+
+               __camera_stop_stream(handle, handle->buffer_count);
+
+               g_mutex_unlock(&handle->lock);
+
+               return ret;
+       }
+
+       handle->preview_cb = callback;
+       handle->preview_cb_data = user_data;
+
+       g_mutex_unlock(&handle->buffer_lock);
+
+       handle->state = CAMERA_STATE_PREVIEWING;
+
+       LOGD("start preview done");
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_release_preview_buffer(void *camera_handle, int buffer_index)
+{
+       int ret = CAMERA_ERROR_NONE;
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (buffer_index >= handle->buffer_count) {
+               LOGE("invalid buffer index %d", buffer_index);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       ret = __camera_v4l2_qbuf(handle->device_fd,
+               handle->buffer_type, V4L2_MEMORY_MMAP, buffer_index);
+
+       g_mutex_lock(&handle->buffer_lock);
+
+       if (ret == CAMERA_ERROR_NONE) {
+               if (handle->buffer_dequeued_count > 0)
+                       handle->buffer_dequeued_count--;
+               else
+                       LOGW("invalid dequeued buffer count[%u]", handle->buffer_dequeued_count);
+
+               /*LOGD("qbud done : index %d, dequeued buffer count %d",
+                       buffer_index, handle->buffer_dequeued_count);*/
+       } else {
+               LOGE("qbuf failed [index %d]", buffer_index);
+       }
+
+       g_cond_signal(&handle->buffer_cond);
+
+       g_mutex_unlock(&handle->buffer_lock);
+
+       return ret;
+}
+
+
+int camera_v4l2_stop_preview(void *camera_handle)
+{
+       int ret = CAMERA_ERROR_NONE;
+       gint64 end_time;
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("start");
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->state != CAMERA_STATE_PREVIEWING) {
+               LOGE("invalid state %d", handle->state);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INVALID_STATE;
+       }
+
+       g_mutex_lock(&handle->buffer_lock);
+
+       handle->buffer_thread_run = FALSE;
+
+       while (handle->buffer_dequeued_count > 0) {
+               LOGD("wait for dequeued buffer [%d]", handle->buffer_dequeued_count);
+               end_time = g_get_monotonic_time() + 3 * G_TIME_SPAN_SECOND;
+               if (!g_cond_wait_until(&handle->buffer_cond, &handle->buffer_lock, end_time)) {
+                       LOGE("buffer wait failed");
+                       break;
+               } else {
+                       LOGD("signal received. check again...");
+               }
+       }
+
+       g_mutex_unlock(&handle->buffer_lock);
+
+       ret = __camera_stop_stream(handle, handle->buffer_count);
+
+       /* wait for preview thread exit */
+       g_thread_join(handle->buffer_thread);
+       handle->buffer_thread = NULL;
+
+       handle->state = CAMERA_STATE_OPENED;
+
+       LOGD("stop preview done [0x%x]", ret);
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_start_auto_focus(void *camera_handle)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGE("NOT SUPPORTED");
+
+       /* auto focus is not supported */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_v4l2_stop_auto_focus(void *camera_handle)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGE("NOT SUPPORTED");
+
+       /* auto focus is not supported */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_v4l2_start_capture(void *camera_handle, hal_camera_capture_cb callback, void *user_data)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle || !callback) {
+               LOGE("NULL param %p %p", camera_handle, callback);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->state != CAMERA_STATE_PREVIEWING) {
+               LOGE("invalid state %d", handle->state);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INVALID_STATE;
+       }
+
+       /* set callback and user data */
+       handle->capture_cb = callback;
+       handle->capture_cb_data = user_data;
+
+       /* reset captured count */
+       handle->captured_count = 0;
+
+       LOGD("start capture - count %u", handle->capture_count);
+
+       /* set capture request flag */
+       handle->capture_request = TRUE;
+
+       handle->state = CAMERA_STATE_CAPTURING;
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_stop_capture(void *camera_handle)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->state != CAMERA_STATE_CAPTURING) {
+               LOGE("invalid state %d", handle->state);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INVALID_STATE;
+       }
+
+       g_mutex_lock(&handle->buffer_lock);
+
+       if (handle->captured_count == 0) {
+               LOGE("No captured image yet.");
+               g_mutex_unlock(&handle->buffer_lock);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       LOGD("send signal to start preview after capture");
+
+       g_cond_signal(&handle->buffer_cond);
+       g_mutex_unlock(&handle->buffer_lock);
+
+       handle->state = CAMERA_STATE_PREVIEWING;
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_set_video_stream_format(void *camera_handle, camera_format_s *format)
+{
+       if (!camera_handle || !format) {
+               LOGE("NULL param %p %p", camera_handle, format);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGE("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_v4l2_get_video_stream_format(void *camera_handle, camera_format_s *format)
+{
+       if (!camera_handle || !format) {
+               LOGE("NULL param %p %p", camera_handle, format);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGE("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_v4l2_start_record(void *camera_handle, hal_camera_video_frame_cb callback, void *user_data)
+{
+       if (!camera_handle || !callback) {
+               LOGE("NULL param %p %p", camera_handle, callback);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGE("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_v4l2_release_video_buffer(void *camera_handle, int buffer_index)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGE("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_v4l2_stop_record(void *camera_handle)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGE("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_v4l2_set_extra_preview_frame_cb(void *camera_handle, hal_camera_extra_preview_frame_cb callback, void *user_data)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->extra_preview_lock);
+
+       handle->extra_preview_cb = callback;
+       handle->extra_preview_cb_data = user_data;
+
+       g_mutex_unlock(&handle->extra_preview_lock);
+
+       LOGI("done");
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_unset_extra_preview_frame_cb(void *camera_handle)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->extra_preview_lock);
+
+       handle->extra_preview_cb = NULL;
+       handle->extra_preview_cb_data = NULL;
+
+       g_mutex_unlock(&handle->extra_preview_lock);
+
+       LOGI("done");
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_release_extra_preview_buffer(void *camera_handle, int stream_id, int buffer_index)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGI("done - stream_id[%d], index[%d]", stream_id, buffer_index);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_set_extra_preview_stream_format(void *camera_handle, int stream_id, camera_format_s *format)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (stream_id < 0 || stream_id >= EXTRA_PREVIEW_STREAM_MAX) {
+               LOGE("invalid stream_id[%d]", stream_id);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGI("stream_id[%d], [%d,%dx%d,%d]",
+               stream_id, format->stream_format,
+               format->stream_resolution.width, format->stream_resolution.height,
+               format->stream_fps);
+
+       memcpy(&handle->extra_preview_format[stream_id], format, sizeof(camera_format_s));
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_get_extra_preview_stream_format(void *camera_handle, int stream_id, camera_format_s *format)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle || !format) {
+               LOGE("NULL param[%p,%p]", handle, format);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (stream_id < 0 || stream_id >= EXTRA_PREVIEW_STREAM_MAX) {
+               LOGE("invalid stream_id[%d]", stream_id);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       memcpy(format, &handle->extra_preview_format[stream_id], sizeof(camera_format_s));
+
+       LOGI("stream_id[%d], [%d,%dx%d,%d]",
+               stream_id, format->stream_format,
+               format->stream_resolution.width, format->stream_resolution.height,
+               format->stream_fps);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_set_extra_preview_bitrate(void *camera_handle, int stream_id, int bitrate)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (stream_id < 0 || stream_id >= EXTRA_PREVIEW_STREAM_MAX) {
+               LOGE("invalid stream_id[%d]", stream_id);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGI("set bitrate[%d] for stream_id[%d]", bitrate, stream_id);
+
+       handle->extra_preview_format[stream_id].stream_bitrate = (uint32_t)bitrate;
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_get_extra_preview_bitrate(void *camera_handle, int stream_id, int *bitrate)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle || !bitrate) {
+               LOGE("NULL param[%p,%p]", handle, bitrate);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (stream_id < 0 || stream_id >= EXTRA_PREVIEW_STREAM_MAX) {
+               LOGE("invalid stream_id[%d]", stream_id);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       *bitrate = (int)handle->extra_preview_format[stream_id].stream_bitrate;
+
+       LOGI("get bitrate[%d] for stream_id[%d]", *bitrate, stream_id);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_set_extra_preview_gop_interval(void *camera_handle, int stream_id, int interval)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (stream_id < 0 || stream_id >= EXTRA_PREVIEW_STREAM_MAX) {
+               LOGE("invalid stream_id[%d]", stream_id);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGI("set GOP interval[%d] for stream_id[%d]", interval, stream_id);
+
+       handle->extra_preview_gop_interval[stream_id] = interval;
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_get_extra_preview_gop_interval(void *camera_handle, int stream_id, int *interval)
+{
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle || !interval) {
+               LOGE("NULL param[%p,%p]", handle, interval);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (stream_id < 0 || stream_id >= EXTRA_PREVIEW_STREAM_MAX) {
+               LOGE("invalid stream_id[%d]", stream_id);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       *interval = (int)handle->extra_preview_gop_interval[stream_id];
+
+       LOGI("get GOP interval[%d] for stream_id[%d]", *interval, stream_id);
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+static int __set_command(hal_camera_handle *handle, int64_t command, void *value)
+{
+       int cid = 0;
+       int ctrl_ret = 0;
+       int set_value = 0;
+
+       if (!handle || !value) {
+               LOGE("NULL param %p %p", handle, value);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       set_value = *(int *)value;
+
+       if (handle->state < CAMERA_STATE_OPENED) {
+               LOGE("invalid state %d", handle->state);
+               return CAMERA_ERROR_INVALID_STATE;
+       }
+
+       LOGD("set command %"PRIx64" - state %d", command, handle->state);
+
+       switch (command) {
+       case CAMERA_COMMAND_BRIGHTNESS:
+               cid = V4L2_CID_BRIGHTNESS;
+               break;
+       case CAMERA_COMMAND_CONTRAST:
+               cid = V4L2_CID_CONTRAST;
+               break;
+       case CAMERA_COMMAND_SATURATION:
+               cid = V4L2_CID_SATURATION;
+               break;
+       case CAMERA_COMMAND_SHARPNESS:
+               cid = V4L2_CID_SHARPNESS;
+               break;
+       case CAMERA_COMMAND_PTZ_TYPE:
+               if (set_value != CAMERA_PTZ_TYPE_ELECTRONIC) {
+                       LOGE("not supported PTZ type %d", set_value);
+                       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+               }
+               return CAMERA_ERROR_NONE;
+       case CAMERA_COMMAND_PAN:
+               cid = V4L2_CID_PAN_ABSOLUTE;
+               break;
+       case CAMERA_COMMAND_TILT:
+               cid = V4L2_CID_TILT_ABSOLUTE;
+               break;
+       case CAMERA_COMMAND_FLIP:
+               if (set_value != CAMERA_FLIP_NONE) {
+                       LOGE("NOT_SUPPORTED flip %d", set_value);
+                       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+               }
+               return CAMERA_ERROR_NONE;
+       case CAMERA_COMMAND_CAPTURE_COUNT:
+               handle->capture_count = set_value;
+               LOGI("capture count %u", handle->capture_count);
+               return CAMERA_ERROR_NONE;
+       case CAMERA_COMMAND_CAPTURE_INTERVAL:
+               handle->capture_interval_ms = set_value;
+               LOGI("capture interval %u ms", handle->capture_interval_ms);
+               return CAMERA_ERROR_NONE;
+       case CAMERA_COMMAND_FOCUS_MODE:
+               LOGI("set focus mode [old:%d -> new:%d]", handle->focus_mode, set_value);
+               handle->focus_mode = set_value;
+               return CAMERA_ERROR_NONE;
+       case CAMERA_COMMAND_FOCUS_RANGE:
+               LOGI("set focus range [old:%d -> new:%d]", handle->focus_range, set_value);
+               handle->focus_range = set_value;
+               return CAMERA_ERROR_NONE;
+       case CAMERA_COMMAND_FOCUS_LEVEL:
+               LOGI("set focus level [old:%d -> new:%d]", handle->focus_level, set_value);
+               handle->focus_level = set_value;
+               return CAMERA_ERROR_NONE;
+       default:
+               LOGE("NOT_SUPPORTED command %"PRIx64, command);
+               return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+       }
+
+       ctrl_ret = __camera_v4l2_s_ctrl(handle->device_fd, cid, set_value);
+       if (ctrl_ret < 0) {
+               switch (errno) {
+               case EACCES:
+               case EPERM:
+                       LOGE("Permission denied %d", errno);
+                       return CAMERA_ERROR_PERMISSION_DENIED;
+               case EINVAL:
+                       LOGE("Invalid argument");
+                       return CAMERA_ERROR_INVALID_PARAMETER;
+               case EBUSY:
+                       LOGE("Device busy");
+                       return CAMERA_ERROR_DEVICE_BUSY;
+               case ENOTSUP:
+                       LOGE("Not supported");
+                       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+               default:
+                       LOGE("Unknown errro %d", errno);
+                       return CAMERA_ERROR_INTERNAL;
+               }
+       }
+
+       return CAMERA_ERROR_NONE;
+}
+
+
+int camera_v4l2_set_command(void *camera_handle, int64_t command, void *value)
+{
+       int ret = CAMERA_ERROR_NONE;
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       g_mutex_lock(&handle->lock);
+
+       ret = __set_command(handle, command, value);
+
+       g_mutex_unlock(&handle->lock);
+
+       return ret;
+}
+
+
+int camera_v4l2_get_command(void *camera_handle, int64_t command, void **value)
+{
+       int ret = CAMERA_ERROR_NONE;
+       int cid = 0;
+       int ctrl_ret = 0;
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+
+       if (!handle || !value) {
+               LOGE("NULL param %p %p", handle, value);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       LOGD("get command %"PRIx64" - state %d", command, handle->state);
+
+       switch (command) {
+       case CAMERA_COMMAND_BRIGHTNESS:
+               cid = V4L2_CID_BRIGHTNESS;
+               break;
+       case CAMERA_COMMAND_CONTRAST:
+               cid = V4L2_CID_CONTRAST;
+               break;
+       case CAMERA_COMMAND_SATURATION:
+               cid = V4L2_CID_SATURATION;
+               break;
+       case CAMERA_COMMAND_SHARPNESS:
+               cid = V4L2_CID_SHARPNESS;
+               break;
+       case CAMERA_COMMAND_FOCUS_MODE:
+               **(int **)value = handle->focus_mode;
+               LOGI("get focus mode %d", **(int **)value);
+               goto _GET_COMMAND_DONE;
+       case CAMERA_COMMAND_FOCUS_RANGE:
+               **(int **)value = handle->focus_range;
+               LOGI("get focus range %d", **(int **)value);
+               goto _GET_COMMAND_DONE;
+       case CAMERA_COMMAND_FOCUS_LEVEL:
+               **(int **)value = handle->focus_level;
+               LOGI("get focus level %d", **(int **)value);
+               goto _GET_COMMAND_DONE;
+       default:
+               LOGE("NOT_SUPPORTED %"PRIx64, command);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+       }
+
+       ctrl_ret = __camera_v4l2_g_ctrl(handle->device_fd, cid, (int *)*value);
+       if (ctrl_ret < 0) {
+               switch (errno) {
+               case EACCES:
+               case EPERM:
+                       LOGE("Permission denied %d", errno);
+                       ret = CAMERA_ERROR_PERMISSION_DENIED;
+                       break;
+               case EINVAL:
+                       LOGE("Invalid argument");
+                       ret = CAMERA_ERROR_INVALID_PARAMETER;
+                       break;
+               case EBUSY:
+                       LOGE("Device busy");
+                       ret = CAMERA_ERROR_DEVICE_BUSY;
+                       break;
+               case ENOTSUP:
+                       LOGE("Not supported");
+                       ret = CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+                       break;
+               default:
+                       LOGE("Unknown errro %d", errno);
+                       ret = CAMERA_ERROR_INTERNAL;
+                       break;
+               }
+       }
+
+_GET_COMMAND_DONE:
+       g_mutex_unlock(&handle->lock);
+
+       return ret;
+}
+
+
+static void __dump_batch_command(camera_batch_command_control_s *batch_command)
+{
+       if (!batch_command) {
+               LOGE("NULL batch command");
+               return;
+       }
+
+       LOGI("[WHITE_BALANCE] %d", batch_command->white_balance);
+       LOGI("[ISO] %d", batch_command->iso);
+       LOGI("[CONTRAST] %d", batch_command->contrast);
+       LOGI("[HUE] %d", batch_command->hue);
+       LOGI("[SATURATION] %d", batch_command->saturation);
+       LOGI("[SHARPNESS] %d", batch_command->sharpness);
+       LOGI("[BRIGHTNESS] %d", batch_command->brightness);
+       LOGI("[EFFECT] %d", batch_command->effect);
+       LOGI("[SCENE_MODE] %d", batch_command->scene_mode);
+       LOGI("[EXPOSURE_MODE] %d", batch_command->exposure_mode);
+       LOGI("[EXPOSURE] %d", batch_command->exposure);
+       LOGI("[ROTATION] %d", batch_command->rotation);
+       LOGI("[FLIP] %d", batch_command->flip);
+       LOGI("[FOCUS_MODE] %d", batch_command->focus_mode);
+       LOGI("[FOCUS_RANGE] %d", batch_command->focus_range);
+       LOGI("[FOCUS_AREA] %d,%d,%dx%d", batch_command->focus_area.x, batch_command->focus_area.y,
+               batch_command->focus_area.width, batch_command->focus_area.height);
+       LOGI("[FOCUS_LEVEL] %d", batch_command->focus_level);
+       LOGI("[SHOT_MODE] %d", batch_command->shot_mode);
+       LOGI("[ANTI_SHAKE] %d", batch_command->anti_shake);
+       LOGI("[DIGITAL_ZOOM] %d", batch_command->digital_zoom);
+       LOGI("[OPTICAL_ZOOM] %d", batch_command->optical_zoom);
+       LOGI("[RECORDING_HINT] %d", batch_command->recording_hint);
+       LOGI("[WDR] %d", batch_command->wdr);
+       LOGI("[SHUTTER_SPEED] %d/%d", batch_command->shutter_speed.numerator, batch_command->shutter_speed.denominator);
+       LOGI("[FLASH_MODE] %d", batch_command->flash_mode);
+       LOGI("[FLASH_BRIGHTNESS] %d", batch_command->flash_brightness);
+       LOGI("[FACE_DETECTION] %d", batch_command->face_detection);
+       LOGI("[PTZ_TYPE] %d", batch_command->ptz_type);
+       LOGI("[PAN] %d", batch_command->pan);
+       LOGI("[TILT] %d", batch_command->tilt);
+       LOGI("[BITRATE] %d", batch_command->bitrate);
+       LOGI("[GOP_INTERVAL] %d", batch_command->gop_interval);
+       LOGI("[CAPTURE_COUNT] %d", batch_command->capture_count);
+       LOGI("[CAPTURE_INTERVAL] %d", batch_command->capture_interval);
+}
+
+
+int camera_v4l2_set_batch_command(void *camera_handle, camera_batch_command_control_s *batch_command, int64_t *error_command)
+{
+       int ret = CAMERA_ERROR_NONE;
+       int i = 0;
+       int support_count = 0;
+       hal_camera_handle *handle = (hal_camera_handle *)camera_handle;
+       set_batch_table_s set_table[] = {
+               {CAMERA_COMMAND_BRIGHTNESS, batch_command ? (void *)&batch_command->brightness : NULL},
+               {CAMERA_COMMAND_CONTRAST, batch_command ? (void *)&batch_command->contrast : NULL},
+               {CAMERA_COMMAND_SATURATION, batch_command ? (void *)&batch_command->saturation : NULL},
+               {CAMERA_COMMAND_SHARPNESS, batch_command ? (void *)&batch_command->sharpness : NULL},
+               {CAMERA_COMMAND_PTZ_TYPE, batch_command ? (void *)&batch_command->ptz_type : NULL},
+               {CAMERA_COMMAND_PAN, batch_command ? (void *)&batch_command->pan : NULL},
+               {CAMERA_COMMAND_TILT, batch_command ? (void *)&batch_command->tilt : NULL},
+               {CAMERA_COMMAND_FLIP, batch_command ? (void *)&batch_command->flip : NULL},
+               {CAMERA_COMMAND_CAPTURE_COUNT, batch_command ? (void *)&batch_command->capture_count : NULL},
+               {CAMERA_COMMAND_CAPTURE_INTERVAL, batch_command ? (void *)&batch_command->capture_interval : NULL},
+               {CAMERA_COMMAND_FOCUS_MODE, batch_command ? (void *)&batch_command->focus_mode : NULL},
+               {CAMERA_COMMAND_FOCUS_RANGE, batch_command ? (void *)&batch_command->focus_range : NULL},
+               {CAMERA_COMMAND_FOCUS_LEVEL, batch_command ? (void *)&batch_command->focus_level : NULL}
+       };
+
+       if (!handle || !batch_command) {
+               LOGE("NULL param %p %p", handle, batch_command);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       support_count = sizeof(set_table) / sizeof(set_batch_table_s);
+
+       LOGD("set batch command - support count %d", support_count);
+
+       __dump_batch_command(batch_command);
+
+       for (i = 0 ; i < support_count ; i++) {
+               if (!(batch_command->command_set_flag & set_table[i].command))
+                       continue;
+
+               ret = __set_command(handle, set_table[i].command, set_table[i].value);
+               if (ret != CAMERA_ERROR_NONE) {
+                       LOGE("failed command %"PRIx64", ret 0x%x", set_table[i].command, ret);
+                       break;
+               }
+       }
+
+       g_mutex_unlock(&handle->lock);
+
+       return ret;
+}
+
+
+static int camera_v4l2_backend_init(void **data)
+{
+       hal_backend_camera_funcs *funcs;
+
+       funcs = calloc(1, sizeof(hal_backend_camera_funcs));
+       if (!funcs)
+               return CAMERA_ERROR_OUT_OF_MEMORY;
+
+       funcs->init = camera_v4l2_init;
+       funcs->deinit = camera_v4l2_deinit;
+       funcs->get_device_info_list = camera_v4l2_get_device_info_list;
+       funcs->open_device = camera_v4l2_open_device;
+       funcs->open_device_ext = camera_v4l2_open_device_ext;
+       funcs->close_device = camera_v4l2_close_device;
+       funcs->add_message_callback = camera_v4l2_add_message_callback;
+       funcs->remove_message_callback = camera_v4l2_remove_message_callback;
+       funcs->set_preview_stream_format = camera_v4l2_set_preview_stream_format;
+       funcs->get_preview_stream_format = camera_v4l2_get_preview_stream_format;
+       funcs->set_user_buffer_fd = camera_v4l2_set_user_buffer_fd;
+       funcs->start_preview = camera_v4l2_start_preview;
+       funcs->release_preview_buffer = camera_v4l2_release_preview_buffer;
+       funcs->stop_preview = camera_v4l2_stop_preview;
+       funcs->start_auto_focus = camera_v4l2_start_auto_focus;
+       funcs->stop_auto_focus = camera_v4l2_stop_auto_focus;
+       funcs->start_capture = camera_v4l2_start_capture;
+       funcs->stop_capture = camera_v4l2_stop_capture;
+       funcs->set_video_stream_format = camera_v4l2_set_video_stream_format;
+       funcs->get_video_stream_format = camera_v4l2_get_video_stream_format;
+       funcs->start_record = camera_v4l2_start_record;
+       funcs->release_video_buffer = camera_v4l2_release_video_buffer;
+       funcs->stop_record = camera_v4l2_stop_record;
+       funcs->set_command = camera_v4l2_set_command;
+       funcs->get_command = camera_v4l2_get_command;
+       funcs->set_batch_command = camera_v4l2_set_batch_command;
+       funcs->set_extra_preview_frame_cb = camera_v4l2_set_extra_preview_frame_cb;
+       funcs->unset_extra_preview_frame_cb = camera_v4l2_unset_extra_preview_frame_cb;
+       funcs->release_extra_preview_buffer = camera_v4l2_release_extra_preview_buffer;
+       funcs->set_extra_preview_stream_format = camera_v4l2_set_extra_preview_stream_format;
+       funcs->get_extra_preview_stream_format = camera_v4l2_get_extra_preview_stream_format;
+       funcs->set_extra_preview_bitrate = camera_v4l2_set_extra_preview_bitrate;
+       funcs->get_extra_preview_bitrate = camera_v4l2_get_extra_preview_bitrate;
+       funcs->set_extra_preview_gop_interval = camera_v4l2_set_extra_preview_gop_interval;
+       funcs->get_extra_preview_gop_interval = camera_v4l2_get_extra_preview_gop_interval;
+
+       *data = (void *)funcs;
+
+       return 0;
+}
+
+
+static int camera_v4l2_backend_exit(void *data)
+{
+       if (!data)
+               return 0;
+
+       free(data);
+
+       return 0;
+}
+
+
+hal_backend hal_backend_camera_data = {
+       .name = "camera-v4l2",
+       .vendor = "TIZEN",
+       .abi_version = HAL_ABI_VERSION_TIZEN_6_5,
+       .init = camera_v4l2_backend_init,
+       .exit = camera_v4l2_backend_exit,
+};
diff --git a/src/hal_backend_camera_v4l2_private.h b/src/hal_backend_camera_v4l2_private.h
new file mode 100644 (file)
index 0000000..f5e6e1a
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * hal_backend_camera_v4l2_private.h
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HAL_BACKEND_CAMERA_V4L2_PRIVATE_H__
+#define __HAL_BACKEND_CAMERA_V4L2_PRIVATE_H__
+
+#include <linux/videodev2.h>
+#include <glib.h>
+#include <tbm_bufmgr.h>
+#include <hal/hal-common-interface.h>
+#include <hal/hal-camera-interface.h>
+
+#ifdef HAVE_LIBV4L2
+#include <libv4l2.h>
+#else
+#define v4l2_fd_open(fd, flags) (fd)
+#define v4l2_close              close
+#define v4l2_dup                dup
+#define v4l2_ioctl              ioctl
+#define v4l2_read               read
+#define v4l2_mmap               mmap
+#define v4l2_munmap             munmap
+#endif /* ENABLE_LIBV4L2 */
+
+#define CAMERA_HAL_INITIAL_INDEX    -1
+#define CAMERA_HAL_INITIAL_FD       -1
+#define MESSAGE_CALLBACK_MAX        10
+#define BUFFER_MAX                  4
+#define V4L2_PLANES_MAX             4
+#define EXTRA_PREVIEW_STREAM_MAX    10
+
+typedef struct _set_batch_table_s {
+       int64_t command;
+       void *value;
+} set_batch_table_s;
+
+typedef struct _camera_hal_handle {
+       /* tbm */
+       tbm_bufmgr bufmgr;
+
+       /* device */
+       gint32 device_index;
+       gint32 device_fd;
+
+       /* buffer */
+       guint32 buffer_dequeued_count;
+       GThread *buffer_thread;
+       gboolean buffer_thread_run;
+       guint32 buffer_count;
+       camera_buffer_s camera_buffers[BUFFER_MAX];
+       enum v4l2_buf_type buffer_type;
+       GMutex buffer_lock;
+       GCond buffer_cond;
+
+       /* preview */
+       camera_format_s preview_format;
+       hal_camera_preview_frame_cb preview_cb;
+       gpointer preview_cb_data;
+       hal_camera_extra_preview_frame_cb extra_preview_cb;
+       gpointer extra_preview_cb_data;
+       GMutex extra_preview_lock;
+       camera_format_s extra_preview_format[EXTRA_PREVIEW_STREAM_MAX];
+       gint32 extra_preview_gop_interval[EXTRA_PREVIEW_STREAM_MAX];
+
+       /* capture */
+       hal_camera_capture_cb capture_cb;
+       gpointer capture_cb_data;
+       guint32 capture_count;
+       guint32 capture_interval_ms;
+       guint32 captured_count;
+       gboolean capture_request;
+       gboolean capture_restart_stream;
+
+       /* message */
+       GThread *msg_thread;
+       hal_camera_message_cb msg_cb[MESSAGE_CALLBACK_MAX];
+       gpointer msg_cb_data[MESSAGE_CALLBACK_MAX];
+       gboolean msg_cb_run;
+       GQueue *msg_list;
+       GMutex msg_cb_lock;
+       GCond msg_cb_cond;
+
+       /* focus */
+       gint32 focus_mode;
+       gint32 focus_range;
+       gint32 focus_level;
+
+       /* etc */
+       GMutex lock;
+       camera_state_e state;
+} hal_camera_handle;
+
+int camera_v4l2_init(void **camera_handle);
+int camera_v4l2_deinit(void *camera_handle);
+int camera_v4l2_get_device_info_list(camera_device_info_list_s *device_info_list);
+int camera_v4l2_open_device(void *camera_handle, int device_index);
+int camera_v4l2_open_device_ext(void *camera_handle, const char *device_name);
+int camera_v4l2_close_device(void *camera_handle);
+int camera_v4l2_add_message_callback(void *camera_handle, hal_camera_message_cb callback, void *user_data, uint32_t *cb_id);
+int camera_v4l2_remove_message_callback(void *camera_handle, uint32_t cb_id);
+int camera_v4l2_set_preview_stream_format(void *camera_handle, camera_format_s *format);
+int camera_v4l2_get_preview_stream_format(void *camera_handle, camera_format_s *format);
+int camera_v4l2_set_user_buffer_fd(void *camera_handle, int *fds, int number);
+int camera_v4l2_start_preview(void *camera_handle, hal_camera_preview_frame_cb callback, void *user_data);
+int camera_v4l2_release_preview_buffer(void *camera_handle, int buffer_index);
+int camera_v4l2_stop_preview(void *camera_handle);
+int camera_v4l2_start_auto_focus(void *camera_handle);
+int camera_v4l2_stop_auto_focus(void *camera_handle);
+int camera_v4l2_start_capture(void *camera_handle, hal_camera_capture_cb callback, void *user_data);
+int camera_v4l2_stop_capture(void *camera_handle);
+int camera_v4l2_set_video_stream_format(void *camera_handle, camera_format_s *format);
+int camera_v4l2_get_video_stream_format(void *camera_handle, camera_format_s *format);
+int camera_v4l2_start_record(void *camera_handle, hal_camera_video_frame_cb callback, void *user_data);
+int camera_v4l2_release_video_buffer(void *camera_handle, int buffer_index);
+int camera_v4l2_stop_record(void *camera_handle);
+int camera_v4l2_set_command(void *camera_handle, int64_t command, void *value);
+int camera_v4l2_get_command(void *camera_handle, int64_t command, void **value);
+int camera_v4l2_set_batch_command(void *camera_handle, camera_batch_command_control_s *batch_command, int64_t *error_command);
+
+#endif /* __HAL_BACKEND_CAMERA_V4L2_PRIVATE_H__ */