--- /dev/null
+/*
+ * Common header of MARU Virtual Camera device.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _MARU_CAMERA_COMMON_H_
+#define _MARU_CAMERA_COMMON_H_
+
+#include "pci.h"
+#include <pthread.h>
+
+#define MARUCAM_MAX_PARAM 20
+
+/* must sync with GUEST camera_driver */
+#define MARUCAM_CMD_INIT 0x00
+#define MARUCAM_CMD_OPEN 0x04
+#define MARUCAM_CMD_CLOSE 0x08
+#define MARUCAM_CMD_ISSTREAM 0x0C
+#define MARUCAM_CMD_START_PREVIEW 0x10
+#define MARUCAM_CMD_STOP_PREVIEW 0x14
+#define MARUCAM_CMD_S_PARAM 0x18
+#define MARUCAM_CMD_G_PARAM 0x1C
+#define MARUCAM_CMD_ENUM_FMT 0x20
+#define MARUCAM_CMD_TRY_FMT 0x24
+#define MARUCAM_CMD_S_FMT 0x28
+#define MARUCAM_CMD_G_FMT 0x2C
+#define MARUCAM_CMD_QCTRL 0x30
+#define MARUCAM_CMD_S_CTRL 0x34
+#define MARUCAM_CMD_G_CTRL 0x38
+#define MARUCAM_CMD_ENUM_FSIZES 0x3C
+#define MARUCAM_CMD_ENUM_FINTV 0x40
+#define MARUCAM_CMD_S_DATA 0x44
+#define MARUCAM_CMD_G_DATA 0x48
+#define MARUCAM_CMD_CLRIRQ 0x4C
+#define MARUCAM_CMD_DATACLR 0x50
+#define MARUCAM_CMD_REQFRAME 0x54
+
+typedef struct MaruCamState MaruCamState;
+typedef struct MaruCamThreadInfo MaruCamThreadInfo;
+typedef struct MaruCamParam MaruCamParam;
+
+struct MaruCamParam {
+ uint32_t top;
+ uint32_t retVal;
+ uint32_t errCode;
+ uint32_t stack[MARUCAM_MAX_PARAM];
+};
+
+struct MaruCamThreadInfo {
+ MaruCamState* state;
+ MaruCamParam* param;
+
+ pthread_t thread_id;
+ pthread_cond_t thread_cond;
+ pthread_mutex_t mutex_lock;
+};
+
+struct MaruCamState {
+ PCIDevice dev;
+
+ void *vaddr; /* vram ptr */
+ uint32_t streamon;
+ uint32_t buf_size;
+ uint32_t req_frame;
+
+ MemoryRegion vram;
+ MemoryRegion mmio;
+
+ MaruCamThreadInfo *thread;
+};
+
+/* ----------------------------------------------------------------------------- */
+/* Fucntion prototype */
+/* ----------------------------------------------------------------------------- */
+void marucam_device_init(MaruCamState *state);
+void marucam_device_open(MaruCamState *state);
+void marucam_device_close(MaruCamState *state);
+void marucam_device_start_preview(MaruCamState *state);
+void marucam_device_stop_preview(MaruCamState *state);
+void marucam_device_s_param(MaruCamState *state);
+void marucam_device_g_param(MaruCamState *state);
+void marucam_device_s_fmt(MaruCamState *state);
+void marucam_device_g_fmt(MaruCamState *state);
+void marucam_device_try_fmt(MaruCamState *state);
+void marucam_device_enum_fmt(MaruCamState *state);
+void marucam_device_qctrl(MaruCamState *state);
+void marucam_device_s_ctrl(MaruCamState *state);
+void marucam_device_g_ctrl(MaruCamState *state);
+void marucam_device_enum_fsizes(MaruCamState *state);
+void marucam_device_enum_fintv(MaruCamState *state);
+
+
+#endif /* _MARU_CAMERA_COMMON_H_ */
--- /dev/null
+/*
+ * Common implementation of MARU Virtual Camera device by PCI bus.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+
+#include "qemu-common.h"
+#include "cpu-common.h"
+
+#include "pc.h"
+#include "pci.h"
+#include "pci_ids.h"
+
+#include "maru_camera_common.h"
+#include "tizen/src/debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(tizen, camera_pci);
+
+#define MARU_PCI_CAMERA_DEVICE_NAME "maru_camera_pci"
+
+#define MARUCAM_MEM_SIZE (4 * 1024 * 1024) // 4MB
+#define MARUCAM_REG_SIZE (256) // 64 * 4
+
+/*
+ * I/O functions
+ */
+static inline uint32_t marucam_mmio_read(void *opaque, target_phys_addr_t offset)
+{
+ uint32_t ret = 0;
+ MaruCamState *state = (MaruCamState*)opaque;
+
+ switch (offset & 0xFF) {
+ case MARUCAM_CMD_ISSTREAM:
+ pthread_mutex_lock(&state->thread->mutex_lock);
+ ret = state->streamon;
+ pthread_mutex_unlock(&state->thread->mutex_lock);
+ break;
+ case MARUCAM_CMD_G_DATA:
+ ret = state->thread->param->stack[state->thread->param->top++];
+ break;
+ case MARUCAM_CMD_OPEN:
+ case MARUCAM_CMD_CLOSE:
+ case MARUCAM_CMD_START_PREVIEW:
+ case MARUCAM_CMD_STOP_PREVIEW:
+ case MARUCAM_CMD_S_PARAM:
+ case MARUCAM_CMD_G_PARAM:
+ case MARUCAM_CMD_ENUM_FMT:
+ case MARUCAM_CMD_TRY_FMT:
+ case MARUCAM_CMD_S_FMT:
+ case MARUCAM_CMD_G_FMT:
+ case MARUCAM_CMD_QCTRL:
+ case MARUCAM_CMD_S_CTRL:
+ case MARUCAM_CMD_G_CTRL:
+ case MARUCAM_CMD_ENUM_FSIZES:
+ case MARUCAM_CMD_ENUM_FINTV:
+ ret = state->thread->param->errCode;
+ state->thread->param->errCode = 0;
+ break;
+ ldefault:
+ WARN("Not supported command!!\n");
+ break;
+ }
+ return ret;
+}
+
+static inline void marucam_mmio_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ MaruCamState *state = (MaruCamState*)opaque;
+
+ switch(offset & 0xFF) {
+ case MARUCAM_CMD_OPEN:
+ marucam_device_open(state);
+ break;
+ case MARUCAM_CMD_CLOSE:
+ marucam_device_close(state);
+ break;
+ case MARUCAM_CMD_START_PREVIEW:
+ marucam_device_start_preview(state);
+ break;
+ case MARUCAM_CMD_STOP_PREVIEW:
+ marucam_device_stop_preview(state);
+ break;
+ case MARUCAM_CMD_S_PARAM:
+ marucam_device_s_param(state);
+ break;
+ case MARUCAM_CMD_G_PARAM:
+ marucam_device_g_param(state);
+ break;
+ case MARUCAM_CMD_ENUM_FMT:
+ marucam_device_enum_fmt(state);
+ break;
+ case MARUCAM_CMD_TRY_FMT:
+ marucam_device_try_fmt(state);
+ break;
+ case MARUCAM_CMD_S_FMT:
+ marucam_device_s_fmt(state);
+ break;
+ case MARUCAM_CMD_G_FMT:
+ marucam_device_g_fmt(state);
+ break;
+ case MARUCAM_CMD_QCTRL:
+ marucam_device_qctrl(state);
+ break;
+ case MARUCAM_CMD_S_CTRL:
+ marucam_device_s_ctrl(state);
+ break;
+ case MARUCAM_CMD_G_CTRL:
+ marucam_device_g_ctrl(state);
+ break;
+ case MARUCAM_CMD_ENUM_FSIZES:
+ marucam_device_enum_fsizes(state);
+ break;
+ case MARUCAM_CMD_ENUM_FINTV:
+ marucam_device_enum_fintv(state);
+ break;
+ case MARUCAM_CMD_S_DATA:
+ state->thread->param->stack[state->thread->param->top++] = value;
+ break;
+ case MARUCAM_CMD_DATACLR:
+ memset(state->thread->param, 0, sizeof(MaruCamParam));
+ break;
+ case MARUCAM_CMD_CLRIRQ:
+ qemu_irq_lower(state->dev.irq[2]);
+ break;
+ case MARUCAM_CMD_REQFRAME:
+ pthread_mutex_lock(&state->thread->mutex_lock);
+ state->req_frame = value + 1;
+ pthread_mutex_unlock(&state->thread->mutex_lock);
+ break;
+ default:
+ WARN("Not supported command!!\n");
+ break;
+ }
+}
+
+static const MemoryRegionOps maru_camera_mmio_ops = {
+ .old_mmio = {
+ .read = {
+ marucam_mmio_read,
+ marucam_mmio_read,
+ marucam_mmio_read,
+ },
+ .write = {
+ marucam_mmio_write,
+ marucam_mmio_write,
+ marucam_mmio_write,
+ },
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/*
+ * Initialization function
+ */
+static int marucam_initfn(PCIDevice *dev)
+{
+ MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev);
+ uint8_t *pci_conf = s->dev.config;
+ MaruCamThreadInfo *thread;
+ MaruCamParam *param;
+
+ pci_config_set_interrupt_pin(pci_conf, 0x03);
+
+ memory_region_init_ram(&s->vram, NULL, "marucamera.ram", MARUCAM_MEM_SIZE);
+ s->vaddr = memory_region_get_ram_ptr(&s->vram);
+
+ memory_region_init_io (&s->mmio, &maru_camera_mmio_ops, s, "maru-camera-mmio", MARUCAM_REG_SIZE);
+ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+ pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+
+ /* for worker thread */
+ thread = (MaruCamThreadInfo*)g_malloc0(sizeof(MaruCamThreadInfo));
+ param = (MaruCamParam*)g_malloc0(sizeof(MaruCamParam));
+
+ thread->state = s;
+ thread->param = param;
+ s->thread = thread;
+
+ marucam_device_init(s);
+
+ return 0;
+}
+
+/*
+ * Termination function
+ */
+static int marucam_exitfn(PCIBus *bus)
+{
+ MaruCamState *s = DO_UPCAST(MaruCamState, dev, dev);
+
+ g_free((gpointer)s->thread->param);
+ g_free((gpointer)s->thread);
+
+ memory_region_destroy (&s->vram);
+ memory_region_destroy (&s->mmio);
+ return 0;
+}
+
+int maru_camera_pci_init(PCIBus *bus)
+{
+ INFO("[%s] camera device was initialized.\n", __func__);
+ pci_create_simple(bus, -1, MARU_PCI_CAMERA_DEVICE_NAME);
+ return 0;
+}
+
+static PCIDeviceInfo maru_camera_info = {
+ .qdev.name = MARU_PCI_CAMERA_DEVICE_NAME,
+ .qdev.desc = "MARU Virtual Camera device for Tizen emulator",
+ .qdev.size = sizeof(MaruCamState),
+ .no_hotplug = 1,
+ .init = marucam_initfn,
+ .exit = marucam_exitfn,
+ .vendor_id = PCI_VENDOR_ID_TIZEN,
+ .device_id = PCI_DEVICE_ID_VIRTUAL_CAMERA,
+ .class_id = PCI_CLASS_MULTIMEDIA_OTHER,
+};
+
+static void maru_camera_pci_register(void)
+{
+ pci_qdev_register(&maru_camera_info);
+}
+
+device_init(maru_camera_pci_register);
--- /dev/null
+/*
+ * Implementation of MARU Virtual Camera device by PCI bus on Linux.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu-common.h"
+#include "maru_camera_common.h"
+#include "pci.h"
+#include "kvm.h"
+#include "tizen/src/debug_ch.h"
+
+#include <linux/videodev2.h>
+
+#include <libv4l2.h>
+#include <libv4lconvert.h>
+
+MULTI_DEBUG_CHANNEL(tizen, camera_linux);
+
+static int v4l2_fd;
+static int convert_trial;
+
+static struct v4l2_format dst_fmt;
+
+static int xioctl(int fd, int req, void *arg)
+{
+ int r;
+
+ do {
+ r = v4l2_ioctl(fd, req, arg);
+ } while ( r < 0 && errno == EINTR);
+
+ return r;
+}
+
+#define MARUCAM_CTRL_VALUE_MAX 20
+#define MARUCAM_CTRL_VALUE_MIN 1
+#define MARUCAM_CTRL_VALUE_MID 10
+#define MARUCAM_CTRL_VALUE_STEP 1
+
+struct marucam_qctrl {
+ uint32_t id;
+ uint32_t hit;
+ int32_t min;
+ int32_t max;
+ int32_t step;
+ int32_t init_val;
+};
+
+static struct marucam_qctrl qctrl_tbl[] = {
+ { V4L2_CID_BRIGHTNESS, 0, },
+ { V4L2_CID_CONTRAST, 0, },
+ { V4L2_CID_SATURATION,0, },
+ { V4L2_CID_SHARPNESS, 0, },
+};
+
+static void marucam_reset_controls(void)
+{
+ uint32_t i;
+ for (i = 0; i < ARRAY_SIZE(qctrl_tbl); i++) {
+ if (qctrl_tbl[i].hit) {
+ struct v4l2_control ctrl = {0,};
+ ctrl.id = qctrl_tbl[i].id;
+ ctrl.value = qctrl_tbl[i].init_val;
+ if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {
+ ERR("failed to set video control value while reset values : %s\n", strerror(errno));
+ }
+ }
+ }
+}
+
+static int32_t value_convert_from_guest(int32_t min, int32_t max, int32_t value)
+{
+ double rate = 0.0;
+ int32_t dist = 0, ret = 0;
+
+ dist = max - min;
+
+ if (dist < MARUCAM_CTRL_VALUE_MAX) {
+ rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+ ret = min + (int32_t)(value / rate);
+ } else {
+ rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+ ret = min + (int32_t)(rate * value);
+ }
+ return ret;
+}
+
+static int32_t value_convert_to_guest(int32_t min, int32_t max, int32_t value)
+{
+ double rate = 0.0;
+ int32_t dist = 0, ret = 0;
+
+ dist = max - min;
+
+ if (dist < MARUCAM_CTRL_VALUE_MAX) {
+ rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+ ret = (int32_t)((double)(value - min) * rate);
+ } else {
+ rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+ ret = (int32_t)((double)(value - min) / rate);
+ }
+
+ return ret;
+}
+
+static int __v4l2_grab(MaruCamState *state)
+{
+ fd_set fds;
+ static uint32_t index = 0;
+ struct timeval tv;
+ void *buf;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(v4l2_fd, &fds);
+
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+
+ ret = select(v4l2_fd + 1, &fds, NULL, NULL, &tv);
+ if ( ret < 0) {
+ if (errno == EINTR)
+ return 0;
+ ERR("select : %s\n", strerror(errno));
+ return -1;
+ }
+ if (!ret) {
+ WARN("Timed out\n");
+ return 0;
+ }
+
+ if (!v4l2_fd) {
+ WARN("file descriptor is closed or not opened \n");
+ return -1;
+ }
+
+ buf = state->vaddr + (state->buf_size * index);
+ ret = v4l2_read(v4l2_fd, buf, state->buf_size);
+ if ( ret < 0) {
+ switch (errno) {
+ case EINVAL:
+ case ENOMEM:
+ ERR("v4l2_read failed : %s\n", strerror(errno));
+ return -1;
+ case EAGAIN:
+ case EIO:
+ case EINTR:
+ default:
+ if (convert_trial-- == -1) {
+ ERR("Try count for v4l2_read is exceeded\n");
+ return -1;
+ }
+ return 0;
+ }
+ }
+
+ index = !index;
+
+ pthread_mutex_lock(&state->thread->mutex_lock);
+ if (state->streamon) {
+ if (state->req_frame) {
+ qemu_irq_raise(state->dev.irq[2]);
+ state->req_frame = 0;
+ }
+ ret = 1;
+ } else {
+ ret = -1;
+ }
+ pthread_mutex_unlock(&state->thread->mutex_lock);
+
+ return ret;
+}
+
+// Worker thread
+static void *marucam_worker_thread(void *thread_param)
+{
+ MaruCamThreadInfo* thread = (MaruCamThreadInfo*)thread_param;
+
+wait_worker_thread:
+ pthread_mutex_lock(&thread->mutex_lock);
+ thread->state->streamon = 0;
+ convert_trial = 10;
+ pthread_cond_wait(&thread->thread_cond, &thread->mutex_lock);
+ pthread_mutex_unlock(&thread->mutex_lock);
+ INFO("Streaming on ......\n");
+
+ while (1)
+ {
+ pthread_mutex_lock(&thread->mutex_lock);
+ if (thread->state->streamon) {
+ pthread_mutex_unlock(&thread->mutex_lock);
+ if (__v4l2_grab(thread->state) < 0) {
+ INFO("...... Streaming off\n");
+ goto wait_worker_thread;
+ }
+ } else {
+ pthread_mutex_unlock(&thread->mutex_lock);
+ goto wait_worker_thread;
+ }
+ }
+ pthread_exit(0);
+}
+
+void marucam_device_init(MaruCamState* state)
+{
+ MaruCamThreadInfo *thread = state->thread;
+
+ if (pthread_cond_init(&thread->thread_cond, NULL)) {
+ ERR("failed to initialize thread condition\n");
+ exit(61);
+ }
+ if (pthread_mutex_init(&thread->mutex_lock, NULL)) {
+ ERR("failed to initialize mutex\n");
+ exit(62);
+ }
+
+ if (pthread_create(&thread->thread_id, NULL, marucam_worker_thread, (void*)thread) != 0) {
+ perror("failed to create a worker thread for webcam connection\n");
+ exit(63);
+ }
+}
+
+// MARUCAM_CMD_OPEN
+void marucam_device_open(MaruCamState* state)
+{
+ struct v4l2_capability cap;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ v4l2_fd = v4l2_open("/dev/video0", O_RDWR | O_NONBLOCK);
+ if (v4l2_fd < 0) {
+ ERR("v4l2 device open failed.(/dev/video0)\n");
+ param->errCode = EINVAL;
+ return;
+ }
+ if (xioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap) < 0) {
+ ERR("Could not qeury video capabilities\n");
+ v4l2_close(v4l2_fd);
+ param->errCode = EINVAL;
+ return;
+ }
+ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
+ !(cap.capabilities & V4L2_CAP_STREAMING)) {
+ ERR("Not supported video driver.\n");
+ v4l2_close(v4l2_fd);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ memset(&dst_fmt, 0, sizeof(dst_fmt));
+ INFO("Opened\n");
+}
+
+// MARUCAM_CMD_START_PREVIEW
+void marucam_device_start_preview(MaruCamState* state)
+{
+ pthread_mutex_lock(&state->thread->mutex_lock);
+ state->streamon = 1;
+ state->buf_size = dst_fmt.fmt.pix.sizeimage;
+ if (pthread_cond_signal(&state->thread->thread_cond))
+ ERR("failed to send a signal to the worker thread\n");
+ pthread_mutex_unlock(&state->thread->mutex_lock);
+}
+
+// MARUCAM_CMD_STOP_PREVIEW
+void marucam_device_stop_preview(MaruCamState* state)
+{
+ pthread_mutex_lock(&state->thread->mutex_lock);
+ state->streamon = 0;
+ state->buf_size = 0;
+ pthread_mutex_unlock(&state->thread->mutex_lock);
+ sleep(0);
+}
+
+void marucam_device_s_param(MaruCamState* state)
+{
+ struct v4l2_streamparm sp;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&sp, 0, sizeof(struct v4l2_streamparm));
+ sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ sp.parm.capture.timeperframe.numerator = param->stack[0];
+ sp.parm.capture.timeperframe.denominator = param->stack[1];
+
+ if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) {
+ ERR("failed to set FPS: %s\n", strerror(errno));
+ param->errCode = errno;
+ }
+}
+
+void marucam_device_g_param(MaruCamState* state)
+{
+ struct v4l2_streamparm sp;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&sp, 0, sizeof(struct v4l2_streamparm));
+ sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (xioctl(v4l2_fd, VIDIOC_G_PARM, &sp) < 0) {
+ ERR("failed to get FPS: %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+ param->stack[0] = sp.parm.capture.capability;
+ param->stack[1] = sp.parm.capture.timeperframe.numerator;
+ param->stack[2] = sp.parm.capture.timeperframe.denominator;
+}
+
+void marucam_device_s_fmt(MaruCamState* state)
+{
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&dst_fmt, 0, sizeof(struct v4l2_format));
+ dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_fmt.fmt.pix.width = param->stack[0];
+ dst_fmt.fmt.pix.height = param->stack[1];
+ dst_fmt.fmt.pix.pixelformat = param->stack[2];
+ dst_fmt.fmt.pix.field = param->stack[3];
+
+ if (xioctl(v4l2_fd, VIDIOC_S_FMT, &dst_fmt) < 0) {
+ ERR("failed to set video format: %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+
+ param->stack[0] = dst_fmt.fmt.pix.width;
+ param->stack[1] = dst_fmt.fmt.pix.height;
+ param->stack[2] = dst_fmt.fmt.pix.field;
+ param->stack[3] = dst_fmt.fmt.pix.pixelformat;
+ param->stack[4] = dst_fmt.fmt.pix.bytesperline;
+ param->stack[5] = dst_fmt.fmt.pix.sizeimage;
+ param->stack[6] = dst_fmt.fmt.pix.colorspace;
+ param->stack[7] = dst_fmt.fmt.pix.priv;
+}
+
+void marucam_device_g_fmt(MaruCamState* state)
+{
+ struct v4l2_format format;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&format, 0, sizeof(struct v4l2_format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (xioctl(v4l2_fd, VIDIOC_G_FMT, &format) < 0) {
+ ERR("failed to get video format: %s\n", strerror(errno));
+ param->errCode = errno;
+ } else {
+ param->stack[0] = format.fmt.pix.width;
+ param->stack[1] = format.fmt.pix.height;
+ param->stack[2] = format.fmt.pix.field;
+ param->stack[3] = format.fmt.pix.pixelformat;
+ param->stack[4] = format.fmt.pix.bytesperline;
+ param->stack[5] = format.fmt.pix.sizeimage;
+ param->stack[6] = format.fmt.pix.colorspace;
+ param->stack[7] = format.fmt.pix.priv;
+ memcpy(&dst_fmt, &format, sizeof(format));
+ }
+}
+
+void marucam_device_try_fmt(MaruCamState* state)
+{
+ struct v4l2_format format;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&format, 0, sizeof(struct v4l2_format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ format.fmt.pix.width = param->stack[0];
+ format.fmt.pix.height = param->stack[1];
+ format.fmt.pix.pixelformat = param->stack[2];
+ format.fmt.pix.field = param->stack[3];
+
+ if (xioctl(v4l2_fd, VIDIOC_TRY_FMT, &format) < 0) {
+ ERR("failed to check video format: %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+ param->stack[0] = format.fmt.pix.width;
+ param->stack[1] = format.fmt.pix.height;
+ param->stack[2] = format.fmt.pix.field;
+ param->stack[3] = format.fmt.pix.pixelformat;
+ param->stack[4] = format.fmt.pix.bytesperline;
+ param->stack[5] = format.fmt.pix.sizeimage;
+ param->stack[6] = format.fmt.pix.colorspace;
+ param->stack[7] = format.fmt.pix.priv;
+}
+
+void marucam_device_enum_fmt(MaruCamState* state)
+{
+ struct v4l2_fmtdesc format;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&format, 0, sizeof(struct v4l2_fmtdesc));
+ format.index = param->stack[0];
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (xioctl(v4l2_fd, VIDIOC_ENUM_FMT, &format) < 0) {
+ if (errno != EINVAL)
+ ERR("failed to enumerate video formats: %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+ param->stack[0] = format.index;
+ param->stack[1] = format.flags;
+ param->stack[2] = format.pixelformat;
+ /* set description */
+ memcpy(¶m->stack[3], format.description, sizeof(format.description));
+}
+
+void marucam_device_qctrl(MaruCamState* state)
+{
+ uint32_t i;
+ char name[32] = {0,};
+ struct v4l2_queryctrl ctrl;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&ctrl, 0, sizeof(struct v4l2_queryctrl));
+ ctrl.id = param->stack[0];
+
+ switch (ctrl.id) {
+ case V4L2_CID_BRIGHTNESS:
+ TRACE("Query : BRIGHTNESS\n");
+ memcpy((void*)name, (void*)"brightness", 32);
+ i = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ TRACE("Query : CONTRAST\n");
+ memcpy((void*)name, (void*)"contrast", 32);
+ i = 1;
+ break;
+ case V4L2_CID_SATURATION:
+ TRACE("Query : SATURATION\n");
+ memcpy((void*)name, (void*)"saturation", 32);
+ i = 2;
+ break;
+ case V4L2_CID_SHARPNESS:
+ TRACE("Query : SHARPNESS\n");
+ memcpy((void*)name, (void*)"sharpness", 32);
+ i = 3;
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+
+ if (xioctl(v4l2_fd, VIDIOC_QUERYCTRL, &ctrl) < 0) {
+ if (errno != EINVAL)
+ ERR("failed to query video controls : %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ } else {
+ struct v4l2_control sctrl;
+ memset(&sctrl, 0, sizeof(struct v4l2_control));
+ sctrl.id = ctrl.id;
+ if ((ctrl.maximum + ctrl.minimum) == 0) {
+ sctrl.value = 0;
+ } else {
+ sctrl.value = (ctrl.maximum + ctrl.minimum) / 2;
+ }
+ if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &sctrl) < 0) {
+ ERR("failed to set video control value : %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+ qctrl_tbl[i].hit = 1;
+ qctrl_tbl[i].min = ctrl.minimum;
+ qctrl_tbl[i].max = ctrl.maximum;
+ qctrl_tbl[i].step = ctrl.step;
+ qctrl_tbl[i].init_val = ctrl.default_value;
+ }
+
+ // set fixed values by FW configuration file
+ param->stack[0] = ctrl.id;
+ param->stack[1] = MARUCAM_CTRL_VALUE_MIN; // minimum
+ param->stack[2] = MARUCAM_CTRL_VALUE_MAX; // maximum
+ param->stack[3] = MARUCAM_CTRL_VALUE_STEP;// step
+ param->stack[4] = MARUCAM_CTRL_VALUE_MID; // default_value
+ param->stack[5] = ctrl.flags;
+ /* name field setting */
+ memcpy(¶m->stack[6], (void*)name, sizeof(ctrl.name));
+}
+
+void marucam_device_s_ctrl(MaruCamState* state)
+{
+ uint32_t i;
+ struct v4l2_control ctrl;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&ctrl, 0, sizeof(struct v4l2_control));
+ ctrl.id = param->stack[0];
+
+ switch (ctrl.id) {
+ case V4L2_CID_BRIGHTNESS:
+ i = 0;
+ TRACE("%d is set to the value of the BRIGHTNESS\n", param->stack[1]);
+ break;
+ case V4L2_CID_CONTRAST:
+ i = 1;
+ TRACE("%d is set to the value of the CONTRAST\n", param->stack[1]);
+ break;
+ case V4L2_CID_SATURATION:
+ i = 2;
+ TRACE("%d is set to the value of the SATURATION\n", param->stack[1]);
+ break;
+ case V4L2_CID_SHARPNESS:
+ i = 3;
+ TRACE("%d is set to the value of the SHARPNESS\n", param->stack[1]);
+ break;
+ default:
+ ERR("our emulator does not support this control : 0x%x\n", ctrl.id);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ ctrl.value = value_convert_from_guest(qctrl_tbl[i].min,
+ qctrl_tbl[i].max, param->stack[1]);
+ if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {
+ ERR("failed to set video control value : value(%d), %s\n", param->stack[1], strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+}
+
+void marucam_device_g_ctrl(MaruCamState* state)
+{
+ uint32_t i;
+ struct v4l2_control ctrl;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&ctrl, 0, sizeof(struct v4l2_control));
+ ctrl.id = param->stack[0];
+
+ switch (ctrl.id) {
+ case V4L2_CID_BRIGHTNESS:
+ TRACE("Gets the value of the BRIGHTNESS\n");
+ i = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ TRACE("Gets the value of the CONTRAST\n");
+ i = 1;
+ break;
+ case V4L2_CID_SATURATION:
+ TRACE("Gets the value of the SATURATION\n");
+ i = 2;
+ break;
+ case V4L2_CID_SHARPNESS:
+ TRACE("Gets the value of the SHARPNESS\n");
+ i = 3;
+ break;
+ default:
+ ERR("our emulator does not support this control : 0x%x\n", ctrl.id);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ if (xioctl(v4l2_fd, VIDIOC_G_CTRL, &ctrl) < 0) {
+ ERR("failed to get video control value : %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+ param->stack[0] = value_convert_to_guest(qctrl_tbl[i].min,
+ qctrl_tbl[i].max, ctrl.value);
+ TRACE("Value : %d\n", param->stack[0]);
+}
+
+void marucam_device_enum_fsizes(MaruCamState* state)
+{
+ struct v4l2_frmsizeenum fsize;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&fsize, 0, sizeof(struct v4l2_frmsizeenum));
+ fsize.index = param->stack[0];
+ fsize.pixel_format = param->stack[1];
+
+ if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &fsize) < 0) {
+ if (errno != EINVAL)
+ ERR("failed to get frame sizes : %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+
+ if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ param->stack[0] = fsize.discrete.width;
+ param->stack[1] = fsize.discrete.height;
+ } else {
+ param->errCode = EINVAL;
+ ERR("Not Supported mode, we only support DISCRETE\n");
+ }
+}
+
+void marucam_device_enum_fintv(MaruCamState* state)
+{
+ struct v4l2_frmivalenum ival;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ memset(&ival, 0, sizeof(struct v4l2_frmivalenum));
+ ival.index = param->stack[0];
+ ival.pixel_format = param->stack[1];
+ ival.width = param->stack[2];
+ ival.height = param->stack[3];
+
+ if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) {
+ if (errno != EINVAL)
+ ERR("failed to get frame intervals : %s\n", strerror(errno));
+ param->errCode = errno;
+ return;
+ }
+
+ if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
+ param->stack[0] = ival.discrete.numerator;
+ param->stack[1] = ival.discrete.denominator;
+ } else {
+ param->errCode = EINVAL;
+ ERR("Not Supported mode, we only support DISCRETE\n");
+ }
+}
+
+// MARUCAM_CMD_CLOSE
+void marucam_device_close(MaruCamState* state)
+{
+ pthread_mutex_lock(&state->thread->mutex_lock);
+ state->streamon = 0;
+ pthread_mutex_unlock(&state->thread->mutex_lock);
+
+ marucam_reset_controls();
+
+ v4l2_close(v4l2_fd);
+ v4l2_fd = 0;
+ INFO("Closed\n");
+}
--- /dev/null
+/*
+ * Implementation of MARU Virtual Camera device by PCI bus on Windows.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include "qemu-common.h"
+#include "maru_camera_common.h"
+#include "pci.h"
+#include "kvm.h"
+#include "tizen/src/debug_ch.h"
+
+#include "windows.h"
+#include "basetyps.h"
+#include "mmsystem.h"
+
+MULTI_DEBUG_CHANNEL(tizen, camera_win32);
+
+// V4L2 defines copy from videodev2.h
+#define V4L2_CTRL_FLAG_SLIDER 0x0020
+
+#define V4L2_CTRL_CLASS_USER 0x00980000
+#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
+#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
+#define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
+#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27)
+
+#define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
+#define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
+#define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */
+
+enum {
+ HWC_OPEN,
+ HWC_CLOSE,
+ HWC_START,
+ HWC_STOP,
+ HWC_S_FPS,
+ HWC_G_FPS,
+ HWC_S_FMT,
+ HWC_G_FMT,
+ HWC_TRY_FMT,
+ HWC_ENUM_FMT,
+ HWC_QCTRL,
+ HWC_S_CTRL,
+ HWC_G_CTRL,
+ HWC_ENUM_FSIZES,
+ HWC_ENUM_INTERVALS
+};
+
+typedef enum tagVideoProcAmpProperty {
+ VideoProcAmp_Brightness,
+ VideoProcAmp_Contrast,
+ VideoProcAmp_Hue,
+ VideoProcAmp_Saturation,
+ VideoProcAmp_Sharpness,
+ VideoProcAmp_Gamma,
+ VideoProcAmp_ColorEnable,
+ VideoProcAmp_WhiteBalance,
+ VideoProcAmp_BacklightCompensation,
+ VideoProcAmp_Gain
+} VideoProcAmpProperty;
+
+typedef struct tagHWCParam {
+ long val1;
+ long val2;
+ long val3;
+ long val4;
+ long val5;
+} HWCParam;
+
+typedef struct tagMaruCamConvertPixfmt {
+ uint32_t fmt; /* fourcc */
+ uint32_t bpp; /* bits per pixel, 0 for compressed formats */
+ uint32_t needs_conversion;
+} MaruCamConvertPixfmt;
+
+static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
+ { V4L2_PIX_FMT_YUYV, 16, 0 },
+ { V4L2_PIX_FMT_YUV420, 12, 0 },
+ { V4L2_PIX_FMT_YVU420, 12, 0 },
+};
+
+typedef struct tagMaruCamConvertFrameInfo {
+ uint32_t width;
+ uint32_t height;
+} MaruCamConvertFrameInfo;
+
+static MaruCamConvertFrameInfo supported_dst_frames[] = {
+ { 640, 480 },
+ { 352, 288 },
+ { 320, 240 },
+ { 176, 144 },
+ { 160, 120 },
+};
+
+#define MARUCAM_CTRL_VALUE_MAX 20
+#define MARUCAM_CTRL_VALUE_MIN 1
+#define MARUCAM_CTRL_VALUE_MID 10
+#define MARUCAM_CTRL_VALUE_STEP 1
+
+struct marucam_qctrl {
+ uint32_t id;
+ uint32_t hit;
+ long min;
+ long max;
+ long step;
+ long init_val;
+};
+
+static struct marucam_qctrl qctrl_tbl[] = {
+ { V4L2_CID_BRIGHTNESS, 0, },
+ { V4L2_CID_CONTRAST, 0, },
+ { V4L2_CID_SATURATION,0, },
+ { V4L2_CID_SHARPNESS, 0, },
+};
+
+typedef int (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);
+typedef HRESULT (STDAPICALLTYPE *CTRLFN)(UINT, UINT, LPVOID);
+typedef HRESULT (STDAPICALLTYPE *SETCALLBACKFN)(CallbackFn);
+
+
+static HINSTANCE g_hInst = NULL;
+static MaruCamState *g_state = NULL;
+
+static CTRLFN MaruCamCtrl;
+static SETCALLBACKFN MaruCamSetCallbackFn;
+
+static uint32_t cur_fmt_idx = 0;
+static uint32_t cur_frame_idx = 0;
+
+void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height, uint32_t yvu);
+
+
+static long value_convert_from_guest(long min, long max, long value)
+{
+ double rate = 0.0;
+ long dist = 0, ret = 0;
+
+ dist = max - min;
+
+ if (dist < MARUCAM_CTRL_VALUE_MAX) {
+ rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+ ret = min + (int32_t)(value / rate);
+ } else {
+ rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+ ret = min + (int32_t)(rate * value);
+ }
+ return ret;
+}
+
+static long value_convert_to_guest(long min, long max, long value)
+{
+ double rate = 0.0;
+ long dist = 0, ret = 0;
+
+ dist = max - min;
+
+ if (dist < MARUCAM_CTRL_VALUE_MAX) {
+ rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+ ret = (int32_t)((double)(value - min) * rate);
+ } else {
+ rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+ ret = (int32_t)((double)(value - min) / rate);
+ }
+
+ return ret;
+}
+
+static int STDAPICALLTYPE marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)
+{
+ static uint32_t index = 0;
+ uint32_t width, height;
+ width = supported_dst_frames[cur_frame_idx].width;
+ height = supported_dst_frames[cur_frame_idx].height;
+ void *buf = g_state->vaddr + (g_state->buf_size * index);
+
+ switch (supported_dst_pixfmts[cur_fmt_idx].fmt) {
+ case V4L2_PIX_FMT_YUV420:
+ v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 0);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 1);
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ memcpy(buf, (void*)pBuffer, dwSize);
+ break;
+ }
+ index = !index;
+
+ if (g_state->req_frame) {
+ qemu_irq_raise(g_state->dev.irq[2]);
+ g_state->req_frame = 0;
+ }
+ return 1;
+}
+
+// MARUCAM_CMD_INIT
+void marucam_device_init(MaruCamState* state)
+{
+ MaruCamThreadInfo *thread = state->thread;
+
+ pthread_cond_init(&thread->thread_cond, NULL);
+ pthread_mutex_init(&thread->mutex_lock, NULL);
+
+ g_state = state;
+}
+
+// MARUCAM_CMD_OPEN
+void marucam_device_open(MaruCamState* state)
+{
+ HRESULT hr;
+ MaruCamParam *param = state->thread->param;
+ param->top = 0;
+
+ g_hInst = LoadLibrary("hwcfilter.dll");
+
+ if (!g_hInst) {
+ g_hInst = LoadLibrary("bin\\hwcfilter.dll");
+ if (!g_hInst) {
+ ERR("load library failed!!!!\n");
+ param->errCode = EINVAL;
+ return;
+ }
+ }
+
+ MaruCamCtrl = (CTRLFN)GetProcAddress(g_hInst, "HWCCtrl");
+ if (!MaruCamCtrl) {
+ ERR("HWCCtrl get failed!!!\n");
+ FreeLibrary(g_hInst);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ MaruCamSetCallbackFn = (SETCALLBACKFN)GetProcAddress(g_hInst, "HWCSetCallback");
+ if (!MaruCamSetCallbackFn) {
+ ERR("HWCSetCallback get failed!!!\n");
+ FreeLibrary(g_hInst);
+ param->errCode = EINVAL;
+ return;
+ }
+
+ hr = MaruCamCtrl(HWC_OPEN, 0, NULL);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ FreeLibrary(g_hInst);
+ ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+ hr = MaruCamSetCallbackFn((CallbackFn)marucam_device_callbackfn);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ MaruCamCtrl(HWC_CLOSE, 0, NULL);
+ FreeLibrary(g_hInst);
+ ERR("call back function set failed!!!, [HRESULT : 0x%x]\n", hr);
+ }
+
+ TRACE("camera device open success!!!, [HRESULT : 0x%x]\n", hr);
+}
+
+// MARUCAM_CMD_CLOSE
+void marucam_device_close(MaruCamState* state)
+{
+ HRESULT hr;
+ MaruCamParam *param = state->thread->param;
+ param->top = 0;
+ hr = MaruCamCtrl(HWC_CLOSE, 0, NULL);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("camera device close failed!!!, [HRESULT : 0x%x]\n", hr);
+ }
+ FreeLibrary(g_hInst);
+ TRACE("camera device close success!!!, [HRESULT : 0x%x]\n", hr);
+}
+
+// MARUCAM_CMD_START_PREVIEW
+void marucam_device_start_preview(MaruCamState* state)
+{
+ HRESULT hr;
+ uint32_t width, height;
+ MaruCamParam *param = state->thread->param;
+ TRACE("marucam_device_start_preview\n");
+ param->top = 0;
+ hr = MaruCamCtrl(HWC_START, 0, NULL);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("start preview failed!!!, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+ pthread_mutex_lock(&state->thread->mutex_lock);
+ state->streamon = 1;
+ pthread_mutex_unlock(&state->thread->mutex_lock);
+
+ width = supported_dst_frames[cur_frame_idx].width;
+ height = supported_dst_frames[cur_frame_idx].height;
+ state->buf_size = height * ((width * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3);
+}
+
+// MARUCAM_CMD_STOP_PREVIEW
+void marucam_device_stop_preview(MaruCamState* state)
+{
+ HRESULT hr;
+ MaruCamParam *param = state->thread->param;
+ TRACE("marucam_device_stop_preview\n");
+ param->top = 0;
+ hr = MaruCamCtrl(HWC_STOP, 0, NULL);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("stop preview failed!!!, [HRESULT : 0x%x]\n", hr);
+ }
+ pthread_mutex_lock(&state->thread->mutex_lock);
+ state->streamon = 0;
+ pthread_mutex_unlock(&state->thread->mutex_lock);
+ state->buf_size = 0;
+}
+
+// MARUCAM_CMD_S_PARAM
+void marucam_device_s_param(MaruCamState* state)
+{
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ TRACE("setting fps : %d/%d\n", param->stack[0], param->stack[1]);
+}
+
+// MARUCAM_CMD_G_PARAM
+void marucam_device_g_param(MaruCamState* state)
+{
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ TRACE("getting fps : 30/1\n");
+
+ param->stack[0] = 0x1000; // V4L2_CAP_TIMEPERFRAME
+ param->stack[1] = 1; // numerator;
+ param->stack[2] = 30; // denominator;
+}
+
+// MARUCAM_CMD_S_FMT
+void marucam_device_s_fmt(MaruCamState* state)
+{
+ uint32_t width, height, pixfmt, pidx, fidx;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ width = param->stack[0]; // width
+ height = param->stack[1]; // height
+ pixfmt = param->stack[2]; // pixelformat
+
+ for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
+ if ((supported_dst_frames[fidx].width == width) &&
+ (supported_dst_frames[fidx].height == height)) {
+ break;
+ }
+ }
+ if (fidx == ARRAY_SIZE(supported_dst_frames)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
+ if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
+ break;
+ }
+ }
+ if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ if ((supported_dst_frames[cur_frame_idx].width != width) &&
+ (supported_dst_frames[cur_frame_idx].height != height)) {
+ HWCParam inParam = {0,};
+ inParam.val1 = width;
+ inParam.val2 = height;
+ HRESULT hr = MaruCamCtrl(HWC_S_FMT, sizeof(HWCParam), &inParam);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ }
+
+ param->stack[0] = width;
+ param->stack[1] = height;
+ param->stack[2] = 1; // V4L2_FIELD_NONE
+ param->stack[3] = pixfmt;
+ // bytes per line = (width * bpp) / 8
+ param->stack[4] = (width * supported_dst_pixfmts[pidx].bpp) >> 3;
+ param->stack[5] = param->stack[4] * height; // height * bytesperline
+ param->stack[6] = 0;
+ param->stack[7] = 0;
+
+ cur_frame_idx = fidx;
+ cur_fmt_idx = pidx;
+}
+
+// MARUCAM_CMD_G_FMT
+void marucam_device_g_fmt(MaruCamState* state)
+{
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+
+ param->stack[0] = supported_dst_frames[cur_frame_idx].width; // width
+ param->stack[1] = supported_dst_frames[cur_frame_idx].height; // height
+ param->stack[2] = 1; // V4L2_FIELD_NONE
+ param->stack[3] = supported_dst_pixfmts[cur_fmt_idx].fmt; // pixelformat
+ // bytes per line = (width * bpp) / 8
+ param->stack[4] = (param->stack[0] * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3;
+ param->stack[5] = param->stack[1] * param->stack[4]; // height * bytesperline
+ param->stack[6] = 0;
+ param->stack[7] = 0;
+}
+
+void marucam_device_try_fmt(MaruCamState* state)
+{
+ uint32_t width, height, pixfmt, i;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ width = param->stack[0]; // width
+ height = param->stack[1]; // height
+ pixfmt = param->stack[2]; // pixelformat
+
+ for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) {
+ if ((supported_dst_frames[i].width == width) &&
+ (supported_dst_frames[i].height == height)) {
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(supported_dst_frames)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
+ if (supported_dst_pixfmts[i].fmt == pixfmt) {
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ param->stack[0] = width;
+ param->stack[1] = height;
+ param->stack[2] = 1; // V4L2_FIELD_NONE
+ param->stack[3] = pixfmt;
+ // bytes per line = (width * bpp) / 8
+ param->stack[4] = (width * supported_dst_pixfmts[i].bpp) >> 3;
+ param->stack[5] = param->stack[4] * height; // height * bytesperline
+ param->stack[6] = 0;
+ param->stack[7] = 0;
+}
+
+void marucam_device_enum_fmt(MaruCamState* state)
+{
+ uint32_t index;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ index = param->stack[0];
+
+ if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ param->stack[1] = 0; // flags = NONE;
+ param->stack[2] = supported_dst_pixfmts[index].fmt; // pixelformat;
+ /* set description */
+ switch (supported_dst_pixfmts[index].fmt) {
+ case V4L2_PIX_FMT_YUYV:
+ memcpy(¶m->stack[3], "YUY2", 32);
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ memcpy(¶m->stack[3], "YU12", 32);
+ break;
+ case V4L2_PIX_FMT_YVU420:
+ memcpy(¶m->stack[3], "YV12", 32);
+ break;
+ }
+}
+
+void marucam_device_qctrl(MaruCamState* state)
+{
+ HRESULT hr;
+ uint32_t id, i;
+ HWCParam inParam = {0,};
+ char name[32] = {0,};
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ id = param->stack[0];
+
+ switch (id) {
+ case V4L2_CID_BRIGHTNESS:
+ TRACE("V4L2_CID_BRIGHTNESS\n");
+ inParam.val1 = VideoProcAmp_Brightness;
+ memcpy((void*)name, (void*)"brightness", 32);
+ i = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ TRACE("V4L2_CID_CONTRAST\n");
+ inParam.val1 = VideoProcAmp_Contrast;
+ memcpy((void*)name, (void*)"contrast", 32);
+ i = 1;
+ break;
+ case V4L2_CID_SATURATION:
+ TRACE("V4L2_CID_SATURATION\n");
+ inParam.val1 = VideoProcAmp_Saturation;
+ memcpy((void*)name, (void*)"saturation", 32);
+ i = 2;
+ break;
+ case V4L2_CID_SHARPNESS:
+ TRACE("V4L2_CID_SHARPNESS\n");
+ inParam.val1 = VideoProcAmp_Sharpness;
+ memcpy((void*)name, (void*)"sharpness", 32);
+ i = 3;
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+ hr = MaruCamCtrl(HWC_QCTRL, sizeof(inParam), &inParam);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);
+ return;
+ } else {
+ qctrl_tbl[i].hit = 1;
+ qctrl_tbl[i].min = inParam.val2;
+ qctrl_tbl[i].max = inParam.val3;
+ qctrl_tbl[i].step = inParam.val4;
+ qctrl_tbl[i].init_val = inParam.val5;
+
+ if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {
+ inParam.val2 = 0;
+ } else {
+ inParam.val2 = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;
+ }
+ hr = MaruCamCtrl(HWC_S_CTRL, sizeof(inParam), &inParam);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+ }
+
+ param->stack[0] = id;
+ param->stack[1] = MARUCAM_CTRL_VALUE_MIN; // minimum
+ param->stack[2] = MARUCAM_CTRL_VALUE_MAX; // maximum
+ param->stack[3] = MARUCAM_CTRL_VALUE_STEP;// step
+ param->stack[4] = MARUCAM_CTRL_VALUE_MID; // default_value
+ param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
+ /* name field setting */
+ memcpy(¶m->stack[6], (void*)name, sizeof(name)/sizeof(name[0]));
+}
+
+void marucam_device_s_ctrl(MaruCamState* state)
+{
+ HRESULT hr;
+ uint32_t i;
+ HWCParam inParam = {0,};
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+
+ switch (param->stack[0]) {
+ case V4L2_CID_BRIGHTNESS:
+ i = 0;
+ inParam.val1 = VideoProcAmp_Brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ i = 1;
+ inParam.val1 = VideoProcAmp_Contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ i = 2;
+ inParam.val1 = VideoProcAmp_Saturation;
+ break;
+ case V4L2_CID_SHARPNESS:
+ i = 3;
+ inParam.val1 = VideoProcAmp_Sharpness;
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+ inParam.val2 = value_convert_from_guest(qctrl_tbl[i].min,
+ qctrl_tbl[i].max, (long)param->stack[1]);
+ hr = MaruCamCtrl(HWC_S_CTRL, sizeof(inParam), &inParam);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+}
+
+void marucam_device_g_ctrl(MaruCamState* state)
+{
+ HRESULT hr;
+ uint32_t i;
+ HWCParam inParam = {0,};
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ switch (param->stack[0]) {
+ case V4L2_CID_BRIGHTNESS:
+ i = 0;
+ inParam.val1 = VideoProcAmp_Brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ i = 1;
+ inParam.val1 = VideoProcAmp_Contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ i = 2;
+ inParam.val1 = VideoProcAmp_Saturation;
+ break;
+ case V4L2_CID_SHARPNESS:
+ i = 3;
+ inParam.val1 = VideoProcAmp_Sharpness;
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+
+ hr = MaruCamCtrl(HWC_G_CTRL, sizeof(inParam), &inParam);
+ if (FAILED(hr)) {
+ param->errCode = EINVAL;
+ ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);
+ return;
+ }
+ param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,
+ qctrl_tbl[i].max, inParam.val2);
+}
+
+void marucam_device_enum_fsizes(MaruCamState* state)
+{
+ uint32_t index, pixfmt, i;
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+ index = param->stack[0];
+ pixfmt = param->stack[1];
+
+ if (index >= ARRAY_SIZE(supported_dst_frames)) {
+ param->errCode = EINVAL;
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
+ if (supported_dst_pixfmts[i].fmt == pixfmt)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
+ param->errCode = EINVAL;
+ return;
+ }
+
+ param->stack[0] = supported_dst_frames[index].width;
+ param->stack[1] = supported_dst_frames[index].height;
+}
+
+void marucam_device_enum_fintv(MaruCamState* state)
+{
+ MaruCamParam *param = state->thread->param;
+
+ param->top = 0;
+
+ // switch by index(param->stack[0])
+ switch (param->stack[0]) {
+ case 0:
+ param->stack[1] = 30; // denominator
+ break;
+ default:
+ param->errCode = EINVAL;
+ return;
+ }
+ param->stack[0] = 1; // numerator
+}
+
+void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
+ uint32_t width, uint32_t height, uint32_t yvu)
+{
+ uint32_t i, j;
+ const unsigned char *src1;
+ unsigned char *udest, *vdest;
+
+ /* copy the Y values */
+ src1 = src;
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j += 2) {
+ *dest++ = src1[0];
+ *dest++ = src1[2];
+ src1 += 4;
+ }
+ }
+
+ /* copy the U and V values */
+ src++; /* point to V */
+ src1 = src + width * 2; /* next line */
+ if (yvu) {
+ vdest = dest;
+ udest = dest + width * height / 4;
+ } else {
+ udest = dest;
+ vdest = dest + width * height / 4;
+ }
+ for (i = 0; i < height; i += 2) {
+ for (j = 0; j < width; j += 2) {
+ *udest++ = ((int) src[0] + src1[0]) / 2; /* U */
+ *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */
+ src += 4;
+ src1 += 4;
+ }
+ src = src1;
+ src1 += width * 2;
+ }
+}