Merge commit '260bf01' into tizen-arm
[sdk/emulator/qemu.git] / tizen / src / hw / maru_camera_linux_pci.c
index d8a6a64..193354c 100644 (file)
 \r
 #include <linux/videodev2.h>\r
 \r
+#include <sys/stat.h>\r
+#include <sys/ioctl.h>\r
+\r
 #include <libv4l2.h>\r
 #include <libv4lconvert.h>\r
 \r
 MULTI_DEBUG_CHANNEL(tizen, camera_linux);\r
 \r
+enum {\r
+    _MC_THREAD_PAUSED,\r
+    _MC_THREAD_STREAMON,\r
+    _MC_THREAD_STREAMOFF,\r
+};\r
+\r
+static const char *dev_name = "/dev/video0";\r
 static int v4l2_fd;\r
 static int convert_trial;\r
+static int ready_count;\r
 \r
 static struct v4l2_format dst_fmt;\r
 \r
+#define CLEAR(x) memset(&(x), 0, sizeof(x))\r
+\r
 static int xioctl(int fd, int req, void *arg)\r
 {\r
     int r;\r
@@ -56,6 +69,29 @@ static int xioctl(int fd, int req, void *arg)
     return r;\r
 }\r
 \r
+typedef struct tagMaruCamConvertPixfmt {\r
+    uint32_t fmt;   /* fourcc */\r
+} MaruCamConvertPixfmt;\r
+\r
+static MaruCamConvertPixfmt supported_dst_pixfmts[] = {\r
+        { V4L2_PIX_FMT_YUYV },\r
+        { V4L2_PIX_FMT_YUV420 },\r
+        { V4L2_PIX_FMT_YVU420 },\r
+};\r
+\r
+typedef struct tagMaruCamConvertFrameInfo {\r
+    uint32_t width;\r
+    uint32_t height;\r
+} MaruCamConvertFrameInfo;\r
+\r
+static MaruCamConvertFrameInfo supported_dst_frames[] = {\r
+        { 640, 480 },\r
+        { 352, 288 },\r
+        { 320, 240 },\r
+        { 176, 144 },\r
+        { 160, 120 },\r
+};\r
+\r
 #define MARUCAM_CTRL_VALUE_MAX      20\r
 #define MARUCAM_CTRL_VALUE_MIN      1\r
 #define MARUCAM_CTRL_VALUE_MID      10\r
@@ -73,7 +109,7 @@ struct marucam_qctrl {
 static struct marucam_qctrl qctrl_tbl[] = {\r
     { V4L2_CID_BRIGHTNESS, 0, },\r
     { V4L2_CID_CONTRAST, 0, },\r
-    { V4L2_CID_SATURATION,0, },\r
+    { V4L2_CID_SATURATION, 0, },\r
     { V4L2_CID_SHARPNESS, 0, },\r
 };\r
 \r
@@ -83,10 +119,12 @@ static void marucam_reset_controls(void)
     for (i = 0; i < ARRAY_SIZE(qctrl_tbl); i++) {\r
         if (qctrl_tbl[i].hit) {\r
             struct v4l2_control ctrl = {0,};\r
+            qctrl_tbl[i].hit = 0;\r
             ctrl.id = qctrl_tbl[i].id;\r
             ctrl.value = qctrl_tbl[i].init_val;\r
             if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {\r
-                ERR("failed to set video control value while reset values : %s\n", strerror(errno));\r
+                ERR("failed to reset control value : id(0x%x), errstr(%s)\n",\r
+                    ctrl.id, strerror(errno));\r
             }\r
         }\r
     }\r
@@ -127,10 +165,90 @@ static int32_t value_convert_to_guest(int32_t min, int32_t max, int32_t value)
     return ret;\r
 }\r
 \r
