libv4l2 has moved from hardware/samsung_slsi/exynos5
authorYunji Kim <yunji.kim@samsung.com>
Fri, 12 Oct 2012 08:49:12 +0000 (08:49 +0000)
committerHuisung Kang <hs1218.kang@samsung.com>
Sun, 28 Oct 2012 22:42:22 +0000 (07:42 +0900)
Change-Id: I19d6c714e9f810e5c4db680eee358c3022462d80
Signed-off-by: Yunji Kim <yunji.kim@samsung.com>
Android.mk
libv4l2/Android.mk [new file with mode: 0644]
libv4l2/exynos_mc.c [new file with mode: 0644]
libv4l2/exynos_subdev.c [new file with mode: 0644]
libv4l2/exynos_v4l2.c [new file with mode: 0644]

index a93a9a8870b85947d769d86dd4a3553319c6028a..34cf63d9cd91df9f0f7ea5a854b0a39679e3d224 100644 (file)
@@ -15,6 +15,7 @@
 #
 
 common_exynos_dirs := \
-       libcsc
+       libcsc \
+       libv4l2
 
 include $(call all-named-subdir-makefiles,$(common_exynos_dirs))
diff --git a/libv4l2/Android.mk b/libv4l2/Android.mk
new file mode 100644 (file)
index 0000000..f7d06cf
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       exynos_v4l2.c \
+       exynos_subdev.c \
+       exynos_mc.c
+
+LOCAL_C_INCLUDES := \
+       $(LOCAL_PATH)/../include \
+       $(TOP)/hardware/samsung_slsi/exynos/libexynosutils
+
+LOCAL_SHARED_LIBRARIES := \
+       liblog \
+       libutils \
+       libexynosutils 
+
+LOCAL_MODULE := libexynosv4l2
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libv4l2/exynos_mc.c b/libv4l2/exynos_mc.c
new file mode 100644 (file)
index 0000000..8c5230c
--- /dev/null
@@ -0,0 +1,777 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*!
+ * \file      exynos_mc.c
+ * \brief     source file for libexynosv4l2
+ * \author    Jinsung Yang (jsgood.yang@samsung.com)
+ * \author    Sangwoo Park (sw5771.park@samsung.com)
+ * \date      2012/01/17
+ *
+ * <b>Revision History: </b>
+ * - 2012/01/17: Jinsung Yang (jsgood.yang@samsung.com) \n
+ *   Initial version
+ *
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <media.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+
+#include "exynos_v4l2.h"
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "libexynosv4l2-mc"
+#include <utils/Log.h>
+
+static inline unsigned int __media_entity_type(struct media_entity *entity)
+{
+    return entity->info.type & MEDIA_ENT_TYPE_MASK;
+}
+
+static void __media_debug_default(void *ptr, ...)
+{
+    va_list argptr;
+    va_start(argptr, ptr);
+    vprintf((const char*)ptr, argptr);
+    va_end(argptr);
+}
+
+static void __media_debug_set_handler(
+                struct media_device *media,
+                void (*debug_handler)(void *, ...),
+                void *debug_priv)
+{
+    if (debug_handler) {
+        media->debug_handler = debug_handler;
+        media->debug_priv = debug_priv;
+    } else {
+        media->debug_handler = __media_debug_default;
+        media->debug_priv = NULL;
+    }
+}
+
+static struct media_link *__media_entity_add_link(struct media_entity *entity)
+{
+    if (entity->num_links >= entity->max_links) {
+        struct media_link *links = entity->links;
+        unsigned int max_links = entity->max_links * 2;
+        unsigned int i;
+
+        links = (struct media_link*)realloc(links, max_links * sizeof *links);
+        if (links == NULL)
+            return NULL;
+
+        for (i = 0; i < entity->num_links; ++i)
+            links[i].twin->twin = &links[i];
+
+        entity->max_links = max_links;
+        entity->links = links;
+    }
+
+    return &entity->links[entity->num_links++];
+}
+
+
+static int __media_enum_links(struct media_device *media)
+{
+    ALOGD("%s: start", __func__);
+    __u32 id;
+    int ret = 0;
+
+    for (id = 1; id <= media->entities_count; id++) {
+        struct media_entity *entity = &media->entities[id - 1];
+        struct media_links_enum links;
+        unsigned int i;
+
+        links.entity = entity->info.id;
+        links.pads = (struct media_pad_desc*)malloc(entity->info.pads * sizeof(struct media_pad_desc));
+        links.links = (struct media_link_desc*)malloc(entity->info.links * sizeof(struct media_link_desc));
+
+        if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
+            ALOGE("Unable to enumerate pads and links (%s)", strerror(errno));
+            free(links.pads);
+            free(links.links);
+            return -errno;
+        }
+
+        for (i = 0; i < entity->info.pads; ++i) {
+            entity->pads[i].entity = entity;
+            entity->pads[i].index = links.pads[i].index;
+            entity->pads[i].flags = links.pads[i].flags;
+        }
+
+        for (i = 0; i < entity->info.links; ++i) {
+            struct media_link_desc *link = &links.links[i];
+            struct media_link *fwdlink;
+            struct media_link *backlink;
+            struct media_entity *source;
+            struct media_entity *sink;
+
+            source = exynos_media_get_entity_by_id(media, link->source.entity);
+            sink = exynos_media_get_entity_by_id(media, link->sink.entity);
+            if (source == NULL || sink == NULL) {
+                ALOGE("WARNING entity %u link %u from %u/%u to %u/%u is invalid!",
+                      id, i, link->source.entity,
+                      link->source.index,
+                      link->sink.entity,
+                      link->sink.index);
+                ret = -EINVAL;
+            } else {
+                fwdlink = __media_entity_add_link(source);
+                fwdlink->source = &source->pads[link->source.index];
+                fwdlink->sink = &sink->pads[link->sink.index];
+                fwdlink->flags = link->flags;
+
+                backlink = __media_entity_add_link(sink);
+                backlink->source = &source->pads[link->source.index];
+                backlink->sink = &sink->pads[link->sink.index];
+                backlink->flags = link->flags;
+
+                fwdlink->twin = backlink;
+                backlink->twin = fwdlink;
+            }
+        }
+
+        free(links.pads);
+        free(links.links);
+    }
+    return ret;
+}
+
+static int __media_get_devname_sysfs(struct media_entity *entity)
+{
+    //struct stat devstat;
+    char devname[32];
+    char sysname[32];
+    char target[1024];
+    char *p;
+    int ret;
+
+    sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
+        entity->info.v4l.minor);
+
+    ret = readlink(sysname, target, sizeof(target));
+    if (ret < 0)
+        return -errno;
+
+    target[ret] = '\0';
+    p = strrchr(target, '/');
+    if (p == NULL)
+        return -EINVAL;
+
+    sprintf(devname, "/tmp/%s", p + 1);
+
+    ret = mknod(devname, 0666 | S_IFCHR, MKDEV(81, entity->info.v4l.minor));
+    strcpy(entity->devname, devname);
+
+    return 0;
+}
+
+static int __media_get_media_fd(const char *filename, struct media_device *media)
+{
+    ssize_t num;
+    int media_node;
+    char *ptr;
+    char media_buf[6];
+
+    ALOGD("%s: %s", __func__, filename);
+
+    media->fd = open(filename, O_RDWR, 0);
+    if (media->fd < 0) {
+        ALOGE("Open sysfs media device failed, media->fd: %d", media->fd);
+        return -1;
+    }
+
+    ALOGD("%s: media->fd: %d", __func__, media->fd);
+
+    return media->fd;
+
+}
+
+static int __media_enum_entities(struct media_device *media)
+{
+    struct media_entity *entity, *temp_entity;
+    unsigned int size;
+    __u32 id;
+    int ret;
+
+    temp_entity = entity = (struct media_entity*)calloc(1,  sizeof(struct media_entity));
+    for (id = 0, ret = 0; ; id = entity->info.id) {
+        size = (media->entities_count + 1) * sizeof(*media->entities);
+        media->entities = (struct media_entity*)realloc(media->entities, size);
+
+        entity = &media->entities[media->entities_count];
+        memset(entity, 0, sizeof(*entity));
+        entity->fd = -1;
+        entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
+        entity->media = media;
+
+        ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
+
+        if (ret < 0) {
+            ret = errno != EINVAL ? -errno : 0;
+            break;
+        }
+
+        /* Number of links (for outbound links) plus number of pads (for
+         * inbound links) is a good safe initial estimate of the total
+         * number of links.
+         */
+        entity->max_links = entity->info.pads + entity->info.links;
+
+        entity->pads = (struct media_pad*)malloc(entity->info.pads * sizeof(*entity->pads));
+        entity->links = (struct media_link*)malloc(entity->max_links * sizeof(*entity->links));
+        if (entity->pads == NULL || entity->links == NULL) {
+            ret = -ENOMEM;
+            break;
+        }
+
+        media->entities_count++;
+
+        /* Find the corresponding device name. */
+        if (__media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
+            __media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+            continue;
+
+        /* Fall back to get the device name via sysfs */
+        __media_get_devname_sysfs(entity);
+        if (ret < 0)
+            ALOGE("media_get_devname failed");
+    }
+    free(temp_entity);
+
+    return ret;
+}
+
+static struct media_device *__media_open_debug(
+        const char *filename,
+        void (*debug_handler)(void *, ...),
+        void *debug_priv)
+{
+    struct media_device *media;
+    int ret;
+
+    media = (struct media_device *)calloc(1, sizeof(struct media_device));
+    if (media == NULL) {
+        ALOGE("media: %p", media);
+        return NULL;
+    }
+
+    __media_debug_set_handler(media, debug_handler, debug_priv);
+
+    ALOGD("%s: Opening media device %s", __func__, filename);
+    ALOGD("%s: media: %p", __func__, media);
+
+    media->fd = __media_get_media_fd(filename, media);
+    if (media->fd < 0) {
+        exynos_media_close(media);
+        ALOGE("failed __media_get_media_fd %s", filename);
+        return NULL;
+    }
+
+    ALOGD("%s: media->fd: %d", __func__, media->fd);
+    ret = __media_enum_entities(media);
+
+    if (ret < 0) {
+        ALOGE("Unable to enumerate entities for device %s (%s)", filename, strerror(-ret));
+        exynos_media_close(media);
+        return NULL;
+    }
+
+    ALOGD("%s: Found %u entities", __func__, media->entities_count);
+    ALOGD("%s: Enumerating pads and links", __func__);
+
+    ret = __media_enum_links(media);
+    if (ret < 0) {
+        ALOGE("Unable to enumerate pads and links for device %s", filename);
+        exynos_media_close(media);
+        return NULL;
+    }
+
+    return media;
+}
+
+/**
+ * @brief Open a media device.
+ * @param filename - name (including path) of the device node.
+ *
+ * Open the media device referenced by @a filename and enumerate entities, pads and
+ * links.
+ *
+ * @return A pointer to a newly allocated media_device structure instance on
+ * success and NULL on failure. The returned pointer must be freed with
+ * exynos_media_close when the device isn't needed anymore.
+ */
+struct media_device *exynos_media_open(const char *filename)
+{
+    return __media_open_debug(filename, (void (*)(void *, ...))fprintf, stdout);
+}
+
+/**
+ * @brief Close a media device.
+ * @param media - device instance.
+ *
+ * Close the @a media device instance and free allocated resources. Access to the
+ * device instance is forbidden after this function returns.
+ */
+void exynos_media_close(struct media_device *media)
+{
+    unsigned int i;
+
+    if (media->fd != -1)
+        close(media->fd);
+
+    for (i = 0; i < media->entities_count; ++i) {
+        struct media_entity *entity = &media->entities[i];
+
+        free(entity->pads);
+        free(entity->links);
+        if (entity->fd != -1)
+            close(entity->fd);
+    }
+
+    free(media->entities);
+    free(media);
+}
+
+/**
+ * @brief Locate the pad at the other end of a link.
+ * @param pad - sink pad at one end of the link.
+ *
+ * Locate the source pad connected to @a pad through an enabled link. As only one
+ * link connected to a sink pad can be enabled at a time, the connected source
+ * pad is guaranteed to be unique.
+ *
+ * @return A pointer to the connected source pad, or NULL if all links connected
+ * to @a pad are disabled. Return NULL also if @a pad is not a sink pad.
+ */
+struct media_pad *exynos_media_entity_remote_source(struct media_pad *pad)
+{
+    unsigned int i;
+
+    if (!(pad->flags & MEDIA_PAD_FL_SINK))
+        return NULL;
+
+    for (i = 0; i < pad->entity->num_links; ++i) {
+        struct media_link *link = &pad->entity->links[i];
+
+        if (!(link->flags & MEDIA_LNK_FL_ENABLED))
+            continue;
+
+        if (link->sink == pad)
+            return link->source;
+    }
+
+    return NULL;
+}
+
+/**
+ * @brief Find an entity by its name.
+ * @param media - media device.
+ * @param name - entity name.
+ * @param length - size of @a name.
+ *
+ * Search for an entity with a name equal to @a name.
+ *
+ * @return A pointer to the entity if found, or NULL otherwise.
+ */
+struct media_entity *exynos_media_get_entity_by_name(struct media_device *media,
+                          const char *name, size_t length)
+{
+    unsigned int i;
+    struct media_entity *entity;
+
+    for (i = 0; i < media->entities_count; ++i) {
+        entity = &media->entities[i];
+
+        if (strncmp(entity->info.name, name, length) == 0)
+            return entity;
+    }
+
+    return NULL;
+}
+
+/**
+ * @brief Find an entity by its ID.
+ * @param media - media device.
+ * @param id - entity ID.
+ *
+ * Search for an entity with an ID equal to @a id.
+ *
+ * @return A pointer to the entity if found, or NULL otherwise.
+ */
+struct media_entity *exynos_media_get_entity_by_id(struct media_device *media,
+                        __u32 id)
+{
+    unsigned int i;
+
+    for (i = 0; i < media->entities_count; ++i) {
+        struct media_entity *entity = &media->entities[i];
+
+        if (entity->info.id == id)
+            return entity;
+    }
+
+    return NULL;
+}
+
+/**
+ * @brief Configure a link.
+ * @param media - media device.
+ * @param source - source pad at the link origin.
+ * @param sink - sink pad at the link target.
+ * @param flags - configuration flags.
+ *
+ * Locate the link between @a source and @a sink, and configure it by applying
+ * the new @a flags.
+ *
+ * Only the MEDIA_LINK_FLAG_ENABLED flag is writable.
+ *
+ * @return 0 on success, -1 on failure:
+ *       -ENOENT: link not found
+ *       - other error codes returned by MEDIA_IOC_SETUP_LINK
+ */
+int exynos_media_setup_link(struct media_device *media,
+             struct media_pad *source,
+             struct media_pad *sink,
+             __u32 flags)
+{
+    struct media_link *link;
+    struct media_link_desc ulink;
+    unsigned int i;
+    int ret;
+
+    for (i = 0; i < source->entity->num_links; i++) {
+        link = &source->entity->links[i];
+
+        if (link->source->entity == source->entity &&
+            link->source->index == source->index &&
+            link->sink->entity == sink->entity &&
+            link->sink->index == sink->index)
+            break;
+    }
+
+    if (i == source->entity->num_links) {
+        ALOGE("Link not found");
+        return -ENOENT;
+    }
+
+    /* source pad */
+    ulink.source.entity = source->entity->info.id;
+    ulink.source.index = source->index;
+    ulink.source.flags = MEDIA_PAD_FL_SOURCE;
+
+    /* sink pad */
+    ulink.sink.entity = sink->entity->info.id;
+    ulink.sink.index = sink->index;
+    ulink.sink.flags = MEDIA_PAD_FL_SINK;
+
+    ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
+
+    ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
+    if (ret == -1) {
+        ALOGE("Unable to setup link (%s)", strerror(errno));
+        return -errno;
+    }
+
+    link->flags = ulink.flags;
+    link->twin->flags = ulink.flags;
+    return 0;
+}
+
+/**
+ * @brief Reset all links to the disabled state.
+ * @param media - media device.
+ *
+ * Disable all links in the media device. This function is usually used after
+ * opening a media device to reset all links to a known state.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_media_reset_links(struct media_device *media)
+{
+    unsigned int i, j;
+    int ret;
+
+    for (i = 0; i < media->entities_count; ++i) {
+        struct media_entity *entity = &media->entities[i];
+
+        for (j = 0; j < entity->num_links; j++) {
+            struct media_link *link = &entity->links[j];
+
+            if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
+                link->source->entity != entity)
+                continue;
+
+            ret = exynos_media_setup_link(media, link->source, link->sink,
+                           link->flags & ~MEDIA_LNK_FL_ENABLED);
+            if (ret < 0)
+                return ret;
+        }
+    }
+
+    return 0;
+}
+
+#ifdef HAVE_LIBUDEV
+
+#include <libudev.h>
+
+static inline int __media_udev_open(struct udev **udev)
+{
+    *udev = udev_new();
+    if (*udev == NULL)
+        return -ENOMEM;
+    return 0;
+}
+
+static inline void __media_udev_close(struct udev *udev)
+{
+    if (udev != NULL)
+        udev_unref(udev);
+}
+
+static int __media_get_devname_udev(struct udev *udev,
+        struct media_entity *entity)
+{
+    struct udev_device *device;
+    dev_t devnum;
+    const char *p;
+    int ret = -ENODEV;
+
+    if (udev == NULL)
+        return -EINVAL;
+
+    devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
+    ALOGE("looking up device: %u:%u",
+          major(devnum), minor(devnum));
+    device = udev_device_new_from_devnum(udev, 'c', devnum);
+    if (device) {
+        p = udev_device_get_devnode(device);
+        if (p) {
+            strncpy(entity->devname, p, sizeof(entity->devname));
+            entity->devname[sizeof(entity->devname) - 1] = '\0';
+        }
+        ret = 0;
+    }
+
+    udev_device_unref(device);
+
+    return ret;
+}
+
+#else    /* HAVE_LIBUDEV */
+
+struct udev;
+
+static inline int __media_udev_open(struct udev **udev) { return 0; }
+
+static inline void __media_udev_close(struct udev *udev) { }
+
+static inline int __media_get_devname_udev(struct udev *udev,
+        struct media_entity *entity)
+{
+    return -ENOTSUP;
+}
+
+#endif    /* HAVE_LIBUDEV */
+
+/**
+ * @brief Parse string to a pad on the media device.
+ * @param media - media device.
+ * @param p - input string
+ * @param endp - pointer to string where parsing ended
+ *
+ * Parse NULL terminated string describing a pad and return its struct
+ * media_pad instance.
+ *
+ * @return Pointer to struct media_pad on success, NULL on failure.
+ */
+struct media_pad *exynos_media_parse_pad(struct media_device *media,
+                  const char *p, char **endp)
+{
+    unsigned int entity_id, pad;
+    struct media_entity *entity;
+    char *end;
+
+    for (; isspace(*p); ++p);
+
+    if (*p == '"') {
+        for (end = (char *)p + 1; *end && *end != '"'; ++end);
+        if (*end != '"')
+            return NULL;
+
+        entity = exynos_media_get_entity_by_name(media, p + 1, end - p - 1);
+        if (entity == NULL)
+            return NULL;
+
+        ++end;
+    } else {
+        entity_id = strtoul(p, &end, 10);
+        entity = exynos_media_get_entity_by_id(media, entity_id);
+        if (entity == NULL)
+            return NULL;
+    }
+    for (; isspace(*end); ++end);
+
+    if (*end != ':')
+        return NULL;
+    for (p = end + 1; isspace(*p); ++p);
+
+    pad = strtoul(p, &end, 10);
+    for (p = end; isspace(*p); ++p);
+
+    if (pad >= entity->info.pads)
+        return NULL;
+
+    for (p = end; isspace(*p); ++p);
+    if (endp)
+        *endp = (char *)p;
+
+    return &entity->pads[pad];
+}
+
+/**
+ * @brief Parse string to a link on the media device.
+ * @param media - media device.
+ * @param p - input string
+ * @param endp - pointer to p where parsing ended
+ *
+ * Parse NULL terminated string p describing a link and return its struct
+ * media_link instance.
+ *
+ * @return Pointer to struct media_link on success, NULL on failure.
+ */
+struct media_link *exynos_media_parse_link(
+        struct media_device *media,
+        const char *p,
+        char **endp)
+{
+    struct media_link *link;
+    struct media_pad *source;
+    struct media_pad *sink;
+    unsigned int i;
+    char *end;
+
+    source = exynos_media_parse_pad(media, p, &end);
+    if (source == NULL)
+        return NULL;
+
+    if (end[0] != '-' || end[1] != '>')
+        return NULL;
+    p = end + 2;
+
+    sink = exynos_media_parse_pad(media, p, &end);
+    if (sink == NULL)
+        return NULL;
+
+    *endp = end;
+
+    for (i = 0; i < source->entity->num_links; i++) {
+        link = &source->entity->links[i];
+
+        if (link->source == source && link->sink == sink)
+            return link;
+    }
+
+    return NULL;
+}
+
+/**
+ * @brief Parse string to a link on the media device and set it up.
+ * @param media - media device.
+ * @param p - input string
+ *
+ * Parse NULL terminated string p describing a link and its configuration
+ * and configure the link.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_media_parse_setup_link(
+        struct media_device *media,
+        const char *p,
+        char **endp)
+{
+    struct media_link *link;
+    __u32 flags;
+    char *end;
+
+    link = exynos_media_parse_link(media, p, &end);
+    if (link == NULL) {
+        ALOGE("Unable to parse link");
+        return -EINVAL;
+    }
+
+    p = end;
+    if (*p++ != '[') {
+        ALOGE("Unable to parse link flags");
+        return -EINVAL;
+    }
+
+    flags = strtoul(p, &end, 10);
+    for (p = end; isspace(*p); p++);
+    if (*p++ != ']') {
+        ALOGE("Unable to parse link flags");
+        return -EINVAL;
+    }
+
+    for (; isspace(*p); p++);
+    *endp = (char *)p;
+
+    ALOGD("%s: Setting up link %u:%u -> %u:%u [%u]", __func__,
+          link->source->entity->info.id, link->source->index,
+          link->sink->entity->info.id, link->sink->index,
+          flags);
+
+    return exynos_media_setup_link(media, link->source, link->sink, flags);
+}
+
+/**
+ * @brief Parse string to link(s) on the media device and set it up.
+ * @param media - media device.
+ * @param p - input string
+ *
+ * Parse NULL terminated string p describing link(s) separated by
+ * commas (,) and configure the link(s).
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_media_parse_setup_links(struct media_device *media, const char *p)
+{
+    char *end;
+    int ret;
+
+    do {
+        ret = exynos_media_parse_setup_link(media, p, &end);
+        if (ret < 0)
+            return ret;
+
+        p = end + 1;
+    } while (*end == ',');
+
+    return *end ? -EINVAL : 0;
+}
diff --git a/libv4l2/exynos_subdev.c b/libv4l2/exynos_subdev.c
new file mode 100644 (file)
index 0000000..54b6e74
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*!
+ * \file      exynos_subdev.c
+ * \brief     source file for libv4l2
+ * \author    Jinsung Yang (jsgood.yang@samsung.com)
+ * \author    Sangwoo Park (sw5771.park@samsung.com)
+ * \date      2012/01/17
+ *
+ * <b>Revision History: </b>
+ * - 2012/01/17: Jinsung Yang (jsgood.yang@samsung.com) \n
+ *   Initial version
+ *
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include "exynos_v4l2.h"
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "libexynosv4l2-subdev"
+#include <utils/Log.h>
+
+#define SUBDEV_MINOR_MAX 191
+
+static int __subdev_open(const char *filename, int oflag, va_list ap)
+{
+    mode_t mode = 0;
+    int fd;
+
+    if (oflag & O_CREAT)
+        mode = va_arg(ap, int);
+
+    fd = open(filename, oflag, mode);
+
+    return fd;
+}
+
+int exynos_subdev_open(const char *filename, int oflag, ...)
+{
+    va_list ap;
+    int fd;
+
+    va_start(ap, oflag);
+    fd = __subdev_open(filename, oflag, ap);
+    va_end(ap);
+
+    return fd;
+}
+
+int exynos_subdev_open_devname(const char *devname, int oflag, ...)
+{
+    bool found = false;
+    int fd = -1;
+    struct stat s;
+    va_list ap;
+    FILE *stream_fd;
+    char filename[64], name[64];
+    int minor, size, i = 0;
+
+    do {
+        if (i > (SUBDEV_MINOR_MAX - 128))
+            break;
+
+        /* video device node */
+        sprintf(filename, "/dev/v4l-subdev%d", i++);
+
+        /* if the node is video device */
+        if ((lstat(filename, &s) == 0) && S_ISCHR(s.st_mode) &&
+                ((int)((unsigned short)(s.st_rdev) >> 8) == 81)) {
+            minor = (int)((unsigned short)(s.st_rdev & 0x3f));
+            ALOGD("try node: %s, minor: %d", filename, minor);
+            /* open sysfs entry */
+            sprintf(filename, "/sys/class/video4linux/v4l-subdev%d/name", minor);
+            stream_fd = fopen(filename, "r");
+            if (stream_fd == NULL) {
+                ALOGE("failed to open sysfs entry for subdev");
+                continue;   /* try next */
+            }
+
+            /* read sysfs entry for device name */
+            size = (int)fgets(name, sizeof(name), stream_fd);
+            fclose(stream_fd);
+
+            /* check read size */
+            if (size == 0) {
+                ALOGE("failed to read sysfs entry for subdev");
+            } else {
+                /* matched */
+                if (strncmp(name, devname, strlen(devname)) == 0) {
+                    ALOGI("node found for device %s: /dev/v4l-subdev%d", devname, minor);
+                    found = true;
+                }
+            }
+        }
+    } while (found == false);
+
+    if (found) {
+        sprintf(filename, "/dev/v4l-subdev%d", minor);
+        va_start(ap, oflag);
+        fd = __subdev_open(filename, oflag, ap);
+        va_end(ap);
+
+        if (fd > 0)
+            ALOGI("open subdev device %s", filename);
+        else
+            ALOGE("failed to open subdev device %s", filename);
+    } else {
+        ALOGE("no subdev device found");
+    }
+
+    return fd;
+}
+
+/**
+ * @brief enum frame size on a pad.
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_subdev_enum_frame_size(int fd, struct v4l2_subdev_frame_size_enum *frame_size_enum)
+{
+    int ret = -1;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!frame_size_enum) {
+        ALOGE("%s: frame_size_enum is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, frame_size_enum);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_SIZE");
+        return ret;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Retrieve the format on a pad.
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_subdev_g_fmt(int fd, struct v4l2_subdev_format *fmt)
+{
+    int ret = -1;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!fmt) {
+        ALOGE("%s: fmt is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_SUBDEV_G_FMT, fmt);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FMT");
+        return ret;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Set the format on a pad.
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_subdev_s_fmt(int fd, struct v4l2_subdev_format *fmt)
+{
+    int ret = -1;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!fmt) {
+        ALOGE("%s: fmt is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_SUBDEV_S_FMT, fmt);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FMT");
+        return ret;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Retrieve the crop rectangle on a pad.
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_subdev_g_crop(int fd, struct v4l2_subdev_crop *crop)
+{
+    int ret = -1;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!crop) {
+        ALOGE("%s: crop is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_SUBDEV_G_CROP, crop);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_CROP");
+        return ret;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Set the crop rectangle on a pad.
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_subdev_s_crop(int fd, struct v4l2_subdev_crop *crop)
+{
+    int ret = -1;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!crop) {
+        ALOGE("%s: crop is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_SUBDEV_S_CROP, crop);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_CROP");
+        return ret;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Retrieve the frame interval on a sub-device.
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_subdev_enum_frame_interval(int fd, struct v4l2_subdev_frame_interval_enum *frame_internval_enum)
+{
+    int ret = -1;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!frame_internval_enum) {
+        ALOGE("%s: frame_internval_enum is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, frame_internval_enum);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL");
+        return ret;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Retrieve the frame interval on a sub-device.
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_subdev_g_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval)
+{
+    int ret = -1;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!frame_internval) {
+        ALOGE("%s: frame_internval is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, frame_internval);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_SUBDEV_G_FRAME_INTERVAL");
+        return ret;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief Set the frame interval on a sub-device.
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_subdev_s_frame_interval(int fd, struct v4l2_subdev_frame_interval *frame_internval)
+{
+    int ret = -1;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!frame_internval) {
+        ALOGE("%s: frame_internval is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, frame_internval);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_SUBDEV_S_FRAME_INTERVAL");
+        return ret;
+    }
+
+    return ret;
+}
+
+/**
+ * @brief enum mbus code
+ * @return 0 on success, or a negative error code on failure.
+ */
+int exynos_subdev_enum_mbus_code(int fd, struct v4l2_subdev_mbus_code_enum *mbus_code_enum)
+{
+    int ret = -1;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!mbus_code_enum) {
+        ALOGE("%s: mbus_code_enum is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, mbus_code_enum);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE");
+        return ret;
+    }
+
+    return ret;
+}
diff --git a/libv4l2/exynos_v4l2.c b/libv4l2/exynos_v4l2.c
new file mode 100644 (file)
index 0000000..c2b0131
--- /dev/null
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*!
+ * \file      exynos_v4l2.c
+ * \brief     source file for libv4l2
+ * \author    Jinsung Yang (jsgood.yang@samsung.com)
+ * \author    Sangwoo Park (sw5771.park@samsung.com)
+ * \date      2012/01/17
+ *
+ * <b>Revision History: </b>
+ * - 2012/01/17: Jinsung Yang (jsgood.yang@samsung.com) \n
+ *   Initial version
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include "exynos_v4l2.h"
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "libexynosv4l2"
+#include <utils/Log.h>
+#include "Exynos_log.h"
+
+#define VIDEODEV_MINOR_MAX 63
+
+//#define EXYNOS_V4L2_TRACE 0
+#ifdef EXYNOS_V4L2_TRACE
+#define Exynos_v4l2_In() Exynos_Log(EXYNOS_DEV_LOG_DEBUG, LOG_TAG, "%s In , Line: %d", __FUNCTION__, __LINE__)
+#define Exynos_v4l2_Out() Exynos_Log(EXYNOS_DEV_LOG_DEBUG, LOG_TAG, "%s Out , Line: %d", __FUNCTION__, __LINE__)
+#else
+#define Exynos_v4l2_In() ((void *)0)
+#define Exynos_v4l2_Out() ((void *)0)
+#endif
+
+static bool __v4l2_check_buf_type(enum v4l2_buf_type type)
+{
+    bool supported;
+
+    switch (type) {
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+    case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+        supported = true;
+        break;
+
+    default:
+        supported = (type >= V4L2_BUF_TYPE_PRIVATE) ? true : false;
+        break;
+    }
+
+    return supported;
+}
+
+static int __v4l2_open(const char *filename, int oflag, va_list ap)
+{
+    mode_t mode = 0;
+    int fd;
+
+    if (oflag & O_CREAT)
+        mode = va_arg(ap, int);
+
+    fd = open(filename, oflag, mode);
+
+    return fd;
+}
+
+int exynos_v4l2_open(const char *filename, int oflag, ...)
+{
+    va_list ap;
+    int fd;
+
+    Exynos_v4l2_In();
+
+    va_start(ap, oflag);
+    fd = __v4l2_open(filename, oflag, ap);
+    va_end(ap);
+
+    Exynos_v4l2_Out();
+
+    return fd;
+}
+
+int exynos_v4l2_open_devname(const char *devname, int oflag, ...)
+{
+    bool found = false;
+    int fd = -1;
+    struct stat s;
+    va_list ap;
+    FILE *stream_fd;
+    char filename[64], name[64];
+    int minor, size, i = 0;
+
+    Exynos_v4l2_In();
+
+    do {
+        if (i > VIDEODEV_MINOR_MAX)
+            break;
+
+        /* video device node */
+        sprintf(filename, "/dev/video%d", i++);
+
+        /* if the node is video device */
+        if ((lstat(filename, &s) == 0) && S_ISCHR(s.st_mode) &&
+                ((int)((unsigned short)(s.st_rdev) >> 8) == 81)) {
+            minor = (int)((unsigned short)(s.st_rdev & 0x3f));
+            ALOGD("try node: %s, minor: %d", filename, minor);
+            /* open sysfs entry */
+            sprintf(filename, "/sys/class/video4linux/video%d/name", minor);
+            stream_fd = fopen(filename, "r");
+            if (stream_fd == NULL) {
+                ALOGE("failed to open sysfs entry for videodev");
+                continue;   /* try next */
+            }
+
+            /* read sysfs entry for device name */
+            size = (int)fgets(name, sizeof(name), stream_fd);
+            fclose(stream_fd);
+
+            /* check read size */
+            if (size == 0) {
+                ALOGE("failed to read sysfs entry for videodev");
+            } else {
+                /* matched */
+                if (strncmp(name, devname, strlen(devname)) == 0) {
+                    ALOGI("node found for device %s: /dev/video%d", devname, minor);
+                    found = true;
+                }
+            }
+        }
+    } while (found == false);
+
+    if (found) {
+        sprintf(filename, "/dev/video%d", minor);
+        va_start(ap, oflag);
+        fd = __v4l2_open(filename, oflag, ap);
+        va_end(ap);
+
+        if (fd > 0)
+            ALOGI("open video device %s", filename);
+        else
+            ALOGE("failed to open video device %s", filename);
+    } else {
+        ALOGE("no video device found");
+    }
+
+    Exynos_v4l2_Out();
+
+    return fd;
+}
+
+int exynos_v4l2_close(int fd)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0)
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+    else
+        ret = close(fd);
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+bool exynos_v4l2_enuminput(int fd, int index, char *input_name_buf)
+{
+    int ret = -1;
+    struct v4l2_input input;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return NULL;
+    }
+
+    input.index = index;
+    ret = ioctl(fd, VIDIOC_ENUMINPUT, &input);
+    if (ret) {
+        ALOGE("%s: no matching index founds", __func__);
+        return false;
+    }
+
+    ALOGI("Name of input channel[%d] is %s", input.index, input.name);
+
+    strcpy(input_name_buf, (const char *)input.name);
+
+    Exynos_v4l2_Out();
+
+    return true;
+}
+
+int exynos_v4l2_s_input(int fd, int index)
+{
+    int ret = -1;
+    struct v4l2_input input;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    input.index = index;
+
+    ret = ioctl(fd, VIDIOC_S_INPUT, &input);
+    if (ret){
+        ALOGE("failed to ioctl: VIDIOC_S_INPUT (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+bool exynos_v4l2_querycap(int fd, unsigned int need_caps)
+{
+    struct v4l2_capability cap;
+    int ret;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return false;
+    }
+
+    if (!(need_caps & V4L2_CAP_VIDEO_CAPTURE) &&
+            !(need_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) &&
+            !(need_caps & V4L2_CAP_VIDEO_OUTPUT) &&
+            !(need_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE) &&
+            !(need_caps & V4L2_CAP_VIDEO_OVERLAY)) {
+        ALOGE("%s: unsupported capabilities", __func__);
+        return false;
+    }
+
+    memset(&cap, 0, sizeof(cap));
+
+    ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_QUERYCAP (%d - %s)", errno, strerror(errno));
+        return false;
+    }
+
+    if ((need_caps & cap.capabilities) != need_caps) {
+        ALOGE("%s: unsupported capabilities", __func__);
+        return false;
+    }
+
+    Exynos_v4l2_Out();
+
+    return true;
+}
+
+bool exynos_v4l2_enum_fmt(int fd, enum v4l2_buf_type type, unsigned int fmt)
+{
+    struct v4l2_fmtdesc fmtdesc;
+    int found = 0;
+
+    Exynos_v4l2_In();
+
+    fmtdesc.type = type;
+    fmtdesc.index = 0;
+
+    while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
+        if (fmtdesc.pixelformat == fmt) {
+            ALOGE("Passed fmt = %#x found pixel format[%d]: %s", fmt, fmtdesc.index, fmtdesc.description);
+            found = 1;
+            break;
+        }
+
+        fmtdesc.index++;
+    }
+
+    if (!found) {
+        ALOGE("%s: unsupported pixel format", __func__);
+        return false;
+    }
+
+    Exynos_v4l2_Out();
+
+    return true;
+}
+
+int exynos_v4l2_g_fmt(int fd, struct v4l2_format *fmt)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!fmt) {
+        ALOGE("%s: fmt is NULL", __func__);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(fmt->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_G_FMT, fmt);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_G_FMT (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+static int __v4l2_s_fmt(int fd, unsigned int request, struct v4l2_format *fmt)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!fmt) {
+        ALOGE("%s: fmt is NULL", __func__);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(fmt->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    } else {
+        ret = ioctl(fd, request, fmt);
+        if (ret) {
+            if (request == VIDIOC_TRY_FMT)
+                ALOGE("failed to ioctl: VIDIOC_TRY_FMT (%d - %s)", errno, strerror(errno));
+            else
+                ALOGE("failed to ioctl: VIDIOC_S_FMT (%d - %s)", errno, strerror(errno));
+
+            return ret;
+        }
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_try_fmt(int fd, struct v4l2_format *fmt)
+{
+    return __v4l2_s_fmt(fd, VIDIOC_TRY_FMT, fmt);
+}
+
+int exynos_v4l2_s_fmt(int fd, struct v4l2_format *fmt)
+{
+    return __v4l2_s_fmt(fd, VIDIOC_S_FMT, fmt);
+}
+
+int exynos_v4l2_reqbufs(int fd, struct v4l2_requestbuffers *req)
+{
+    int ret = -1;
+    unsigned int count;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!req) {
+        ALOGE("%s: req is NULL", __func__);
+        return ret;
+    }
+
+    if ((req->memory != V4L2_MEMORY_MMAP) &&
+       (req->memory != V4L2_MEMORY_USERPTR) &&
+       (req->memory != V4L2_MEMORY_DMABUF)) {
+        ALOGE("%s: unsupported memory type", __func__);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(req->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    count = req->count;
+
+    ret = ioctl(fd, VIDIOC_REQBUFS, req);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_REQBUFS (%d - %s)", ret, strerror(errno));
+        return ret;
+    }
+
+    if (count != req->count) {
+        ALOGW("number of buffers had been changed: %d => %d", count, req->count);
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_querybuf(int fd, struct v4l2_buffer *buf)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!buf) {
+        ALOGE("%s: buf is NULL", __func__);
+        return ret;
+    }
+
+    if ((buf->memory != V4L2_MEMORY_MMAP) &&
+       (buf->memory != V4L2_MEMORY_DMABUF)) {
+        ALOGE("%s: unsupported memory type", __func__);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(buf->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_QUERYBUF, buf);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_QUERYBUF (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_qbuf(int fd, struct v4l2_buffer *buf)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!buf) {
+        ALOGE("%s: buf is NULL", __func__);
+        return ret;
+    }
+
+    if ((buf->memory != V4L2_MEMORY_MMAP) &&
+       (buf->memory != V4L2_MEMORY_USERPTR) &&
+       (buf->memory != V4L2_MEMORY_DMABUF)) {
+        ALOGE("%s: unsupported memory type", __func__);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(buf->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_QBUF, buf);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_QBUF (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_dqbuf(int fd, struct v4l2_buffer *buf)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!buf) {
+        ALOGE("%s: buf is NULL", __func__);
+        return ret;
+    }
+
+    if ((buf->memory != V4L2_MEMORY_MMAP) &&
+       (buf->memory != V4L2_MEMORY_USERPTR) &&
+       (buf->memory != V4L2_MEMORY_DMABUF)) {
+        ALOGE("%s: unsupported memory type", __func__);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(buf->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_DQBUF, buf);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_DQBUF (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_streamon(int fd, enum v4l2_buf_type type)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_STREAMON, &type);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_STREAMON (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_streamoff(int fd, enum v4l2_buf_type type)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_STREAMOFF (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_cropcap(int fd, struct v4l2_cropcap *crop)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!crop) {
+        ALOGE("%s: crop is NULL", __func__);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(crop->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_CROPCAP, crop);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_CROPCAP (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_g_crop(int fd, struct v4l2_crop *crop)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!crop) {
+        ALOGE("%s: crop is NULL", __func__);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(crop->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_G_CROP, crop);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_G_CROP (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_s_crop(int fd, struct v4l2_crop *crop)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (!crop) {
+        ALOGE("%s: crop is NULL", __func__);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(crop->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_S_CROP, crop);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_S_CROP (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_g_ctrl(int fd, unsigned int id, int *value)
+{
+    int ret = -1;
+    struct v4l2_control ctrl;
+
+    Exynos_v4l2_In();
+
+    ctrl.id = id;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_G_CTRL, &ctrl);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_G_CTRL (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    *value = ctrl.value;
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_s_ctrl(int fd, unsigned int id, int value)
+{
+    int ret = -1;
+    struct v4l2_control ctrl;
+
+    Exynos_v4l2_In();
+
+    ctrl.id = id;
+    ctrl.value = value;
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_S_CTRL (%d)", errno);
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_g_parm(int fd, struct v4l2_streamparm *streamparm)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(streamparm->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_G_PARM, streamparm);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_G_PARM (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_s_parm(int fd, struct v4l2_streamparm *streamparm)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (__v4l2_check_buf_type(streamparm->type) == false) {
+        ALOGE("%s: unsupported buffer type", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_S_PARM, streamparm);
+    if (ret) {
+        ALOGE("failed to ioctl: VIDIOC_S_PARM (%d - %s)", errno, strerror(errno));
+        return ret;
+    }
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_g_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (ctrl == NULL) {
+        ALOGE("%s: ctrl is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_G_EXT_CTRLS, ctrl);
+    if (ret)
+        ALOGE("failed to ioctl: VIDIOC_G_EXT_CTRLS (%d - %s)", errno, strerror(errno));
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}
+
+int exynos_v4l2_s_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl)
+{
+    int ret = -1;
+
+    Exynos_v4l2_In();
+
+    if (fd < 0) {
+        ALOGE("%s: invalid fd: %d", __func__, fd);
+        return ret;
+    }
+
+    if (ctrl == NULL) {
+        ALOGE("%s: ctrl is NULL", __func__);
+        return ret;
+    }
+
+    ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, ctrl);
+    if (ret)
+        ALOGE("failed to ioctl: VIDIOC_S_EXT_CTRLS (%d - %s)", errno, strerror(errno));
+
+    Exynos_v4l2_Out();
+
+    return ret;
+}