From a9489702d8a8cf12128b6cd3edd0993c79c07bcb Mon Sep 17 00:00:00 2001 From: "jinhyung.jo" Date: Mon, 23 Mar 2015 18:10:43 +0900 Subject: [PATCH] maru-camera: Code refactoring Modified the common & the linux module. Change-Id: I0239158aac07a217b8a47f8df239f96bc38f45ea Signed-off-by: Jinhyung Jo --- tizen/src/hw/pci/maru_camera.c | 109 ++-- tizen/src/hw/pci/maru_camera.h | 105 +-- tizen/src/hw/pci/maru_camera_linux.c | 942 +++++++++++++-------------- 3 files changed, 577 insertions(+), 579 deletions(-) diff --git a/tizen/src/hw/pci/maru_camera.c b/tizen/src/hw/pci/maru_camera.c index 112c2866b4..4103f2698d 100644 --- a/tizen/src/hw/pci/maru_camera.c +++ b/tizen/src/hw/pci/maru_camera.c @@ -47,8 +47,10 @@ MULTI_DEBUG_CHANNEL(tizen, camera); #define MARU_PCI_CAMERA_DEVICE_NAME "maru-camera" -#define MARUCAM_MEM_SIZE (4 * 1024 * 1024) /* 4MB */ -#define MARUCAM_REG_SIZE (256) /* 64 * 4Byte */ +/* WQXGA(2560x1600) * RGBA(4Byte) */ +#define MARUCAM_MEM_SIZE (2560 * 1600 * 4) +#define MARUCAM_REG_SIZE (256) /* 64 * 4Byte */ +#define MARUCAM_IOMEM_SIZE (512) /* 512Byte */ /* * I/O functions @@ -69,27 +71,6 @@ marucam_mmio_read(void *opaque, hwaddr offset) } qemu_mutex_unlock(&state->thread_mutex); break; - case MARUCAM_CMD_G_DATA: - ret = state->param->stack[state->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->param->errCode; - state->param->errCode = 0; - break; default: ERR("Not supported command: 0x%x\n", offset); ret = EINVAL; @@ -105,56 +86,49 @@ marucam_mmio_write(void *opaque, hwaddr offset, uint32_t value) switch (offset & 0xFF) { case MARUCAM_CMD_OPEN: - marucam_device_open(state); + state->backend->open(state); break; case MARUCAM_CMD_CLOSE: - marucam_device_close(state); + state->backend->close(state); break; - case MARUCAM_CMD_START_PREVIEW: - marucam_device_start_preview(state); + case MARUCAM_CMD_STREAMON: + state->backend->stream_on(state); break; - case MARUCAM_CMD_STOP_PREVIEW: - marucam_device_stop_preview(state); - memset(state->vaddr, 0, MARUCAM_MEM_SIZE); + case MARUCAM_CMD_STREAMOFF: + state->backend->stream_off(state); break; - case MARUCAM_CMD_S_PARAM: - marucam_device_s_param(state); + case MARUCAM_CMD_S_PARM: + state->backend->s_parm(state); break; - case MARUCAM_CMD_G_PARAM: - marucam_device_g_param(state); + case MARUCAM_CMD_G_PARM: + state->backend->g_parm(state); break; case MARUCAM_CMD_ENUM_FMT: - marucam_device_enum_fmt(state); + state->backend->enum_fmt(state); break; case MARUCAM_CMD_TRY_FMT: - marucam_device_try_fmt(state); + state->backend->try_fmt(state); break; case MARUCAM_CMD_S_FMT: - marucam_device_s_fmt(state); + state->backend->s_fmt(state); break; case MARUCAM_CMD_G_FMT: - marucam_device_g_fmt(state); + state->backend->g_fmt(state); break; - case MARUCAM_CMD_QCTRL: - marucam_device_qctrl(state); + case MARUCAM_CMD_QUERYCTRL: + state->backend->query_ctrl(state); break; case MARUCAM_CMD_S_CTRL: - marucam_device_s_ctrl(state); + state->backend->s_ctrl(state); break; case MARUCAM_CMD_G_CTRL: - marucam_device_g_ctrl(state); + state->backend->g_ctrl(state); break; case MARUCAM_CMD_ENUM_FSIZES: - marucam_device_enum_fsizes(state); + state->backend->enum_framesizes(state); break; case MARUCAM_CMD_ENUM_FINTV: - marucam_device_enum_fintv(state); - break; - case MARUCAM_CMD_S_DATA: - state->param->stack[state->param->top++] = value; - break; - case MARUCAM_CMD_DATACLR: - memset(state->param, 0, sizeof(MaruCamParam)); + state->backend->enum_frameintervals(state); break; case MARUCAM_CMD_REQFRAME: qemu_mutex_lock(&state->thread_mutex); @@ -209,7 +183,7 @@ static int marucam_initfn(PCIDevice *dev) /* Check available webcam * If there is not one, you can't use the camera. */ - if (!marucam_device_check(1)) { + if (!marucam_device_check()) { s->initialized = false; ERR("Failed to check the camera device, " "You can *not* use the camera\n"); @@ -218,26 +192,32 @@ static int marucam_initfn(PCIDevice *dev) pci_config_set_interrupt_pin(pci_conf, 0x03); - memory_region_init_ram(&s->vram, OBJECT(s), "marucamera.ram", MARUCAM_MEM_SIZE, - &error_abort); - s->vaddr = memory_region_get_ram_ptr(&s->vram); - memset(s->vaddr, 0, MARUCAM_MEM_SIZE); + memory_region_init_ram(&s->fbmem, OBJECT(s), "marucamera.fbmem", + MARUCAM_MEM_SIZE, &error_abort); + s->fb_ptr = memory_region_get_ram_ptr(&s->fbmem); + memset(s->fb_ptr, 0, MARUCAM_MEM_SIZE); + + memory_region_init_ram(&s->iomem, OBJECT(s), "marucamera.iomem", + MARUCAM_IOMEM_SIZE, &error_abort); + s->io_ptr = (ArgsMem *)memory_region_get_ram_ptr(&s->iomem); + memset((void *)s->io_ptr, 0, MARUCAM_IOMEM_SIZE); - memory_region_init_io(&s->mmio, OBJECT(s), + memory_region_init_io(&s->ioreg, OBJECT(s), &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); + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->fbmem); + pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ioreg); + pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->iomem); /* for worker thread */ - s->param = (MaruCamParam *)g_malloc0(sizeof(MaruCamParam)); qemu_cond_init(&s->thread_cond); qemu_mutex_init(&s->thread_mutex); - marucam_device_init(s); + s->backend = marucam_backend_create(s); + s->backend->init(s); s->tx_bh = qemu_bh_new(marucam_tx_bh, s); s->initialized = true; @@ -255,8 +235,7 @@ static void marucam_exitfn(PCIDevice *pci_dev) OBJECT_CHECK(MaruCamState, pci_dev, MARU_PCI_CAMERA_DEVICE_NAME); if (s->initialized) { - marucam_device_exit(s); - g_free(s->param); + s->backend->release(s); qemu_cond_destroy(&s->thread_cond); qemu_mutex_destroy(&s->thread_mutex); } @@ -269,12 +248,12 @@ static void marucam_resetfn(DeviceState *d) MaruCamState *s = (MaruCamState *)d; if (s->initialized) { - marucam_device_close(s); + s->backend->reset(s); qemu_mutex_lock(&s->thread_mutex); s->isr = s->streamon = s->req_frame = s->buf_size = 0; qemu_mutex_unlock(&s->thread_mutex); - memset(s->vaddr, 0, MARUCAM_MEM_SIZE); - memset(s->param, 0x00, sizeof(MaruCamParam)); + memset(s->fb_ptr, 0, MARUCAM_MEM_SIZE); + memset((void *)s->io_ptr, 0, MARUCAM_IOMEM_SIZE); INFO("reset maru-camera device\n"); } } diff --git a/tizen/src/hw/pci/maru_camera.h b/tizen/src/hw/pci/maru_camera.h index 429446023e..c321f0849f 100644 --- a/tizen/src/hw/pci/maru_camera.h +++ b/tizen/src/hw/pci/maru_camera.h @@ -33,45 +33,80 @@ #include "hw/pci/pci.h" #include "qemu/thread.h" -#define MARUCAM_MAX_PARAM 20 #define MARUCAM_SKIPFRAMES 2 +#define MARUCAM_THREAD_NAME "marucam_worker_thread" + /* must sync with GUEST camera_driver */ #define MARUCAM_CMD_INIT 0x00 #define MARUCAM_CMD_OPEN 0x04 #define MARUCAM_CMD_CLOSE 0x08 #define MARUCAM_CMD_ISR 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_STREAMON 0x10 +#define MARUCAM_CMD_STREAMOFF 0x14 +#define MARUCAM_CMD_S_PARM 0x18 +#define MARUCAM_CMD_G_PARM 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_QUERYCTRL 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_DATACLR 0x50 -#define MARUCAM_CMD_REQFRAME 0x54 +#define MARUCAM_CMD_REQFRAME 0x44 +#define MARUCAM_CMD_EXIT 0x48 + +enum { + _MC_THREAD_PAUSED, + _MC_THREAD_STREAMON, + _MC_THREAD_STREAMOFF, +}; + +#define MARUCAM_CTRL_VALUE_MAX 20 +#define MARUCAM_CTRL_VALUE_MIN 1 +#define MARUCAM_CTRL_VALUE_MID 10 +#define MARUCAM_CTRL_VALUE_STEP 1 typedef struct MaruCamState MaruCamState; -typedef struct MaruCamParam MaruCamParam; -struct MaruCamParam { - uint32_t top; - uint32_t retVal; - uint32_t errCode; - uint32_t stack[MARUCAM_MAX_PARAM]; -}; +typedef struct MaruCamBackend { + MaruCamState *state; + + uint32_t type; + + void (*init)(MaruCamState *state); + void (*release)(MaruCamState *state); + void (*reset)(MaruCamState *state); + void (*open)(MaruCamState *state); + void (*close)(MaruCamState *state); + void (*stream_on)(MaruCamState *state); + void (*stream_off)(MaruCamState *state); + void (*s_parm)(MaruCamState *state); + void (*g_parm)(MaruCamState *state); + void (*enum_fmt)(MaruCamState *state); + void (*try_fmt)(MaruCamState *state); + void (*s_fmt)(MaruCamState *state); + void (*g_fmt)(MaruCamState *state); + void (*query_ctrl)(MaruCamState *state); + void (*s_ctrl)(MaruCamState *state); + void (*g_ctrl)(MaruCamState *state); + void (*enum_framesizes)(MaruCamState *state); + void (*enum_frameintervals)(MaruCamState *state); +} MaruCamBackend; + +typedef struct ArgsMem { + uint32_t index; + uint32_t type; + size_t size; + int32_t ret_val; + int32_t err_code; + void *data; +} ArgsMem; struct MaruCamState { PCIDevice dev; - MaruCamParam *param; QemuThread thread_id; QemuMutex thread_mutex;; QemuCond thread_cond; @@ -79,37 +114,23 @@ struct MaruCamState { bool initialized; bool destroying; - void *vaddr; /* vram ptr */ + void *fb_ptr; /* fbmem ptr */ + ArgsMem *io_ptr; /* iomem ptr */ uint32_t isr; uint32_t streamon; uint32_t buf_size; uint32_t req_frame; - MemoryRegion vram; - MemoryRegion mmio; + MemoryRegion fbmem; + MemoryRegion iomem; + MemoryRegion ioreg; + + MaruCamBackend *backend; }; -/* ------------------------------------------------------------------------- */ -/* Fucntion prototype */ -/* ------------------------------------------------------------------------- */ -int marucam_device_check(int log_flag); -void marucam_device_init(MaruCamState *state); -void marucam_device_exit(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); +MaruCamBackend *marucam_backend_create(MaruCamState *state); + +int marucam_device_check(void); int maru_camera_pci_init(PCIBus *bus); diff --git a/tizen/src/hw/pci/maru_camera_linux.c b/tizen/src/hw/pci/maru_camera_linux.c index 2a76c07ab1..8748a8c17d 100644 --- a/tizen/src/hw/pci/maru_camera_linux.c +++ b/tizen/src/hw/pci/maru_camera_linux.c @@ -43,29 +43,58 @@ MULTI_DEBUG_CHANNEL(tizen, camera); -#define MARUCAM_THREAD_NAME "marucam_worker_thread" +#define MAKE_BACKEND_V4L2(state) \ + MCBackendV4l2 *backend = (MCBackendV4l2 *)(state->backend) #define CLEAR(x) memset(&(x), 0, sizeof(x)) #define MARUCAM_DEFAULT_BUFFER_COUNT 4 -#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 MCFormat { + uint32_t fmt; /* fourcc */ +}; + +static struct MCFormat support_fmts[] = { + { V4L2_PIX_FMT_YUYV }, + { V4L2_PIX_FMT_YUV420 }, + { V4L2_PIX_FMT_YVU420 }, +}; + +struct MCFrame { + uint32_t width; + uint32_t height; +}; + +static struct MCFrame support_frames[] = { + { 640, 480 }, + { 352, 288 }, + { 320, 240 }, + { 176, 144 }, + { 160, 120 }, +}; + +struct MCControls { + uint32_t id; + uint32_t hit; + int32_t min; + int32_t max; + int32_t step; + int32_t init_val; +}; -enum { - _MC_THREAD_PAUSED, - _MC_THREAD_STREAMON, - _MC_THREAD_STREAMOFF, +static struct MCControls ctrl_tbl[] = { + { V4L2_CID_BRIGHTNESS, 0, }, + { V4L2_CID_CONTRAST, 0, }, + { V4L2_CID_SATURATION, 0, }, + { V4L2_CID_SHARPNESS, 0, }, }; -typedef struct marucam_framebuffer { +typedef struct MCBuffer { void *data; size_t size; -} marucam_framebuffer; +} MCBuffer; -struct marucam_saved_frame { +struct MCStoredFrame { void *data; uint32_t pixelformat; uint32_t width; @@ -73,19 +102,24 @@ struct marucam_saved_frame { uint32_t size; }; -static struct marucam_saved_frame saved_frame; -static char has_success_frame; -static int n_framebuffer; -static int previous_frame_index = -1; -static struct marucam_framebuffer *framebuffer; +typedef struct MCBackendV4l2 { + MaruCamBackend base; + + char *dev_name; + int fd; + int convert_trial; + int ready_count; + int timeout; + int has_success; + int prev_index; + int fb_num; -static const char *dev_name = "/dev/video0"; -static int v4l2_fd; -static int convert_trial; -static int ready_count; -static int timeout_n; + struct v4l2_format src_fmt; + struct v4l2_format dst_fmt; -static struct v4l2_format dst_fmt; + struct MCStoredFrame stored; + struct MCBuffer *fbs; +} MCBackendV4l2; static void ScalePlaneSimple(int src_width, int src_height, int dst_width, int dst_height, @@ -183,56 +217,17 @@ static int xioctl(int fd, int req, void *arg) return r; } -typedef struct tagMaruCamConvertPixfmt { - uint32_t fmt; /* fourcc */ -} MaruCamConvertPixfmt; - -static MaruCamConvertPixfmt supported_dst_pixfmts[] = { - { V4L2_PIX_FMT_YUYV }, - { V4L2_PIX_FMT_YUV420 }, - { V4L2_PIX_FMT_YVU420 }, -}; - -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 }, -}; - -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) +static void backend_v4l2_reset_controls(MCBackendV4l2 *backend) { uint32_t i; - for (i = 0; i < ARRAY_SIZE(qctrl_tbl); i++) { - if (qctrl_tbl[i].hit) { + for (i = 0; i < ARRAY_SIZE(ctrl_tbl); i++) { + if (ctrl_tbl[i].hit) { struct v4l2_control ctrl = {0,}; - ctrl.id = qctrl_tbl[i].id; - ctrl.value = qctrl_tbl[i].init_val; - qctrl_tbl[i].hit = qctrl_tbl[i].init_val = 0; - qctrl_tbl[i].min = qctrl_tbl[i].max = qctrl_tbl[i].step = 0; - if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) { + ctrl.id = ctrl_tbl[i].id; + ctrl.value = ctrl_tbl[i].init_val; + ctrl_tbl[i].hit = ctrl_tbl[i].init_val = 0; + ctrl_tbl[i].min = ctrl_tbl[i].max = ctrl_tbl[i].step = 0; + if (xioctl(backend->fd, VIDIOC_S_CTRL, &ctrl) < 0) { ERR("Failed to reset control value: id(0x%x), errstr(%s)\n", ctrl.id, strerror(errno)); } @@ -276,7 +271,7 @@ static int32_t value_convert_to_guest(int32_t min, int32_t max, int32_t value) return ret; } -static void set_maxframeinterval(MaruCamState *state, uint32_t pixel_format, +static void set_maxframeinterval(int fd, uint32_t pixel_format, uint32_t width, uint32_t height) { struct v4l2_frmivalenum fival; @@ -288,7 +283,7 @@ static void set_maxframeinterval(MaruCamState *state, uint32_t pixel_format, fival.width = width; fival.height = height; - if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) < 0) { + if (xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) < 0) { ERR("Unable to enumerate intervals for pixelformat(0x%x), (%d:%d)\n", pixel_format, width, height); return; @@ -307,7 +302,7 @@ static void set_maxframeinterval(MaruCamState *state, uint32_t pixel_format, TRACE("Discrete frame interval %u/%u supported\n", fival.discrete.numerator, fival.discrete.denominator); fival.index++; - } while (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) >= 0); + } while (xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) >= 0); } else if ((fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) || (fival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)) { TRACE("Frame intervals from %u/%u to %u/%u supported", @@ -335,86 +330,118 @@ static void set_maxframeinterval(MaruCamState *state, uint32_t pixel_format, sp.parm.capture.timeperframe.numerator = min_num; sp.parm.capture.timeperframe.denominator = min_denom; - if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) { + if (xioctl(fd, VIDIOC_S_PARM, &sp) < 0) { ERR("Failed to set to minimum FPS(%u/%u)\n", min_num, min_denom); } } -static uint32_t stop_capturing(void) +static uint32_t stop_capturing(MCBackendV4l2 *backend) { enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (xioctl(v4l2_fd, VIDIOC_STREAMOFF, &type) < 0) { + if (xioctl(backend->fd, VIDIOC_STREAMOFF, &type) < 0) { ERR("Failed to ioctl() with VIDIOC_STREAMOFF: %s\n", strerror(errno)); return errno; } return 0; } -static uint32_t start_capturing(void) +static uint32_t start_capturing(MCBackendV4l2 *backend) { enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (xioctl(v4l2_fd, VIDIOC_STREAMON, &type) < 0) { + if (xioctl(backend->fd, VIDIOC_STREAMON, &type) < 0) { ERR("Failed to ioctl() with VIDIOC_STREAMON: %s\n", strerror(errno)); return errno; } return 0; } -static void free_framebuffers(marucam_framebuffer *fb, int buf_num) +static void backend_v4l2_storedframe_clear(MCBackendV4l2 *backend) +{ + if (backend->stored.data) { + g_free(backend->stored.data); + backend->stored.data = NULL; + } + memset(&backend->stored, 0x00, sizeof(struct MCStoredFrame)); +} + +static void backend_v4l2_storedframe_set(MCBackendV4l2 *backend) +{ + backend->stored.width = backend->dst_fmt.fmt.pix.width; + backend->stored.height = backend->dst_fmt.fmt.pix.height; + backend->stored.pixelformat = backend->dst_fmt.fmt.pix.pixelformat; + backend->stored.size = backend->dst_fmt.fmt.pix.sizeimage; + if (backend->stored.data) { + g_free(backend->stored.data); + backend->stored.data = NULL; + } + backend->stored.data = (void *)g_malloc0(backend->stored.size); + memcpy(backend->stored.data, + backend->fbs[backend->prev_index].data, + backend->stored.size); + TRACE("Saves a frame data\n"); +} + +static void free_framebuffers(MCBackendV4l2 *backend) { int i; - if (fb == NULL) { + if (backend->fbs == NULL) { ERR("The framebuffer is NULL. Failed to release the framebuffer\n"); return; - } else if (buf_num == 0) { + } else if (backend->fb_num == 0) { ERR("The buffer count is 0. Failed to release the framebuffer\n"); return; } else { - TRACE("[%s]:fb(0x%p), buf_num(%d)\n", __func__, fb, buf_num); + TRACE("[%s]: fbs(0x%p), buf_num(%d)\n", + __func__, backend->fbs, backend->fb_num); } /* Unmap framebuffers. */ - for (i = 0; i < buf_num; i++) { - if (fb[i].data != NULL) { - v4l2_munmap(fb[i].data, fb[i].size); - fb[i].data = NULL; - fb[i].size = 0; + for (i = 0; i < backend->fb_num; i++) { + if (backend->fbs[i].data != NULL) { + v4l2_munmap(backend->fbs[i].data, backend->fbs[i].size); + backend->fbs[i].data = NULL; + backend->fbs[i].size = 0; } else { ERR("framebuffer[%d].data is NULL.\n", i); } } - previous_frame_index = -1; + backend->prev_index = -1; + g_free(backend->fbs); + backend->fbs = NULL; + backend->fb_num = 0; } static uint32_t -mmap_framebuffers(marucam_framebuffer **fb, int *buf_num) +mmap_framebuffers(MCBackendV4l2 *backend) { struct v4l2_requestbuffers req; + MCBuffer **fb = &backend->fbs; + int *buf_num = &backend->fb_num; CLEAR(req); req.count = MARUCAM_DEFAULT_BUFFER_COUNT; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; - if (xioctl(v4l2_fd, VIDIOC_REQBUFS, &req) < 0) { + if (xioctl(backend->fd, VIDIOC_REQBUFS, &req) < 0) { if (errno == EINVAL) { ERR("%s does not support memory mapping: %s\n", - dev_name, strerror(errno)); + backend->dev_name, strerror(errno)); } else { ERR("Failed to request bufs: %s\n", strerror(errno)); } return errno; } if (req.count == 0) { - ERR("Insufficient buffer memory on %s\n", dev_name); + ERR("Insufficient buffer memory on %s\n", backend->dev_name); return EINVAL; } - *fb = g_new0(marucam_framebuffer, req.count); + *fb = g_new0(MCBuffer, req.count); if (*fb == NULL) { ERR("Not enough memory to allocate framebuffers\n"); return ENOMEM; @@ -426,7 +453,7 @@ mmap_framebuffers(marucam_framebuffer **fb, int *buf_num) buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = *buf_num; - if (xioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf) < 0) { + if (xioctl(backend->fd, VIDIOC_QUERYBUF, &buf) < 0) { ERR("Failed to ioctl() with VIDIOC_QUERYBUF: %s\n", strerror(errno)); return errno; @@ -437,7 +464,7 @@ mmap_framebuffers(marucam_framebuffer **fb, int *buf_num) buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, - v4l2_fd, buf.m.offset); + backend->fd, buf.m.offset); if (MAP_FAILED == (*fb)[*buf_num].data) { ERR("Failed to mmap: %s\n", strerror(errno)); return errno; @@ -448,7 +475,7 @@ mmap_framebuffers(marucam_framebuffer **fb, int *buf_num) buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = *buf_num; - if (xioctl(v4l2_fd, VIDIOC_QBUF, &buf) < 0) { + if (xioctl(backend->fd, VIDIOC_QBUF, &buf) < 0) { ERR("Failed to ioctl() with VIDIOC_QBUF: %s\n", strerror(errno)); return errno; } @@ -478,27 +505,31 @@ static int is_stream_paused(MaruCamState *state) /* TODO: add other pixel format method */ static void __raise_dummy_intr(MaruCamState *state) { + MAKE_BACKEND_V4L2(state); void *buf = NULL; + qemu_mutex_lock(&state->thread_mutex); if (state->streamon == _MC_THREAD_STREAMON && state->req_frame) { - buf = state->vaddr + state->buf_size * (state->req_frame - 1); - if (saved_frame.data) { - if (saved_frame.width == dst_fmt.fmt.pix.width && - saved_frame.height == dst_fmt.fmt.pix.height) { + buf = state->fb_ptr + state->buf_size * (state->req_frame - 1); + if (backend->stored.data) { + if (backend->stored.width == backend->dst_fmt.fmt.pix.width && + backend->stored.height == backend->dst_fmt.fmt.pix.height) { TRACE("Copies the previuos frame\n"); - memcpy(buf, saved_frame.data, state->buf_size); + memcpy(buf, backend->stored.data, state->buf_size); } else { TRACE("Resizes the previous frame\n"); - marucam_scale_yuv420(saved_frame.data, saved_frame.width, - saved_frame.height, - buf, dst_fmt.fmt.pix.width, - dst_fmt.fmt.pix.height); + marucam_scale_yuv420(backend->stored.data, + backend->stored.width, + backend->stored.height, + buf, + backend->dst_fmt.fmt.pix.width, + backend->dst_fmt.fmt.pix.height); } } else { TRACE("Sends a black frame\n"); make_yu12_black(buf, - dst_fmt.fmt.pix.width, - dst_fmt.fmt.pix.height); + backend->dst_fmt.fmt.pix.width, + backend->dst_fmt.fmt.pix.height); } state->req_frame = 0; /* clear request */ state->isr |= 0x01; /* set a flag of raising a interrupt */ @@ -521,14 +552,15 @@ static void __raise_err_intr(MaruCamState *state) static void notify_buffer_ready(MaruCamState *state, uint32_t buf_index) { + MAKE_BACKEND_V4L2(state); void *buf = NULL; qemu_mutex_lock(&state->thread_mutex); if (state->streamon == _MC_THREAD_STREAMON) { - if (ready_count < MARUCAM_SKIPFRAMES) { + if (backend->ready_count < MARUCAM_SKIPFRAMES) { /* skip a frame cause first some frame are distorted */ - ++ready_count; - TRACE("Skip %d frame\n", ready_count); + ++backend->ready_count; + TRACE("Skip %d frame\n", backend->ready_count); qemu_mutex_unlock(&state->thread_mutex); return; } @@ -536,10 +568,10 @@ notify_buffer_ready(MaruCamState *state, uint32_t buf_index) qemu_mutex_unlock(&state->thread_mutex); return; } - buf = state->vaddr + state->buf_size * (state->req_frame - 1); - memcpy(buf, framebuffer[buf_index].data, state->buf_size); - previous_frame_index = buf_index; - has_success_frame = 1; + buf = state->fb_ptr + state->buf_size * (state->req_frame - 1); + memcpy(buf, backend->fbs[buf_index].data, state->buf_size); + backend->prev_index = buf_index; + backend->has_success = 1; state->req_frame = 0; /* clear request */ state->isr |= 0x01; /* set a flag of rasing a interrupt */ qemu_bh_schedule(state->tx_bh); @@ -549,12 +581,13 @@ notify_buffer_ready(MaruCamState *state, uint32_t buf_index) static int read_frame(MaruCamState *state) { + MAKE_BACKEND_V4L2(state); struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; - if (xioctl(v4l2_fd, VIDIOC_DQBUF, &buf) < 0) { + if (xioctl(backend->fd, VIDIOC_DQBUF, &buf) < 0) { switch (errno) { case EAGAIN: case EINTR: @@ -562,7 +595,7 @@ static int read_frame(MaruCamState *state) return 0; case EIO: ERR("The v4l2_read() met the EIO\n"); - if (convert_trial-- == -1) { + if (backend->convert_trial-- == -1) { ERR("Try count for v4l2_read is exceeded: %s\n", strerror(errno)); return -1; @@ -576,7 +609,7 @@ static int read_frame(MaruCamState *state) notify_buffer_ready(state, buf.index); - if (xioctl(v4l2_fd, VIDIOC_QBUF, &buf) < 0) { + if (xioctl(backend->fd, VIDIOC_QBUF, &buf) < 0) { ERR("QBUF error: %s\n", strerror(errno)); return -1; } @@ -585,17 +618,18 @@ static int read_frame(MaruCamState *state) static int __v4l2_streaming(MaruCamState *state) { + MAKE_BACKEND_V4L2(state); fd_set fds; struct timeval tv; int ret; FD_ZERO(&fds); - FD_SET(v4l2_fd, &fds); + FD_SET(backend->fd, &fds); tv.tv_sec = 1; tv.tv_usec = 0; - ret = select(v4l2_fd + 1, &fds, NULL, NULL, &tv); + ret = select(backend->fd + 1, &fds, NULL, NULL, &tv); if (ret < 0) { if (errno == EAGAIN || errno == EINTR) { ERR("Select again: %s\n", strerror(errno)); @@ -605,10 +639,10 @@ static int __v4l2_streaming(MaruCamState *state) __raise_err_intr(state); return -1; } else if (!ret) { - timeout_n++; - ERR("Select timed out: count(%u)\n", timeout_n); - if (ready_count <= MARUCAM_SKIPFRAMES) { - switch (timeout_n) { + backend->timeout++; + ERR("Select timed out: count(%u)\n", backend->timeout); + if (backend->ready_count <= MARUCAM_SKIPFRAMES) { + switch (backend->timeout) { case 1: ERR("Waiting for reading a frame data\n"); return 0; @@ -625,19 +659,19 @@ static int __v4l2_streaming(MaruCamState *state) return -1; } } - if (timeout_n >= 5) { + if (backend->timeout >= 5) { ERR("Webcam is busy, failed to a read frame. Raises an error\n"); __raise_err_intr(state); return -1; } - if (previous_frame_index != -1) { + if (backend->prev_index != -1) { ERR("Sends previous frame data\n"); - notify_buffer_ready(state, previous_frame_index); + notify_buffer_ready(state, backend->prev_index); } return 0; } - if (!v4l2_fd || (v4l2_fd == -1)) { + if (!backend->fd || (backend->fd == -1)) { ERR("The file descriptor is closed or not opened\n"); __raise_err_intr(state); return -1; @@ -651,8 +685,8 @@ static int __v4l2_streaming(MaruCamState *state) } /* clear the skip count for select time-out */ - if (timeout_n > 0) { - timeout_n = 0; + if (backend->timeout > 0) { + backend->timeout = 0; } return 0; @@ -662,6 +696,7 @@ static int __v4l2_streaming(MaruCamState *state) static void *marucam_worker_thread(void *thread_param) { MaruCamState *state = (MaruCamState *)thread_param; + MAKE_BACKEND_V4L2(state); while (1) { qemu_mutex_lock(&state->thread_mutex); @@ -673,10 +708,10 @@ static void *marucam_worker_thread(void *thread_param) break; } - convert_trial = 10; - ready_count = 0; - timeout_n = 0; - has_success_frame = 0; + backend->convert_trial = 10; + backend->ready_count = 0; + backend->timeout = 0; + backend->has_success = 0; qemu_mutex_lock(&state->thread_mutex); state->streamon = _MC_THREAD_STREAMON; qemu_mutex_unlock(&state->thread_mutex); @@ -698,7 +733,7 @@ static void *marucam_worker_thread(void *thread_param) return NULL; } -int marucam_device_check(int log_flag) +int marucam_device_check(void) { int tmp_fd; struct timeval t1, t2; @@ -707,15 +742,14 @@ int marucam_device_check(int log_flag) struct v4l2_frmsizeenum size; struct v4l2_capability cap; int ret = 0; + const char *dev_name = "/dev/video0"; gettimeofday(&t1, NULL); if (stat(dev_name, &st) < 0) { - INFO(" Cannot identify '%s': %s\n", - dev_name, strerror(errno)); + INFO(" Cannot identify '%s': %s\n", dev_name, strerror(errno)); } else { if (!S_ISCHR(st.st_mode)) { - INFO("%s is no character device\n", - dev_name); + INFO("%s is no character device\n", dev_name); } } @@ -724,7 +758,7 @@ int marucam_device_check(int log_flag) ERR("Camera device open failed: %s\n", dev_name); gettimeofday(&t2, NULL); ERR("Elapsed time: %lu:%06lu\n", - t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); + t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); return ret; } if (ioctl(tmp_fd, VIDIOC_QUERYCAP, &cap) < 0) { @@ -732,7 +766,7 @@ int marucam_device_check(int log_flag) close(tmp_fd); gettimeofday(&t2, NULL); ERR("Elapsed time: %lu:%06lu\n", - t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); + t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); return ret; } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) || @@ -741,81 +775,79 @@ int marucam_device_check(int log_flag) close(tmp_fd); gettimeofday(&t2, NULL); ERR("Elapsed time: %lu:%06lu\n", - t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); + t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); return ret; } ret = 1; - if (log_flag) { - INFO("Driver: %s\n", cap.driver); - INFO("Card: %s\n", cap.card); - INFO("Bus info: %s\n", cap.bus_info); + INFO("Driver: %s\n", cap.driver); + INFO("Card: %s\n", cap.card); + INFO("Bus info: %s\n", cap.bus_info); + + CLEAR(format); + format.index = 0; + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) < 0) { + close(tmp_fd); + gettimeofday(&t2, NULL); + ERR("Elapsed time: %lu:%06lu\n", + t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); + return ret; + } + + do { + CLEAR(size); + size.index = 0; + size.pixel_format = format.pixelformat; - CLEAR(format); - format.index = 0; - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + INFO("PixelFormat: %c%c%c%c\n", + (char)(format.pixelformat), + (char)(format.pixelformat >> 8), + (char)(format.pixelformat >> 16), + (char)(format.pixelformat >> 24)); - if (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) < 0) { + if (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0) { close(tmp_fd); gettimeofday(&t2, NULL); ERR("Elapsed time: %lu:%06lu\n", - t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); + t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); return ret; } - do { - CLEAR(size); - size.index = 0; - size.pixel_format = format.pixelformat; - - INFO("PixelFormat: %c%c%c%c\n", - (char)(format.pixelformat), - (char)(format.pixelformat >> 8), - (char)(format.pixelformat >> 16), - (char)(format.pixelformat >> 24)); - - if (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0) { - close(tmp_fd); - gettimeofday(&t2, NULL); - ERR("Elapsed time: %lu:%06lu\n", - t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); - return ret; - } + if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { + do { + INFO("\tGot a discrete frame size %dx%d\n", + size.discrete.width, size.discrete.height); + size.index++; + } while (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0); + } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { + INFO("We have stepwise frame sizes:\n"); + INFO("\tmin width: %d, min height: %d\n", + size.stepwise.min_width, size.stepwise.min_height); + INFO("\tmax width: %d, max height: %d\n", + size.stepwise.max_width, size.stepwise.max_height); + INFO("\tstep width: %d, step height: %d\n", + size.stepwise.step_width, size.stepwise.step_height); + } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { + INFO("We have continuous frame sizes:\n"); + INFO("\tmin width: %d, min height: %d\n", + size.stepwise.min_width, size.stepwise.min_height); + INFO("\tmax width: %d, max height: %d\n", + size.stepwise.max_width, size.stepwise.max_height); - if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { - do { - INFO("\tGot a discrete frame size %dx%d\n", - size.discrete.width, size.discrete.height); - size.index++; - } while (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0); - } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { - INFO("We have stepwise frame sizes:\n"); - INFO("\tmin width: %d, min height: %d\n", - size.stepwise.min_width, size.stepwise.min_height); - INFO("\tmax width: %d, max height: %d\n", - size.stepwise.max_width, size.stepwise.max_height); - INFO("\tstep width: %d, step height: %d\n", - size.stepwise.step_width, size.stepwise.step_height); - } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { - INFO("We have continuous frame sizes:\n"); - INFO("\tmin width: %d, min height: %d\n", - size.stepwise.min_width, size.stepwise.min_height); - INFO("\tmax width: %d, max height: %d\n", - size.stepwise.max_width, size.stepwise.max_height); - - } - format.index++; - } while (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) >= 0); - } + } + format.index++; + } while (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) >= 0); close(tmp_fd); gettimeofday(&t2, NULL); INFO("Elapsed time: %lu:%06lu\n", - t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); + t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec); return ret; } -void marucam_device_init(MaruCamState *state) +static void backend_v4l2_init(MaruCamState *state) { state->destroying = false; qemu_thread_create(&state->thread_id, @@ -825,7 +857,11 @@ void marucam_device_init(MaruCamState *state) QEMU_THREAD_JOINABLE); } -void marucam_device_exit(MaruCamState *state) +static void backend_v4l2_reset(MaruCamState *state) +{ +} + +static void backend_v4l2_release(MaruCamState *state) { state->destroying = true; qemu_mutex_lock(&state->thread_mutex); @@ -834,20 +870,20 @@ void marucam_device_exit(MaruCamState *state) qemu_thread_join(&state->thread_id); } -void marucam_device_open(MaruCamState *state) +static void backend_v4l2_open(MaruCamState *state) { - MaruCamParam *param = state->param; + MAKE_BACKEND_V4L2(state); - param->top = 0; - v4l2_fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0); - if (v4l2_fd < 0) { - ERR("The v4l2 device open failed: %s\n", dev_name); - param->errCode = EINVAL; + backend->fd = v4l2_open(backend->dev_name, O_RDWR | O_NONBLOCK, 0); + if (backend->fd < 0) { + ERR("The v4l2 device open failed: %s\n", backend->dev_name); + state->io_ptr->err_code = EINVAL; + state->io_ptr->ret_val = -1; return; } INFO("Opened\n"); - /* FIXME : Do not use fixed values */ + /* FIXME : Do not use fixed values CLEAR(dst_fmt); dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; dst_fmt.fmt.pix.width = 640; @@ -869,50 +905,63 @@ void marucam_device_open(MaruCamState *state) dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height, dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.sizeimage, dst_fmt.fmt.pix.colorspace, dst_fmt.fmt.pix.field); + */ +} + +static void backend_v4l2_close(MaruCamState *state) +{ + MAKE_BACKEND_V4L2(state); + + if (!is_stream_paused(state)) { + state->backend->stream_off(state); + } + + backend_v4l2_reset_controls(backend); + backend_v4l2_storedframe_clear(backend); + + v4l2_close(backend->fd); + backend->fd = 0; + INFO("Closed\n"); } -void marucam_device_start_preview(MaruCamState *state) +static void backend_v4l2_stream_on(MaruCamState *state) { + MAKE_BACKEND_V4L2(state); + struct timespec req; - MaruCamParam *param = state->param; - param->top = 0; req.tv_sec = 0; req.tv_nsec = 10000000; INFO("Pixfmt(%c%c%c%C), W:H(%d:%d), buf size(%u)\n", - (char)(dst_fmt.fmt.pix.pixelformat), - (char)(dst_fmt.fmt.pix.pixelformat >> 8), - (char)(dst_fmt.fmt.pix.pixelformat >> 16), - (char)(dst_fmt.fmt.pix.pixelformat >> 24), - dst_fmt.fmt.pix.width, - dst_fmt.fmt.pix.height, - dst_fmt.fmt.pix.sizeimage); - - param->errCode = mmap_framebuffers(&framebuffer, &n_framebuffer); - if (param->errCode) { + (char)(backend->dst_fmt.fmt.pix.pixelformat), + (char)(backend->dst_fmt.fmt.pix.pixelformat >> 8), + (char)(backend->dst_fmt.fmt.pix.pixelformat >> 16), + (char)(backend->dst_fmt.fmt.pix.pixelformat >> 24), + backend->dst_fmt.fmt.pix.width, + backend->dst_fmt.fmt.pix.height, + backend->dst_fmt.fmt.pix.sizeimage); + + state->io_ptr->err_code = mmap_framebuffers(backend); + if (state->io_ptr->err_code) { ERR("Failed to mmap framebuffers\n"); - if (framebuffer != NULL) { - free_framebuffers(framebuffer, n_framebuffer); - g_free(framebuffer); - framebuffer = NULL; - n_framebuffer = 0; + if (backend->fbs != NULL) { + free_framebuffers(backend); } + state->io_ptr->ret_val = -1; return; } - param->errCode = start_capturing(); - if (param->errCode) { - if (framebuffer != NULL) { - free_framebuffers(framebuffer, n_framebuffer); - g_free(framebuffer); - framebuffer = NULL; - n_framebuffer = 0; + state->io_ptr->err_code = start_capturing(backend); + if (state->io_ptr->err_code) { + if (backend->fbs != NULL) { + free_framebuffers(backend); } + state->io_ptr->ret_val = -1; return; } INFO("Starting preview\n"); - state->buf_size = dst_fmt.fmt.pix.sizeimage; + state->buf_size = backend->dst_fmt.fmt.pix.sizeimage; qemu_mutex_lock(&state->thread_mutex); qemu_cond_signal(&state->thread_cond); qemu_mutex_unlock(&state->thread_mutex); @@ -923,12 +972,11 @@ void marucam_device_start_preview(MaruCamState *state) } } -void marucam_device_stop_preview(MaruCamState *state) +static void backend_v4l2_stream_off(MaruCamState *state) { + MAKE_BACKEND_V4L2(state); struct timespec req; struct v4l2_requestbuffers reqbuf; - MaruCamParam *param = state->param; - param->top = 0; req.tv_sec = 0; req.tv_nsec = 50000000; @@ -943,355 +991,295 @@ void marucam_device_stop_preview(MaruCamState *state) } } - if (has_success_frame) { - saved_frame.width = dst_fmt.fmt.pix.width; - saved_frame.height = dst_fmt.fmt.pix.height; - saved_frame.size = dst_fmt.fmt.pix.sizeimage; - if (saved_frame.data) { - g_free(saved_frame.data); - saved_frame.data = NULL; - } - saved_frame.data = (void *)g_malloc0(saved_frame.size); - memcpy(saved_frame.data, - framebuffer[previous_frame_index].data, - saved_frame.size); - TRACE("Saves a frame data\n"); + if (backend->has_success) { + backend_v4l2_storedframe_set(backend); } - param->errCode = stop_capturing(); - if (framebuffer != NULL) { - free_framebuffers(framebuffer, n_framebuffer); - g_free(framebuffer); - framebuffer = NULL; - n_framebuffer = 0; + state->io_ptr->err_code = stop_capturing(backend); + if (state->io_ptr->err_code) { + ERR("Try again to turn off streaming\n"); + state->io_ptr->err_code = stop_capturing(backend); + } + if (backend->fbs != NULL) { + free_framebuffers(backend); } state->buf_size = 0; reqbuf.count = 0; reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; reqbuf.memory = V4L2_MEMORY_MMAP; - if (xioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf) < 0) { + if (xioctl(backend->fd, VIDIOC_REQBUFS, &reqbuf) < 0) { ERR("Failed to ioctl() with VIDIOC_REQBUF in stop_preview: %s\n", strerror(errno)); } + + if (state->io_ptr->err_code) { + state->io_ptr->ret_val = -1; + } + INFO("Stopping preview\n"); } -void marucam_device_s_param(MaruCamState *state) -{ - MaruCamParam *param = state->param; - param->top = 0; +static void backend_v4l2_s_parm(MaruCamState *state) +{ + MAKE_BACKEND_V4L2(state); /* If KVM enabled, We use default FPS of the webcam. * If KVM disabled, we use mininum FPS of the webcam */ if (!kvm_enabled()) { - set_maxframeinterval(state, dst_fmt.fmt.pix.pixelformat, - dst_fmt.fmt.pix.width, - dst_fmt.fmt.pix.height); + set_maxframeinterval(backend->fd, + backend->dst_fmt.fmt.pix.pixelformat, + backend->dst_fmt.fmt.pix.width, + backend->dst_fmt.fmt.pix.height); } } -void marucam_device_g_param(MaruCamState *state) +static void backend_v4l2_g_parm(MaruCamState *state) { - MaruCamParam *param = state->param; - + struct v4l2_captureparm *cp = (struct v4l2_captureparm *)state->io_ptr->data; /* We use default FPS of the webcam * return a fixed value on guest ini file (1/30). */ - param->top = 0; - param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */ - param->stack[1] = 1; /* numerator */ - param->stack[2] = 30; /* denominator */ + cp->capability = V4L2_CAP_TIMEPERFRAME; + cp->timeperframe.numerator = 1; + cp->timeperframe.denominator = 30; } -void marucam_device_s_fmt(MaruCamState *state) +static void backend_v4l2_s_fmt(MaruCamState *state) { - struct v4l2_format format; - MaruCamParam *param = state->param; + MAKE_BACKEND_V4L2(state); + struct v4l2_format *format = (struct v4l2_format *)state->io_ptr->data; - param->top = 0; - CLEAR(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 = V4L2_FIELD_ANY; - - if (xioctl(v4l2_fd, VIDIOC_S_FMT, &format) < 0) { + if (xioctl(backend->fd, VIDIOC_S_FMT, format) < 0) { ERR("Failed to set video format: format(0x%x), width:height(%d:%d), " - "errstr(%s)\n", format.fmt.pix.pixelformat, format.fmt.pix.width, - format.fmt.pix.height, strerror(errno)); - param->errCode = errno; + "errstr(%s)\n", format->fmt.pix.pixelformat, format->fmt.pix.width, + format->fmt.pix.height, strerror(errno)); + state->io_ptr->err_code = errno; + state->io_ptr->ret_val = -1; return; } - memcpy(&dst_fmt, &format, sizeof(format)); - 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; + memcpy(&backend->dst_fmt, format, sizeof(struct v4l2_format)); TRACE("Set the format: w:h(%dx%d), fmt(0x%x), size(%d), " "color(%d), field(%d)\n", - dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height, - dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.sizeimage, - dst_fmt.fmt.pix.colorspace, dst_fmt.fmt.pix.field); + format->fmt.pix.width, format->fmt.pix.height, + format->fmt.pix.pixelformat, format->fmt.pix.sizeimage, + format->fmt.pix.colorspace, format->fmt.pix.field); } -void marucam_device_g_fmt(MaruCamState *state) +static void backend_v4l2_g_fmt(MaruCamState *state) { - struct v4l2_format format; - MaruCamParam *param = state->param; - - param->top = 0; - CLEAR(format); - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + MAKE_BACKEND_V4L2(state); + struct v4l2_format *format = (struct v4l2_format *)state->io_ptr->data; - if (xioctl(v4l2_fd, VIDIOC_G_FMT, &format) < 0) { + if (xioctl(backend->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; - TRACE("Get the format: w:h(%dx%d), fmt(0x%x), size(%d), " - "color(%d), field(%d)\n", - format.fmt.pix.width, format.fmt.pix.height, - format.fmt.pix.pixelformat, format.fmt.pix.sizeimage, - format.fmt.pix.colorspace, format.fmt.pix.field); + state->io_ptr->err_code = errno; + state->io_ptr->ret_val = -1; + return; } + TRACE("Get the format: w:h(%dx%d), fmt(0x%x), size(%d), " + "color(%d), field(%d)\n", + format->fmt.pix.width, format->fmt.pix.height, + format->fmt.pix.pixelformat, format->fmt.pix.sizeimage, + format->fmt.pix.colorspace, format->fmt.pix.field); } -void marucam_device_try_fmt(MaruCamState *state) +static void backend_v4l2_try_fmt(MaruCamState *state) { - struct v4l2_format format; - MaruCamParam *param = state->param; + MAKE_BACKEND_V4L2(state); + struct v4l2_format *format = (struct v4l2_format *)state->io_ptr->data; - param->top = 0; - CLEAR(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 = V4L2_FIELD_ANY; - - if (xioctl(v4l2_fd, VIDIOC_TRY_FMT, &format) < 0) { + if (xioctl(backend->fd, VIDIOC_TRY_FMT, format) < 0) { ERR("Failed to check video format: format(0x%x), width:height(%d:%d)," - " errstr(%s)\n", format.fmt.pix.pixelformat, format.fmt.pix.width, - format.fmt.pix.height, strerror(errno)); - param->errCode = errno; + " errstr(%s)\n", format->fmt.pix.pixelformat, format->fmt.pix.width, + format->fmt.pix.height, strerror(errno)); + state->io_ptr->err_code = errno; + state->io_ptr->ret_val = -1; 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; TRACE("Check the format: w:h(%dx%d), fmt(0x%x), size(%d), " "color(%d), field(%d)\n", - format.fmt.pix.width, format.fmt.pix.height, - format.fmt.pix.pixelformat, format.fmt.pix.sizeimage, - format.fmt.pix.colorspace, format.fmt.pix.field); + format->fmt.pix.width, format->fmt.pix.height, + format->fmt.pix.pixelformat, format->fmt.pix.sizeimage, + format->fmt.pix.colorspace, format->fmt.pix.field); } -void marucam_device_enum_fmt(MaruCamState *state) +static void backend_v4l2_enum_fmt(MaruCamState *state) { - uint32_t index; - MaruCamParam *param = state->param; + struct v4l2_fmtdesc *f = (struct v4l2_fmtdesc *)state->io_ptr->data; - param->top = 0; - index = param->stack[0]; - - if (index >= ARRAY_SIZE(supported_dst_pixfmts)) { - param->errCode = EINVAL; + if (f->index >= ARRAY_SIZE(support_fmts)) { + state->io_ptr->err_code = errno; + state->io_ptr->ret_val = -1; return; } - param->stack[1] = 0; /* flags = NONE */ - param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */ + + f->flags = 0; /* flags = NONE */ + f->pixelformat = support_fmts[f->index].fmt; /* pixelformat */ + /* set description */ - switch (supported_dst_pixfmts[index].fmt) { + switch (support_fmts[f->index].fmt) { case V4L2_PIX_FMT_YUYV: - strcpy((char *)¶m->stack[3], "YUYV"); + pstrcpy((char *)f->description, sizeof(f->description), "YUYV"); break; case V4L2_PIX_FMT_YUV420: - strcpy((char *)¶m->stack[3], "YU12"); + pstrcpy((char *)f->description, sizeof(f->description), "YU12"); break; case V4L2_PIX_FMT_YVU420: - strcpy((char *)¶m->stack[3], "YV12"); + pstrcpy((char *)f->description, sizeof(f->description), "YV12"); break; default: ERR("Invalid fixel format\n"); - param->errCode = EINVAL; + state->io_ptr->err_code = EINVAL; + state->io_ptr->ret_val = -1; break; } } -void marucam_device_qctrl(MaruCamState *state) +static void backend_v4l2_query_ctrl(MaruCamState *state) { + MAKE_BACKEND_V4L2(state); + struct v4l2_queryctrl *qc = (struct v4l2_queryctrl *)state->io_ptr->data; uint32_t i; - char name[32] = {0,}; - struct v4l2_queryctrl ctrl; - MaruCamParam *param = state->param; - - param->top = 0; - CLEAR(ctrl); - ctrl.id = param->stack[0]; /* NOTICE: Tizen MMFW hardcoded for control name Do Not Modified the name */ - switch (ctrl.id) { + switch (qc->id) { case V4L2_CID_BRIGHTNESS: TRACE("Query : BRIGHTNESS\n"); - strcpy(name, "brightness"); + pstrcpy((char *)qc->name, sizeof(qc->name), "brightness"); i = 0; break; case V4L2_CID_CONTRAST: TRACE("Query : CONTRAST\n"); - strcpy(name, "contrast"); + pstrcpy((char *)qc->name, sizeof(qc->name), "contrast"); i = 1; break; case V4L2_CID_SATURATION: TRACE("Query : SATURATION\n"); - strcpy(name, "saturation"); + pstrcpy((char *)qc->name, sizeof(qc->name), "saturation"); i = 2; break; case V4L2_CID_SHARPNESS: TRACE("Query : SHARPNESS\n"); - strcpy(name, "sharpness"); + pstrcpy((char *)qc->name, sizeof(qc->name), "sharpness"); i = 3; break; default: ERR("Invalid control ID\n"); - param->errCode = EINVAL; + state->io_ptr->err_code = EINVAL; + state->io_ptr->ret_val = -1; return; } - if (xioctl(v4l2_fd, VIDIOC_QUERYCTRL, &ctrl) < 0) { + if (xioctl(backend->fd, VIDIOC_QUERYCTRL, qc) < 0) { if (errno != EINVAL) { ERR("Failed to query video controls: %s\n", strerror(errno)); } - param->errCode = errno; + state->io_ptr->err_code = errno; + state->io_ptr->ret_val = -1; return; } else { struct v4l2_control sctrl, gctrl; CLEAR(sctrl); CLEAR(gctrl); - sctrl.id = gctrl.id = ctrl.id; - if (xioctl(v4l2_fd, VIDIOC_G_CTRL, &gctrl) < 0) { + sctrl.id = gctrl.id = qc->id; + if (xioctl(backend->fd, VIDIOC_G_CTRL, &gctrl) < 0) { ERR("[%s] Failed to get video control value: id(0x%x), " "errstr(%s)\n", __func__, gctrl.id, strerror(errno)); - param->errCode = errno; + state->io_ptr->err_code = errno; + state->io_ptr->ret_val = -1; 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 = gctrl.value; + ctrl_tbl[i].hit = 1; + ctrl_tbl[i].min = qc->minimum; + ctrl_tbl[i].max = qc->maximum; + ctrl_tbl[i].step = qc->step; + ctrl_tbl[i].init_val = gctrl.value; - if ((ctrl.maximum + ctrl.minimum) == 0) { + if ((qc->maximum + qc->minimum) == 0) { sctrl.value = 0; } else { - sctrl.value = (ctrl.maximum + ctrl.minimum) / 2; + sctrl.value = (qc->maximum + qc->minimum) / 2; } - if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &sctrl) < 0) { + if (xioctl(backend->fd, VIDIOC_S_CTRL, &sctrl) < 0) { ERR("[%s] Failed to set control value: id(0x%x), value(%d), " "errstr(%s)\n", __func__, sctrl.id, sctrl.value, strerror(errno)); - param->errCode = errno; + state->io_ptr->err_code = errno; + state->io_ptr->ret_val = -1; return; } INFO("Query Control: id(0x%x), name(%s), min(%d), max(%d), " "step(%d), def_value(%d)\n" "flags(0x%x), get_value(%d), set_value(%d)\n", - ctrl.id, ctrl.name, ctrl.minimum, ctrl.maximum, - ctrl.step, ctrl.default_value, ctrl.flags, + qc->id, qc->name, qc->minimum, qc->maximum, + qc->step, qc->default_value, qc->flags, gctrl.value, sctrl.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)); + qc->minimum = MARUCAM_CTRL_VALUE_MIN; /* minimum */ + qc->maximum = MARUCAM_CTRL_VALUE_MAX; /* maximum */ + qc->step = MARUCAM_CTRL_VALUE_STEP; /* step */ + qc->default_value = MARUCAM_CTRL_VALUE_MID; /* default_value */ } -void marucam_device_s_ctrl(MaruCamState *state) +static void backend_v4l2_s_ctrl(MaruCamState *state) { + MAKE_BACKEND_V4L2(state); + struct v4l2_control *ctrl = (struct v4l2_control *)state->io_ptr->data; uint32_t i; - struct v4l2_control ctrl; - MaruCamParam *param = state->param; - param->top = 0; - CLEAR(ctrl); - ctrl.id = param->stack[0]; - - switch (ctrl.id) { + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: i = 0; - TRACE("%d is set to the value of the BRIGHTNESS\n", param->stack[1]); + TRACE("%d is set to the value of the BRIGHTNESS\n", ctrl->value); break; case V4L2_CID_CONTRAST: i = 1; - TRACE("%d is set to the value of the CONTRAST\n", param->stack[1]); + TRACE("%d is set to the value of the CONTRAST\n", ctrl->value); break; case V4L2_CID_SATURATION: i = 2; - TRACE("%d is set to the value of the SATURATION\n", param->stack[1]); + TRACE("%d is set to the value of the SATURATION\n", ctrl->value); break; case V4L2_CID_SHARPNESS: i = 3; - TRACE("%d is set to the value of the SHARPNESS\n", param->stack[1]); + TRACE("%d is set to the value of the SHARPNESS\n", ctrl->value); break; default: - ERR("Our emulator does not support this control: 0x%x\n", ctrl.id); - param->errCode = EINVAL; + ERR("Our emulator does not support this control: 0x%x\n", ctrl->id); + state->io_ptr->err_code= EINVAL; + state->io_ptr->ret_val = -1; 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 control value: id(0x%x), value(r:%d, c:%d), " - "errstr(%s)\n", ctrl.id, param->stack[1], ctrl.value, - strerror(errno)); - param->errCode = errno; + ctrl->value = value_convert_from_guest(ctrl_tbl[i].min, + ctrl_tbl[i].max, ctrl->value); + if (xioctl(backend->fd, VIDIOC_S_CTRL, ctrl) < 0) { + ERR("Failed to set control value: id(0x%x), value(%d), errstr(%s)\n", + ctrl->id, ctrl->value, strerror(errno)); + state->io_ptr->err_code = errno; + state->io_ptr->ret_val = -1; return; } } -void marucam_device_g_ctrl(MaruCamState *state) +static void backend_v4l2_g_ctrl(MaruCamState *state) { + MAKE_BACKEND_V4L2(state); + struct v4l2_control *ctrl = (struct v4l2_control *)state->io_ptr->data; uint32_t i; - struct v4l2_control ctrl; - MaruCamParam *param = state->param; - - param->top = 0; - CLEAR(ctrl); - ctrl.id = param->stack[0]; - switch (ctrl.id) { + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: TRACE("Gets the value of the BRIGHTNESS\n"); i = 0; @@ -1309,83 +1297,93 @@ void marucam_device_g_ctrl(MaruCamState *state) i = 3; break; default: - ERR("Our emulator does not support this control: 0x%x\n", ctrl.id); - param->errCode = EINVAL; + ERR("Our emulator does not support this control: 0x%x\n", ctrl->id); + state->io_ptr->err_code = EINVAL; + state->io_ptr->ret_val = -1; return; } - if (xioctl(v4l2_fd, VIDIOC_G_CTRL, &ctrl) < 0) { + if (xioctl(backend->fd, VIDIOC_G_CTRL, ctrl) < 0) { ERR("Failed to get video control value: %s\n", strerror(errno)); - param->errCode = errno; + state->io_ptr->err_code = errno; + state->io_ptr->ret_val = -1; 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]); + ctrl->value = value_convert_to_guest(ctrl_tbl[i].min, + ctrl_tbl[i].max, ctrl->value); + TRACE("Value: %d\n", ctrl->value); } -void marucam_device_enum_fsizes(MaruCamState *state) +static void backend_v4l2_enum_fsizes(MaruCamState *state) { - uint32_t index, pixfmt, i; - MaruCamParam *param = state->param; - - param->top = 0; - index = param->stack[0]; - pixfmt = param->stack[1]; + struct v4l2_frmsizeenum *fsize = (struct v4l2_frmsizeenum *)state->io_ptr->data; + uint32_t i; - if (index >= ARRAY_SIZE(supported_dst_frames)) { - param->errCode = EINVAL; + if (fsize->index >= ARRAY_SIZE(support_frames)) { + state->io_ptr->err_code = EINVAL; + state->io_ptr->ret_val = -1; return; } - for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) { - if (supported_dst_pixfmts[i].fmt == pixfmt) { + for (i = 0; i < ARRAY_SIZE(support_fmts); i++) { + if (support_fmts[i].fmt == fsize->pixel_format) { break; } } - if (i == ARRAY_SIZE(supported_dst_pixfmts)) { - param->errCode = EINVAL; + if (i == ARRAY_SIZE(support_fmts)) { + state->io_ptr->err_code = EINVAL; + state->io_ptr->ret_val = -1; return; } - param->stack[0] = supported_dst_frames[index].width; - param->stack[1] = supported_dst_frames[index].height; + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = support_frames[fsize->index].width; + fsize->discrete.height = support_frames[fsize->index].height; } -void marucam_device_enum_fintv(MaruCamState *state) +static void backend_v4l2_enum_fintv(MaruCamState *state) { - MaruCamParam *param = state->param; - - param->top = 0; + struct v4l2_frmivalenum *fival = (struct v4l2_frmivalenum *)state->io_ptr->data; - /* switch by index(param->stack[0]) */ - switch (param->stack[0]) { + /* switch by index) */ + switch (fival->index) { case 0: /* we only use 1/30 frame interval */ - param->stack[1] = 30; /* denominator */ + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = 1; + fival->discrete.denominator = 30; break; default: - param->errCode = EINVAL; + state->io_ptr->err_code = EINVAL; + state->io_ptr->ret_val = -1; return; } - param->stack[0] = 1; /* numerator */ } -void marucam_device_close(MaruCamState *state) +MaruCamBackend *marucam_backend_create(MaruCamState *state) { - if (!is_stream_paused(state)) { - marucam_device_stop_preview(state); - } - - marucam_reset_controls(); - - if (saved_frame.data) { - g_free(saved_frame.data); - saved_frame.data = NULL; - } - memset(&saved_frame, 0x00, sizeof(saved_frame)); - - v4l2_close(v4l2_fd); - v4l2_fd = 0; - INFO("Closed\n"); + MCBackendV4l2 *backend_v4l2; + + backend_v4l2 = g_new0(MCBackendV4l2, 1); + + backend_v4l2->base.init = backend_v4l2_init; + backend_v4l2->base.reset = backend_v4l2_reset; + backend_v4l2->base.release = backend_v4l2_release; + backend_v4l2->base.open = backend_v4l2_open; + backend_v4l2->base.close = backend_v4l2_close; + backend_v4l2->base.stream_on = backend_v4l2_stream_on; + backend_v4l2->base.stream_off = backend_v4l2_stream_off; + backend_v4l2->base.enum_fmt = backend_v4l2_enum_fmt; + backend_v4l2->base.try_fmt = backend_v4l2_try_fmt; + backend_v4l2->base.s_fmt = backend_v4l2_s_fmt; + backend_v4l2->base.g_fmt = backend_v4l2_g_fmt; + backend_v4l2->base.s_parm = backend_v4l2_s_parm; + backend_v4l2->base.g_parm = backend_v4l2_g_parm; + backend_v4l2->base.query_ctrl = backend_v4l2_query_ctrl; + backend_v4l2->base.s_ctrl = backend_v4l2_s_ctrl; + backend_v4l2->base.g_ctrl = backend_v4l2_g_ctrl; + backend_v4l2->base.enum_framesizes = backend_v4l2_enum_fsizes; + backend_v4l2->base.enum_frameintervals = backend_v4l2_enum_fintv; + + return &backend_v4l2->base; } -- 2.34.1