+static void set_maxframeinterval(MaruCamState *state, uint32_t pixel_format,\r
+                        uint32_t width, uint32_t height)\r
+{\r
+    struct v4l2_frmivalenum fival;\r
+    struct v4l2_streamparm sp;\r
+    uint32_t min_num = 0, min_denom = 0;\r
+\r
+    CLEAR(fival);\r
+    fival.pixel_format = pixel_format;\r
+    fival.width = width;\r
+    fival.height = height;\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) < 0) {\r
+        ERR("Unable to enumerate intervals for pixelformat(0x%x), (%d:%d)\n",\r
+            pixel_format, width, height);\r
+        return;\r
+    }\r
+\r
+    if (fival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {\r
+        float max_ival = -1.0;\r
+        do {\r
+            float cur_ival = (float)fival.discrete.numerator\r
+                        / (float)fival.discrete.denominator;\r
+            if (cur_ival > max_ival) {\r
+                max_ival = cur_ival;\r
+                min_num = fival.discrete.numerator;\r
+                min_denom = fival.discrete.denominator;\r
+            }\r
+            TRACE("Discrete frame interval %u/%u supported\n",\r
+                 fival.discrete.numerator, fival.discrete.denominator);\r
+            fival.index++;\r
+        } while (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) >= 0);\r
+    } else if ((fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) ||\r
+                (fival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)) {\r
+        TRACE("Frame intervals from %u/%u to %u/%u supported",\r
+            fival.stepwise.min.numerator, fival.stepwise.min.denominator,\r
+            fival.stepwise.max.numerator, fival.stepwise.max.denominator);\r
+        if(fival.type == V4L2_FRMIVAL_TYPE_STEPWISE)\r
+            TRACE("with %u/%u step",\r
+                 fival.stepwise.step.numerator, fival.stepwise.step.denominator);\r
+        if (((float)fival.stepwise.max.denominator /\r
+             (float)fival.stepwise.max.numerator) >\r
+            ((float)fival.stepwise.min.denominator /\r
+             (float)fival.stepwise.min.numerator)) {\r
+            min_num = fival.stepwise.max.numerator;\r
+            min_denom = fival.stepwise.max.denominator;\r
+        } else {\r
+            min_num = fival.stepwise.min.numerator;\r
+            min_denom = fival.stepwise.min.denominator;\r
+        }\r
+    }\r
+    TRACE("actual min values : %u/%u\n", min_num, min_denom);\r
+\r
+    CLEAR(sp);\r
+    sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+    sp.parm.capture.timeperframe.numerator = min_num;\r
+    sp.parm.capture.timeperframe.denominator = min_denom;\r
+\r
+    if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) {\r
+        ERR("Failed to set to minimum FPS(%u/%u)\n", min_num, min_denom);\r
+    }\r
+}\r
+\r
+static int is_streamon(MaruCamState *state)\r
+{\r
+    int st;\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    st = state->streamon;\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
+    return (st == _MC_THREAD_STREAMON);\r
+}\r
+\r
+static int is_stream_paused(MaruCamState *state)\r
+{\r
+    int st;\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    st = state->streamon;\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
+    return (st == _MC_THREAD_PAUSED);\r
+}\r
+\r
 static int __v4l2_grab(MaruCamState *state)\r
 {\r
     fd_set fds;\r
-    static uint32_t index = 0;\r
     struct timeval tv;\r
     void *buf;\r
     int ret;\r
@@ -138,8 +256,8 @@ static int __v4l2_grab(MaruCamState *state)
     FD_ZERO(&fds);\r
     FD_SET(v4l2_fd, &fds);\r
 \r
-    tv.tv_sec = 2;\r
-    tv.tv_usec = 0;\r
+    tv.tv_sec = 0;\r
+    tv.tv_usec = 500000;\r
 \r
     ret = select(v4l2_fd + 1, &fds, NULL, NULL, &tv);\r
     if ( ret < 0) {\r
@@ -158,13 +276,17 @@ static int __v4l2_grab(MaruCamState *state)
         return -1;\r
     }\r
 \r
-       qemu_mutex_lock(&state->thread_mutex);\r
-       ret = state->streamon;\r
-       qemu_mutex_unlock(&state->thread_mutex);\r
-       if (!ret)\r
-              return -1;\r
+    if (!is_streamon(state))\r
+        return -1;\r
+\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    if (state->req_frame == 0) {\r
+        qemu_mutex_unlock(&state->thread_mutex);\r
+        return 0;\r
+    }\r
+    buf = state->vaddr + state->buf_size * (state->req_frame -1);\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
 \r
-    buf = state->vaddr + (state->buf_size * index);\r
     ret = v4l2_read(v4l2_fd, buf, state->buf_size);\r
     if ( ret < 0) {\r
         switch (errno) {\r
@@ -184,52 +306,91 @@ static int __v4l2_grab(MaruCamState *state)
         }\r
     }\r
 \r
-    index = !index;\r
-\r
     qemu_mutex_lock(&state->thread_mutex);\r
-    if (state->streamon) {\r
-        if (state->req_frame) {\r
-            qemu_irq_raise(state->dev.irq[2]);\r
-            state->req_frame = 0;\r
-        }\r
+    if (ready_count < MARUCAM_SKIPFRAMES) {\r
+        ++ready_count; /* skip a frame cause first some frame are distorted */\r
+        qemu_mutex_unlock(&state->thread_mutex);\r
+        return 0;\r
+    }\r
+    if (state->streamon == _MC_THREAD_STREAMON) {\r
+        state->req_frame = 0; /* clear request */\r
+        state->isr |= 0x01;   /* set a flag of rasing a interrupt */\r
+        qemu_bh_schedule(state->tx_bh);\r
         ret = 1;\r
     } else {\r
         ret = -1;\r
     }\r
     qemu_mutex_unlock(&state->thread_mutex);\r
-\r
     return ret;\r
 }\r
 \r
-// Worker thread\r
+/* Worker thread */\r
 static void *marucam_worker_thread(void *thread_param)\r
 {\r
     MaruCamState *state = (MaruCamState*)thread_param;\r
 \r
 wait_worker_thread:\r
     qemu_mutex_lock(&state->thread_mutex);\r
-    state->streamon = 0;\r
-    convert_trial = 10;\r
+    state->streamon = _MC_THREAD_PAUSED;\r
     qemu_cond_wait(&state->thread_cond, &state->thread_mutex);\r
     qemu_mutex_unlock(&state->thread_mutex);\r
+\r
+    convert_trial = 10;\r
+    ready_count = 0;\r
+    qemu_mutex_lock(&state->thread_mutex);\r
+    state->buf_size = dst_fmt.fmt.pix.sizeimage;\r
+    state->streamon = _MC_THREAD_STREAMON;\r
+    qemu_mutex_unlock(&state->thread_mutex);\r
     INFO("Streaming on ......\n");\r
 \r
     while (1)\r
     {\r
-        qemu_mutex_lock(&state->thread_mutex);\r
-        if (state->streamon) {\r
-            qemu_mutex_unlock(&state->thread_mutex);\r
+        if (is_streamon(state)) {\r
             if (__v4l2_grab(state) < 0) {\r
                 INFO("...... Streaming off\n");\r
                 goto wait_worker_thread;\r
             }\r
         } else {\r
-            qemu_mutex_unlock(&state->thread_mutex);\r
             INFO("...... Streaming off\n");\r
             goto wait_worker_thread;\r
         }\r
     }\r
-    qemu_thread_exit((void*)0);\r
+    return NULL;\r
+}\r
+\r
+int marucam_device_check(void)\r
+{\r
+    int tmp_fd;\r
+    struct stat st;\r
+    struct v4l2_capability cap;\r
+\r
+    if (stat(dev_name, &st) < 0) {\r
+        INFO("<WARNING>Cannot identify '%s': %s\n", dev_name, strerror(errno));\r
+    } else {\r
+        if (!S_ISCHR(st.st_mode)) {\r
+            INFO("<WARNING>%s is no character device.\n", dev_name);\r
+        }\r
+    }\r
+\r
+    tmp_fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);\r
+    if (tmp_fd < 0) {\r
+        ERR("Camera device open failed.(%s)\n", dev_name);\r
+        return 0;\r
+    }\r
+    if (ioctl(tmp_fd, VIDIOC_QUERYCAP, &cap) < 0) {\r
+        ERR("Could not qeury video capabilities\n");\r
+        close(tmp_fd);\r
+        return 0;\r
+    }\r
+    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||\r
+            !(cap.capabilities & V4L2_CAP_STREAMING)) {\r
+        ERR("Not supported video driver.\n");\r
+        close(tmp_fd);\r
+        return 0;\r
+    }\r
+\r
+    close(tmp_fd);\r
+    return 1;\r
 }\r
 \r
 void marucam_device_init(MaruCamState* state)\r
