Initial release 72/178672/7 accepted/tizen/unified/20180615.160543 submit/tizen/20180612.005942 submit/tizen/20180615.012602
authorJeongmo Yang <jm80.yang@samsung.com>
Tue, 17 Apr 2018 07:23:51 +0000 (16:23 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Wed, 30 May 2018 09:09:18 +0000 (18:09 +0900)
[Version] 0.0.1
[Profile] Common
[Issue Type] New
[Dependency module] N/A

Change-Id: I1ba12660a4e2cfa6ba151a61faebf750c8adc5fb
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]
camera-hal-v4l2.manifest [new file with mode: 0644]
configure.ac [new file with mode: 0644]
packaging/camera-hal-v4l2.spec [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/tizen_camera_v4l2.c [new file with mode: 0644]
src/tizen_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..bbe9d02
--- /dev/null
@@ -0,0 +1,206 @@
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+\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/camera-hal-v4l2.manifest b/camera-hal-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/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..e605900
--- /dev/null
@@ -0,0 +1,59 @@
+AC_PREREQ(2.52)
+
+AC_INIT([camera-hal-v4l2], [0.8.0])
+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)
+
+# 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/packaging/camera-hal-v4l2.spec b/packaging/camera-hal-v4l2.spec
new file mode 100644 (file)
index 0000000..73acc1f
--- /dev/null
@@ -0,0 +1,43 @@
+Name:       camera-hal-v4l2
+Summary:    Tizen Camera Hal for V4L2
+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:  mm-hal-interface-devel
+BuildRequires:  gtest-devel
+
+%description
+Tizen Camera Hal for V4L2.
+
+
+%prep
+%setup -q
+
+
+%build
+./autogen.sh
+%configure --disable-static
+make %{?jobs:-j%jobs}
+
+%install
+%make_install
+
+
+%post
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest %{name}.manifest
+%license LICENSE.APLv2
+%defattr(-,root,root,-)
+%{_libdir}/*.so
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..46be497
--- /dev/null
@@ -0,0 +1,20 @@
+ACLOCAL_AMFLAGS='-I m4'
+
+lib_LTLIBRARIES = libtizen-camera.la
+
+noinst_HEADERS = tizen_camera_v4l2_private.h
+
+libtizen_camera_la_SOURCES = tizen_camera_v4l2.c
+
+libtizen_camera_la_CFLAGS = -I$(srcdir)/include \
+                            $(GLIB_CFLAGS) \
+                            $(DLOG_CFLAGS) \
+                            $(TBM_CFLAGS)
+
+libtizen_camera_la_LIBADD = $(GLIB_LIBS) \
+                           $(DLOG_LIBS) \
+                           $(TBM_LIBS)
+
+libtizen_camera_la_CFLAGS += -fdata-sections -ffunction-sections -Wl,--gc-sections
+libtizen_camera_la_LDFLAGS = -Wl,--gc-sections -avoid-version
+
diff --git a/src/tizen_camera_v4l2.c b/src/tizen_camera_v4l2.c
new file mode 100644 (file)
index 0000000..f24bf92
--- /dev/null
@@ -0,0 +1,1685 @@
+/*
+ * tizen_camera_v4l2.c
+ *
+ * Copyright (c) 2018 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 "tizen_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_t *g_device_info_list;
+static guint32 device_caps;
+static GMutex g_device_info_lock;
+
+
+static void _camera_hal_v4l2_destructor(void) __attribute__((destructor));
+
+static void _camera_hal_v4l2_destructor(void)
+{
+       LOGD("release device info list %p", g_device_info_list);
+
+       g_free(g_device_info_list);
+
+       return;
+}
+
+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_stream(int device_fd, int type, gboolean onoff)
+{
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (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, int count, int *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 (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 (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 = ioctl(device_fd, VIDIOC_DQBUF, &v4l2_buf);
+       if (ret < 0) {
+               if (errno != EIO) {
+                       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;
+       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, uint8_t *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;
+       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 int _camera_get_device_info(int device_index, int device_fd, camera_device_info_t *device_info, char *node_path)
+{
+       int i = 0;
+       int j = 0;
+       int format_count = 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 and resolution");
+
+       for (i = 0 ; ; i++) {
+               memset(&v4l2_format, 0x0, sizeof(struct v4l2_fmtdesc));
+
+               v4l2_format.index = i;
+               v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+               if (ioctl(device_fd, VIDIOC_ENUM_FMT, &v4l2_format) < 0) {
+                       LOGW("\tformat : end of enumeration");
+                       break;
+               }
+
+               LOGD("\tformat[%d] "FOURCC_FORMAT, i, FOURCC_CONVERT(v4l2_format.pixelformat));
+
+               if (_camera_get_format(v4l2_format.pixelformat, &camera_format) != CAMERA_ERROR_NONE)
+                       continue;
+
+               device_info->format_list.formats[format_count] = camera_format;
+
+               resolution_count = 0;
+
+               for (j = 0 ; ; j++) {
+                       memset(&v4l2_frame, 0x0, sizeof(struct v4l2_frmsizeenum));
+
+                       v4l2_frame.index = j;
+                       v4l2_frame.pixel_format = v4l2_format.pixelformat;
+
+                       if (ioctl(device_fd, VIDIOC_ENUM_FRAMESIZES, &v4l2_frame) < 0) {
+                               LOGW("\t\tframe : end of enumeration ");
+                               break;
+                       }
+
+                       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;
+
+                               resolution_count++;
+
+                               LOGD("\t\tsize[%d] %ux%u", j,
+                                       v4l2_frame.discrete.width,
+                                       v4l2_frame.discrete.height);
+                               break;
+                       case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+                               LOGW("\t\tsize[%d] %ux%u - %ux%u", j,
+                                       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)",
+                                       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);
+
+               format_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;
+       glob_t glob_buf;
+       struct v4l2_capability v4l2_cap;
+       camera_device_info_list_t *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_t, 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 eror : %d", ret);
+                       ret = CAMERA_ERROR_INTERNAL;
+                       goto _GET_DEVICE_INFO_LIST_DONE;
+               }
+       }
+
+       LOGD("device node count : %d", 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;
+               }
+
+               memset(&v4l2_cap, 0x0, sizeof(struct v4l2_capability));
+
+               if (ioctl(device_fd, VIDIOC_QUERYCAP, &v4l2_cap) < 0) {
+                       LOGE("querycap failed. errno %d", errno);
+                       close(device_fd);
+                       continue;
+               }
+
+               if (v4l2_cap.capabilities & V4L2_CAP_DEVICE_CAPS)
+                       device_caps = v4l2_cap.device_caps;
+               else
+                       device_caps = v4l2_cap.capabilities;
+
+               if (!(device_caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) ||
+                       (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], device_caps);
+                       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]);
+
+               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 void *_camera_preview_handler_func(gpointer data)
+{
+       int index = 0;
+       camera_hal_handle *handle = (camera_hal_handle *)data;
+
+       if (!handle) {
+               LOGE("NULL handle for preview handler");
+               return NULL;
+       }
+
+       LOGD("enter - preview handler thread");
+
+       /* run buffer thread */
+       g_mutex_lock(&handle->preview_cb_lock);
+
+       while (handle->preview_cb_run) {
+               if (_camera_v4l2_wait_frame(handle->device_fd, 5) != CAMERA_ERROR_NONE) {
+                       LOGE("frame wait failed");
+                       break;
+               }
+
+               if (_camera_v4l2_dqbuf(handle->device_fd, handle->v4l2_type, V4L2_MEMORY_MMAP, &index) != CAMERA_ERROR_NONE) {
+                       LOGE("dqbuf failed");
+                       break;
+               }
+
+               handle->live_buffer_num++;
+
+               LOGD("live buffer num %d", handle->live_buffer_num);
+
+               g_mutex_unlock(&handle->preview_cb_lock);
+
+               if (handle->preview_cb) {
+                       ((camera_preview_frame_cb)handle->preview_cb)(&handle->preview_buffer[index], NULL, handle->preview_cb_data);
+               } else {
+                       LOGW("preview callback is NULL");
+                       camera_release_preview_buffer((void *)handle, index);
+               }
+
+               sched_yield();
+
+               g_mutex_lock(&handle->preview_cb_lock);
+       }
+
+       g_mutex_unlock(&handle->preview_cb_lock);
+
+       LOGD("leave - preview handler thread");
+
+       return NULL;
+}
+
+
+static void _camera_message_release_func(gpointer data)
+{
+       camera_message_t *message = (camera_message_t *)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_t *message = NULL;
+       camera_hal_handle *handle = (camera_hal_handle *)data;
+
+       if (!handle) {
+               LOGE("NULL handle for capture thread");
+               return NULL;
+       }
+
+       LOGD("enter - message thread");
+
+       g_mutex_lock(&handle->message_cb_lock);
+
+       while (handle->message_cb_run) {
+               if (g_queue_is_empty(handle->message_list)) {
+                       LOGD("wait for message");
+                       g_cond_wait(&handle->message_cb_cond, &handle->message_cb_lock);
+                       LOGD("message signal received");
+               }
+
+               if (!handle->message_cb_run) {
+                       LOGW("break message thread");
+                       break;
+               }
+
+               message = g_queue_pop_head(handle->message_list);
+               if (!message) {
+                       LOGW("NULL message");
+                       continue;
+               }
+
+               g_mutex_unlock(&handle->message_cb_lock);
+
+               for (i = 0 ; i < MESSAGE_CALLBACK_MAX ; i++) {
+                       if (handle->message_cb[i]) {
+                               LOGD("call message callback type %d", message->type);
+                               ((camera_message_cb)handle->message_cb[i])(message, handle->message_cb_data[i]);
+                       }
+               }
+
+               g_free(message);
+               message = NULL;
+
+               g_mutex_lock(&handle->message_cb_lock);
+       }
+
+       g_mutex_unlock(&handle->message_cb_lock);
+
+       LOGD("leave - message thread");
+
+       return NULL;
+}
+
+
+void _camera_release_handle(camera_hal_handle *handle)
+{
+       if (!handle) {
+               LOGW("NULL handle");
+               return;
+       }
+
+       if (handle->message_thread) {
+               g_mutex_lock(&handle->message_cb_lock);
+               handle->message_cb_run = FALSE;
+               g_cond_signal(&handle->message_cb_cond);
+               g_mutex_unlock(&handle->message_cb_lock);
+               g_thread_join(handle->message_thread);
+               g_queue_free_full(handle->message_list, (GDestroyNotify)_camera_message_release_func);
+               handle->message_list = NULL;
+       }
+
+       g_mutex_clear(&handle->lock);
+       g_mutex_clear(&handle->preview_cb_lock);
+       g_mutex_clear(&handle->message_cb_lock);
+       g_cond_clear(&handle->preview_cb_cond);
+       g_cond_clear(&handle->message_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_init(void **camera_handle)
+{
+       int ret = CAMERA_ERROR_NONE;
+       camera_hal_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(camera_hal_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->preview_cb_lock);
+       g_mutex_init(&new_handle->message_cb_lock);
+       g_cond_init(&new_handle->preview_cb_cond);
+       g_cond_init(&new_handle->message_cb_cond);
+
+       /* message thread */
+       new_handle->message_list = g_queue_new();
+       new_handle->message_cb_run = TRUE;
+       new_handle->message_thread = g_thread_try_new("camera_hal_message_thread",
+               _camera_message_handler_func, (gpointer)new_handle, NULL);
+       if (!new_handle->message_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;
+       }
+
+       *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_deinit(void *camera_handle)
+{
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       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_get_device_info_list(camera_device_info_list_t *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_t));
+
+       return CAMERA_ERROR_NONE;
+}
+
+int camera_open_device(void *camera_handle, int device_index)
+{
+       int ret = CAMERA_ERROR_NONE;
+       int device_fd = CAMERA_HAL_INITIAL_FD;
+       char *node_path = NULL;
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       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 (device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
+               handle->v4l2_type = V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+       else
+               handle->v4l2_type = V4L2_CAP_VIDEO_CAPTURE;
+
+       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->v4l2_type);
+
+_OPEN_DEVICE_DONE:
+       g_mutex_unlock(&handle->lock);
+
+       return ret;
+}
+
+int camera_close_device(void *camera_handle)
+{
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       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);
+
+               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_add_message_callback(void *camera_handle, camera_message_cb callback, void *user_data, uint32_t *cb_id)
+{
+       uint32_t i = 0;
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_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;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       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;
+       }
+
+       for (i = 0 ; i < MESSAGE_CALLBACK_MAX ; i++) {
+               if (handle->message_cb[i] == NULL) {
+                       handle->message_cb[i] = callback;
+                       handle->message_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_remove_message_callback(void *camera_handle, uint32_t cb_id)
+{
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_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;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       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 (cb_id >= MESSAGE_CALLBACK_MAX) {
+               LOGE("invalid id %u", cb_id);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (handle->message_cb[cb_id]) {
+               LOGD("remove message callback %p, user data %p - cb_id %u",
+                       handle->message_cb[cb_id], handle->message_cb_data[cb_id], cb_id);
+
+               handle->message_cb[cb_id] = NULL;
+               handle->message_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_set_preview_stream_format(void *camera_handle, camera_format_t *format)
+{
+       int i = 0;
+       int j = 0;
+       int ret = CAMERA_ERROR_NONE;
+       gboolean capability_check = FALSE;
+       guint32 fourcc = 0;
+       camera_hal_handle *handle = NULL;
+       camera_device_info_t *device_info = NULL;
+       struct v4l2_format v4l2_fmt;
+       struct v4l2_streamparm v4l2_parm;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!format) {
+               LOGE("NULL format");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!g_device_info_list) {
+               LOGE("no device info list");
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       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;
+       }
+
+       /* 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;
+       }
+
+       /* S_FMT */
+       ret = _camera_get_fourcc_plane_num(format->stream_format, &fourcc, &handle->plane_num);
+       if (ret != CAMERA_ERROR_NONE) {
+               LOGE("get fourcc failed [format %d]", format->stream_format);
+               g_mutex_unlock(&handle->lock);
+               return ret;
+       }
+
+       memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format));
+
+       v4l2_fmt.type = handle->v4l2_type;
+       if (V4L2_TYPE_IS_MULTIPLANAR(handle->v4l2_type)) {
+               v4l2_fmt.fmt.pix_mp.width = format->stream_resolution.width;
+               v4l2_fmt.fmt.pix_mp.height = format->stream_resolution.height;
+               v4l2_fmt.fmt.pix_mp.pixelformat = fourcc;
+               v4l2_fmt.fmt.pix_mp.num_planes = handle->plane_num;
+       } else {
+               v4l2_fmt.fmt.pix.width = format->stream_resolution.width;
+               v4l2_fmt.fmt.pix.height = format->stream_resolution.height;
+               v4l2_fmt.fmt.pix.pixelformat = fourcc;
+               v4l2_fmt.fmt.pix.bytesperline = format->stream_resolution.width;
+       }
+
+       if (ioctl(handle->device_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) {
+               LOGE("S_FMT failed. errno %d", errno);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(handle->v4l2_type)) {
+               for (i = 0 ; i < v4l2_fmt.fmt.pix_mp.num_planes ; i++) {
+                       LOGD("plane[%d] stride %d, sizeimage %d",
+                               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->v4l2_type;
+
+       if (ioctl(handle->device_fd, VIDIOC_G_PARM, &v4l2_parm) < 0) {
+               LOGE("G_PARM failed. errno %d", errno);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       /* S_PARM to set fps */
+       v4l2_parm.parm.capture.timeperframe.numerator = 1;
+       v4l2_parm.parm.capture.timeperframe.denominator = format->stream_fps;
+
+       if (ioctl(handle->device_fd, VIDIOC_S_PARM, &v4l2_parm) < 0) {
+               LOGE("S_PARM failed. errno %d", errno);
+               g_mutex_unlock(&handle->lock);
+               return CAMERA_ERROR_INTERNAL;
+       }
+
+       memcpy(&handle->preview_format, format, sizeof(camera_format_t));
+
+       LOGD("set preview stream [%d: %dx%d, fps %d]",
+               format->stream_format,
+               format->stream_resolution.width,
+               format->stream_resolution.height,
+               format->stream_fps);
+
+       LOGW("CAPTURE STREAM [%d: %dx%d] IS NOT SUPPORTED",
+               format->capture_format,
+               format->capture_resolution.width,
+               format->capture_resolution.height);
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+int camera_get_preview_stream_format(void *camera_handle, camera_format_t *format)
+{
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!format) {
+               LOGE("NULL format");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       g_mutex_lock(&handle->lock);
+
+       memcpy(format, &handle->preview_format, sizeof(camera_format_t));
+
+       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_start_preview(void *camera_handle, camera_preview_frame_cb callback, void *user_data)
+{
+       int i = 0;
+       int ret = 0;
+       int result_count = 0;
+       camera_hal_handle *handle = NULL;
+       camera_buffer_t *buffer = NULL;
+
+       struct v4l2_buffer v4l2_buf;
+       struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!callback) {
+               LOGE("NULL callback for preview");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       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;
+       }
+
+       /* request buffer */
+       ret = _camera_v4l2_reqbufs(handle->device_fd,
+               handle->v4l2_type, V4L2_MEMORY_MMAP, PREVIEW_BUFFER_MAX, &result_count);
+       if (ret != CAMERA_ERROR_NONE) {
+               g_mutex_unlock(&handle->lock);
+               return ret;
+       }
+
+       LOGD("REQUESTED buffer count %d", result_count);
+
+       handle->preview_buffer_num = result_count;
+
+       /* query buffer, mmap and qbuf */
+       for (i = 0 ; i < handle->preview_buffer_num ; i++) {
+               memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+               memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
+
+               v4l2_buf.type = handle->v4l2_type;
+               v4l2_buf.memory = V4L2_MEMORY_MMAP;
+               v4l2_buf.index = i;
+               v4l2_buf.m.planes = v4l2_planes;
+               v4l2_buf.length = handle->plane_num;
+
+               if (ioctl(handle->device_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) {
+                       LOGE("[%d] query buf failed. errno %d", i, errno);
+                       goto _START_PREVIEW_FAILED;
+               }
+
+               buffer = &handle->preview_buffer[i];
+
+               buffer->index = i;
+               buffer->format = handle->preview_format.stream_format;
+               buffer->resolution = handle->preview_format.stream_resolution;
+               buffer->total_size = v4l2_buf.length;
+               buffer->num_planes = handle->plane_num;
+               buffer->planes[0].size = v4l2_buf.length;
+               buffer->planes[0].data = 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_PREVIEW_FAILED;
+               }
+       }
+
+       for (i = 0 ; i < handle->preview_buffer_num ; i++) {
+               if (_camera_v4l2_qbuf(handle->device_fd, handle->v4l2_type, V4L2_MEMORY_MMAP, i) != CAMERA_ERROR_NONE) {
+                       LOGE("qbuf failed");
+                       goto _START_PREVIEW_FAILED;
+               }
+       }
+
+       /* stream on */
+       ret = _camera_v4l2_stream(handle->device_fd, handle->v4l2_type, TRUE);
+       if (ret != CAMERA_ERROR_NONE) {
+               LOGE("stream on failed");
+               goto _START_PREVIEW_FAILED;
+       }
+
+       g_mutex_lock(&handle->preview_cb_lock);
+
+       handle->preview_cb_run = TRUE;
+
+       handle->preview_thread = g_thread_try_new("camera_hal_preview_thread",
+               _camera_preview_handler_func, (gpointer)handle, NULL);
+       if (!handle->preview_thread) {
+               LOGE("failed to create preview callback thread");
+               g_mutex_unlock(&handle->preview_cb_lock);
+               goto _START_PREVIEW_FAILED;
+       }
+
+       handle->preview_cb = callback;
+       handle->preview_cb_data = user_data;
+
+       g_mutex_unlock(&handle->preview_cb_lock);
+
+       handle->state = CAMERA_STATE_PREVIEWING;
+
+       LOGD("start preview done");
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+
+_START_PREVIEW_FAILED:
+       /* stream off */
+       if (ioctl(handle->device_fd, VIDIOC_STREAMOFF, &handle->v4l2_type) < 0)
+               LOGE("stream off failed. errno %d", errno);
+
+       /* munmap */
+       for (i = 0 ; i < handle->preview_buffer_num ; i++) {
+               buffer = &handle->preview_buffer[i];
+               if (buffer->planes[0].data != NULL &&
+                       buffer->planes[0].data != MAP_FAILED) {
+                       LOGW("munmap %p", buffer->planes[0].data);
+                       munmap(buffer->planes[0].data, buffer->planes[0].size);
+               }
+               memset(buffer, 0x0, sizeof(camera_buffer_t));
+       }
+
+       /* reqbufs 0 */
+       if (_camera_v4l2_reqbufs(handle->device_fd,
+               handle->v4l2_type, V4L2_MEMORY_MMAP, 0, &result_count) != CAMERA_ERROR_NONE)
+               LOGE("reqbufs 0 failed");
+
+       g_mutex_unlock(&handle->lock);
+
+       return ret;
+}
+
+int camera_release_preview_buffer(void *camera_handle, int buffer_index)
+{
+       int ret = CAMERA_ERROR_NONE;
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       g_mutex_lock(&handle->preview_cb_lock);
+
+       if (buffer_index >= handle->preview_buffer_num) {
+               LOGE("invalid buffer index %d", buffer_index);
+               g_mutex_unlock(&handle->preview_cb_lock);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       ret = _camera_v4l2_qbuf(handle->device_fd,
+               handle->v4l2_type, V4L2_MEMORY_MMAP, buffer_index);
+
+       if (ret == CAMERA_ERROR_NONE) {
+               handle->live_buffer_num--;
+               LOGD("qbud done : index %d, live buffer num %d",
+                       buffer_index, handle->live_buffer_num);
+       } else {
+               LOGE("qbuf failed [index %d]", buffer_index);
+       }
+
+       g_cond_signal(&handle->preview_cb_cond);
+
+       g_mutex_unlock(&handle->preview_cb_lock);
+
+       return ret;
+}
+
+int camera_stop_preview(void *camera_handle)
+{
+       int ret = CAMERA_ERROR_NONE;
+       int i = 0;
+       int result_count = 0;
+       gint64 end_time;
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       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->preview_cb_lock);
+
+       handle->preview_cb_run = FALSE;
+
+       while (handle->live_buffer_num > 0) {
+               LOGD("wait for live buffer [num %d]", handle->live_buffer_num);
+               end_time = g_get_monotonic_time() + 3 * G_TIME_SPAN_SECOND;
+               if (!g_cond_wait_until(&handle->preview_cb_cond, &handle->preview_cb_lock, end_time)) {
+                       LOGE("buffer wait failed");
+                       break;
+               } else {
+                       LOGD("signal received. check again...");
+               }
+       }
+
+       g_mutex_unlock(&handle->preview_cb_lock);
+
+       /* stream off */
+       ret = _camera_v4l2_stream(handle->device_fd, handle->v4l2_type, FALSE);
+
+       LOGD("stream off : 0x%x", ret);
+
+       /* munmap */
+       for (i = 0 ; i < handle->preview_buffer_num ; i++) {
+               if (handle->preview_buffer[i].planes[0].data != NULL) {
+                       LOGW("munmap %p", handle->preview_buffer[i].planes[0].data);
+
+                       munmap(handle->preview_buffer[i].planes[0].data, handle->preview_buffer[i].planes[0].size);
+
+                       handle->preview_buffer[i].planes[0].data = 0;
+                       handle->preview_buffer[i].planes[0].size = 0;
+               } else {
+                       LOGW("NULL data [index %d]", i);
+               }
+       }
+
+       /* reqbufs 0 */
+       ret = _camera_v4l2_reqbufs(handle->device_fd,
+               handle->v4l2_type, V4L2_MEMORY_MMAP, 0, &result_count);
+
+       LOGD("reqbufs 0 : 0x%x", ret);
+
+       /* wait for preview thread exit */
+       g_thread_join(handle->preview_thread);
+       handle->preview_thread = NULL;
+
+       handle->state = CAMERA_STATE_OPENED;
+
+       LOGD("stop preview done");
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+int camera_start_auto_focus(void *camera_handle)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("NOT SUPPORTED");
+
+       /* auto focus is not supported */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+int camera_stop_auto_focus(void *camera_handle)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("NOT SUPPORTED");
+
+       /* auto focus is not supported */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+
+int camera_start_capture(void *camera_handle, camera_capture_cb callback, void *user_data)
+{
+       if (!camera_handle || !callback) {
+               LOGE("NULL handle %p or callback %p", camera_handle, callback);
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("NOT SUPPORTED");
+
+       /* capture function is not supported */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+int camera_stop_capture(void *camera_handle)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("NOT SUPPORTED");
+
+       /* capture function is not supported */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+int camera_set_video_stream_format(void *camera_handle, camera_format_t *format)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!format) {
+               LOGE("NULL format");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+int camera_get_video_stream_format(void *camera_handle, camera_format_t *format)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!format) {
+               LOGE("NULL format");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+int camera_start_record(void *camera_handle, camera_video_frame_cb callback, void *user_data)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!callback) {
+               LOGE("NULL callback for video");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+int camera_release_video_buffer(void *camera_handle, int buffer_index)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+int camera_stop_record(void *camera_handle)
+{
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("NOT SUPPORTED");
+
+       /* single stream device can not support video stream */
+       return CAMERA_ERROR_DEVICE_NOT_SUPPORTED;
+}
+
+int camera_set_command(void *camera_handle, int64_t command, void *value)
+{
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!value) {
+               LOGE("invalid pointer for value");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       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;
+       }
+
+       LOGD("set command %lld - state %d", command, handle->state);
+
+       /* TODO: to be implemented */
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+int camera_get_command(void *camera_handle, int64_t command, void **value)
+{
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!value) {
+               LOGE("invalid pointer for value");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       g_mutex_lock(&handle->lock);
+
+       LOGD("get command %lld - state %d", command, handle->state);
+
+       /* TODO: to be implemented */
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
+
+int camera_set_batch_command(void *camera_handle, camera_batch_command_control_t *batch_command, int64_t *error_command)
+{
+       camera_hal_handle *handle = NULL;
+
+       if (!camera_handle) {
+               LOGE("NULL handle");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!batch_command) {
+               LOGE("invalid pointer for batch_command");
+               return CAMERA_ERROR_INVALID_PARAMETER;
+       }
+
+       handle = (camera_hal_handle *)camera_handle;
+
+       g_mutex_lock(&handle->lock);
+
+       LOGD("set batch command - flag 0x"PRIx64", state %d",
+               batch_command->command_set_flag, handle->state);
+
+       /* TODO: to be implemented */
+
+       g_mutex_unlock(&handle->lock);
+
+       return CAMERA_ERROR_NONE;
+}
diff --git a/src/tizen_camera_v4l2_private.h b/src/tizen_camera_v4l2_private.h
new file mode 100644 (file)
index 0000000..e70ceac
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * tizen_camera_private.c
+ *
+ * Copyright (c) 2018 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 __TIZEN_CAMERA_PRIVATE_H__
+#define __TIZEN_CAMERA_PRIVATE_H__
+
+#include <linux/videodev2.h>
+#include <glib.h>
+#include <tbm_bufmgr.h>
+#include <tizen-camera.h>
+
+#define CAMERA_HAL_INITIAL_INDEX    -1
+#define CAMERA_HAL_INITIAL_FD       -1
+#define MESSAGE_CALLBACK_MAX        10
+#define PREVIEW_BUFFER_MAX          4
+#define VIDEO_BUFFER_MAX            8
+#define V4L2_PLANES_MAX             4
+
+typedef struct _camera_hal_handle {
+       tbm_bufmgr bufmgr;
+
+       int device_index;
+       int device_fd;
+       camera_state_t state;
+       camera_format_t preview_format;
+       camera_format_t video_format;
+
+       /* V4L2 */
+       enum v4l2_buf_type v4l2_type;
+       uint8_t plane_num;
+       int live_buffer_num;
+
+       /* thread */
+       GThread *preview_thread;
+       GThread *message_thread;
+
+       /* preview callback */
+       camera_preview_frame_cb preview_cb;
+       void *preview_cb_data;
+       gboolean preview_cb_run;
+       uint32_t preview_buffer_num;
+       camera_buffer_t preview_buffer[PREVIEW_BUFFER_MAX];
+
+       /* video callback */
+       camera_video_frame_cb video_cb;
+       void *video_cb_data;
+       gboolean video_cb_run;
+       uint32_t video_buffer_num;
+       camera_buffer_t video_buffer[VIDEO_BUFFER_MAX];
+
+       /* message callback */
+       camera_message_cb message_cb[MESSAGE_CALLBACK_MAX];
+       void *message_cb_data[MESSAGE_CALLBACK_MAX];
+       gboolean message_cb_run;
+       GQueue *message_list;
+
+       /* thread safe */
+       GMutex lock;
+       GMutex preview_cb_lock;
+       GMutex message_cb_lock;
+       GCond preview_cb_cond;
+       GCond message_cb_cond;
+} camera_hal_handle;
+
+#endif /* __TIZEN_CAMERA_PRIVATE_H__ */