@@ -238,97 +399,82 @@ void marucam_device_init(MaruCamState* state)
             QEMU_THREAD_JOINABLE);\r
 }\r
 \r
-// MARUCAM_CMD_OPEN\r
 void marucam_device_open(MaruCamState* state)\r
 {\r
-    struct v4l2_capability cap;\r
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    v4l2_fd = v4l2_open("/dev/video0", O_RDWR);\r
+    v4l2_fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);\r
     if (v4l2_fd < 0) {\r
-        ERR("v4l2 device open failed.(/dev/video0)\n");\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-    if (xioctl(v4l2_fd, VIDIOC_QUERYCAP, &cap) < 0) {\r
-        ERR("Could not qeury video capabilities\n");\r
-        v4l2_close(v4l2_fd);\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||\r
-            !(cap.capabilities & V4L2_CAP_STREAMING)) {\r
-        ERR("Not supported video driver.\n");\r
-        v4l2_close(v4l2_fd);\r
+        ERR("v4l2 device open failed.(%s)\n", dev_name);\r
         param->errCode = EINVAL;\r
         return;\r
     }\r
 \r
-    memset(&dst_fmt, 0, sizeof(dst_fmt));\r
+    CLEAR(dst_fmt);\r
     INFO("Opened\n");\r
 }\r
 \r
-// MARUCAM_CMD_START_PREVIEW\r
 void marucam_device_start_preview(MaruCamState* state)\r
 {\r
+    struct timespec req;\r
+    req.tv_sec = 0;\r
+    req.tv_nsec = 10000000;\r
+\r
+    INFO("Starting preview!\n");\r
     qemu_mutex_lock(&state->thread_mutex);\r
-    state->streamon = 1;\r
-    state->buf_size = dst_fmt.fmt.pix.sizeimage;\r
     qemu_cond_signal(&state->thread_cond);\r
     qemu_mutex_unlock(&state->thread_mutex);\r
-       INFO("Starting preview!\n");\r
+\r
+    /* nanosleep until thread is streamon  */\r
+    while (!is_streamon(state))\r
+        nanosleep(&req, NULL);\r
 }\r
 \r
-// MARUCAM_CMD_STOP_PREVIEW\r
 void marucam_device_stop_preview(MaruCamState* state)\r
 {\r
-       struct timespec req;\r
-       req.tv_sec = 0;\r
-       req.tv_nsec = 333333333;\r
+    struct timespec req;\r
+    req.tv_sec = 0;\r
+    req.tv_nsec = 50000000;\r
 \r
     qemu_mutex_lock(&state->thread_mutex);\r
-    state->streamon = 0;\r
+    state->streamon = _MC_THREAD_STREAMOFF;\r
     state->buf_size = 0;\r
     qemu_mutex_unlock(&state->thread_mutex);\r
-    nanosleep(&req, NULL);\r
-       INFO("Stopping preview!\n");\r
+\r
+    /* nanosleep until thread is paused  */\r
+    while (!is_stream_paused(state))\r
+        nanosleep(&req, NULL);\r
+\r
+    INFO("Stopping preview!\n");\r
 }\r
 \r
 void marucam_device_s_param(MaruCamState* state)\r
 {\r
-    struct v4l2_streamparm sp;\r
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&sp, 0, sizeof(struct v4l2_streamparm));\r
-    sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
-    sp.parm.capture.timeperframe.numerator = param->stack[0];\r
-    sp.parm.capture.timeperframe.denominator = param->stack[1];\r
 \r
-    if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) {\r
-        ERR("failed to set FPS: %s\n", strerror(errno));\r
-        param->errCode = errno;\r
+    /* If KVM enabled, We use default FPS of the webcam.\r
+     * If KVM disabled, we use mininum FPS of the webcam */\r
+    if (!kvm_enabled()) {\r
+        set_maxframeinterval(state, dst_fmt.fmt.pix.pixelformat,\r
+                     dst_fmt.fmt.pix.width,\r
+                     dst_fmt.fmt.pix.height);\r
     }\r
 }\r
 \r
 void marucam_device_g_param(MaruCamState* state)\r
 {\r
-    struct v4l2_streamparm sp;\r
     MaruCamParam *param = state->param;\r
-    \r
-    param->top = 0;\r
-    memset(&sp, 0, sizeof(struct v4l2_streamparm));\r
-    sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
 \r
-    if (xioctl(v4l2_fd, VIDIOC_G_PARM, &sp) < 0) {\r
-        ERR("failed to get FPS: %s\n", strerror(errno));\r
-        param->errCode = errno;\r
-        return;\r
-    }\r
-    param->stack[0] = sp.parm.capture.capability;\r
-    param->stack[1] = sp.parm.capture.timeperframe.numerator;\r
-    param->stack[2] = sp.parm.capture.timeperframe.denominator;\r
+    /* We use default FPS of the webcam\r
+     * return a fixed value on guest ini file (1/30).\r
+     */\r
+    param->top = 0;\r
+    param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */\r
+    param->stack[1] = 1; /* numerator */\r
+    param->stack[2] = 30; /* denominator */\r
 }\r
 \r
 void marucam_device_s_fmt(MaruCamState* state)\r
@@ -336,7 +482,7 @@ void marucam_device_s_fmt(MaruCamState* state)
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&dst_fmt, 0, sizeof(struct v4l2_format));\r
+    CLEAR(dst_fmt);\r
     dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
     dst_fmt.fmt.pix.width = param->stack[0];\r
     dst_fmt.fmt.pix.height = param->stack[1];\r
@@ -344,7 +490,9 @@ void marucam_device_s_fmt(MaruCamState* state)
     dst_fmt.fmt.pix.field = param->stack[3];\r
 \r
     if (xioctl(v4l2_fd, VIDIOC_S_FMT, &dst_fmt) < 0) {\r
-        ERR("failed to set video format: %s\n", strerror(errno));\r
+        ERR("failed to set video format: format(0x%x), width:height(%d:%d), "\r
+          "errstr(%s)\n", dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.width,\r
+          dst_fmt.fmt.pix.height, strerror(errno));\r
         param->errCode = errno;\r
         return;\r
     }\r
@@ -365,7 +513,7 @@ void marucam_device_g_fmt(MaruCamState* state)
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&format, 0, sizeof(struct v4l2_format));\r
+    CLEAR(format);\r
     format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
 \r
     if (xioctl(v4l2_fd, VIDIOC_G_FMT, &format) < 0) {\r
@@ -390,7 +538,7 @@ void marucam_device_try_fmt(MaruCamState* state)
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&format, 0, sizeof(struct v4l2_format));\r
+    CLEAR(format);\r
     format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
     format.fmt.pix.width = param->stack[0];\r
     format.fmt.pix.height = param->stack[1];\r
@@ -398,7 +546,9 @@ void marucam_device_try_fmt(MaruCamState* state)
     format.fmt.pix.field = param->stack[3];\r
 \r
     if (xioctl(v4l2_fd, VIDIOC_TRY_FMT, &format) < 0) {\r
-        ERR("failed to check video format: %s\n", strerror(errno));\r
+        ERR("failed to check video format: format(0x%x), width:height(%d:%d),"\r
+            " errstr(%s)\n", format.fmt.pix.pixelformat, format.fmt.pix.width,\r
+            format.fmt.pix.height, strerror(errno));\r
         param->errCode = errno;\r
         return;\r
     }\r
@@ -414,25 +564,30 @@ void marucam_device_try_fmt(MaruCamState* state)
 \r
 void marucam_device_enum_fmt(MaruCamState* state)\r
 {\r
-    struct v4l2_fmtdesc format;\r
+    uint32_t index;\r
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&format, 0, sizeof(struct v4l2_fmtdesc));\r
-    format.index = param->stack[0];\r
-    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+    index = param->stack[0];\r
 \r
-    if (xioctl(v4l2_fd, VIDIOC_ENUM_FMT, &format) < 0) {\r
-        if (errno != EINVAL)\r
-            ERR("failed to enumerate video formats: %s\n", strerror(errno));\r
-        param->errCode = errno;\r
+    if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {\r
+        param->errCode = EINVAL;\r
         return;\r
     }\r
-    param->stack[0] = format.index;\r
-    param->stack[1] = format.flags;\r
-    param->stack[2] = format.pixelformat;\r
+    param->stack[1] = 0; /* flags = NONE */\r
+    param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */\r
     /* set description */\r
-    memcpy(&param->stack[3], format.description, sizeof(format.description));\r
+    switch (supported_dst_pixfmts[index].fmt) {\r
+    case V4L2_PIX_FMT_YUYV:\r
+        memcpy(&param->stack[3], "YUYV", 32);\r
+        break;\r
+    case V4L2_PIX_FMT_YUV420:\r
+        memcpy(&param->stack[3], "YU12", 32);\r
+        break;\r
+    case V4L2_PIX_FMT_YVU420:\r
+        memcpy(&param->stack[3], "YV12", 32);\r
+        break;\r
+    }\r
 }\r
 \r
 void marucam_device_qctrl(MaruCamState* state)\r
@@ -443,7 +598,7 @@ void marucam_device_qctrl(MaruCamState* state)
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&ctrl, 0, sizeof(struct v4l2_queryctrl));\r
+    CLEAR(ctrl);\r
     ctrl.id = param->stack[0];\r
 \r
     switch (ctrl.id) {\r
@@ -479,7 +634,7 @@ void marucam_device_qctrl(MaruCamState* state)
         return;\r
     } else {\r
         struct v4l2_control sctrl;\r
-        memset(&sctrl, 0, sizeof(struct v4l2_control));\r
+        CLEAR(sctrl);\r
         sctrl.id = ctrl.id;\r
         if ((ctrl.maximum + ctrl.minimum) == 0) {\r
             sctrl.value = 0;\r
@@ -487,7 +642,8 @@ void marucam_device_qctrl(MaruCamState* state)
             sctrl.value = (ctrl.maximum + ctrl.minimum) / 2;\r
         }\r
         if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &sctrl) < 0) {\r
-            ERR("failed to set video control value : %s\n", strerror(errno));\r
+            ERR("failed to set control value: id(0x%x), value(%d), "\r
+                "errstr(%s)\n", sctrl.id, sctrl.value, strerror(errno));\r
             param->errCode = errno;\r
             return;\r
         }\r
@@ -516,7 +672,7 @@ void marucam_device_s_ctrl(MaruCamState* state)
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&ctrl, 0, sizeof(struct v4l2_control));\r
+    CLEAR(ctrl);\r
     ctrl.id = param->stack[0];\r
 \r
     switch (ctrl.id) {\r
@@ -545,7 +701,9 @@ void marucam_device_s_ctrl(MaruCamState* state)
     ctrl.value = value_convert_from_guest(qctrl_tbl[i].min,\r
             qctrl_tbl[i].max, param->stack[1]);\r
     if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {\r
-        ERR("failed to set video control value : value(%d), %s\n", param->stack[1], strerror(errno));\r
+        ERR("failed to set control value : id0x%x), value(r:%d, c:%d), "\r
+            "errstr(%s)\n", ctrl.id, param->stack[1], ctrl.value,\r
+            strerror(errno));\r
         param->errCode = errno;\r
         return;\r
     }\r
@@ -558,7 +716,7 @@ void marucam_device_g_ctrl(MaruCamState* state)
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&ctrl, 0, sizeof(struct v4l2_control));\r
+    CLEAR(ctrl);\r
     ctrl.id = param->stack[0];\r
 \r
     switch (ctrl.id) {\r
@@ -596,73 +754,58 @@ void marucam_device_g_ctrl(MaruCamState* state)
 \r
 void marucam_device_enum_fsizes(MaruCamState* state)\r
 {\r
-    struct v4l2_frmsizeenum fsize;\r
+    uint32_t index, pixfmt, i;\r
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&fsize, 0, sizeof(struct v4l2_frmsizeenum));\r
-    fsize.index = param->stack[0];\r
-    fsize.pixel_format = param->stack[1];\r
+    index = param->stack[0];\r
+    pixfmt = param->stack[1];\r
 \r
-    if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &fsize) < 0) {\r
-        if (errno != EINVAL)\r
-            ERR("failed to get frame sizes : %s\n", strerror(errno));\r
-        param->errCode = errno;\r
+    if (index >= ARRAY_SIZE(supported_dst_frames)) {\r
+        param->errCode = EINVAL;\r
         return;\r
     }\r
+    for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {\r
+        if (supported_dst_pixfmts[i].fmt == pixfmt)\r
+            break;\r
+    }\r
 \r
-    if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {\r
-        param->stack[0] = fsize.discrete.width;\r
-        param->stack[1] = fsize.discrete.height;\r
-    } else {\r
+    if (i == ARRAY_SIZE(supported_dst_pixfmts)) {\r
         param->errCode = EINVAL;\r
-        ERR("Not Supported mode, we only support DISCRETE\n");\r
+        return;\r
     }\r
+\r
+    param->stack[0] = supported_dst_frames[index].width;\r
+    param->stack[1] = supported_dst_frames[index].height;\r
 }\r
 \r
 void marucam_device_enum_fintv(MaruCamState* state)\r
 {\r
-    struct v4l2_frmivalenum ival;\r
     MaruCamParam *param = state->param;\r
 \r
     param->top = 0;\r
-    memset(&ival, 0, sizeof(struct v4l2_frmivalenum));\r
-    ival.index = param->stack[0];\r
-    ival.pixel_format = param->stack[1];\r
-    ival.width = param->stack[2];\r
-    ival.height = param->stack[3];\r
-\r
-    if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) {\r
-        if (errno != EINVAL)\r
-            ERR("failed to get frame intervals : %s\n", strerror(errno));\r
-        param->errCode = errno;\r
-        return;\r
-    }\r
 \r
-    if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {\r
-        param->stack[0] = ival.discrete.numerator;\r
-        param->stack[1] = ival.discrete.denominator;\r
-    } else {\r
+    /* switch by index(param->stack[0]) */\r
+    switch (param->stack[0]) {\r
+    case 0:\r
+        /* we only use 1/30 frame interval */\r
+        param->stack[1] = 30;   /* denominator */\r
+        break;\r
+    default:\r
         param->errCode = EINVAL;\r
-        ERR("Not Supported mode, we only support DISCRETE\n");\r
+        return;\r
     }\r
+    param->stack[0] = 1;    /* numerator */\r
 }\r
 \r
-// MARUCAM_CMD_CLOSE\r
 void marucam_device_close(MaruCamState* state)\r
 {\r
-       uint32_t is_streamon;\r
-\r
-    qemu_mutex_lock(&state->thread_mutex);\r
-    is_streamon = state->streamon;\r
-    qemu_mutex_unlock(&state->thread_mutex);\r
-\r
-       if (is_streamon)\r
-              marucam_device_stop_preview(state);\r
+    if (!is_stream_paused(state))\r
+        marucam_device_stop_preview(state);\r
 \r
     marucam_reset_controls();\r
 \r
     v4l2_close(v4l2_fd);\r
-    v4l2_fd = 0;\r
+    v4l2_fd = -1;\r
     INFO("Closed\n");\r
 }\r