All of lore.kernel.org
 help / color / mirror / Atom feed
* [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2009-01-13  2:03   ` Aguirre Rodriguez, Sergio Alberto
  0 siblings, 0 replies; 43+ messages in thread
From: Aguirre Rodriguez, Sergio Alberto @ 2009-01-13  2:03 UTC (permalink / raw)
  To: linux-omap
  Cc: linux-media, video4linux-list, Sakari Ailus, Tuukka.O Toivonen,
	Nagalla, Hari


Signed-off-by: Sakari Ailus <sakari.ailus@nokia.com>
Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
---
 drivers/media/video/Kconfig       |    8 +
 drivers/media/video/Makefile      |    2 +
 drivers/media/video/omap34xxcam.c | 2017 +++++++++++++++++++++++++++++++++++++
 drivers/media/video/omap34xxcam.h |  215 ++++
 4 files changed, 2242 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/omap34xxcam.c
 create mode 100644 drivers/media/video/omap34xxcam.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 47102c2..dcd3960 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -700,6 +700,14 @@ config VIDEO_CAFE_CCIC
          CMOS camera controller.  This is the controller found on first-
          generation OLPC systems.

+config VIDEO_OMAP3
+        tristate "OMAP 3 Camera support"
+       select VIDEOBUF_GEN
+       select VIDEOBUF_DMA_SG
+       depends on VIDEO_V4L2 && ARCH_OMAP34XX
+       ---help---
+         Driver for an OMAP 3 camera controller.
+
 config SOC_CAMERA
        tristate "SoC camera support"
        depends on VIDEO_V4L2 && HAS_DMA
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 16962f3..a2f73cf 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -101,6 +101,8 @@ obj-$(CONFIG_VIDEO_OV7670)  += ov7670.o

 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o

+obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o isp/
+
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_SE401)         += se401.o
diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
new file mode 100644
index 0000000..a920bf2
--- /dev/null
+++ b/drivers/media/video/omap34xxcam.c
@@ -0,0 +1,2017 @@
+/*
+ * drivers/media/video/omap34xxcam.c
+ *
+ * Copyright (C) 2006--2008 Nokia Corporation
+ * Copyright (C) 2007, 2008 Texas Instruments
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *
+ * Originally based on the OMAP 2 camera driver.
+ *
+ * Written by Sakari Ailus <sakari.ailus@nokia.com>
+ *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *            Sergio Aguirre <saaguirre@ti.com>
+ *            Mohit Jalori
+ *            Sameer Venkatraman
+ *            Leonides Martinez
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/pci.h>         /* needed for videobufs */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "omap34xxcam.h"
+#include "isp/isp.h"
+#include "isp/ispmmu.h"
+#include "isp/ispreg.h"
+#include "isp/ispccdc.h"
+#include "isp/isph3a.h"
+#include "isp/isp_af.h"
+#include "isp/isphist.h"
+#include "isp/isppreview.h"
+#include "isp/ispresizer.h"
+
+#define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+/* global variables */
+static struct omap34xxcam_device *omap34xxcam;
+
+struct omap34xxcam_fh *camfh_saved;
+
+#define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ)
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/**
+ * omap34xxcam_slave_power_set - set slave power state
+ * @vdev: per-video device data structure
+ * @power: new power state
+ */
+static int omap34xxcam_slave_power_set(struct omap34xxcam_videodev *vdev,
+                                      enum v4l2_power power,
+                                      int mask)
+{
+       int rval = 0, i = 0;
+
+       BUG_ON(!mutex_is_locked(&vdev->mutex));
+
+       vdev->power_state_wish = -1;
+
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               if (vdev->slave[i] == v4l2_int_device_dummy())
+                       continue;
+
+               if (!(mask & (1 << i))
+                   || power == vdev->power_state[i])
+                       continue;
+
+               rval = vidioc_int_s_power(vdev->slave[i], power);
+
+               if (rval && power != V4L2_POWER_OFF) {
+                       power = V4L2_POWER_OFF;
+                       goto out;
+               }
+
+               vdev->power_state[i] = power;
+       }
+
+       return 0;
+
+out:
+       for (i--; i >= 0; i--) {
+               if (vdev->slave[i] == v4l2_int_device_dummy())
+                       continue;
+
+               if (!(mask & (1 << i)))
+                       continue;
+
+               vidioc_int_s_power(vdev->slave[i], power);
+               vdev->power_state[i] = power;
+       }
+
+       return rval;
+}
+
+static void omap34xxcam_slave_power_work(struct work_struct *work)
+{
+       struct omap34xxcam_videodev *vdev =
+               container_of(work, struct omap34xxcam_videodev, poweroff_work);
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->power_state_wish != -1)
+               omap34xxcam_slave_power_set(vdev, vdev->power_state_wish,
+                                           vdev->power_state_mask);
+
+       mutex_unlock(&vdev->mutex);
+}
+
+static void omap34xxcam_slave_power_timer(unsigned long ptr)
+{
+       struct omap34xxcam_videodev *vdev = (void *)ptr;
+
+       schedule_work(&vdev->poweroff_work);
+}
+
+/**
+ * omap34xxcam_slave_power_suggest - delayed power state change
+ *
+ * @vdev: per-video device data structure
+ * @power: new power state
+ */
+static void omap34xxcam_slave_power_suggest(struct omap34xxcam_videodev *vdev,
+                                           enum v4l2_power power,
+                                           int mask)
+{
+       BUG_ON(!mutex_is_locked(&vdev->mutex));
+
+       del_timer(&vdev->poweroff_timer);
+
+       vdev->power_state_wish = power;
+       vdev->power_state_mask = mask;
+
+       mod_timer(&vdev->poweroff_timer, jiffies + OMAP34XXCAM_POWEROFF_DELAY);
+}
+
+/**
+ * omap34xxcam_update_vbq - Updates VBQ with completed input buffer
+ * @vb: ptr. to standard V4L2 video buffer structure
+ *
+ * Updates video buffer queue with completed buffer passed as
+ * input parameter.  Also updates ISP H3A timestamp and field count
+ * statistics.
+ */
+int omap34xxcam_update_vbq(struct videobuf_buffer *vb)
+{
+       struct omap34xxcam_fh *fh = camfh_saved;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       int rval = 0;
+
+       do_gettimeofday(&vb->ts);
+       vb->field_count = atomic_add_return(2, &fh->field_count);
+       vb->state = VIDEOBUF_DONE;
+
+       if (vdev->streaming)
+               rval = 1;
+
+       wake_up(&vb->done);
+
+       return rval;
+}
+
+/**
+ * omap34xxcam_vbq_setup - Calcs size and num of buffs allowed in queue
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @cnt: ptr to location to hold the count of buffers to be in the queue
+ * @size: ptr to location to hold the size of a frame
+ *
+ * Calculates the number of buffers of current image size that can be
+ * supported by the available capture memory.
+ */
+static int omap34xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+                                unsigned int *size)
+{
+       struct omap34xxcam_fh *fh = vbq->priv_data;
+
+       if (*cnt <= 0)
+               *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+       if (*cnt > VIDEO_MAX_FRAME)
+               *cnt = VIDEO_MAX_FRAME;
+
+       *size = fh->pix.sizeimage;
+
+       while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
+               (*cnt)--;
+
+       while ((*size * *cnt) > ispmmu_get_mapeable_space())
+               (*cnt)--;
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_vbq_release - Free resources for input VBQ and VB
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ *
+ * Unmap and free all memory associated with input VBQ and VB, also
+ * unmap the address in ISP MMU.  Reset the VB state.
+ */
+static void omap34xxcam_vbq_release(struct videobuf_queue *vbq,
+                                   struct videobuf_buffer *vb)
+{
+       if (!vbq->streaming) {
+               isp_vbq_release(vbq, vb);
+               videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+               videobuf_dma_free(videobuf_to_dma(vb));
+               vb->state = VIDEOBUF_NEEDS_INIT;
+       }
+       return;
+}
+
+/**
+ * omap34xxcam_vbq_prepare - V4L2 video ops buf_prepare handler
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ * @field: standard V4L2 field enum
+ *
+ * Verifies there is sufficient locked memory for the requested
+ * buffer, or if there is not, allocates, locks and initializes
+ * it.
+ */
+static int omap34xxcam_vbq_prepare(struct videobuf_queue *vbq,
+                                  struct videobuf_buffer *vb,
+                                  enum v4l2_field field)
+{
+       struct omap34xxcam_fh *fh = vbq->priv_data;
+       int err = 0;
+
+       /*
+        * Accessing pix here is okay since it's constant while
+        * streaming is on (and we only get called then).
+        */
+       if (vb->baddr) {
+               /* This is a userspace buffer. */
+               if (fh->pix.sizeimage > vb->bsize)
+                       /* The buffer isn't big enough. */
+                       return -EINVAL;
+       } else {
+               if (vb->state != VIDEOBUF_NEEDS_INIT
+                   && fh->pix.sizeimage > vb->bsize)
+                       /*
+                        * We have a kernel bounce buffer that has
+                        * already been allocated.
+                        */
+                       omap34xxcam_vbq_release(vbq, vb);
+       }
+
+       vb->size = fh->pix.bytesperline * fh->pix.height;
+       vb->width = fh->pix.width;
+       vb->height = fh->pix.height;
+       vb->field = field;
+
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               err = videobuf_iolock(vbq, vb, NULL);
+               if (!err) {
+                       /* isp_addr will be stored locally inside isp code */
+                       err = isp_vbq_prepare(vbq, vb, field);
+               }
+       }
+
+       if (!err)
+               vb->state = VIDEOBUF_PREPARED;
+       else
+               omap34xxcam_vbq_release(vbq, vb);
+
+       return err;
+
+}
+
+/**
+ * omap34xxcam_vbq_queue - V4L2 video ops buf_queue handler
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ *
+ * Maps the video buffer to sgdma and through the isp, sets
+ * the isp buffer done callback and sets the video buffer state
+ * to active.
+ */
+static void omap34xxcam_vbq_queue(struct videobuf_queue *vbq,
+                                 struct videobuf_buffer *vb)
+{
+       struct omap34xxcam_fh *fh = vbq->priv_data;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       enum videobuf_state state = vb->state;
+       isp_vbq_callback_ptr func_ptr;
+       int err = 0;
+       camfh_saved = fh;
+
+       func_ptr = omap34xxcam_update_vbq;
+       vb->state = VIDEOBUF_ACTIVE;
+
+       err = isp_sgdma_queue(videobuf_to_dma(vb),
+                             vb, 0, &vdev->cam->dma_notify, func_ptr);
+       if (err) {
+               dev_dbg(vdev->cam->dev, "vbq queue failed\n");
+               vb->state = state;
+       }
+
+}
+
+static struct videobuf_queue_ops omap34xxcam_vbq_ops = {
+       .buf_setup = omap34xxcam_vbq_setup,
+       .buf_prepare = omap34xxcam_vbq_prepare,
+       .buf_queue = omap34xxcam_vbq_queue,
+       .buf_release = omap34xxcam_vbq_release,
+};
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+/**
+ * vidioc_querycap - V4L2 query capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @cap: ptr to standard V4L2 capability structure
+ *
+ * Fill in the V4L2 capabliity structure for the camera device
+ */
+static int vidioc_querycap(struct file *file, void *fh,
+                          struct v4l2_capability *cap)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+
+       strlcpy(cap->driver, CAM_SHORT_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, vdev->vfd->name, sizeof(cap->card));
+       cap->version = OMAP34XXCAM_VERSION;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+/**
+ * vidioc_enum_fmt_vid_cap - V4L2 enumerate format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format description structure
+ *
+ * Fills in enumerate format capabilities information for sensor (if SOC
+ * sensor attached) or ISP (if raw sensor attached).
+ */
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+                                  struct v4l2_fmtdesc *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, f);
+       else
+               rval = isp_enum_fmt_cap(f);
+
+       return rval;
+}
+
+/**
+ * vidioc_g_fmt_vid_cap - V4L2 get format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Fills in format capabilities for sensor (if SOC sensor attached) or ISP
+ * (if raw sensor attached).
+ */
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+
+       mutex_lock(&vdev->mutex);
+       f->fmt.pix = ofh->pix;
+       mutex_unlock(&vdev->mutex);
+
+       return 0;
+}
+
+static int try_pix_parm(struct omap34xxcam_videodev *vdev,
+                       struct v4l2_pix_format *best_pix_in,
+                       struct v4l2_pix_format *wanted_pix_out,
+                       struct v4l2_fract *best_ival)
+{
+       int fps;
+       int rval;
+       int size_index;
+       struct v4l2_pix_format best_pix_out;
+
+       if (best_ival->numerator == 0
+           || best_ival->denominator == 0)
+               best_ival->denominator = 30, best_ival->numerator = 1;
+
+       fps = best_ival->denominator / best_ival->numerator;
+
+       best_ival->denominator = 0;
+
+       best_pix_out.height = INT_MAX >> 1;
+       best_pix_out.width = best_pix_out.height;
+
+       /*
+        * Get supported resolutions.
+        */
+       for (size_index = 0; ; size_index++) {
+               struct v4l2_frmsizeenum frms;
+               struct v4l2_pix_format pix_tmp_in, pix_tmp_out;
+               int ival_index;
+
+               frms.index = size_index;
+               frms.pixel_format = best_pix_in->pixelformat;
+
+               rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, &frms);
+               if (rval) {
+                       rval = 0;
+                       break;
+               }
+
+               pix_tmp_in.pixelformat = frms.pixel_format;
+               pix_tmp_in.width = frms.discrete.width;
+               pix_tmp_in.height = frms.discrete.height;
+               pix_tmp_out = *wanted_pix_out;
+               /* Don't do upscaling. */
+               if (pix_tmp_out.width > pix_tmp_in.width)
+                       pix_tmp_out.width = pix_tmp_in.width;
+               if (pix_tmp_out.height > pix_tmp_in.height)
+                       pix_tmp_out.height = pix_tmp_in.height;
+               rval = isp_try_fmt_cap(&pix_tmp_in, &pix_tmp_out);
+               if (rval)
+                       return rval;
+
+#define IS_SMALLER_OR_EQUAL(pix1, pix2)                        \
+               ((pix1)->width + (pix1)->height         \
+                < (pix2)->width + (pix2)->height)
+#define SIZE_DIFF(pix1, pix2)                                  \
+               (abs((pix1)->width - (pix2)->width)             \
+                + abs((pix1)->height - (pix2)->height))
+
+               /*
+                * Don't use modes that are farther from wanted size
+                * that what we already got.
+                */
+               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
+                   > SIZE_DIFF(&best_pix_out, wanted_pix_out))
+                       continue;
+
+               /*
+                * There's an input mode that can provide output
+                * closer to wanted.
+                */
+               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
+                   < SIZE_DIFF(&best_pix_out, wanted_pix_out))
+                       /* Force renegotation of fps etc. */
+                       best_ival->denominator = 0;
+
+               for (ival_index = 0; ; ival_index++) {
+                       struct v4l2_frmivalenum frmi;
+
+                       frmi.index = ival_index;
+                       frmi.pixel_format = frms.pixel_format;
+                       frmi.width = frms.discrete.width;
+                       frmi.height = frms.discrete.height;
+                       /* FIXME: try to fix standard... */
+                       frmi.reserved[0] = 0xdeafbeef;
+
+                       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor,
+                                                             &frmi);
+                       if (rval) {
+                               rval = 0;
+                               break;
+                       }
+
+                       if (best_ival->denominator == 0)
+                               goto do_it_now;
+
+                       /*
+                        * We aim to use maximum resolution from the
+                        * sensor, provided that the fps is at least
+                        * as close as on the current mode.
+                        */
+#define FPS_ABS_DIFF(fps, ival) abs(fps - (ival).denominator / (ival).numerator)
+
+                       /* Select mode with closest fps. */
+                       if (FPS_ABS_DIFF(fps, frmi.discrete)
+                           < FPS_ABS_DIFF(fps, *best_ival))
+                               goto do_it_now;
+
+                       /*
+                        * Select bigger resolution if it's available
+                        * at same fps.
+                        */
+                       if (frmi.width > best_pix_in->width
+                           && FPS_ABS_DIFF(fps, frmi.discrete)
+                           <= FPS_ABS_DIFF(fps, *best_ival))
+                               goto do_it_now;
+
+                       continue;
+
+do_it_now:
+                       *best_ival = frmi.discrete;
+                       best_pix_out = pix_tmp_out;
+                       best_pix_in->width = frmi.width;
+                       best_pix_in->height = frmi.height;
+                       best_pix_in->pixelformat = frmi.pixel_format;
+               }
+       }
+
+       if (best_ival->denominator == 0)
+               return -EINVAL;
+
+       *wanted_pix_out = best_pix_out;
+
+       dev_info(vdev->cam->dev, "w %d, h %d -> w %d, h %d\n",
+                best_pix_in->width, best_pix_in->height,
+                best_pix_out.width, best_pix_out.height);
+
+       return isp_try_fmt_cap(best_pix_in, wanted_pix_out);
+}
+
+static int s_pix_parm(struct omap34xxcam_videodev *vdev,
+                     struct v4l2_pix_format *best_pix,
+                     struct v4l2_pix_format *pix,
+                     struct v4l2_fract *best_ival)
+{
+       struct v4l2_streamparm a;
+       struct v4l2_format fmt;
+       int rval;
+       int fmtd_index;
+
+       for (fmtd_index = 0; ; fmtd_index++) {
+               struct v4l2_fmtdesc fmtd;
+
+               fmtd.index = fmtd_index;
+               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
+               if (rval)
+                       return rval;
+               best_pix->pixelformat = fmtd.pixelformat;
+
+               rval = try_pix_parm(vdev, best_pix, pix, best_ival);
+               if (!rval)
+                       break;
+       }
+
+       rval = isp_s_fmt_cap(best_pix, pix);
+       if (rval)
+               return rval;
+
+       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt.fmt.pix = *best_pix;
+       rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &fmt);
+       if (rval)
+               return rval;
+
+       a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a.parm.capture.timeperframe = *best_ival;
+       rval = vidioc_int_s_parm(vdev->vdev_sensor, &a);
+
+       return rval;
+}
+
+/**
+ * vidioc_s_fmt_vid_cap - V4L2 set format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Attempts to set input format with the sensor driver (first) and then the
+ * ISP.  Returns the return code from vidioc_g_fmt_vid_cap().
+ */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format pix_tmp;
+       struct v4l2_fract timeperframe;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       vdev->want_pix = f->fmt.pix;
+
+       timeperframe = vdev->want_timeperframe;
+
+       rval = s_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
+       pix_tmp = f->fmt.pix;
+
+out:
+       mutex_unlock(&vdev->mutex);
+
+       if (!rval) {
+               mutex_lock(&ofh->vbq.vb_lock);
+               ofh->pix = pix_tmp;
+               mutex_unlock(&ofh->vbq.vb_lock);
+       }
+
+       return rval;
+}
+
+/**
+ * vidioc_try_fmt_vid_cap - V4L2 try format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Checks if the given format is supported by the sensor driver and
+ * by the ISP.
+ */
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+                                 struct v4l2_format *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format pix_tmp;
+       struct v4l2_fract timeperframe;
+       int rval;
+       int fmtd_index;
+
+       mutex_lock(&vdev->mutex);
+
+
+       for (fmtd_index = 0; ; fmtd_index++) {
+               struct v4l2_fmtdesc fmtd;
+
+               timeperframe = vdev->want_timeperframe;
+
+               fmtd.index = fmtd_index;
+               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
+               if (rval)
+                       return rval;
+               pix_tmp.pixelformat = fmtd.pixelformat;
+
+               rval = try_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
+               if (!rval)
+                       break;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_reqbufs - V4L2 request buffers IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 request buffers structure
+ *
+ * Attempts to get a buffer from the buffer queue associated with the
+ * fh through the video buffer library API.
+ */
+static int vidioc_reqbufs(struct file *file, void *fh,
+                         struct v4l2_requestbuffers *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               mutex_unlock(&vdev->mutex);
+               return -EBUSY;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       rval = videobuf_reqbufs(&ofh->vbq, b);
+
+       /*
+        * Either videobuf_reqbufs failed or the buffers are not
+        * memory-mapped (which would need special attention).
+        */
+       if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+               goto out;
+
+out:
+       return rval;
+}
+
+/**
+ * vidioc_querybuf - V4L2 query buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to fill in the v4l2_buffer structure for the buffer queue
+ * associated with the fh through the video buffer library API.
+ */
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+
+       return videobuf_querybuf(&ofh->vbq, b);
+}
+
+/**
+ * vidioc_qbuf - V4L2 queue buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to queue the v4l2_buffer on the buffer queue
+ * associated with the fh through the video buffer library API.
+ */
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+
+       return videobuf_qbuf(&ofh->vbq, b);
+}
+
+/**
+ * vidioc_dqbuf - V4L2 dequeue buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to dequeue the v4l2_buffer from the buffer queue
+ * associated with the fh through the video buffer library API.  If the
+ * buffer is a user space buffer, then this function will also requeue it,
+ * as user does not expect to do this.
+ */
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+
+       return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vidioc_streamon - V4L2 streamon IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: V4L2 buffer type
+ *
+ * Attempts to start streaming by enabling the sensor interface and turning
+ * on video buffer streaming through the video buffer library API.  Upon
+ * success the function returns 0, otherwise an error code is returned.
+ */
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct omap34xxcam_device *cam = vdev->cam;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       cam->dma_notify = 1;
+       isp_sgdma_init();
+       rval = videobuf_streamon(&ofh->vbq);
+       if (rval) {
+               dev_dbg(vdev->cam->dev, "omap34xxcam_slave_power_set failed\n");
+               goto out;
+       }
+
+
+       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                          OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
+       if (!rval) {
+               vdev->streaming = file;
+       } else {
+               isp_stop();
+               videobuf_streamoff(&ofh->vbq);
+       }
+
+out:
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_streamoff - V4L2 streamoff IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: V4L2 buffer type
+ *
+ * Attempts to stop streaming by flushing all scheduled work, waiting on
+ * any queued buffers to complete and then stopping the ISP and turning
+ * off video buffer streaming through the video buffer library API.  Upon
+ * success the function returns 0, otherwise an error code is returned.
+ */
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct videobuf_queue *q = &ofh->vbq;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->streaming == file)
+               isp_stop();
+
+       rval = videobuf_streamoff(q);
+       if (!rval)
+               vdev->streaming = NULL;
+
+       omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
+                                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+       omap34xxcam_slave_power_suggest(vdev, V4L2_POWER_STANDBY,
+                                       OMAP34XXCAM_SLAVE_POWER_LENS);
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_enum_input - V4L2 enumerate input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @inp: V4L2 input type information structure
+ *
+ * Fills in v4l2_input structure.  Returns 0.
+ */
+static int vidioc_enum_input(struct file *file, void *fh,
+                            struct v4l2_input *inp)
+{
+       if (inp->index > 0)
+               return -EINVAL;
+
+       strlcpy(inp->name, "camera", sizeof(inp->name));
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+/**
+ * vidioc_g_input - V4L2 get input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: address to hold index of input supported
+ *
+ * Sets index to 0.
+ */
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       *i = 0;
+
+       return 0;
+}
+
+/**
+ * vidioc_s_input - V4L2 set input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: index of input selected
+ *
+ * 0 is only index supported.
+ */
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+       if (i > 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * vidioc_queryctrl - V4L2 query control IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 query control ioctl structure
+ *
+ * If the requested control is supported, returns the control information
+ * in the v4l2_queryctrl structure.  Otherwise, returns -EINVAL if the
+ * control is not supported.  If the sensor being used is a "smart sensor",
+ * this request is passed to the sensor driver, otherwise the ISP is
+ * queried and if it does not support the requested control, the request
+ * is forwarded to the "raw" sensor driver to see if it supports it.
+ */
+static int vidioc_queryctrl(struct file *file, void *fh,
+                           struct v4l2_queryctrl *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_queryctrl a_tmp;
+       int best_slave = -1;
+       u32 best_ctrl = (u32)-1;
+       int i;
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               return vidioc_int_queryctrl(vdev->vdev_sensor, a);
+
+       /* No next flags: try slaves directly. */
+       if (!(a->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
+               for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+                       if (!vidioc_int_queryctrl(vdev->slave[i], a))
+                               return 0;
+               }
+               return isp_queryctrl(a);
+       }
+
+       /* Find slave with smallest next control id. */
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               a_tmp = *a;
+
+               if (vidioc_int_queryctrl(vdev->slave[i], &a_tmp))
+                       continue;
+
+               if (a_tmp.id < best_ctrl) {
+                       best_slave = i;
+                       best_ctrl = a_tmp.id;
+               }
+       }
+
+       a_tmp = *a;
+       if (!isp_queryctrl(&a_tmp)) {
+               if (a_tmp.id < best_ctrl) {
+                       *a = a_tmp;
+
+                       return 0;
+               }
+       }
+
+       if (best_slave == -1)
+               return -EINVAL;
+
+       a->id = best_ctrl;
+       return vidioc_int_queryctrl(vdev->slave[best_slave], a);
+}
+
+/**
+ * vidioc_querymenu - V4L2 query menu IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 query menu ioctl structure
+ *
+ * If the requested control is supported, returns the menu information
+ * in the v4l2_querymenu structure.  Otherwise, returns -EINVAL if the
+ * control is not supported or is not a menu.  If the sensor being used
+ * is a "smart sensor", this request is passed to the sensor driver,
+ * otherwise the ISP is queried and if it does not support the requested
+ * menu control, the request is forwarded to the "raw" sensor driver to
+ * see if it supports it.
+ */
+static int vidioc_querymenu(struct file *file, void *fh,
+                           struct v4l2_querymenu *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int i;
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               return vidioc_int_querymenu(vdev->vdev_sensor, a);
+
+       /* Try slaves directly. */
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               if (!vidioc_int_querymenu(vdev->slave[i], a))
+                       return 0;
+       }
+       return isp_querymenu(a);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *fh,
+                             struct v4l2_ext_controls *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int i, ctrl_idx, rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
+               struct v4l2_control ctrl;
+
+               ctrl.id = a->controls[ctrl_idx].id;
+
+               if (vdev->vdev_sensor_config.sensor_isp) {
+                       rval = vidioc_int_g_ctrl(vdev->vdev_sensor, &ctrl);
+               } else {
+                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+                               rval = vidioc_int_g_ctrl(vdev->slave[i], &ctrl);
+                               if (!rval)
+                                       break;
+                       }
+               }
+
+               if (rval)
+                       rval = isp_g_ctrl(&ctrl);
+
+               if (rval) {
+                       a->error_idx = ctrl_idx;
+                       break;
+               }
+
+               a->controls[ctrl_idx].value = ctrl.value;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *fh,
+                             struct v4l2_ext_controls *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int i, ctrl_idx, rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
+               struct v4l2_control ctrl;
+
+               ctrl.id = a->controls[ctrl_idx].id;
+               ctrl.value = a->controls[ctrl_idx].value;
+
+               if (vdev->vdev_sensor_config.sensor_isp) {
+                       rval = vidioc_int_s_ctrl(vdev->vdev_sensor, &ctrl);
+               } else {
+                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+                               rval = vidioc_int_s_ctrl(vdev->slave[i], &ctrl);
+                               if (!rval)
+                                       break;
+                       }
+               }
+
+               if (rval)
+                       rval = isp_s_ctrl(&ctrl);
+
+               if (rval) {
+                       a->error_idx = ctrl_idx;
+                       break;
+               }
+
+               a->controls[ctrl_idx].value = ctrl.value;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_g_parm - V4L2 get parameters IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 stream parameters structure
+ *
+ * If request is for video capture buffer type, handles request by
+ * forwarding to sensor driver.
+ */
+static int vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&vdev->mutex);
+       rval = vidioc_int_g_parm(vdev->vdev_sensor, a);
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_s_parm - V4L2 set parameters IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 stream parameters structure
+ *
+ * If request is for video capture buffer type, handles request by
+ * first getting current stream parameters from sensor, then forwarding
+ * request to set new parameters to sensor driver.  It then attempts to
+ * enable the sensor interface with the new parameters.  If this fails, it
+ * reverts back to the previous parameters.
+ */
+static int vidioc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format pix_tmp_sensor, pix_tmp;
+       int rval;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       vdev->want_timeperframe = a->parm.capture.timeperframe;
+
+       pix_tmp = vdev->want_pix;
+
+       rval = s_pix_parm(vdev, &pix_tmp_sensor, &pix_tmp,
+                         &a->parm.capture.timeperframe);
+
+out:
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_cropcap - V4L2 crop capture IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop capture structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise fills in the v4l2_cropcap values locally.
+ */
+static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_cropcap *cropcap = a;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->vdev_sensor_config.sensor_isp) {
+               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
+       } else {
+               struct v4l2_format f;
+
+               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
+               if (!rval)
+                       return rval;
+
+               /* cropcap failed, try to do this via g_fmt_cap */
+               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &f);
+               if (!rval) {
+                       cropcap->bounds.top = 0;
+                       cropcap->bounds.left = 0;
+                       cropcap->bounds.width = f.fmt.pix.width;
+                       cropcap->bounds.height = f.fmt.pix.height;
+                       cropcap->defrect = cropcap->bounds;
+                       cropcap->pixelaspect.numerator = 1;
+                       cropcap->pixelaspect.denominator = 1;
+               }
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_g_crop - V4L2 get capture crop IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise calls the isp functions to fill in current crop values.
+ */
+static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
+       else
+               rval = isp_g_crop(a);
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_s_crop - V4L2 set capture crop IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise calls the isp functions to set the current crop values.
+ */
+static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format *pix = &ofh->pix;
+       int rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
+       else
+               rval = isp_s_crop(a, pix);
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+                                 struct v4l2_frmsizeenum *frms)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       u32 pixel_format;
+       int rval;
+
+       pixel_format = frms->pixel_format;
+       frms->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
+
+       mutex_lock(&vdev->mutex);
+       rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
+       mutex_unlock(&vdev->mutex);
+
+       frms->pixel_format = pixel_format;
+
+       return rval;
+}
+
+static int vidioc_enum_frameintervals(struct file *file, void *fh,
+                                     struct v4l2_frmivalenum *frmi)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       u32 pixel_format;
+       int rval;
+
+       pixel_format = frmi->pixel_format;
+       frmi->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
+
+       mutex_lock(&vdev->mutex);
+       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
+       mutex_unlock(&vdev->mutex);
+
+       frmi->pixel_format = pixel_format;
+
+       return rval;
+}
+
+/**
+ * vidioc_default - private IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @cmd: ioctl cmd value
+ * @arg: ioctl arg value
+ *
+ * If the sensor being used is a "smart sensor", this request is returned to
+ * caller with -EINVAL err code.  Otherwise if the control id is the private
+ * VIDIOC_PRIVATE_ISP_AEWB_REQ to update the analog gain or exposure,
+ * then this request is forwared directly to the sensor to incorporate the
+ * feedback. The request is then passed on to the ISP private IOCTL handler,
+ * isp_handle_private()
+ */
+static int vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+{
+       struct omap34xxcam_fh *ofh = file->private_data;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       if (vdev->vdev_sensor_config.sensor_isp) {
+               rval = -EINVAL;
+       } else {
+               switch (cmd) {
+               case VIDIOC_ENUM_FRAMESIZES:
+                       rval = vidioc_enum_framesizes(file, fh, arg);
+                       goto out;
+               case VIDIOC_ENUM_FRAMEINTERVALS:
+                       rval = vidioc_enum_frameintervals(file, fh, arg);
+                       goto out;
+               case VIDIOC_PRIVATE_ISP_AEWB_REQ:
+               {
+                       /* Need to update sensor first */
+                       struct isph3a_aewb_data *data;
+                       struct v4l2_control vc;
+
+                       data = (struct isph3a_aewb_data *) arg;
+                       if (data->update & SET_EXPOSURE) {
+                               vc.id = V4L2_CID_EXPOSURE;
+                               vc.value = data->shutter;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
+                                                        &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                       }
+                       if (data->update & SET_ANALOG_GAIN) {
+                               vc.id = V4L2_CID_GAIN;
+                               vc.value = data->gain;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
+                                                        &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                       }
+               }
+               break;
+               case VIDIOC_PRIVATE_ISP_AF_REQ: {
+                       /* Need to update lens first */
+                       struct isp_af_data *data;
+                       struct v4l2_control vc;
+
+                       if (!vdev->vdev_lens) {
+                               rval = -EINVAL;
+                               goto out;
+                       }
+                       data = (struct isp_af_data *) arg;
+                       if (data->update & LENS_DESIRED_POSITION) {
+                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
+                               vc.value = data->desired_lens_direction;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_s_ctrl(vdev->vdev_lens, &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                       }
+                       if (data->update & REQUEST_STATISTICS) {
+                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_g_ctrl(vdev->vdev_lens, &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                               data->xtrastats.lens_position = vc.value;
+                       }
+               }
+                       break;
+               }
+
+               mutex_lock(&vdev->mutex);
+               rval = isp_handle_private(cmd, arg);
+               mutex_unlock(&vdev->mutex);
+       }
+out:
+       return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+static long omap34xxcam_unlocked_ioctl(struct file *file, unsigned int cmd,
+                                      unsigned long arg)
+{
+       return (long)video_ioctl2(file->f_dentry->d_inode, file, cmd, arg);
+}
+
+/**
+ * omap34xxcam_poll - file operations poll handler
+ * @file: ptr. to system file structure
+ * @wait: system poll table structure
+ *
+ */
+static unsigned int omap34xxcam_poll(struct file *file,
+                                    struct poll_table_struct *wait)
+{
+       struct omap34xxcam_fh *fh = file->private_data;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       struct videobuf_buffer *vb;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming != file) {
+               mutex_unlock(&vdev->mutex);
+               return POLLERR;
+       }
+       mutex_unlock(&vdev->mutex);
+
+       mutex_lock(&fh->vbq.vb_lock);
+       if (list_empty(&fh->vbq.stream)) {
+               mutex_unlock(&fh->vbq.vb_lock);
+               return POLLERR;
+       }
+       vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+       mutex_unlock(&fh->vbq.vb_lock);
+
+       poll_wait(file, &vb->done, wait);
+
+       if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_mmap - file operations mmap handler
+ * @file: ptr. to system file structure
+ * @vma: system virt. mem. area structure
+ *
+ * Maps a virtual memory area via the video buffer API
+ */
+static int omap34xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct omap34xxcam_fh *fh = file->private_data;
+       return videobuf_mmap_mapper(&fh->vbq, vma);
+}
+
+/**
+ * omap34xxcam_open - file operations open handler
+ * @inode: ptr. to system inode structure
+ * @file: ptr. to system file structure
+ *
+ * Allocates and initializes the per-filehandle data (omap34xxcam_fh),
+ * enables the sensor, opens/initializes the ISP interface and the
+ * video buffer queue.  Note that this function will allow multiple
+ * file handles to be open simultaneously, however only the first
+ * handle opened will initialize the ISP.  It is the application
+ * responsibility to only use one handle for streaming and the others
+ * for control only.
+ * This function returns 0 upon success and -ENODEV upon error.
+ */
+static int omap34xxcam_open(struct inode *inode, struct file *file)
+{
+       struct omap34xxcam_videodev *vdev = NULL;
+       struct omap34xxcam_device *cam = omap34xxcam;
+       struct omap34xxcam_fh *fh;
+       struct v4l2_format format;
+       int i;
+
+       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+               if (cam->vdevs[i].vfd
+                   && cam->vdevs[i].vfd->minor == iminor(inode)) {
+                       vdev = &cam->vdevs[i];
+                       break;
+               }
+       }
+
+       if (!vdev || !vdev->vfd)
+               return -ENODEV;
+
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (fh == NULL)
+               return -ENOMEM;
+
+       mutex_lock(&vdev->mutex);
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               if (vdev->slave[i] != v4l2_int_device_dummy()
+                   && !try_module_get(vdev->slave[i]->module)) {
+                       mutex_unlock(&vdev->mutex);
+                       goto out_try_module_get;
+               }
+       }
+
+       if (atomic_inc_return(&vdev->users) == 1) {
+               isp_get();
+               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                               OMAP34XXCAM_SLAVE_POWER_ALL))
+                       goto out_slave_power_set_standby;
+               omap34xxcam_slave_power_set(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+               omap34xxcam_slave_power_suggest(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_LENS);
+       }
+
+       fh->vdev = vdev;
+
+       /* FIXME: Check that we have sensor now... */
+       if (vdev->vdev_sensor_config.sensor_isp)
+               vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
+       else
+               isp_g_fmt_cap(&format.fmt.pix);
+
+       mutex_unlock(&vdev->mutex);
+       /* FIXME: how about fh->pix when there are more users? */
+       fh->pix = format.fmt.pix;
+
+       file->private_data = fh;
+
+       spin_lock_init(&fh->vbq_lock);
+
+       videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
+                               &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                               V4L2_FIELD_NONE,
+                               sizeof(struct videobuf_buffer), fh);
+
+       return 0;
+
+out_slave_power_set_standby:
+       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+                                   OMAP34XXCAM_SLAVE_POWER_ALL);
+       isp_put();
+       atomic_dec(&vdev->users);
+       mutex_unlock(&vdev->mutex);
+
+out_try_module_get:
+       for (i--; i >= 0; i--)
+               if (vdev->slave[i] != v4l2_int_device_dummy())
+                       module_put(vdev->slave[i]->module);
+
+       kfree(fh);
+
+       return -ENODEV;
+}
+
+/**
+ * omap34xxcam_release - file operations release handler
+ * @inode: ptr. to system inode structure
+ * @file: ptr. to system file structure
+ *
+ * Complement of omap34xxcam_open.  This function will flush any scheduled
+ * work, disable the sensor, close the ISP interface, stop the
+ * video buffer queue from streaming and free the per-filehandle data
+ * (omap34xxcam_fh).  Note that because multiple open file handles
+ * are allowed, this function will only close the ISP and disable the
+ * sensor when the last open file handle (by count) is closed.
+ * This function returns 0.
+ */
+static int omap34xxcam_release(struct inode *inode, struct file *file)
+{
+       struct omap34xxcam_fh *fh = file->private_data;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       int i;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming == file) {
+               isp_stop();
+               videobuf_streamoff(&fh->vbq);
+               omap34xxcam_slave_power_set(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+               omap34xxcam_slave_power_suggest(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_LENS);
+               vdev->streaming = NULL;
+       }
+
+       if (atomic_dec_return(&vdev->users) == 0) {
+               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+                                           OMAP34XXCAM_SLAVE_POWER_ALL);
+               isp_put();
+       }
+       mutex_unlock(&vdev->mutex);
+
+       file->private_data = NULL;
+
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
+               if (vdev->slave[i] != v4l2_int_device_dummy())
+                       module_put(vdev->slave[i]->module);
+
+       kfree(fh);
+
+       return 0;
+}
+
+static struct file_operations omap34xxcam_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .unlocked_ioctl = omap34xxcam_unlocked_ioctl,
+       .poll = omap34xxcam_poll,
+       .mmap = omap34xxcam_mmap,
+       .open = omap34xxcam_open,
+       .release = omap34xxcam_release,
+};
+
+static void omap34xxcam_vfd_name_update(struct omap34xxcam_videodev *vdev)
+{
+       struct video_device *vfd = vdev->vfd;
+       int i;
+
+       strlcpy(vfd->name, CAM_SHORT_NAME, sizeof(vfd->name));
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               strlcat(vfd->name, "/", sizeof(vfd->name));
+               if (vdev->slave[i] == v4l2_int_device_dummy())
+                       continue;
+               strlcat(vfd->name, vdev->slave[i]->name, sizeof(vfd->name));
+       }
+       dev_info(vdev->cam->dev, "video%d is now %s\n", vfd->minor, vfd->name);
+}
+
+/**
+ * omap34xxcam_device_unregister - V4L2 detach handler
+ * @s: ptr. to standard V4L2 device information structure
+ *
+ * Detach sensor and unregister and release the video device.
+ */
+static void omap34xxcam_device_unregister(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct omap34xxcam_hw_config hwc;
+
+       BUG_ON(vidioc_int_g_priv(s, &hwc) < 0);
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy()) {
+               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
+               vdev->slaves--;
+               omap34xxcam_vfd_name_update(vdev);
+       }
+
+       if (vdev->slaves == 0 && vdev->vfd) {
+               if (vdev->vfd->minor == -1) {
+                       /*
+                        * The device was never registered, so release the
+                        * video_device struct directly.
+                        */
+                       video_device_release(vdev->vfd);
+               } else {
+                       /*
+                        * The unregister function will release the
+                        * video_device struct as well as
+                        * unregistering it.
+                        */
+                       video_unregister_device(vdev->vfd);
+               }
+               vdev->vfd = NULL;
+       }
+
+       mutex_unlock(&vdev->mutex);
+}
+
+static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = {
+       .vidioc_querycap         = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap    = vidioc_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,
+       .vidioc_reqbufs          = vidioc_reqbufs,
+       .vidioc_querybuf         = vidioc_querybuf,
+       .vidioc_qbuf             = vidioc_qbuf,
+       .vidioc_dqbuf            = vidioc_dqbuf,
+       .vidioc_streamon         = vidioc_streamon,
+       .vidioc_streamoff        = vidioc_streamoff,
+       .vidioc_enum_input       = vidioc_enum_input,
+       .vidioc_g_input          = vidioc_g_input,
+       .vidioc_s_input          = vidioc_s_input,
+       .vidioc_queryctrl        = vidioc_queryctrl,
+       .vidioc_querymenu        = vidioc_querymenu,
+       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
+       .vidioc_g_parm           = vidioc_g_parm,
+       .vidioc_s_parm           = vidioc_s_parm,
+       .vidioc_cropcap          = vidioc_cropcap,
+       .vidioc_g_crop           = vidioc_g_crop,
+       .vidioc_s_crop           = vidioc_s_crop,
+       .vidioc_default          = vidioc_default,
+};
+
+/**
+ * omap34xxcam_device_register - V4L2 attach handler
+ * @s: ptr. to standard V4L2 device information structure
+ *
+ * Allocates and initializes the V4L2 video_device structure, initializes
+ * the sensor, and finally
+ registers the device with V4L2 based on the
+ * video_device structure.
+ *
+ * Returns 0 on success, otherwise an appropriate error code on
+ * failure.
+ */
+static int omap34xxcam_device_register(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct omap34xxcam_device *cam = vdev->cam;
+       struct omap34xxcam_hw_config hwc;
+       struct video_device *vfd;
+       int rval;
+
+       /* We need to check rval just once. The place is here. */
+       if (vidioc_int_g_priv(s, &hwc))
+               return -ENODEV;
+
+       if (vdev->index != hwc.dev_index)
+               return -ENODEV;
+
+       if (hwc.dev_type < 0 || hwc.dev_type > OMAP34XXCAM_SLAVE_FLASH)
+               return -EINVAL;
+
+       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy())
+               return -EBUSY;
+
+       mutex_lock(&vdev->mutex);
+       if (atomic_read(&vdev->users)) {
+               dev_err(cam->dev, "we're open (%d), can't register\n",
+                       atomic_read(&vdev->users));
+               mutex_unlock(&vdev->mutex);
+               return -EBUSY;
+       }
+
+       vdev->slaves++;
+       vdev->slave[hwc.dev_type] = s;
+       vdev->slave_config[hwc.dev_type] = hwc;
+
+       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
+               isp_get();
+       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                          1 << hwc.dev_type);
+       if (!rval && hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
+               struct v4l2_format format;
+               struct v4l2_streamparm a;
+
+               format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
+
+               a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval |= vidioc_int_g_parm(vdev->vdev_sensor, &a);
+               if (rval)
+                       rval = -EBUSY;
+
+               vdev->want_pix = format.fmt.pix;
+               vdev->want_timeperframe = a.parm.capture.timeperframe;
+       }
+       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF, 1 << hwc.dev_type);
+       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
+               isp_put();
+
+       if (rval)
+               goto err;
+
+       /* Are we the first slave? */
+       if (vdev->slaves == 1) {
+               /* initialize the video_device struct */
+               vdev->vfd = video_device_alloc();
+               vfd = vdev->vfd;
+               if (!vfd) {
+                       dev_err(cam->dev,
+                               "could not allocate video device struct\n");
+                       return -ENOMEM;
+               }
+               vfd->release    = video_device_release;
+               vfd->minor      = -1;
+               vfd->fops       = &omap34xxcam_fops;
+               vfd->ioctl_ops  = &omap34xxcam_ioctl_ops;
+               video_set_drvdata(vfd, vdev);
+
+               if (video_register_device(vfd, VFL_TYPE_GRABBER,
+                                         hwc.dev_minor) < 0) {
+                       dev_err(cam->dev,
+                               "could not register V4L device\n");
+                       vfd->minor = -1;
+                       rval = -EBUSY;
+                       goto err;
+               }
+       } else {
+               vfd = vdev->vfd;
+       }
+
+       omap34xxcam_vfd_name_update(vdev);
+
+       mutex_unlock(&vdev->mutex);
+
+       return 0;
+
+err:
+       if (s == vdev->slave[hwc.dev_type]) {
+               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
+               vdev->slaves--;
+       }
+
+       mutex_unlock(&vdev->mutex);
+       omap34xxcam_device_unregister(s);
+
+       return rval;
+}
+
+static struct v4l2_int_master omap34xxcam_master = {
+       .attach = omap34xxcam_device_register,
+       .detach = omap34xxcam_device_unregister,
+};
+
+/*
+ *
+ * Driver Suspend/Resume
+ *
+ */
+
+#ifdef CONFIG_PM
+/**
+ * omap34xxcam_suspend - platform driver PM suspend handler
+ * @pdev: ptr. to platform level device information structure
+ * @state: power state
+ *
+ * If applicable, stop capture and disable sensor.
+ *
+ * Returns 0 always
+ */
+static int omap34xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
+
+       if (atomic_read(&vdev->users) == 0)
+               return 0;
+
+       if (vdev->streaming) {
+               isp_stop();
+               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+                                           OMAP34XXCAM_SLAVE_POWER_ALL);
+       }
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_resume - platform driver PM resume handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * If applicable, resume capture and enable sensor.
+ *
+ * Returns 0 always
+ */
+static int omap34xxcam_resume(struct platform_device *pdev)
+{
+       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
+
+       if (atomic_read(&vdev->users) == 0)
+               return 0;
+
+       if (vdev->streaming) {
+               omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                           OMAP34XXCAM_SLAVE_POWER_ALL);
+               isp_start();
+       }
+
+       return 0;
+}
+#endif
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+/**
+ * omap34xxcam_remove - platform driver remove handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * Unregister device with V4L2, unmap camera registers, and
+ * free camera device information structure (omap34xxcam_device).
+ *
+ * Returns 0 always.
+ */
+static int omap34xxcam_remove(struct platform_device *pdev)
+{
+       struct omap34xxcam_device *cam = platform_get_drvdata(pdev);
+       int i;
+
+       if (!cam)
+               return 0;
+
+       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+               if (cam->vdevs[i].cam == NULL)
+                       continue;
+
+               v4l2_int_device_unregister(&cam->vdevs[i].master);
+               cam->vdevs[i].cam = NULL;
+       }
+
+       omap34xxcam = NULL;
+
+       kfree(cam);
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_probe - platform driver probe handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * Allocates and initializes camera device information structure
+ * (omap34xxcam_device), maps the device registers and gets the
+ * device IRQ.  Registers the device as a V4L2 client.
+ *
+ * Returns 0 on success or -ENODEV on failure.
+ */
+static int omap34xxcam_probe(struct platform_device *pdev)
+{
+       struct omap34xxcam_device *cam;
+       struct isp_sysc isp_sysconfig;
+       int i;
+
+       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+       if (!cam) {
+               dev_err(&pdev->dev, "could not allocate memory\n");
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, cam);
+
+       cam->dev = &pdev->dev;
+
+       isp_get();
+       isp_sysconfig.reset = 0;
+       isp_sysconfig.idle_mode = 1;
+       isp_power_settings(isp_sysconfig);
+       isp_put();
+
+       omap34xxcam = cam;
+
+       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+               struct omap34xxcam_videodev *vdev = &cam->vdevs[i];
+               struct v4l2_int_device *m = &vdev->master;
+
+               m->module       = THIS_MODULE;
+               strlcpy(m->name, CAM_NAME, sizeof(m->name));
+               m->type         = v4l2_int_type_master;
+               m->u.master     = &omap34xxcam_master;
+               m->priv         = vdev;
+
+               mutex_init(&vdev->mutex);
+               vdev->index             = i;
+               vdev->cam               = cam;
+               vdev->vdev_sensor =
+                       vdev->vdev_lens =
+                       vdev->vdev_flash = v4l2_int_device_dummy();
+               setup_timer(&vdev->poweroff_timer,
+                           omap34xxcam_slave_power_timer, (unsigned long)vdev);
+               INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
+
+               if (v4l2_int_device_register(m))
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       omap34xxcam_remove(pdev);
+       return -ENODEV;
+}
+
+static struct platform_driver omap34xxcam_driver = {
+       .probe = omap34xxcam_probe,
+       .remove = omap34xxcam_remove,
+#ifdef CONFIG_PM
+       .suspend = omap34xxcam_suspend,
+       .resume = omap34xxcam_resume,
+#endif
+       .driver = {
+                  .name = CAM_NAME,
+                  },
+};
+
+/*
+ *
+ * Module initialisation and deinitialisation
+ *
+ */
+
+/**
+ * omap34xxcam_init - module_init function
+ *
+ * Calls platfrom driver to register probe, remove,
+ * suspend and resume functions.
+ *
+ */
+static int __init omap34xxcam_init(void)
+{
+       return platform_driver_register(&omap34xxcam_driver);
+}
+
+/**
+ * omap34xxcam_cleanup - module_exit function
+ *
+ * Calls platfrom driver to unregister probe, remove,
+ * suspend and resume functions.
+ *
+ */
+static void __exit omap34xxcam_cleanup(void)
+{
+       platform_driver_unregister(&omap34xxcam_driver);
+}
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com");
+MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+
+late_initcall(omap34xxcam_init);
+module_exit(omap34xxcam_cleanup);
diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
new file mode 100644
index 0000000..cc024eb
--- /dev/null
+++ b/drivers/media/video/omap34xxcam.h
@@ -0,0 +1,215 @@
+/*
+ * drivers/media/video/omap34xxcam.c
+ *
+ * Copyright (C) 2006--2008 Nokia Corporation
+ * Copyright (C) 2007, 2008 Texas Instruments
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *
+ * Originally based on the OMAP 2 camera driver.
+ *
+ * Written by Sakari Ailus <sakari.ailus@nokia.com>
+ *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *            Sergio Aguirre <saaguirre@ti.com>
+ *            Mohit Jalori
+ *            Sameer Venkatraman
+ *            Leonides Martinez
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef OMAP34XXCAM_H
+#define OMAP34XXCAM_H
+
+#include <media/v4l2-int-device.h>
+#include "isp/isp.h"
+
+#define CAM_NAME                       "omap34xxcam"
+#define CAM_SHORT_NAME                 "omap3"
+
+#define OMAP_ISP_AF            (1 << 4)
+#define OMAP_ISP_HIST          (1 << 5)
+#define OMAP34XXCAM_XCLK_NONE  -1
+#define OMAP34XXCAM_XCLK_A     0
+#define OMAP34XXCAM_XCLK_B     1
+
+#define OMAP34XXCAM_SLAVE_SENSOR       0
+#define OMAP34XXCAM_SLAVE_LENS         1
+#define OMAP34XXCAM_SLAVE_FLASH                2 /* This is the last slave! */
+
+/* mask for omap34xxcam_slave_power_set */
+#define OMAP34XXCAM_SLAVE_POWER_SENSOR (1 << OMAP34XXCAM_SLAVE_SENSOR)
+#define OMAP34XXCAM_SLAVE_POWER_LENS   (1 << OMAP34XXCAM_SLAVE_LENS)
+#define OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS \
+       (OMAP34XXCAM_SLAVE_POWER_SENSOR | OMAP34XXCAM_SLAVE_POWER_LENS)
+#define OMAP34XXCAM_SLAVE_POWER_FLASH  (1 << OMAP34XXCAM_SLAVE_FLASH)
+#define OMAP34XXCAM_SLAVE_POWER_ALL    -1
+
+#define OMAP34XXCAM_VIDEODEVS          4
+
+struct omap34xxcam_device;
+struct omap34xxcam_videodev;
+
+struct omap34xxcam_sensor_config {
+       int xclk;
+       int sensor_isp;
+       u32 capture_mem;
+};
+
+struct omap34xxcam_lens_config {
+};
+
+struct omap34xxcam_flash_config {
+};
+
+/**
+ * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
+ * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
+ * @sensor_isp: Is sensor smart/SOC or raw
+ * @s_pix_sparm: Access function to set pix and sparm.
+ * Pix will override sparm
+ */
+struct omap34xxcam_hw_config {
+       int dev_index; /* Index in omap34xxcam_sensors */
+       int dev_minor; /* Video device minor number */
+       int dev_type; /* OMAP34XXCAM_SLAVE_* */
+       union {
+               struct omap34xxcam_sensor_config sensor;
+               struct omap34xxcam_lens_config lens;
+               struct omap34xxcam_flash_config flash;
+       } u;
+};
+
+/**
+ * struct omap34xxcam_videodev - per /dev/video* structure
+ * @mutex: serialises access to this structure
+ * @cam: pointer to cam hw structure
+ * @master: we are v4l2_int_device master
+ * @sensor: sensor device
+ * @lens: lens device
+ * @flash: flash device
+ * @slaves: how many slaves we have at the moment
+ * @vfd: our video device
+ * @capture_mem: maximum kernel-allocated capture memory
+ * @if_u: sensor interface stuff
+ * @index: index of this structure in cam->vdevs
+ * @users: how many users we have
+ * @power_state: Current power state
+ * @power_state_wish: New power state when poweroff_timer expires
+ * @power_state_mask: Bitmask of devices to set the new power state
+ * @poweroff_timer: Timer for dispatching poweroff_work
+ * @poweroff_work: Work for slave power state change
+ * @sensor_config: ISP-speicific sensor configuration
+ * @lens_config: ISP-speicific lens configuration
+ * @flash_config: ISP-speicific flash configuration
+ * @streaming: streaming file handle, if streaming is enabled
+ */
+struct omap34xxcam_videodev {
+       struct mutex mutex; /* serialises access to this structure */
+
+       struct omap34xxcam_device *cam;
+       struct v4l2_int_device master;
+
+#define vdev_sensor slave[OMAP34XXCAM_SLAVE_SENSOR]
+#define vdev_lens slave[OMAP34XXCAM_SLAVE_LENS]
+#define vdev_flash slave[OMAP34XXCAM_SLAVE_FLASH]
+       struct v4l2_int_device *slave[OMAP34XXCAM_SLAVE_FLASH + 1];
+
+       /* number of slaves attached */
+       int slaves;
+
+       /*** video device parameters ***/
+       struct video_device *vfd;
+       int capture_mem;
+
+       /*** general driver state information ***/
+       /*
+        * Sensor interface parameters: interface type, CC_CTRL
+        * register value and interface specific data.
+        */
+       u32 xclk;
+       /* index to omap34xxcam_videodevs of this structure */
+       int index;
+       atomic_t users;
+       enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
+       enum v4l2_power power_state_wish;
+       int power_state_mask;
+       struct timer_list poweroff_timer;
+       struct work_struct poweroff_work;
+
+#define vdev_sensor_config slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor
+#define vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens
+#define vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash
+       struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH + 1];
+
+       /*** capture data ***/
+       struct v4l2_fract want_timeperframe;
+       struct v4l2_pix_format want_pix;
+       /* file handle, if streaming is on */
+       struct file *streaming;
+};
+
+/**
+ * struct omap34xxcam_device - per-device data structure
+ * @mutex: mutex serialises access to this structure
+ * @sgdma_in_queue: Number or sgdma requests in scatter-gather queue,
+ * protected by the lock above.
+ * @sgdma: ISP sgdma subsystem information structure
+ * @dma_notify: DMA notify flag
+ * @irq: irq number platform HW resource
+ * @mmio_base: register map memory base (platform HW resource)
+ * @mmio_base_phys: register map memory base physical address
+ * @mmio_size: register map memory size
+ * @dev: device structure
+ * @vdevs: /dev/video specific structures
+ * @fck: camera module fck clock information
+ * @ick: camera module ick clock information
+ */
+struct omap34xxcam_device {
+       struct mutex mutex; /* serialises access to this structure */
+       int sgdma_in_queue;
+       struct isp_sgdma sgdma;
+       int dma_notify;
+
+       /*** interfaces and device ***/
+       struct device *dev;
+       struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
+
+       /*** camera module clocks ***/
+       struct clk *fck;
+       struct clk *ick;
+       bool sensor_if_enabled;
+};
+
+/**
+ * struct omap34xxcam_fh - per-filehandle data structure
+ * @vbq_lock: spinlock for the videobuf queue
+ * @vbq: V4L2 video buffer queue structure
+ * @pix: V4L2 pixel format structure (serialise pix by vbq->lock)
+ * @field_count: field counter for videobuf_buffer
+ * @vdev: our /dev/video specific structure
+ */
+struct omap34xxcam_fh {
+       spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+       struct videobuf_queue vbq;
+       struct v4l2_pix_format pix;
+       atomic_t field_count;
+       /* accessing cam here doesn't need serialisation: it's constant */
+       struct omap34xxcam_videodev *vdev;
+};
+
+#endif /* ifndef OMAP34XXCAM_H */
--
1.5.6.5


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2009-01-13  2:03   ` Aguirre Rodriguez, Sergio Alberto
  0 siblings, 0 replies; 43+ messages in thread
From: Aguirre Rodriguez, Sergio Alberto @ 2009-01-13  2:03 UTC (permalink / raw)
  To: linux-omap
  Cc: video4linux-list, Nagalla, Hari, Sakari Ailus, Tuukka.O Toivonen,
	linux-media


Signed-off-by: Sakari Ailus <sakari.ailus@nokia.com>
Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
---
 drivers/media/video/Kconfig       |    8 +
 drivers/media/video/Makefile      |    2 +
 drivers/media/video/omap34xxcam.c | 2017 +++++++++++++++++++++++++++++++++++++
 drivers/media/video/omap34xxcam.h |  215 ++++
 4 files changed, 2242 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/omap34xxcam.c
 create mode 100644 drivers/media/video/omap34xxcam.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 47102c2..dcd3960 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -700,6 +700,14 @@ config VIDEO_CAFE_CCIC
          CMOS camera controller.  This is the controller found on first-
          generation OLPC systems.

+config VIDEO_OMAP3
+        tristate "OMAP 3 Camera support"
+       select VIDEOBUF_GEN
+       select VIDEOBUF_DMA_SG
+       depends on VIDEO_V4L2 && ARCH_OMAP34XX
+       ---help---
+         Driver for an OMAP 3 camera controller.
+
 config SOC_CAMERA
        tristate "SoC camera support"
        depends on VIDEO_V4L2 && HAS_DMA
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 16962f3..a2f73cf 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -101,6 +101,8 @@ obj-$(CONFIG_VIDEO_OV7670)  += ov7670.o

 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o

+obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o isp/
+
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_SE401)         += se401.o
diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
new file mode 100644
index 0000000..a920bf2
--- /dev/null
+++ b/drivers/media/video/omap34xxcam.c
@@ -0,0 +1,2017 @@
+/*
+ * drivers/media/video/omap34xxcam.c
+ *
+ * Copyright (C) 2006--2008 Nokia Corporation
+ * Copyright (C) 2007, 2008 Texas Instruments
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *
+ * Originally based on the OMAP 2 camera driver.
+ *
+ * Written by Sakari Ailus <sakari.ailus@nokia.com>
+ *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *            Sergio Aguirre <saaguirre@ti.com>
+ *            Mohit Jalori
+ *            Sameer Venkatraman
+ *            Leonides Martinez
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/pci.h>         /* needed for videobufs */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "omap34xxcam.h"
+#include "isp/isp.h"
+#include "isp/ispmmu.h"
+#include "isp/ispreg.h"
+#include "isp/ispccdc.h"
+#include "isp/isph3a.h"
+#include "isp/isp_af.h"
+#include "isp/isphist.h"
+#include "isp/isppreview.h"
+#include "isp/ispresizer.h"
+
+#define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+/* global variables */
+static struct omap34xxcam_device *omap34xxcam;
+
+struct omap34xxcam_fh *camfh_saved;
+
+#define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ)
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/**
+ * omap34xxcam_slave_power_set - set slave power state
+ * @vdev: per-video device data structure
+ * @power: new power state
+ */
+static int omap34xxcam_slave_power_set(struct omap34xxcam_videodev *vdev,
+                                      enum v4l2_power power,
+                                      int mask)
+{
+       int rval = 0, i = 0;
+
+       BUG_ON(!mutex_is_locked(&vdev->mutex));
+
+       vdev->power_state_wish = -1;
+
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               if (vdev->slave[i] == v4l2_int_device_dummy())
+                       continue;
+
+               if (!(mask & (1 << i))
+                   || power == vdev->power_state[i])
+                       continue;
+
+               rval = vidioc_int_s_power(vdev->slave[i], power);
+
+               if (rval && power != V4L2_POWER_OFF) {
+                       power = V4L2_POWER_OFF;
+                       goto out;
+               }
+
+               vdev->power_state[i] = power;
+       }
+
+       return 0;
+
+out:
+       for (i--; i >= 0; i--) {
+               if (vdev->slave[i] == v4l2_int_device_dummy())
+                       continue;
+
+               if (!(mask & (1 << i)))
+                       continue;
+
+               vidioc_int_s_power(vdev->slave[i], power);
+               vdev->power_state[i] = power;
+       }
+
+       return rval;
+}
+
+static void omap34xxcam_slave_power_work(struct work_struct *work)
+{
+       struct omap34xxcam_videodev *vdev =
+               container_of(work, struct omap34xxcam_videodev, poweroff_work);
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->power_state_wish != -1)
+               omap34xxcam_slave_power_set(vdev, vdev->power_state_wish,
+                                           vdev->power_state_mask);
+
+       mutex_unlock(&vdev->mutex);
+}
+
+static void omap34xxcam_slave_power_timer(unsigned long ptr)
+{
+       struct omap34xxcam_videodev *vdev = (void *)ptr;
+
+       schedule_work(&vdev->poweroff_work);
+}
+
+/**
+ * omap34xxcam_slave_power_suggest - delayed power state change
+ *
+ * @vdev: per-video device data structure
+ * @power: new power state
+ */
+static void omap34xxcam_slave_power_suggest(struct omap34xxcam_videodev *vdev,
+                                           enum v4l2_power power,
+                                           int mask)
+{
+       BUG_ON(!mutex_is_locked(&vdev->mutex));
+
+       del_timer(&vdev->poweroff_timer);
+
+       vdev->power_state_wish = power;
+       vdev->power_state_mask = mask;
+
+       mod_timer(&vdev->poweroff_timer, jiffies + OMAP34XXCAM_POWEROFF_DELAY);
+}
+
+/**
+ * omap34xxcam_update_vbq - Updates VBQ with completed input buffer
+ * @vb: ptr. to standard V4L2 video buffer structure
+ *
+ * Updates video buffer queue with completed buffer passed as
+ * input parameter.  Also updates ISP H3A timestamp and field count
+ * statistics.
+ */
+int omap34xxcam_update_vbq(struct videobuf_buffer *vb)
+{
+       struct omap34xxcam_fh *fh = camfh_saved;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       int rval = 0;
+
+       do_gettimeofday(&vb->ts);
+       vb->field_count = atomic_add_return(2, &fh->field_count);
+       vb->state = VIDEOBUF_DONE;
+
+       if (vdev->streaming)
+               rval = 1;
+
+       wake_up(&vb->done);
+
+       return rval;
+}
+
+/**
+ * omap34xxcam_vbq_setup - Calcs size and num of buffs allowed in queue
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @cnt: ptr to location to hold the count of buffers to be in the queue
+ * @size: ptr to location to hold the size of a frame
+ *
+ * Calculates the number of buffers of current image size that can be
+ * supported by the available capture memory.
+ */
+static int omap34xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+                                unsigned int *size)
+{
+       struct omap34xxcam_fh *fh = vbq->priv_data;
+
+       if (*cnt <= 0)
+               *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+       if (*cnt > VIDEO_MAX_FRAME)
+               *cnt = VIDEO_MAX_FRAME;
+
+       *size = fh->pix.sizeimage;
+
+       while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
+               (*cnt)--;
+
+       while ((*size * *cnt) > ispmmu_get_mapeable_space())
+               (*cnt)--;
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_vbq_release - Free resources for input VBQ and VB
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ *
+ * Unmap and free all memory associated with input VBQ and VB, also
+ * unmap the address in ISP MMU.  Reset the VB state.
+ */
+static void omap34xxcam_vbq_release(struct videobuf_queue *vbq,
+                                   struct videobuf_buffer *vb)
+{
+       if (!vbq->streaming) {
+               isp_vbq_release(vbq, vb);
+               videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+               videobuf_dma_free(videobuf_to_dma(vb));
+               vb->state = VIDEOBUF_NEEDS_INIT;
+       }
+       return;
+}
+
+/**
+ * omap34xxcam_vbq_prepare - V4L2 video ops buf_prepare handler
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ * @field: standard V4L2 field enum
+ *
+ * Verifies there is sufficient locked memory for the requested
+ * buffer, or if there is not, allocates, locks and initializes
+ * it.
+ */
+static int omap34xxcam_vbq_prepare(struct videobuf_queue *vbq,
+                                  struct videobuf_buffer *vb,
+                                  enum v4l2_field field)
+{
+       struct omap34xxcam_fh *fh = vbq->priv_data;
+       int err = 0;
+
+       /*
+        * Accessing pix here is okay since it's constant while
+        * streaming is on (and we only get called then).
+        */
+       if (vb->baddr) {
+               /* This is a userspace buffer. */
+               if (fh->pix.sizeimage > vb->bsize)
+                       /* The buffer isn't big enough. */
+                       return -EINVAL;
+       } else {
+               if (vb->state != VIDEOBUF_NEEDS_INIT
+                   && fh->pix.sizeimage > vb->bsize)
+                       /*
+                        * We have a kernel bounce buffer that has
+                        * already been allocated.
+                        */
+                       omap34xxcam_vbq_release(vbq, vb);
+       }
+
+       vb->size = fh->pix.bytesperline * fh->pix.height;
+       vb->width = fh->pix.width;
+       vb->height = fh->pix.height;
+       vb->field = field;
+
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               err = videobuf_iolock(vbq, vb, NULL);
+               if (!err) {
+                       /* isp_addr will be stored locally inside isp code */
+                       err = isp_vbq_prepare(vbq, vb, field);
+               }
+       }
+
+       if (!err)
+               vb->state = VIDEOBUF_PREPARED;
+       else
+               omap34xxcam_vbq_release(vbq, vb);
+
+       return err;
+
+}
+
+/**
+ * omap34xxcam_vbq_queue - V4L2 video ops buf_queue handler
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ *
+ * Maps the video buffer to sgdma and through the isp, sets
+ * the isp buffer done callback and sets the video buffer state
+ * to active.
+ */
+static void omap34xxcam_vbq_queue(struct videobuf_queue *vbq,
+                                 struct videobuf_buffer *vb)
+{
+       struct omap34xxcam_fh *fh = vbq->priv_data;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       enum videobuf_state state = vb->state;
+       isp_vbq_callback_ptr func_ptr;
+       int err = 0;
+       camfh_saved = fh;
+
+       func_ptr = omap34xxcam_update_vbq;
+       vb->state = VIDEOBUF_ACTIVE;
+
+       err = isp_sgdma_queue(videobuf_to_dma(vb),
+                             vb, 0, &vdev->cam->dma_notify, func_ptr);
+       if (err) {
+               dev_dbg(vdev->cam->dev, "vbq queue failed\n");
+               vb->state = state;
+       }
+
+}
+
+static struct videobuf_queue_ops omap34xxcam_vbq_ops = {
+       .buf_setup = omap34xxcam_vbq_setup,
+       .buf_prepare = omap34xxcam_vbq_prepare,
+       .buf_queue = omap34xxcam_vbq_queue,
+       .buf_release = omap34xxcam_vbq_release,
+};
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+/**
+ * vidioc_querycap - V4L2 query capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @cap: ptr to standard V4L2 capability structure
+ *
+ * Fill in the V4L2 capabliity structure for the camera device
+ */
+static int vidioc_querycap(struct file *file, void *fh,
+                          struct v4l2_capability *cap)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+
+       strlcpy(cap->driver, CAM_SHORT_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, vdev->vfd->name, sizeof(cap->card));
+       cap->version = OMAP34XXCAM_VERSION;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+/**
+ * vidioc_enum_fmt_vid_cap - V4L2 enumerate format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format description structure
+ *
+ * Fills in enumerate format capabilities information for sensor (if SOC
+ * sensor attached) or ISP (if raw sensor attached).
+ */
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+                                  struct v4l2_fmtdesc *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, f);
+       else
+               rval = isp_enum_fmt_cap(f);
+
+       return rval;
+}
+
+/**
+ * vidioc_g_fmt_vid_cap - V4L2 get format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Fills in format capabilities for sensor (if SOC sensor attached) or ISP
+ * (if raw sensor attached).
+ */
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+
+       mutex_lock(&vdev->mutex);
+       f->fmt.pix = ofh->pix;
+       mutex_unlock(&vdev->mutex);
+
+       return 0;
+}
+
+static int try_pix_parm(struct omap34xxcam_videodev *vdev,
+                       struct v4l2_pix_format *best_pix_in,
+                       struct v4l2_pix_format *wanted_pix_out,
+                       struct v4l2_fract *best_ival)
+{
+       int fps;
+       int rval;
+       int size_index;
+       struct v4l2_pix_format best_pix_out;
+
+       if (best_ival->numerator == 0
+           || best_ival->denominator == 0)
+               best_ival->denominator = 30, best_ival->numerator = 1;
+
+       fps = best_ival->denominator / best_ival->numerator;
+
+       best_ival->denominator = 0;
+
+       best_pix_out.height = INT_MAX >> 1;
+       best_pix_out.width = best_pix_out.height;
+
+       /*
+        * Get supported resolutions.
+        */
+       for (size_index = 0; ; size_index++) {
+               struct v4l2_frmsizeenum frms;
+               struct v4l2_pix_format pix_tmp_in, pix_tmp_out;
+               int ival_index;
+
+               frms.index = size_index;
+               frms.pixel_format = best_pix_in->pixelformat;
+
+               rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, &frms);
+               if (rval) {
+                       rval = 0;
+                       break;
+               }
+
+               pix_tmp_in.pixelformat = frms.pixel_format;
+               pix_tmp_in.width = frms.discrete.width;
+               pix_tmp_in.height = frms.discrete.height;
+               pix_tmp_out = *wanted_pix_out;
+               /* Don't do upscaling. */
+               if (pix_tmp_out.width > pix_tmp_in.width)
+                       pix_tmp_out.width = pix_tmp_in.width;
+               if (pix_tmp_out.height > pix_tmp_in.height)
+                       pix_tmp_out.height = pix_tmp_in.height;
+               rval = isp_try_fmt_cap(&pix_tmp_in, &pix_tmp_out);
+               if (rval)
+                       return rval;
+
+#define IS_SMALLER_OR_EQUAL(pix1, pix2)                        \
+               ((pix1)->width + (pix1)->height         \
+                < (pix2)->width + (pix2)->height)
+#define SIZE_DIFF(pix1, pix2)                                  \
+               (abs((pix1)->width - (pix2)->width)             \
+                + abs((pix1)->height - (pix2)->height))
+
+               /*
+                * Don't use modes that are farther from wanted size
+                * that what we already got.
+                */
+               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
+                   > SIZE_DIFF(&best_pix_out, wanted_pix_out))
+                       continue;
+
+               /*
+                * There's an input mode that can provide output
+                * closer to wanted.
+                */
+               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
+                   < SIZE_DIFF(&best_pix_out, wanted_pix_out))
+                       /* Force renegotation of fps etc. */
+                       best_ival->denominator = 0;
+
+               for (ival_index = 0; ; ival_index++) {
+                       struct v4l2_frmivalenum frmi;
+
+                       frmi.index = ival_index;
+                       frmi.pixel_format = frms.pixel_format;
+                       frmi.width = frms.discrete.width;
+                       frmi.height = frms.discrete.height;
+                       /* FIXME: try to fix standard... */
+                       frmi.reserved[0] = 0xdeafbeef;
+
+                       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor,
+                                                             &frmi);
+                       if (rval) {
+                               rval = 0;
+                               break;
+                       }
+
+                       if (best_ival->denominator == 0)
+                               goto do_it_now;
+
+                       /*
+                        * We aim to use maximum resolution from the
+                        * sensor, provided that the fps is at least
+                        * as close as on the current mode.
+                        */
+#define FPS_ABS_DIFF(fps, ival) abs(fps - (ival).denominator / (ival).numerator)
+
+                       /* Select mode with closest fps. */
+                       if (FPS_ABS_DIFF(fps, frmi.discrete)
+                           < FPS_ABS_DIFF(fps, *best_ival))
+                               goto do_it_now;
+
+                       /*
+                        * Select bigger resolution if it's available
+                        * at same fps.
+                        */
+                       if (frmi.width > best_pix_in->width
+                           && FPS_ABS_DIFF(fps, frmi.discrete)
+                           <= FPS_ABS_DIFF(fps, *best_ival))
+                               goto do_it_now;
+
+                       continue;
+
+do_it_now:
+                       *best_ival = frmi.discrete;
+                       best_pix_out = pix_tmp_out;
+                       best_pix_in->width = frmi.width;
+                       best_pix_in->height = frmi.height;
+                       best_pix_in->pixelformat = frmi.pixel_format;
+               }
+       }
+
+       if (best_ival->denominator == 0)
+               return -EINVAL;
+
+       *wanted_pix_out = best_pix_out;
+
+       dev_info(vdev->cam->dev, "w %d, h %d -> w %d, h %d\n",
+                best_pix_in->width, best_pix_in->height,
+                best_pix_out.width, best_pix_out.height);
+
+       return isp_try_fmt_cap(best_pix_in, wanted_pix_out);
+}
+
+static int s_pix_parm(struct omap34xxcam_videodev *vdev,
+                     struct v4l2_pix_format *best_pix,
+                     struct v4l2_pix_format *pix,
+                     struct v4l2_fract *best_ival)
+{
+       struct v4l2_streamparm a;
+       struct v4l2_format fmt;
+       int rval;
+       int fmtd_index;
+
+       for (fmtd_index = 0; ; fmtd_index++) {
+               struct v4l2_fmtdesc fmtd;
+
+               fmtd.index = fmtd_index;
+               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
+               if (rval)
+                       return rval;
+               best_pix->pixelformat = fmtd.pixelformat;
+
+               rval = try_pix_parm(vdev, best_pix, pix, best_ival);
+               if (!rval)
+                       break;
+       }
+
+       rval = isp_s_fmt_cap(best_pix, pix);
+       if (rval)
+               return rval;
+
+       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt.fmt.pix = *best_pix;
+       rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &fmt);
+       if (rval)
+               return rval;
+
+       a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a.parm.capture.timeperframe = *best_ival;
+       rval = vidioc_int_s_parm(vdev->vdev_sensor, &a);
+
+       return rval;
+}
+
+/**
+ * vidioc_s_fmt_vid_cap - V4L2 set format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Attempts to set input format with the sensor driver (first) and then the
+ * ISP.  Returns the return code from vidioc_g_fmt_vid_cap().
+ */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format pix_tmp;
+       struct v4l2_fract timeperframe;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       vdev->want_pix = f->fmt.pix;
+
+       timeperframe = vdev->want_timeperframe;
+
+       rval = s_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
+       pix_tmp = f->fmt.pix;
+
+out:
+       mutex_unlock(&vdev->mutex);
+
+       if (!rval) {
+               mutex_lock(&ofh->vbq.vb_lock);
+               ofh->pix = pix_tmp;
+               mutex_unlock(&ofh->vbq.vb_lock);
+       }
+
+       return rval;
+}
+
+/**
+ * vidioc_try_fmt_vid_cap - V4L2 try format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Checks if the given format is supported by the sensor driver and
+ * by the ISP.
+ */
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+                                 struct v4l2_format *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format pix_tmp;
+       struct v4l2_fract timeperframe;
+       int rval;
+       int fmtd_index;
+
+       mutex_lock(&vdev->mutex);
+
+
+       for (fmtd_index = 0; ; fmtd_index++) {
+               struct v4l2_fmtdesc fmtd;
+
+               timeperframe = vdev->want_timeperframe;
+
+               fmtd.index = fmtd_index;
+               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
+               if (rval)
+                       return rval;
+               pix_tmp.pixelformat = fmtd.pixelformat;
+
+               rval = try_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
+               if (!rval)
+                       break;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_reqbufs - V4L2 request buffers IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 request buffers structure
+ *
+ * Attempts to get a buffer from the buffer queue associated with the
+ * fh through the video buffer library API.
+ */
+static int vidioc_reqbufs(struct file *file, void *fh,
+                         struct v4l2_requestbuffers *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               mutex_unlock(&vdev->mutex);
+               return -EBUSY;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       rval = videobuf_reqbufs(&ofh->vbq, b);
+
+       /*
+        * Either videobuf_reqbufs failed or the buffers are not
+        * memory-mapped (which would need special attention).
+        */
+       if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+               goto out;
+
+out:
+       return rval;
+}
+
+/**
+ * vidioc_querybuf - V4L2 query buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to fill in the v4l2_buffer structure for the buffer queue
+ * associated with the fh through the video buffer library API.
+ */
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+
+       return videobuf_querybuf(&ofh->vbq, b);
+}
+
+/**
+ * vidioc_qbuf - V4L2 queue buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to queue the v4l2_buffer on the buffer queue
+ * associated with the fh through the video buffer library API.
+ */
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+
+       return videobuf_qbuf(&ofh->vbq, b);
+}
+
+/**
+ * vidioc_dqbuf - V4L2 dequeue buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to dequeue the v4l2_buffer from the buffer queue
+ * associated with the fh through the video buffer library API.  If the
+ * buffer is a user space buffer, then this function will also requeue it,
+ * as user does not expect to do this.
+ */
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+
+       return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vidioc_streamon - V4L2 streamon IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: V4L2 buffer type
+ *
+ * Attempts to start streaming by enabling the sensor interface and turning
+ * on video buffer streaming through the video buffer library API.  Upon
+ * success the function returns 0, otherwise an error code is returned.
+ */
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct omap34xxcam_device *cam = vdev->cam;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       cam->dma_notify = 1;
+       isp_sgdma_init();
+       rval = videobuf_streamon(&ofh->vbq);
+       if (rval) {
+               dev_dbg(vdev->cam->dev, "omap34xxcam_slave_power_set failed\n");
+               goto out;
+       }
+
+
+       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                          OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
+       if (!rval) {
+               vdev->streaming = file;
+       } else {
+               isp_stop();
+               videobuf_streamoff(&ofh->vbq);
+       }
+
+out:
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_streamoff - V4L2 streamoff IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: V4L2 buffer type
+ *
+ * Attempts to stop streaming by flushing all scheduled work, waiting on
+ * any queued buffers to complete and then stopping the ISP and turning
+ * off video buffer streaming through the video buffer library API.  Upon
+ * success the function returns 0, otherwise an error code is returned.
+ */
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct videobuf_queue *q = &ofh->vbq;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->streaming == file)
+               isp_stop();
+
+       rval = videobuf_streamoff(q);
+       if (!rval)
+               vdev->streaming = NULL;
+
+       omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
+                                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+       omap34xxcam_slave_power_suggest(vdev, V4L2_POWER_STANDBY,
+                                       OMAP34XXCAM_SLAVE_POWER_LENS);
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_enum_input - V4L2 enumerate input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @inp: V4L2 input type information structure
+ *
+ * Fills in v4l2_input structure.  Returns 0.
+ */
+static int vidioc_enum_input(struct file *file, void *fh,
+                            struct v4l2_input *inp)
+{
+       if (inp->index > 0)
+               return -EINVAL;
+
+       strlcpy(inp->name, "camera", sizeof(inp->name));
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+/**
+ * vidioc_g_input - V4L2 get input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: address to hold index of input supported
+ *
+ * Sets index to 0.
+ */
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       *i = 0;
+
+       return 0;
+}
+
+/**
+ * vidioc_s_input - V4L2 set input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: index of input selected
+ *
+ * 0 is only index supported.
+ */
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+       if (i > 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * vidioc_queryctrl - V4L2 query control IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 query control ioctl structure
+ *
+ * If the requested control is supported, returns the control information
+ * in the v4l2_queryctrl structure.  Otherwise, returns -EINVAL if the
+ * control is not supported.  If the sensor being used is a "smart sensor",
+ * this request is passed to the sensor driver, otherwise the ISP is
+ * queried and if it does not support the requested control, the request
+ * is forwarded to the "raw" sensor driver to see if it supports it.
+ */
+static int vidioc_queryctrl(struct file *file, void *fh,
+                           struct v4l2_queryctrl *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_queryctrl a_tmp;
+       int best_slave = -1;
+       u32 best_ctrl = (u32)-1;
+       int i;
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               return vidioc_int_queryctrl(vdev->vdev_sensor, a);
+
+       /* No next flags: try slaves directly. */
+       if (!(a->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
+               for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+                       if (!vidioc_int_queryctrl(vdev->slave[i], a))
+                               return 0;
+               }
+               return isp_queryctrl(a);
+       }
+
+       /* Find slave with smallest next control id. */
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               a_tmp = *a;
+
+               if (vidioc_int_queryctrl(vdev->slave[i], &a_tmp))
+                       continue;
+
+               if (a_tmp.id < best_ctrl) {
+                       best_slave = i;
+                       best_ctrl = a_tmp.id;
+               }
+       }
+
+       a_tmp = *a;
+       if (!isp_queryctrl(&a_tmp)) {
+               if (a_tmp.id < best_ctrl) {
+                       *a = a_tmp;
+
+                       return 0;
+               }
+       }
+
+       if (best_slave == -1)
+               return -EINVAL;
+
+       a->id = best_ctrl;
+       return vidioc_int_queryctrl(vdev->slave[best_slave], a);
+}
+
+/**
+ * vidioc_querymenu - V4L2 query menu IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 query menu ioctl structure
+ *
+ * If the requested control is supported, returns the menu information
+ * in the v4l2_querymenu structure.  Otherwise, returns -EINVAL if the
+ * control is not supported or is not a menu.  If the sensor being used
+ * is a "smart sensor", this request is passed to the sensor driver,
+ * otherwise the ISP is queried and if it does not support the requested
+ * menu control, the request is forwarded to the "raw" sensor driver to
+ * see if it supports it.
+ */
+static int vidioc_querymenu(struct file *file, void *fh,
+                           struct v4l2_querymenu *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int i;
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               return vidioc_int_querymenu(vdev->vdev_sensor, a);
+
+       /* Try slaves directly. */
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               if (!vidioc_int_querymenu(vdev->slave[i], a))
+                       return 0;
+       }
+       return isp_querymenu(a);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *fh,
+                             struct v4l2_ext_controls *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int i, ctrl_idx, rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
+               struct v4l2_control ctrl;
+
+               ctrl.id = a->controls[ctrl_idx].id;
+
+               if (vdev->vdev_sensor_config.sensor_isp) {
+                       rval = vidioc_int_g_ctrl(vdev->vdev_sensor, &ctrl);
+               } else {
+                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+                               rval = vidioc_int_g_ctrl(vdev->slave[i], &ctrl);
+                               if (!rval)
+                                       break;
+                       }
+               }
+
+               if (rval)
+                       rval = isp_g_ctrl(&ctrl);
+
+               if (rval) {
+                       a->error_idx = ctrl_idx;
+                       break;
+               }
+
+               a->controls[ctrl_idx].value = ctrl.value;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *fh,
+                             struct v4l2_ext_controls *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int i, ctrl_idx, rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
+               struct v4l2_control ctrl;
+
+               ctrl.id = a->controls[ctrl_idx].id;
+               ctrl.value = a->controls[ctrl_idx].value;
+
+               if (vdev->vdev_sensor_config.sensor_isp) {
+                       rval = vidioc_int_s_ctrl(vdev->vdev_sensor, &ctrl);
+               } else {
+                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+                               rval = vidioc_int_s_ctrl(vdev->slave[i], &ctrl);
+                               if (!rval)
+                                       break;
+                       }
+               }
+
+               if (rval)
+                       rval = isp_s_ctrl(&ctrl);
+
+               if (rval) {
+                       a->error_idx = ctrl_idx;
+                       break;
+               }
+
+               a->controls[ctrl_idx].value = ctrl.value;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_g_parm - V4L2 get parameters IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 stream parameters structure
+ *
+ * If request is for video capture buffer type, handles request by
+ * forwarding to sensor driver.
+ */
+static int vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&vdev->mutex);
+       rval = vidioc_int_g_parm(vdev->vdev_sensor, a);
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_s_parm - V4L2 set parameters IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 stream parameters structure
+ *
+ * If request is for video capture buffer type, handles request by
+ * first getting current stream parameters from sensor, then forwarding
+ * request to set new parameters to sensor driver.  It then attempts to
+ * enable the sensor interface with the new parameters.  If this fails, it
+ * reverts back to the previous parameters.
+ */
+static int vidioc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format pix_tmp_sensor, pix_tmp;
+       int rval;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       vdev->want_timeperframe = a->parm.capture.timeperframe;
+
+       pix_tmp = vdev->want_pix;
+
+       rval = s_pix_parm(vdev, &pix_tmp_sensor, &pix_tmp,
+                         &a->parm.capture.timeperframe);
+
+out:
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_cropcap - V4L2 crop capture IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop capture structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise fills in the v4l2_cropcap values locally.
+ */
+static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_cropcap *cropcap = a;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->vdev_sensor_config.sensor_isp) {
+               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
+       } else {
+               struct v4l2_format f;
+
+               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
+               if (!rval)
+                       return rval;
+
+               /* cropcap failed, try to do this via g_fmt_cap */
+               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &f);
+               if (!rval) {
+                       cropcap->bounds.top = 0;
+                       cropcap->bounds.left = 0;
+                       cropcap->bounds.width = f.fmt.pix.width;
+                       cropcap->bounds.height = f.fmt.pix.height;
+                       cropcap->defrect = cropcap->bounds;
+                       cropcap->pixelaspect.numerator = 1;
+                       cropcap->pixelaspect.denominator = 1;
+               }
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_g_crop - V4L2 get capture crop IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise calls the isp functions to fill in current crop values.
+ */
+static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
+       else
+               rval = isp_g_crop(a);
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_s_crop - V4L2 set capture crop IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise calls the isp functions to set the current crop values.
+ */
+static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format *pix = &ofh->pix;
+       int rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
+       else
+               rval = isp_s_crop(a, pix);
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+                                 struct v4l2_frmsizeenum *frms)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       u32 pixel_format;
+       int rval;
+
+       pixel_format = frms->pixel_format;
+       frms->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
+
+       mutex_lock(&vdev->mutex);
+       rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
+       mutex_unlock(&vdev->mutex);
+
+       frms->pixel_format = pixel_format;
+
+       return rval;
+}
+
+static int vidioc_enum_frameintervals(struct file *file, void *fh,
+                                     struct v4l2_frmivalenum *frmi)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       u32 pixel_format;
+       int rval;
+
+       pixel_format = frmi->pixel_format;
+       frmi->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
+
+       mutex_lock(&vdev->mutex);
+       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
+       mutex_unlock(&vdev->mutex);
+
+       frmi->pixel_format = pixel_format;
+
+       return rval;
+}
+
+/**
+ * vidioc_default - private IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @cmd: ioctl cmd value
+ * @arg: ioctl arg value
+ *
+ * If the sensor being used is a "smart sensor", this request is returned to
+ * caller with -EINVAL err code.  Otherwise if the control id is the private
+ * VIDIOC_PRIVATE_ISP_AEWB_REQ to update the analog gain or exposure,
+ * then this request is forwared directly to the sensor to incorporate the
+ * feedback. The request is then passed on to the ISP private IOCTL handler,
+ * isp_handle_private()
+ */
+static int vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+{
+       struct omap34xxcam_fh *ofh = file->private_data;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       if (vdev->vdev_sensor_config.sensor_isp) {
+               rval = -EINVAL;
+       } else {
+               switch (cmd) {
+               case VIDIOC_ENUM_FRAMESIZES:
+                       rval = vidioc_enum_framesizes(file, fh, arg);
+                       goto out;
+               case VIDIOC_ENUM_FRAMEINTERVALS:
+                       rval = vidioc_enum_frameintervals(file, fh, arg);
+                       goto out;
+               case VIDIOC_PRIVATE_ISP_AEWB_REQ:
+               {
+                       /* Need to update sensor first */
+                       struct isph3a_aewb_data *data;
+                       struct v4l2_control vc;
+
+                       data = (struct isph3a_aewb_data *) arg;
+                       if (data->update & SET_EXPOSURE) {
+                               vc.id = V4L2_CID_EXPOSURE;
+                               vc.value = data->shutter;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
+                                                        &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                       }
+                       if (data->update & SET_ANALOG_GAIN) {
+                               vc.id = V4L2_CID_GAIN;
+                               vc.value = data->gain;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
+                                                        &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                       }
+               }
+               break;
+               case VIDIOC_PRIVATE_ISP_AF_REQ: {
+                       /* Need to update lens first */
+                       struct isp_af_data *data;
+                       struct v4l2_control vc;
+
+                       if (!vdev->vdev_lens) {
+                               rval = -EINVAL;
+                               goto out;
+                       }
+                       data = (struct isp_af_data *) arg;
+                       if (data->update & LENS_DESIRED_POSITION) {
+                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
+                               vc.value = data->desired_lens_direction;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_s_ctrl(vdev->vdev_lens, &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                       }
+                       if (data->update & REQUEST_STATISTICS) {
+                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_g_ctrl(vdev->vdev_lens, &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                               data->xtrastats.lens_position = vc.value;
+                       }
+               }
+                       break;
+               }
+
+               mutex_lock(&vdev->mutex);
+               rval = isp_handle_private(cmd, arg);
+               mutex_unlock(&vdev->mutex);
+       }
+out:
+       return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+static long omap34xxcam_unlocked_ioctl(struct file *file, unsigned int cmd,
+                                      unsigned long arg)
+{
+       return (long)video_ioctl2(file->f_dentry->d_inode, file, cmd, arg);
+}
+
+/**
+ * omap34xxcam_poll - file operations poll handler
+ * @file: ptr. to system file structure
+ * @wait: system poll table structure
+ *
+ */
+static unsigned int omap34xxcam_poll(struct file *file,
+                                    struct poll_table_struct *wait)
+{
+       struct omap34xxcam_fh *fh = file->private_data;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       struct videobuf_buffer *vb;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming != file) {
+               mutex_unlock(&vdev->mutex);
+               return POLLERR;
+       }
+       mutex_unlock(&vdev->mutex);
+
+       mutex_lock(&fh->vbq.vb_lock);
+       if (list_empty(&fh->vbq.stream)) {
+               mutex_unlock(&fh->vbq.vb_lock);
+               return POLLERR;
+       }
+       vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+       mutex_unlock(&fh->vbq.vb_lock);
+
+       poll_wait(file, &vb->done, wait);
+
+       if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_mmap - file operations mmap handler
+ * @file: ptr. to system file structure
+ * @vma: system virt. mem. area structure
+ *
+ * Maps a virtual memory area via the video buffer API
+ */
+static int omap34xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct omap34xxcam_fh *fh = file->private_data;
+       return videobuf_mmap_mapper(&fh->vbq, vma);
+}
+
+/**
+ * omap34xxcam_open - file operations open handler
+ * @inode: ptr. to system inode structure
+ * @file: ptr. to system file structure
+ *
+ * Allocates and initializes the per-filehandle data (omap34xxcam_fh),
+ * enables the sensor, opens/initializes the ISP interface and the
+ * video buffer queue.  Note that this function will allow multiple
+ * file handles to be open simultaneously, however only the first
+ * handle opened will initialize the ISP.  It is the application
+ * responsibility to only use one handle for streaming and the others
+ * for control only.
+ * This function returns 0 upon success and -ENODEV upon error.
+ */
+static int omap34xxcam_open(struct inode *inode, struct file *file)
+{
+       struct omap34xxcam_videodev *vdev = NULL;
+       struct omap34xxcam_device *cam = omap34xxcam;
+       struct omap34xxcam_fh *fh;
+       struct v4l2_format format;
+       int i;
+
+       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+               if (cam->vdevs[i].vfd
+                   && cam->vdevs[i].vfd->minor == iminor(inode)) {
+                       vdev = &cam->vdevs[i];
+                       break;
+               }
+       }
+
+       if (!vdev || !vdev->vfd)
+               return -ENODEV;
+
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (fh == NULL)
+               return -ENOMEM;
+
+       mutex_lock(&vdev->mutex);
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               if (vdev->slave[i] != v4l2_int_device_dummy()
+                   && !try_module_get(vdev->slave[i]->module)) {
+                       mutex_unlock(&vdev->mutex);
+                       goto out_try_module_get;
+               }
+       }
+
+       if (atomic_inc_return(&vdev->users) == 1) {
+               isp_get();
+               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                               OMAP34XXCAM_SLAVE_POWER_ALL))
+                       goto out_slave_power_set_standby;
+               omap34xxcam_slave_power_set(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+               omap34xxcam_slave_power_suggest(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_LENS);
+       }
+
+       fh->vdev = vdev;
+
+       /* FIXME: Check that we have sensor now... */
+       if (vdev->vdev_sensor_config.sensor_isp)
+               vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
+       else
+               isp_g_fmt_cap(&format.fmt.pix);
+
+       mutex_unlock(&vdev->mutex);
+       /* FIXME: how about fh->pix when there are more users? */
+       fh->pix = format.fmt.pix;
+
+       file->private_data = fh;
+
+       spin_lock_init(&fh->vbq_lock);
+
+       videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
+                               &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                               V4L2_FIELD_NONE,
+                               sizeof(struct videobuf_buffer), fh);
+
+       return 0;
+
+out_slave_power_set_standby:
+       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+                                   OMAP34XXCAM_SLAVE_POWER_ALL);
+       isp_put();
+       atomic_dec(&vdev->users);
+       mutex_unlock(&vdev->mutex);
+
+out_try_module_get:
+       for (i--; i >= 0; i--)
+               if (vdev->slave[i] != v4l2_int_device_dummy())
+                       module_put(vdev->slave[i]->module);
+
+       kfree(fh);
+
+       return -ENODEV;
+}
+
+/**
+ * omap34xxcam_release - file operations release handler
+ * @inode: ptr. to system inode structure
+ * @file: ptr. to system file structure
+ *
+ * Complement of omap34xxcam_open.  This function will flush any scheduled
+ * work, disable the sensor, close the ISP interface, stop the
+ * video buffer queue from streaming and free the per-filehandle data
+ * (omap34xxcam_fh).  Note that because multiple open file handles
+ * are allowed, this function will only close the ISP and disable the
+ * sensor when the last open file handle (by count) is closed.
+ * This function returns 0.
+ */
+static int omap34xxcam_release(struct inode *inode, struct file *file)
+{
+       struct omap34xxcam_fh *fh = file->private_data;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       int i;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming == file) {
+               isp_stop();
+               videobuf_streamoff(&fh->vbq);
+               omap34xxcam_slave_power_set(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+               omap34xxcam_slave_power_suggest(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_LENS);
+               vdev->streaming = NULL;
+       }
+
+       if (atomic_dec_return(&vdev->users) == 0) {
+               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+                                           OMAP34XXCAM_SLAVE_POWER_ALL);
+               isp_put();
+       }
+       mutex_unlock(&vdev->mutex);
+
+       file->private_data = NULL;
+
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
+               if (vdev->slave[i] != v4l2_int_device_dummy())
+                       module_put(vdev->slave[i]->module);
+
+       kfree(fh);
+
+       return 0;
+}
+
+static struct file_operations omap34xxcam_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .unlocked_ioctl = omap34xxcam_unlocked_ioctl,
+       .poll = omap34xxcam_poll,
+       .mmap = omap34xxcam_mmap,
+       .open = omap34xxcam_open,
+       .release = omap34xxcam_release,
+};
+
+static void omap34xxcam_vfd_name_update(struct omap34xxcam_videodev *vdev)
+{
+       struct video_device *vfd = vdev->vfd;
+       int i;
+
+       strlcpy(vfd->name, CAM_SHORT_NAME, sizeof(vfd->name));
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               strlcat(vfd->name, "/", sizeof(vfd->name));
+               if (vdev->slave[i] == v4l2_int_device_dummy())
+                       continue;
+               strlcat(vfd->name, vdev->slave[i]->name, sizeof(vfd->name));
+       }
+       dev_info(vdev->cam->dev, "video%d is now %s\n", vfd->minor, vfd->name);
+}
+
+/**
+ * omap34xxcam_device_unregister - V4L2 detach handler
+ * @s: ptr. to standard V4L2 device information structure
+ *
+ * Detach sensor and unregister and release the video device.
+ */
+static void omap34xxcam_device_unregister(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct omap34xxcam_hw_config hwc;
+
+       BUG_ON(vidioc_int_g_priv(s, &hwc) < 0);
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy()) {
+               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
+               vdev->slaves--;
+               omap34xxcam_vfd_name_update(vdev);
+       }
+
+       if (vdev->slaves == 0 && vdev->vfd) {
+               if (vdev->vfd->minor == -1) {
+                       /*
+                        * The device was never registered, so release the
+                        * video_device struct directly.
+                        */
+                       video_device_release(vdev->vfd);
+               } else {
+                       /*
+                        * The unregister function will release the
+                        * video_device struct as well as
+                        * unregistering it.
+                        */
+                       video_unregister_device(vdev->vfd);
+               }
+               vdev->vfd = NULL;
+       }
+
+       mutex_unlock(&vdev->mutex);
+}
+
+static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = {
+       .vidioc_querycap         = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap    = vidioc_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,
+       .vidioc_reqbufs          = vidioc_reqbufs,
+       .vidioc_querybuf         = vidioc_querybuf,
+       .vidioc_qbuf             = vidioc_qbuf,
+       .vidioc_dqbuf            = vidioc_dqbuf,
+       .vidioc_streamon         = vidioc_streamon,
+       .vidioc_streamoff        = vidioc_streamoff,
+       .vidioc_enum_input       = vidioc_enum_input,
+       .vidioc_g_input          = vidioc_g_input,
+       .vidioc_s_input          = vidioc_s_input,
+       .vidioc_queryctrl        = vidioc_queryctrl,
+       .vidioc_querymenu        = vidioc_querymenu,
+       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
+       .vidioc_g_parm           = vidioc_g_parm,
+       .vidioc_s_parm           = vidioc_s_parm,
+       .vidioc_cropcap          = vidioc_cropcap,
+       .vidioc_g_crop           = vidioc_g_crop,
+       .vidioc_s_crop           = vidioc_s_crop,
+       .vidioc_default          = vidioc_default,
+};
+
+/**
+ * omap34xxcam_device_register - V4L2 attach handler
+ * @s: ptr. to standard V4L2 device information structure
+ *
+ * Allocates and initializes the V4L2 video_device structure, initializes
+ * the sensor, and finally
+ registers the device with V4L2 based on the
+ * video_device structure.
+ *
+ * Returns 0 on success, otherwise an appropriate error code on
+ * failure.
+ */
+static int omap34xxcam_device_register(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct omap34xxcam_device *cam = vdev->cam;
+       struct omap34xxcam_hw_config hwc;
+       struct video_device *vfd;
+       int rval;
+
+       /* We need to check rval just once. The place is here. */
+       if (vidioc_int_g_priv(s, &hwc))
+               return -ENODEV;
+
+       if (vdev->index != hwc.dev_index)
+               return -ENODEV;
+
+       if (hwc.dev_type < 0 || hwc.dev_type > OMAP34XXCAM_SLAVE_FLASH)
+               return -EINVAL;
+
+       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy())
+               return -EBUSY;
+
+       mutex_lock(&vdev->mutex);
+       if (atomic_read(&vdev->users)) {
+               dev_err(cam->dev, "we're open (%d), can't register\n",
+                       atomic_read(&vdev->users));
+               mutex_unlock(&vdev->mutex);
+               return -EBUSY;
+       }
+
+       vdev->slaves++;
+       vdev->slave[hwc.dev_type] = s;
+       vdev->slave_config[hwc.dev_type] = hwc;
+
+       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
+               isp_get();
+       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                          1 << hwc.dev_type);
+       if (!rval && hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
+               struct v4l2_format format;
+               struct v4l2_streamparm a;
+
+               format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
+
+               a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval |= vidioc_int_g_parm(vdev->vdev_sensor, &a);
+               if (rval)
+                       rval = -EBUSY;
+
+               vdev->want_pix = format.fmt.pix;
+               vdev->want_timeperframe = a.parm.capture.timeperframe;
+       }
+       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF, 1 << hwc.dev_type);
+       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
+               isp_put();
+
+       if (rval)
+               goto err;
+
+       /* Are we the first slave? */
+       if (vdev->slaves == 1) {
+               /* initialize the video_device struct */
+               vdev->vfd = video_device_alloc();
+               vfd = vdev->vfd;
+               if (!vfd) {
+                       dev_err(cam->dev,
+                               "could not allocate video device struct\n");
+                       return -ENOMEM;
+               }
+               vfd->release    = video_device_release;
+               vfd->minor      = -1;
+               vfd->fops       = &omap34xxcam_fops;
+               vfd->ioctl_ops  = &omap34xxcam_ioctl_ops;
+               video_set_drvdata(vfd, vdev);
+
+               if (video_register_device(vfd, VFL_TYPE_GRABBER,
+                                         hwc.dev_minor) < 0) {
+                       dev_err(cam->dev,
+                               "could not register V4L device\n");
+                       vfd->minor = -1;
+                       rval = -EBUSY;
+                       goto err;
+               }
+       } else {
+               vfd = vdev->vfd;
+       }
+
+       omap34xxcam_vfd_name_update(vdev);
+
+       mutex_unlock(&vdev->mutex);
+
+       return 0;
+
+err:
+       if (s == vdev->slave[hwc.dev_type]) {
+               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
+               vdev->slaves--;
+       }
+
+       mutex_unlock(&vdev->mutex);
+       omap34xxcam_device_unregister(s);
+
+       return rval;
+}
+
+static struct v4l2_int_master omap34xxcam_master = {
+       .attach = omap34xxcam_device_register,
+       .detach = omap34xxcam_device_unregister,
+};
+
+/*
+ *
+ * Driver Suspend/Resume
+ *
+ */
+
+#ifdef CONFIG_PM
+/**
+ * omap34xxcam_suspend - platform driver PM suspend handler
+ * @pdev: ptr. to platform level device information structure
+ * @state: power state
+ *
+ * If applicable, stop capture and disable sensor.
+ *
+ * Returns 0 always
+ */
+static int omap34xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
+
+       if (atomic_read(&vdev->users) == 0)
+               return 0;
+
+       if (vdev->streaming) {
+               isp_stop();
+               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+                                           OMAP34XXCAM_SLAVE_POWER_ALL);
+       }
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_resume - platform driver PM resume handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * If applicable, resume capture and enable sensor.
+ *
+ * Returns 0 always
+ */
+static int omap34xxcam_resume(struct platform_device *pdev)
+{
+       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
+
+       if (atomic_read(&vdev->users) == 0)
+               return 0;
+
+       if (vdev->streaming) {
+               omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                           OMAP34XXCAM_SLAVE_POWER_ALL);
+               isp_start();
+       }
+
+       return 0;
+}
+#endif
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+/**
+ * omap34xxcam_remove - platform driver remove handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * Unregister device with V4L2, unmap camera registers, and
+ * free camera device information structure (omap34xxcam_device).
+ *
+ * Returns 0 always.
+ */
+static int omap34xxcam_remove(struct platform_device *pdev)
+{
+       struct omap34xxcam_device *cam = platform_get_drvdata(pdev);
+       int i;
+
+       if (!cam)
+               return 0;
+
+       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+               if (cam->vdevs[i].cam == NULL)
+                       continue;
+
+               v4l2_int_device_unregister(&cam->vdevs[i].master);
+               cam->vdevs[i].cam = NULL;
+       }
+
+       omap34xxcam = NULL;
+
+       kfree(cam);
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_probe - platform driver probe handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * Allocates and initializes camera device information structure
+ * (omap34xxcam_device), maps the device registers and gets the
+ * device IRQ.  Registers the device as a V4L2 client.
+ *
+ * Returns 0 on success or -ENODEV on failure.
+ */
+static int omap34xxcam_probe(struct platform_device *pdev)
+{
+       struct omap34xxcam_device *cam;
+       struct isp_sysc isp_sysconfig;
+       int i;
+
+       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+       if (!cam) {
+               dev_err(&pdev->dev, "could not allocate memory\n");
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, cam);
+
+       cam->dev = &pdev->dev;
+
+       isp_get();
+       isp_sysconfig.reset = 0;
+       isp_sysconfig.idle_mode = 1;
+       isp_power_settings(isp_sysconfig);
+       isp_put();
+
+       omap34xxcam = cam;
+
+       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+               struct omap34xxcam_videodev *vdev = &cam->vdevs[i];
+               struct v4l2_int_device *m = &vdev->master;
+
+               m->module       = THIS_MODULE;
+               strlcpy(m->name, CAM_NAME, sizeof(m->name));
+               m->type         = v4l2_int_type_master;
+               m->u.master     = &omap34xxcam_master;
+               m->priv         = vdev;
+
+               mutex_init(&vdev->mutex);
+               vdev->index             = i;
+               vdev->cam               = cam;
+               vdev->vdev_sensor =
+                       vdev->vdev_lens =
+                       vdev->vdev_flash = v4l2_int_device_dummy();
+               setup_timer(&vdev->poweroff_timer,
+                           omap34xxcam_slave_power_timer, (unsigned long)vdev);
+               INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
+
+               if (v4l2_int_device_register(m))
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       omap34xxcam_remove(pdev);
+       return -ENODEV;
+}
+
+static struct platform_driver omap34xxcam_driver = {
+       .probe = omap34xxcam_probe,
+       .remove = omap34xxcam_remove,
+#ifdef CONFIG_PM
+       .suspend = omap34xxcam_suspend,
+       .resume = omap34xxcam_resume,
+#endif
+       .driver = {
+                  .name = CAM_NAME,
+                  },
+};
+
+/*
+ *
+ * Module initialisation and deinitialisation
+ *
+ */
+
+/**
+ * omap34xxcam_init - module_init function
+ *
+ * Calls platfrom driver to register probe, remove,
+ * suspend and resume functions.
+ *
+ */
+static int __init omap34xxcam_init(void)
+{
+       return platform_driver_register(&omap34xxcam_driver);
+}
+
+/**
+ * omap34xxcam_cleanup - module_exit function
+ *
+ * Calls platfrom driver to unregister probe, remove,
+ * suspend and resume functions.
+ *
+ */
+static void __exit omap34xxcam_cleanup(void)
+{
+       platform_driver_unregister(&omap34xxcam_driver);
+}
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com");
+MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+
+late_initcall(omap34xxcam_init);
+module_exit(omap34xxcam_cleanup);
diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
new file mode 100644
index 0000000..cc024eb
--- /dev/null
+++ b/drivers/media/video/omap34xxcam.h
@@ -0,0 +1,215 @@
+/*
+ * drivers/media/video/omap34xxcam.c
+ *
+ * Copyright (C) 2006--2008 Nokia Corporation
+ * Copyright (C) 2007, 2008 Texas Instruments
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *
+ * Originally based on the OMAP 2 camera driver.
+ *
+ * Written by Sakari Ailus <sakari.ailus@nokia.com>
+ *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *            Sergio Aguirre <saaguirre@ti.com>
+ *            Mohit Jalori
+ *            Sameer Venkatraman
+ *            Leonides Martinez
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef OMAP34XXCAM_H
+#define OMAP34XXCAM_H
+
+#include <media/v4l2-int-device.h>
+#include "isp/isp.h"
+
+#define CAM_NAME                       "omap34xxcam"
+#define CAM_SHORT_NAME                 "omap3"
+
+#define OMAP_ISP_AF            (1 << 4)
+#define OMAP_ISP_HIST          (1 << 5)
+#define OMAP34XXCAM_XCLK_NONE  -1
+#define OMAP34XXCAM_XCLK_A     0
+#define OMAP34XXCAM_XCLK_B     1
+
+#define OMAP34XXCAM_SLAVE_SENSOR       0
+#define OMAP34XXCAM_SLAVE_LENS         1
+#define OMAP34XXCAM_SLAVE_FLASH                2 /* This is the last slave! */
+
+/* mask for omap34xxcam_slave_power_set */
+#define OMAP34XXCAM_SLAVE_POWER_SENSOR (1 << OMAP34XXCAM_SLAVE_SENSOR)
+#define OMAP34XXCAM_SLAVE_POWER_LENS   (1 << OMAP34XXCAM_SLAVE_LENS)
+#define OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS \
+       (OMAP34XXCAM_SLAVE_POWER_SENSOR | OMAP34XXCAM_SLAVE_POWER_LENS)
+#define OMAP34XXCAM_SLAVE_POWER_FLASH  (1 << OMAP34XXCAM_SLAVE_FLASH)
+#define OMAP34XXCAM_SLAVE_POWER_ALL    -1
+
+#define OMAP34XXCAM_VIDEODEVS          4
+
+struct omap34xxcam_device;
+struct omap34xxcam_videodev;
+
+struct omap34xxcam_sensor_config {
+       int xclk;
+       int sensor_isp;
+       u32 capture_mem;
+};
+
+struct omap34xxcam_lens_config {
+};
+
+struct omap34xxcam_flash_config {
+};
+
+/**
+ * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
+ * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
+ * @sensor_isp: Is sensor smart/SOC or raw
+ * @s_pix_sparm: Access function to set pix and sparm.
+ * Pix will override sparm
+ */
+struct omap34xxcam_hw_config {
+       int dev_index; /* Index in omap34xxcam_sensors */
+       int dev_minor; /* Video device minor number */
+       int dev_type; /* OMAP34XXCAM_SLAVE_* */
+       union {
+               struct omap34xxcam_sensor_config sensor;
+               struct omap34xxcam_lens_config lens;
+               struct omap34xxcam_flash_config flash;
+       } u;
+};
+
+/**
+ * struct omap34xxcam_videodev - per /dev/video* structure
+ * @mutex: serialises access to this structure
+ * @cam: pointer to cam hw structure
+ * @master: we are v4l2_int_device master
+ * @sensor: sensor device
+ * @lens: lens device
+ * @flash: flash device
+ * @slaves: how many slaves we have at the moment
+ * @vfd: our video device
+ * @capture_mem: maximum kernel-allocated capture memory
+ * @if_u: sensor interface stuff
+ * @index: index of this structure in cam->vdevs
+ * @users: how many users we have
+ * @power_state: Current power state
+ * @power_state_wish: New power state when poweroff_timer expires
+ * @power_state_mask: Bitmask of devices to set the new power state
+ * @poweroff_timer: Timer for dispatching poweroff_work
+ * @poweroff_work: Work for slave power state change
+ * @sensor_config: ISP-speicific sensor configuration
+ * @lens_config: ISP-speicific lens configuration
+ * @flash_config: ISP-speicific flash configuration
+ * @streaming: streaming file handle, if streaming is enabled
+ */
+struct omap34xxcam_videodev {
+       struct mutex mutex; /* serialises access to this structure */
+
+       struct omap34xxcam_device *cam;
+       struct v4l2_int_device master;
+
+#define vdev_sensor slave[OMAP34XXCAM_SLAVE_SENSOR]
+#define vdev_lens slave[OMAP34XXCAM_SLAVE_LENS]
+#define vdev_flash slave[OMAP34XXCAM_SLAVE_FLASH]
+       struct v4l2_int_device *slave[OMAP34XXCAM_SLAVE_FLASH + 1];
+
+       /* number of slaves attached */
+       int slaves;
+
+       /*** video device parameters ***/
+       struct video_device *vfd;
+       int capture_mem;
+
+       /*** general driver state information ***/
+       /*
+        * Sensor interface parameters: interface type, CC_CTRL
+        * register value and interface specific data.
+        */
+       u32 xclk;
+       /* index to omap34xxcam_videodevs of this structure */
+       int index;
+       atomic_t users;
+       enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
+       enum v4l2_power power_state_wish;
+       int power_state_mask;
+       struct timer_list poweroff_timer;
+       struct work_struct poweroff_work;
+
+#define vdev_sensor_config slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor
+#define vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens
+#define vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash
+       struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH + 1];
+
+       /*** capture data ***/
+       struct v4l2_fract want_timeperframe;
+       struct v4l2_pix_format want_pix;
+       /* file handle, if streaming is on */
+       struct file *streaming;
+};
+
+/**
+ * struct omap34xxcam_device - per-device data structure
+ * @mutex: mutex serialises access to this structure
+ * @sgdma_in_queue: Number or sgdma requests in scatter-gather queue,
+ * protected by the lock above.
+ * @sgdma: ISP sgdma subsystem information structure
+ * @dma_notify: DMA notify flag
+ * @irq: irq number platform HW resource
+ * @mmio_base: register map memory base (platform HW resource)
+ * @mmio_base_phys: register map memory base physical address
+ * @mmio_size: register map memory size
+ * @dev: device structure
+ * @vdevs: /dev/video specific structures
+ * @fck: camera module fck clock information
+ * @ick: camera module ick clock information
+ */
+struct omap34xxcam_device {
+       struct mutex mutex; /* serialises access to this structure */
+       int sgdma_in_queue;
+       struct isp_sgdma sgdma;
+       int dma_notify;
+
+       /*** interfaces and device ***/
+       struct device *dev;
+       struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
+
+       /*** camera module clocks ***/
+       struct clk *fck;
+       struct clk *ick;
+       bool sensor_if_enabled;
+};
+
+/**
+ * struct omap34xxcam_fh - per-filehandle data structure
+ * @vbq_lock: spinlock for the videobuf queue
+ * @vbq: V4L2 video buffer queue structure
+ * @pix: V4L2 pixel format structure (serialise pix by vbq->lock)
+ * @field_count: field counter for videobuf_buffer
+ * @vdev: our /dev/video specific structure
+ */
+struct omap34xxcam_fh {
+       spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+       struct videobuf_queue vbq;
+       struct v4l2_pix_format pix;
+       atomic_t field_count;
+       /* accessing cam here doesn't need serialisation: it's constant */
+       struct omap34xxcam_videodev *vdev;
+};
+
+#endif /* ifndef OMAP34XXCAM_H */
--
1.5.6.5


--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-01-13  2:03   ` Aguirre Rodriguez, Sergio Alberto
@ 2009-01-13  7:24     ` Hans Verkuil
  -1 siblings, 0 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-01-13  7:24 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: linux-omap, linux-media, video4linux-list, Sakari Ailus,
	Tuukka.O Toivonen, Nagalla, Hari

On Tuesday 13 January 2009 03:03:34 Aguirre Rodriguez, Sergio Alberto wrote:
> Signed-off-by: Sakari Ailus <sakari.ailus@nokia.com>
> Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
> ---
>  drivers/media/video/Kconfig       |    8 +
>  drivers/media/video/Makefile      |    2 +
>  drivers/media/video/omap34xxcam.c | 2017
> +++++++++++++++++++++++++++++++++++++
> drivers/media/video/omap34xxcam.h |  215 ++++
>  4 files changed, 2242 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/video/omap34xxcam.c
>  create mode 100644 drivers/media/video/omap34xxcam.h
>

...

> +/**
> + * vidioc_default - private IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle
> data) + * @cmd: ioctl cmd value
> + * @arg: ioctl arg value
> + *
> + * If the sensor being used is a "smart sensor", this request is
> returned to + * caller with -EINVAL err code.  Otherwise if the
> control id is the private + * VIDIOC_PRIVATE_ISP_AEWB_REQ to update
> the analog gain or exposure, + * then this request is forwared
> directly to the sensor to incorporate the + * feedback. The request
> is then passed on to the ISP private IOCTL handler, + *
> isp_handle_private()
> + */
> +static int vidioc_default(struct file *file, void *fh, int cmd, void
> *arg) +{
> +       struct omap34xxcam_fh *ofh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp) {
> +               rval = -EINVAL;
> +       } else {
> +               switch (cmd) {
> +               case VIDIOC_ENUM_FRAMESIZES:
> +                       rval = vidioc_enum_framesizes(file, fh, arg);
> +                       goto out;
> +               case VIDIOC_ENUM_FRAMEINTERVALS:
> +                       rval = vidioc_enum_frameintervals(file, fh,
> arg); +                       goto out;

These two have proper v4l2_ioctl_ops entries, so there is no need to handle
them in vidioc_default.

> +               case VIDIOC_PRIVATE_ISP_AEWB_REQ:
> +               {
> +                       /* Need to update sensor first */
> +                       struct isph3a_aewb_data *data;
> +                       struct v4l2_control vc;
> +
> +                       data = (struct isph3a_aewb_data *) arg;
> +                       if (data->update & SET_EXPOSURE) {
> +                               vc.id = V4L2_CID_EXPOSURE;
> +                               vc.value = data->shutter;
> +                               mutex_lock(&vdev->mutex);
> +                               rval =
> vidioc_int_s_ctrl(vdev->vdev_sensor, +                               
>                         &vc); +                              
> mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +                       if (data->update & SET_ANALOG_GAIN) {
> +                               vc.id = V4L2_CID_GAIN;
> +                               vc.value = data->gain;
> +                               mutex_lock(&vdev->mutex);
> +                               rval =
> vidioc_int_s_ctrl(vdev->vdev_sensor, +                               
>                         &vc); +                              
> mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +               }
> +               break;
> +               case VIDIOC_PRIVATE_ISP_AF_REQ: {
> +                       /* Need to update lens first */
> +                       struct isp_af_data *data;
> +                       struct v4l2_control vc;
> +
> +                       if (!vdev->vdev_lens) {
> +                               rval = -EINVAL;
> +                               goto out;
> +                       }
> +                       data = (struct isp_af_data *) arg;
> +                       if (data->update & LENS_DESIRED_POSITION) {
> +                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
> +                               vc.value =
> data->desired_lens_direction; +                              
> mutex_lock(&vdev->mutex);
> +                               rval =
> vidioc_int_s_ctrl(vdev->vdev_lens, &vc); +                           
>    mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +                       if (data->update & REQUEST_STATISTICS) {
> +                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
> +                               mutex_lock(&vdev->mutex);
> +                               rval =
> vidioc_int_g_ctrl(vdev->vdev_lens, &vc); +                           
>    mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                               data->xtrastats.lens_position =
> vc.value; +                       }
> +               }
> +                       break;
> +               }
> +
> +               mutex_lock(&vdev->mutex);
> +               rval = isp_handle_private(cmd, arg);
> +               mutex_unlock(&vdev->mutex);
> +       }
> +out:
> +       return rval;
> +}
> +
> +/*
> + *
> + * File operations.
> + *
> + */
> +
> +static long omap34xxcam_unlocked_ioctl(struct file *file, unsigned
> int cmd, +                                      unsigned long arg)
> +{
> +       return (long)video_ioctl2(file->f_dentry->d_inode, file, cmd,
> arg); +}
> +
> +/**
> + * omap34xxcam_poll - file operations poll handler
> + * @file: ptr. to system file structure
> + * @wait: system poll table structure
> + *
> + */
> +static unsigned int omap34xxcam_poll(struct file *file,
> +                                    struct poll_table_struct *wait)
> +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       struct videobuf_buffer *vb;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming != file) {
> +               mutex_unlock(&vdev->mutex);
> +               return POLLERR;
> +       }
> +       mutex_unlock(&vdev->mutex);
> +
> +       mutex_lock(&fh->vbq.vb_lock);
> +       if (list_empty(&fh->vbq.stream)) {
> +               mutex_unlock(&fh->vbq.vb_lock);
> +               return POLLERR;
> +       }
> +       vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer,
> stream); +       mutex_unlock(&fh->vbq.vb_lock);
> +
> +       poll_wait(file, &vb->done, wait);
> +
> +       if (vb->state == VIDEOBUF_DONE || vb->state ==
> VIDEOBUF_ERROR) +               return POLLIN | POLLRDNORM;
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_mmap - file operations mmap handler
> + * @file: ptr. to system file structure
> + * @vma: system virt. mem. area structure
> + *
> + * Maps a virtual memory area via the video buffer API
> + */
> +static int omap34xxcam_mmap(struct file *file, struct vm_area_struct
> *vma) +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       return videobuf_mmap_mapper(&fh->vbq, vma);
> +}
> +
> +/**
> + * omap34xxcam_open - file operations open handler
> + * @inode: ptr. to system inode structure
> + * @file: ptr. to system file structure
> + *
> + * Allocates and initializes the per-filehandle data
> (omap34xxcam_fh), + * enables the sensor, opens/initializes the ISP
> interface and the + * video buffer queue.  Note that this function
> will allow multiple + * file handles to be open simultaneously,
> however only the first + * handle opened will initialize the ISP.  It
> is the application + * responsibility to only use one handle for
> streaming and the others + * for control only.
> + * This function returns 0 upon success and -ENODEV upon error.
> + */
> +static int omap34xxcam_open(struct inode *inode, struct file *file)
> +{
> +       struct omap34xxcam_videodev *vdev = NULL;
> +       struct omap34xxcam_device *cam = omap34xxcam;
> +       struct omap34xxcam_fh *fh;
> +       struct v4l2_format format;
> +       int i;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               if (cam->vdevs[i].vfd
> +                   && cam->vdevs[i].vfd->minor == iminor(inode)) {
> +                       vdev = &cam->vdevs[i];
> +                       break;
> +               }
> +       }
> +
> +       if (!vdev || !vdev->vfd)
> +               return -ENODEV;
> +
> +       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
> +       if (fh == NULL)
> +               return -ENOMEM;
> +
> +       mutex_lock(&vdev->mutex);
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               if (vdev->slave[i] != v4l2_int_device_dummy()
> +                   && !try_module_get(vdev->slave[i]->module)) {
> +                       mutex_unlock(&vdev->mutex);
> +                       goto out_try_module_get;
> +               }
> +       }
> +
> +       if (atomic_inc_return(&vdev->users) == 1) {
> +               isp_get();
> +               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                              
> OMAP34XXCAM_SLAVE_POWER_ALL)) +                       goto
> out_slave_power_set_standby;
> +               omap34xxcam_slave_power_set(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +               omap34xxcam_slave_power_suggest(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +       }
> +
> +       fh->vdev = vdev;
> +
> +       /* FIXME: Check that we have sensor now... */
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
> +       else
> +               isp_g_fmt_cap(&format.fmt.pix);
> +
> +       mutex_unlock(&vdev->mutex);
> +       /* FIXME: how about fh->pix when there are more users? */
> +       fh->pix = format.fmt.pix;
> +
> +       file->private_data = fh;
> +
> +       spin_lock_init(&fh->vbq_lock);
> +
> +       videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
> +                               &fh->vbq_lock,
> V4L2_BUF_TYPE_VIDEO_CAPTURE, +                              
> V4L2_FIELD_NONE,
> +                               sizeof(struct videobuf_buffer), fh);
> +
> +       return 0;
> +
> +out_slave_power_set_standby:
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                   OMAP34XXCAM_SLAVE_POWER_ALL);
> +       isp_put();
> +       atomic_dec(&vdev->users);
> +       mutex_unlock(&vdev->mutex);
> +
> +out_try_module_get:
> +       for (i--; i >= 0; i--)
> +               if (vdev->slave[i] != v4l2_int_device_dummy())
> +                       module_put(vdev->slave[i]->module);
> +
> +       kfree(fh);
> +
> +       return -ENODEV;
> +}
> +
> +/**
> + * omap34xxcam_release - file operations release handler
> + * @inode: ptr. to system inode structure
> + * @file: ptr. to system file structure
> + *
> + * Complement of omap34xxcam_open.  This function will flush any
> scheduled + * work, disable the sensor, close the ISP interface, stop
> the + * video buffer queue from streaming and free the per-filehandle
> data + * (omap34xxcam_fh).  Note that because multiple open file
> handles + * are allowed, this function will only close the ISP and
> disable the + * sensor when the last open file handle (by count) is
> closed. + * This function returns 0.
> + */
> +static int omap34xxcam_release(struct inode *inode, struct file
> *file) +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       int i;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming == file) {
> +               isp_stop();
> +               videobuf_streamoff(&fh->vbq);
> +               omap34xxcam_slave_power_set(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +               omap34xxcam_slave_power_suggest(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +               vdev->streaming = NULL;
> +       }
> +
> +       if (atomic_dec_return(&vdev->users) == 0) {
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                          
> OMAP34XXCAM_SLAVE_POWER_ALL); +               isp_put();
> +       }
> +       mutex_unlock(&vdev->mutex);
> +
> +       file->private_data = NULL;
> +
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
> +               if (vdev->slave[i] != v4l2_int_device_dummy())
> +                       module_put(vdev->slave[i]->module);
> +
> +       kfree(fh);
> +
> +       return 0;
> +}
> +
> +static struct file_operations omap34xxcam_fops = {
> +       .owner = THIS_MODULE,
> +       .llseek = no_llseek,
> +       .unlocked_ioctl = omap34xxcam_unlocked_ioctl,
> +       .poll = omap34xxcam_poll,
> +       .mmap = omap34xxcam_mmap,
> +       .open = omap34xxcam_open,
> +       .release = omap34xxcam_release,
> +};
> +
> +static void omap34xxcam_vfd_name_update(struct omap34xxcam_videodev
> *vdev) +{
> +       struct video_device *vfd = vdev->vfd;
> +       int i;
> +
> +       strlcpy(vfd->name, CAM_SHORT_NAME, sizeof(vfd->name));
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               strlcat(vfd->name, "/", sizeof(vfd->name));
> +               if (vdev->slave[i] == v4l2_int_device_dummy())
> +                       continue;
> +               strlcat(vfd->name, vdev->slave[i]->name,
> sizeof(vfd->name)); +       }
> +       dev_info(vdev->cam->dev, "video%d is now %s\n", vfd->minor,
> vfd->name); +}
> +
> +/**
> + * omap34xxcam_device_unregister - V4L2 detach handler
> + * @s: ptr. to standard V4L2 device information structure
> + *
> + * Detach sensor and unregister and release the video device.
> + */
> +static void omap34xxcam_device_unregister(struct v4l2_int_device *s)
> +{
> +       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
> +       struct omap34xxcam_hw_config hwc;
> +
> +       BUG_ON(vidioc_int_g_priv(s, &hwc) < 0);
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy()) {
> +               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +               vdev->slaves--;
> +               omap34xxcam_vfd_name_update(vdev);
> +       }
> +
> +       if (vdev->slaves == 0 && vdev->vfd) {
> +               if (vdev->vfd->minor == -1) {
> +                       /*
> +                        * The device was never registered, so
> release the +                        * video_device struct directly.
> +                        */
> +                       video_device_release(vdev->vfd);
> +               } else {
> +                       /*
> +                        * The unregister function will release the
> +                        * video_device struct as well as
> +                        * unregistering it.
> +                        */
> +                       video_unregister_device(vdev->vfd);
> +               }
> +               vdev->vfd = NULL;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +}
> +
> +static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = {
> +       .vidioc_querycap         = vidioc_querycap,
> +       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
> +       .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
> +       .vidioc_s_fmt_vid_cap    = vidioc_s_fmt_vid_cap,
> +       .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,
> +       .vidioc_reqbufs          = vidioc_reqbufs,
> +       .vidioc_querybuf         = vidioc_querybuf,
> +       .vidioc_qbuf             = vidioc_qbuf,
> +       .vidioc_dqbuf            = vidioc_dqbuf,
> +       .vidioc_streamon         = vidioc_streamon,
> +       .vidioc_streamoff        = vidioc_streamoff,
> +       .vidioc_enum_input       = vidioc_enum_input,
> +       .vidioc_g_input          = vidioc_g_input,
> +       .vidioc_s_input          = vidioc_s_input,
> +       .vidioc_queryctrl        = vidioc_queryctrl,
> +       .vidioc_querymenu        = vidioc_querymenu,
> +       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
> +       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
> +       .vidioc_g_parm           = vidioc_g_parm,
> +       .vidioc_s_parm           = vidioc_s_parm,
> +       .vidioc_cropcap          = vidioc_cropcap,
> +       .vidioc_g_crop           = vidioc_g_crop,
> +       .vidioc_s_crop           = vidioc_s_crop,
> +       .vidioc_default          = vidioc_default,
> +};
> +
> +/**
> + * omap34xxcam_device_register - V4L2 attach handler
> + * @s: ptr. to standard V4L2 device information structure
> + *
> + * Allocates and initializes the V4L2 video_device structure,
> initializes + * the sensor, and finally
> + registers the device with V4L2 based on the
> + * video_device structure.
> + *
> + * Returns 0 on success, otherwise an appropriate error code on
> + * failure.
> + */
> +static int omap34xxcam_device_register(struct v4l2_int_device *s)
> +{
> +       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
> +       struct omap34xxcam_device *cam = vdev->cam;
> +       struct omap34xxcam_hw_config hwc;
> +       struct video_device *vfd;
> +       int rval;
> +
> +       /* We need to check rval just once. The place is here. */
> +       if (vidioc_int_g_priv(s, &hwc))
> +               return -ENODEV;
> +
> +       if (vdev->index != hwc.dev_index)
> +               return -ENODEV;
> +
> +       if (hwc.dev_type < 0 || hwc.dev_type >
> OMAP34XXCAM_SLAVE_FLASH) +               return -EINVAL;
> +
> +       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy())
> +               return -EBUSY;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (atomic_read(&vdev->users)) {
> +               dev_err(cam->dev, "we're open (%d), can't
> register\n", +                       atomic_read(&vdev->users));
> +               mutex_unlock(&vdev->mutex);
> +               return -EBUSY;
> +       }
> +
> +       vdev->slaves++;
> +       vdev->slave[hwc.dev_type] = s;
> +       vdev->slave_config[hwc.dev_type] = hwc;
> +
> +       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +               isp_get();
> +       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                          1 << hwc.dev_type);
> +       if (!rval && hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
> +               struct v4l2_format format;
> +               struct v4l2_streamparm a;
> +
> +               format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor,
> &format); +
> +               a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval |= vidioc_int_g_parm(vdev->vdev_sensor, &a);
> +               if (rval)
> +                       rval = -EBUSY;
> +
> +               vdev->want_pix = format.fmt.pix;
> +               vdev->want_timeperframe =
> a.parm.capture.timeperframe; +       }
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF, 1 <<
> hwc.dev_type); +       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +               isp_put();
> +
> +       if (rval)
> +               goto err;
> +
> +       /* Are we the first slave? */
> +       if (vdev->slaves == 1) {
> +               /* initialize the video_device struct */
> +               vdev->vfd = video_device_alloc();
> +               vfd = vdev->vfd;
> +               if (!vfd) {
> +                       dev_err(cam->dev,
> +                               "could not allocate video device
> struct\n"); +                       return -ENOMEM;
> +               }
> +               vfd->release    = video_device_release;
> +               vfd->minor      = -1;
> +               vfd->fops       = &omap34xxcam_fops;
> +               vfd->ioctl_ops  = &omap34xxcam_ioctl_ops;
> +               video_set_drvdata(vfd, vdev);
> +
> +               if (video_register_device(vfd, VFL_TYPE_GRABBER,
> +                                         hwc.dev_minor) < 0) {
> +                       dev_err(cam->dev,
> +                               "could not register V4L device\n");
> +                       vfd->minor = -1;
> +                       rval = -EBUSY;
> +                       goto err;
> +               }
> +       } else {
> +               vfd = vdev->vfd;
> +       }
> +
> +       omap34xxcam_vfd_name_update(vdev);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return 0;
> +
> +err:
> +       if (s == vdev->slave[hwc.dev_type]) {
> +               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +               vdev->slaves--;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +       omap34xxcam_device_unregister(s);
> +
> +       return rval;
> +}
> +
> +static struct v4l2_int_master omap34xxcam_master = {
> +       .attach = omap34xxcam_device_register,
> +       .detach = omap34xxcam_device_unregister,
> +};
> +
> +/*
> + *
> + * Driver Suspend/Resume
> + *
> + */
> +
> +#ifdef CONFIG_PM
> +/**
> + * omap34xxcam_suspend - platform driver PM suspend handler
> + * @pdev: ptr. to platform level device information structure
> + * @state: power state
> + *
> + * If applicable, stop capture and disable sensor.
> + *
> + * Returns 0 always
> + */
> +static int omap34xxcam_suspend(struct platform_device *pdev,
> pm_message_t state) +{
> +       struct omap34xxcam_videodev *vdev =
> platform_get_drvdata(pdev); +
> +       if (atomic_read(&vdev->users) == 0)
> +               return 0;
> +
> +       if (vdev->streaming) {
> +               isp_stop();
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                          
> OMAP34XXCAM_SLAVE_POWER_ALL); +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_resume - platform driver PM resume handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * If applicable, resume capture and enable sensor.
> + *
> + * Returns 0 always
> + */
> +static int omap34xxcam_resume(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_videodev *vdev =
> platform_get_drvdata(pdev); +
> +       if (atomic_read(&vdev->users) == 0)
> +               return 0;
> +
> +       if (vdev->streaming) {
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                          
> OMAP34XXCAM_SLAVE_POWER_ALL); +               isp_start();
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
> +/*
> + *
> + * Driver initialisation and deinitialisation.
> + *
> + */
> +
> +/**
> + * omap34xxcam_remove - platform driver remove handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * Unregister device with V4L2, unmap camera registers, and
> + * free camera device information structure (omap34xxcam_device).
> + *
> + * Returns 0 always.
> + */
> +static int omap34xxcam_remove(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_device *cam = platform_get_drvdata(pdev);
> +       int i;
> +
> +       if (!cam)
> +               return 0;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               if (cam->vdevs[i].cam == NULL)
> +                       continue;
> +
> +               v4l2_int_device_unregister(&cam->vdevs[i].master);
> +               cam->vdevs[i].cam = NULL;
> +       }
> +
> +       omap34xxcam = NULL;
> +
> +       kfree(cam);
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_probe - platform driver probe handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * Allocates and initializes camera device information structure
> + * (omap34xxcam_device), maps the device registers and gets the
> + * device IRQ.  Registers the device as a V4L2 client.
> + *
> + * Returns 0 on success or -ENODEV on failure.
> + */
> +static int omap34xxcam_probe(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_device *cam;
> +       struct isp_sysc isp_sysconfig;
> +       int i;
> +
> +       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
> +       if (!cam) {
> +               dev_err(&pdev->dev, "could not allocate memory\n");
> +               goto err;
> +       }
> +
> +       platform_set_drvdata(pdev, cam);
> +
> +       cam->dev = &pdev->dev;
> +
> +       isp_get();
> +       isp_sysconfig.reset = 0;
> +       isp_sysconfig.idle_mode = 1;
> +       isp_power_settings(isp_sysconfig);
> +       isp_put();
> +
> +       omap34xxcam = cam;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               struct omap34xxcam_videodev *vdev = &cam->vdevs[i];
> +               struct v4l2_int_device *m = &vdev->master;
> +
> +               m->module       = THIS_MODULE;
> +               strlcpy(m->name, CAM_NAME, sizeof(m->name));
> +               m->type         = v4l2_int_type_master;
> +               m->u.master     = &omap34xxcam_master;
> +               m->priv         = vdev;
> +
> +               mutex_init(&vdev->mutex);
> +               vdev->index             = i;
> +               vdev->cam               = cam;
> +               vdev->vdev_sensor =
> +                       vdev->vdev_lens =
> +                       vdev->vdev_flash = v4l2_int_device_dummy();
> +               setup_timer(&vdev->poweroff_timer,
> +                           omap34xxcam_slave_power_timer, (unsigned
> long)vdev); +               INIT_WORK(&vdev->poweroff_work,
> omap34xxcam_slave_power_work); +
> +               if (v4l2_int_device_register(m))
> +                       goto err;
> +       }
> +
> +       return 0;
> +
> +err:
> +       omap34xxcam_remove(pdev);
> +       return -ENODEV;
> +}
> +
> +static struct platform_driver omap34xxcam_driver = {
> +       .probe = omap34xxcam_probe,
> +       .remove = omap34xxcam_remove,
> +#ifdef CONFIG_PM
> +       .suspend = omap34xxcam_suspend,
> +       .resume = omap34xxcam_resume,
> +#endif
> +       .driver = {
> +                  .name = CAM_NAME,
> +                  },
> +};
> +
> +/*
> + *
> + * Module initialisation and deinitialisation
> + *
> + */
> +
> +/**
> + * omap34xxcam_init - module_init function
> + *
> + * Calls platfrom driver to register probe, remove,
> + * suspend and resume functions.
> + *
> + */
> +static int __init omap34xxcam_init(void)
> +{
> +       return platform_driver_register(&omap34xxcam_driver);
> +}
> +
> +/**
> + * omap34xxcam_cleanup - module_exit function
> + *
> + * Calls platfrom driver to unregister probe, remove,
> + * suspend and resume functions.
> + *
> + */
> +static void __exit omap34xxcam_cleanup(void)
> +{
> +       platform_driver_unregister(&omap34xxcam_driver);
> +}
> +
> +MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com");
> +MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
> +MODULE_LICENSE("GPL");
> +
> +late_initcall(omap34xxcam_init);
> +module_exit(omap34xxcam_cleanup);
> diff --git a/drivers/media/video/omap34xxcam.h
> b/drivers/media/video/omap34xxcam.h new file mode 100644
> index 0000000..cc024eb
> --- /dev/null
> +++ b/drivers/media/video/omap34xxcam.h
> @@ -0,0 +1,215 @@
> +/*
> + * drivers/media/video/omap34xxcam.c
> + *
> + * Copyright (C) 2006--2008 Nokia Corporation
> + * Copyright (C) 2007, 2008 Texas Instruments
> + *
> + * Contact: Sakari Ailus <sakari.ailus@nokia.com>
> + *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *
> + * Originally based on the OMAP 2 camera driver.
> + *
> + * Written by Sakari Ailus <sakari.ailus@nokia.com>
> + *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *            Sergio Aguirre <saaguirre@ti.com>
> + *            Mohit Jalori
> + *            Sameer Venkatraman
> + *            Leonides Martinez
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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 St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef OMAP34XXCAM_H
> +#define OMAP34XXCAM_H
> +
> +#include <media/v4l2-int-device.h>
> +#include "isp/isp.h"
> +
> +#define CAM_NAME                       "omap34xxcam"
> +#define CAM_SHORT_NAME                 "omap3"
> +
> +#define OMAP_ISP_AF            (1 << 4)
> +#define OMAP_ISP_HIST          (1 << 5)
> +#define OMAP34XXCAM_XCLK_NONE  -1
> +#define OMAP34XXCAM_XCLK_A     0
> +#define OMAP34XXCAM_XCLK_B     1
> +
> +#define OMAP34XXCAM_SLAVE_SENSOR       0
> +#define OMAP34XXCAM_SLAVE_LENS         1
> +#define OMAP34XXCAM_SLAVE_FLASH                2 /* This is the last
> slave! */ +
> +/* mask for omap34xxcam_slave_power_set */
> +#define OMAP34XXCAM_SLAVE_POWER_SENSOR (1 <<
> OMAP34XXCAM_SLAVE_SENSOR) +#define OMAP34XXCAM_SLAVE_POWER_LENS   (1
> << OMAP34XXCAM_SLAVE_LENS) +#define
> OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS \
> +       (OMAP34XXCAM_SLAVE_POWER_SENSOR |
> OMAP34XXCAM_SLAVE_POWER_LENS) +#define OMAP34XXCAM_SLAVE_POWER_FLASH 
> (1 << OMAP34XXCAM_SLAVE_FLASH) +#define OMAP34XXCAM_SLAVE_POWER_ALL  
>  -1
> +
> +#define OMAP34XXCAM_VIDEODEVS          4
> +
> +struct omap34xxcam_device;
> +struct omap34xxcam_videodev;
> +
> +struct omap34xxcam_sensor_config {
> +       int xclk;
> +       int sensor_isp;
> +       u32 capture_mem;
> +};
> +
> +struct omap34xxcam_lens_config {
> +};
> +
> +struct omap34xxcam_flash_config {
> +};
> +
> +/**
> + * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
> + * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
> + * @sensor_isp: Is sensor smart/SOC or raw
> + * @s_pix_sparm: Access function to set pix and sparm.
> + * Pix will override sparm
> + */
> +struct omap34xxcam_hw_config {
> +       int dev_index; /* Index in omap34xxcam_sensors */
> +       int dev_minor; /* Video device minor number */
> +       int dev_type; /* OMAP34XXCAM_SLAVE_* */
> +       union {
> +               struct omap34xxcam_sensor_config sensor;
> +               struct omap34xxcam_lens_config lens;
> +               struct omap34xxcam_flash_config flash;
> +       } u;
> +};
> +
> +/**
> + * struct omap34xxcam_videodev - per /dev/video* structure
> + * @mutex: serialises access to this structure
> + * @cam: pointer to cam hw structure
> + * @master: we are v4l2_int_device master
> + * @sensor: sensor device
> + * @lens: lens device
> + * @flash: flash device
> + * @slaves: how many slaves we have at the moment
> + * @vfd: our video device
> + * @capture_mem: maximum kernel-allocated capture memory
> + * @if_u: sensor interface stuff
> + * @index: index of this structure in cam->vdevs
> + * @users: how many users we have
> + * @power_state: Current power state
> + * @power_state_wish: New power state when poweroff_timer expires
> + * @power_state_mask: Bitmask of devices to set the new power state
> + * @poweroff_timer: Timer for dispatching poweroff_work
> + * @poweroff_work: Work for slave power state change
> + * @sensor_config: ISP-speicific sensor configuration
> + * @lens_config: ISP-speicific lens configuration
> + * @flash_config: ISP-speicific flash configuration
> + * @streaming: streaming file handle, if streaming is enabled
> + */
> +struct omap34xxcam_videodev {
> +       struct mutex mutex; /* serialises access to this structure */
> +
> +       struct omap34xxcam_device *cam;
> +       struct v4l2_int_device master;
> +
> +#define vdev_sensor slave[OMAP34XXCAM_SLAVE_SENSOR]
> +#define vdev_lens slave[OMAP34XXCAM_SLAVE_LENS]
> +#define vdev_flash slave[OMAP34XXCAM_SLAVE_FLASH]
> +       struct v4l2_int_device *slave[OMAP34XXCAM_SLAVE_FLASH + 1];
> +
> +       /* number of slaves attached */
> +       int slaves;
> +
> +       /*** video device parameters ***/
> +       struct video_device *vfd;
> +       int capture_mem;
> +
> +       /*** general driver state information ***/
> +       /*
> +        * Sensor interface parameters: interface type, CC_CTRL
> +        * register value and interface specific data.
> +        */
> +       u32 xclk;
> +       /* index to omap34xxcam_videodevs of this structure */
> +       int index;
> +       atomic_t users;
> +       enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
> +       enum v4l2_power power_state_wish;
> +       int power_state_mask;
> +       struct timer_list poweroff_timer;
> +       struct work_struct poweroff_work;
> +
> +#define vdev_sensor_config
> slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor +#define
> vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens +#define
> vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash +    
>   struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH +
> 1]; +
> +       /*** capture data ***/
> +       struct v4l2_fract want_timeperframe;
> +       struct v4l2_pix_format want_pix;
> +       /* file handle, if streaming is on */
> +       struct file *streaming;
> +};
> +
> +/**
> + * struct omap34xxcam_device - per-device data structure
> + * @mutex: mutex serialises access to this structure
> + * @sgdma_in_queue: Number or sgdma requests in scatter-gather
> queue, + * protected by the lock above.
> + * @sgdma: ISP sgdma subsystem information structure
> + * @dma_notify: DMA notify flag
> + * @irq: irq number platform HW resource
> + * @mmio_base: register map memory base (platform HW resource)
> + * @mmio_base_phys: register map memory base physical address
> + * @mmio_size: register map memory size
> + * @dev: device structure
> + * @vdevs: /dev/video specific structures
> + * @fck: camera module fck clock information
> + * @ick: camera module ick clock information
> + */
> +struct omap34xxcam_device {
> +       struct mutex mutex; /* serialises access to this structure */
> +       int sgdma_in_queue;
> +       struct isp_sgdma sgdma;
> +       int dma_notify;
> +
> +       /*** interfaces and device ***/
> +       struct device *dev;
> +       struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
> +
> +       /*** camera module clocks ***/
> +       struct clk *fck;
> +       struct clk *ick;
> +       bool sensor_if_enabled;
> +};
> +
> +/**
> + * struct omap34xxcam_fh - per-filehandle data structure
> + * @vbq_lock: spinlock for the videobuf queue
> + * @vbq: V4L2 video buffer queue structure
> + * @pix: V4L2 pixel format structure (serialise pix by vbq->lock)
> + * @field_count: field counter for videobuf_buffer
> + * @vdev: our /dev/video specific structure
> + */
> +struct omap34xxcam_fh {
> +       spinlock_t vbq_lock; /* spinlock for the videobuf queue */
> +       struct videobuf_queue vbq;
> +       struct v4l2_pix_format pix;
> +       atomic_t field_count;
> +       /* accessing cam here doesn't need serialisation: it's
> constant */ +       struct omap34xxcam_videodev *vdev;
> +};
> +
> +#endif /* ifndef OMAP34XXCAM_H */

Urgh. v4l2_pix_format is NOT filehandle-specific! It is device global and
should be part of omap34xxcam_device. The same should probably be true for
videobuf_queue.

I know that there is a bunch of other v4l drivers that do the same that
you are doing here, but these are all wrong and do not follow the v4l2
specification correctly. They are on my to do list to fix.

Also note that substantial changes were made in the v4l2 core for 2.6.29,
so this patch will not apply there. The file_operations struct is replaced
by a v4l2_file_operations struct and the inode pointer was dropped from
the various ops.

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2009-01-13  7:24     ` Hans Verkuil
  0 siblings, 0 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-01-13  7:24 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: video4linux-list, Sakari Ailus, linux-media, linux-omap,
	Tuukka.O Toivonen, Nagalla, Hari

On Tuesday 13 January 2009 03:03:34 Aguirre Rodriguez, Sergio Alberto wrote:
> Signed-off-by: Sakari Ailus <sakari.ailus@nokia.com>
> Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
> ---
>  drivers/media/video/Kconfig       |    8 +
>  drivers/media/video/Makefile      |    2 +
>  drivers/media/video/omap34xxcam.c | 2017
> +++++++++++++++++++++++++++++++++++++
> drivers/media/video/omap34xxcam.h |  215 ++++
>  4 files changed, 2242 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/video/omap34xxcam.c
>  create mode 100644 drivers/media/video/omap34xxcam.h
>

...

> +/**
> + * vidioc_default - private IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle
> data) + * @cmd: ioctl cmd value
> + * @arg: ioctl arg value
> + *
> + * If the sensor being used is a "smart sensor", this request is
> returned to + * caller with -EINVAL err code.  Otherwise if the
> control id is the private + * VIDIOC_PRIVATE_ISP_AEWB_REQ to update
> the analog gain or exposure, + * then this request is forwared
> directly to the sensor to incorporate the + * feedback. The request
> is then passed on to the ISP private IOCTL handler, + *
> isp_handle_private()
> + */
> +static int vidioc_default(struct file *file, void *fh, int cmd, void
> *arg) +{
> +       struct omap34xxcam_fh *ofh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp) {
> +               rval = -EINVAL;
> +       } else {
> +               switch (cmd) {
> +               case VIDIOC_ENUM_FRAMESIZES:
> +                       rval = vidioc_enum_framesizes(file, fh, arg);
> +                       goto out;
> +               case VIDIOC_ENUM_FRAMEINTERVALS:
> +                       rval = vidioc_enum_frameintervals(file, fh,
> arg); +                       goto out;

These two have proper v4l2_ioctl_ops entries, so there is no need to handle
them in vidioc_default.

> +               case VIDIOC_PRIVATE_ISP_AEWB_REQ:
> +               {
> +                       /* Need to update sensor first */
> +                       struct isph3a_aewb_data *data;
> +                       struct v4l2_control vc;
> +
> +                       data = (struct isph3a_aewb_data *) arg;
> +                       if (data->update & SET_EXPOSURE) {
> +                               vc.id = V4L2_CID_EXPOSURE;
> +                               vc.value = data->shutter;
> +                               mutex_lock(&vdev->mutex);
> +                               rval =
> vidioc_int_s_ctrl(vdev->vdev_sensor, +                               
>                         &vc); +                              
> mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +                       if (data->update & SET_ANALOG_GAIN) {
> +                               vc.id = V4L2_CID_GAIN;
> +                               vc.value = data->gain;
> +                               mutex_lock(&vdev->mutex);
> +                               rval =
> vidioc_int_s_ctrl(vdev->vdev_sensor, +                               
>                         &vc); +                              
> mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +               }
> +               break;
> +               case VIDIOC_PRIVATE_ISP_AF_REQ: {
> +                       /* Need to update lens first */
> +                       struct isp_af_data *data;
> +                       struct v4l2_control vc;
> +
> +                       if (!vdev->vdev_lens) {
> +                               rval = -EINVAL;
> +                               goto out;
> +                       }
> +                       data = (struct isp_af_data *) arg;
> +                       if (data->update & LENS_DESIRED_POSITION) {
> +                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
> +                               vc.value =
> data->desired_lens_direction; +                              
> mutex_lock(&vdev->mutex);
> +                               rval =
> vidioc_int_s_ctrl(vdev->vdev_lens, &vc); +                           
>    mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +                       if (data->update & REQUEST_STATISTICS) {
> +                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
> +                               mutex_lock(&vdev->mutex);
> +                               rval =
> vidioc_int_g_ctrl(vdev->vdev_lens, &vc); +                           
>    mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                               data->xtrastats.lens_position =
> vc.value; +                       }
> +               }
> +                       break;
> +               }
> +
> +               mutex_lock(&vdev->mutex);
> +               rval = isp_handle_private(cmd, arg);
> +               mutex_unlock(&vdev->mutex);
> +       }
> +out:
> +       return rval;
> +}
> +
> +/*
> + *
> + * File operations.
> + *
> + */
> +
> +static long omap34xxcam_unlocked_ioctl(struct file *file, unsigned
> int cmd, +                                      unsigned long arg)
> +{
> +       return (long)video_ioctl2(file->f_dentry->d_inode, file, cmd,
> arg); +}
> +
> +/**
> + * omap34xxcam_poll - file operations poll handler
> + * @file: ptr. to system file structure
> + * @wait: system poll table structure
> + *
> + */
> +static unsigned int omap34xxcam_poll(struct file *file,
> +                                    struct poll_table_struct *wait)
> +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       struct videobuf_buffer *vb;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming != file) {
> +               mutex_unlock(&vdev->mutex);
> +               return POLLERR;
> +       }
> +       mutex_unlock(&vdev->mutex);
> +
> +       mutex_lock(&fh->vbq.vb_lock);
> +       if (list_empty(&fh->vbq.stream)) {
> +               mutex_unlock(&fh->vbq.vb_lock);
> +               return POLLERR;
> +       }
> +       vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer,
> stream); +       mutex_unlock(&fh->vbq.vb_lock);
> +
> +       poll_wait(file, &vb->done, wait);
> +
> +       if (vb->state == VIDEOBUF_DONE || vb->state ==
> VIDEOBUF_ERROR) +               return POLLIN | POLLRDNORM;
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_mmap - file operations mmap handler
> + * @file: ptr. to system file structure
> + * @vma: system virt. mem. area structure
> + *
> + * Maps a virtual memory area via the video buffer API
> + */
> +static int omap34xxcam_mmap(struct file *file, struct vm_area_struct
> *vma) +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       return videobuf_mmap_mapper(&fh->vbq, vma);
> +}
> +
> +/**
> + * omap34xxcam_open - file operations open handler
> + * @inode: ptr. to system inode structure
> + * @file: ptr. to system file structure
> + *
> + * Allocates and initializes the per-filehandle data
> (omap34xxcam_fh), + * enables the sensor, opens/initializes the ISP
> interface and the + * video buffer queue.  Note that this function
> will allow multiple + * file handles to be open simultaneously,
> however only the first + * handle opened will initialize the ISP.  It
> is the application + * responsibility to only use one handle for
> streaming and the others + * for control only.
> + * This function returns 0 upon success and -ENODEV upon error.
> + */
> +static int omap34xxcam_open(struct inode *inode, struct file *file)
> +{
> +       struct omap34xxcam_videodev *vdev = NULL;
> +       struct omap34xxcam_device *cam = omap34xxcam;
> +       struct omap34xxcam_fh *fh;
> +       struct v4l2_format format;
> +       int i;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               if (cam->vdevs[i].vfd
> +                   && cam->vdevs[i].vfd->minor == iminor(inode)) {
> +                       vdev = &cam->vdevs[i];
> +                       break;
> +               }
> +       }
> +
> +       if (!vdev || !vdev->vfd)
> +               return -ENODEV;
> +
> +       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
> +       if (fh == NULL)
> +               return -ENOMEM;
> +
> +       mutex_lock(&vdev->mutex);
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               if (vdev->slave[i] != v4l2_int_device_dummy()
> +                   && !try_module_get(vdev->slave[i]->module)) {
> +                       mutex_unlock(&vdev->mutex);
> +                       goto out_try_module_get;
> +               }
> +       }
> +
> +       if (atomic_inc_return(&vdev->users) == 1) {
> +               isp_get();
> +               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                              
> OMAP34XXCAM_SLAVE_POWER_ALL)) +                       goto
> out_slave_power_set_standby;
> +               omap34xxcam_slave_power_set(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +               omap34xxcam_slave_power_suggest(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +       }
> +
> +       fh->vdev = vdev;
> +
> +       /* FIXME: Check that we have sensor now... */
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
> +       else
> +               isp_g_fmt_cap(&format.fmt.pix);
> +
> +       mutex_unlock(&vdev->mutex);
> +       /* FIXME: how about fh->pix when there are more users? */
> +       fh->pix = format.fmt.pix;
> +
> +       file->private_data = fh;
> +
> +       spin_lock_init(&fh->vbq_lock);
> +
> +       videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
> +                               &fh->vbq_lock,
> V4L2_BUF_TYPE_VIDEO_CAPTURE, +                              
> V4L2_FIELD_NONE,
> +                               sizeof(struct videobuf_buffer), fh);
> +
> +       return 0;
> +
> +out_slave_power_set_standby:
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                   OMAP34XXCAM_SLAVE_POWER_ALL);
> +       isp_put();
> +       atomic_dec(&vdev->users);
> +       mutex_unlock(&vdev->mutex);
> +
> +out_try_module_get:
> +       for (i--; i >= 0; i--)
> +               if (vdev->slave[i] != v4l2_int_device_dummy())
> +                       module_put(vdev->slave[i]->module);
> +
> +       kfree(fh);
> +
> +       return -ENODEV;
> +}
> +
> +/**
> + * omap34xxcam_release - file operations release handler
> + * @inode: ptr. to system inode structure
> + * @file: ptr. to system file structure
> + *
> + * Complement of omap34xxcam_open.  This function will flush any
> scheduled + * work, disable the sensor, close the ISP interface, stop
> the + * video buffer queue from streaming and free the per-filehandle
> data + * (omap34xxcam_fh).  Note that because multiple open file
> handles + * are allowed, this function will only close the ISP and
> disable the + * sensor when the last open file handle (by count) is
> closed. + * This function returns 0.
> + */
> +static int omap34xxcam_release(struct inode *inode, struct file
> *file) +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       int i;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming == file) {
> +               isp_stop();
> +               videobuf_streamoff(&fh->vbq);
> +               omap34xxcam_slave_power_set(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +               omap34xxcam_slave_power_suggest(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +               vdev->streaming = NULL;
> +       }
> +
> +       if (atomic_dec_return(&vdev->users) == 0) {
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                          
> OMAP34XXCAM_SLAVE_POWER_ALL); +               isp_put();
> +       }
> +       mutex_unlock(&vdev->mutex);
> +
> +       file->private_data = NULL;
> +
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
> +               if (vdev->slave[i] != v4l2_int_device_dummy())
> +                       module_put(vdev->slave[i]->module);
> +
> +       kfree(fh);
> +
> +       return 0;
> +}
> +
> +static struct file_operations omap34xxcam_fops = {
> +       .owner = THIS_MODULE,
> +       .llseek = no_llseek,
> +       .unlocked_ioctl = omap34xxcam_unlocked_ioctl,
> +       .poll = omap34xxcam_poll,
> +       .mmap = omap34xxcam_mmap,
> +       .open = omap34xxcam_open,
> +       .release = omap34xxcam_release,
> +};
> +
> +static void omap34xxcam_vfd_name_update(struct omap34xxcam_videodev
> *vdev) +{
> +       struct video_device *vfd = vdev->vfd;
> +       int i;
> +
> +       strlcpy(vfd->name, CAM_SHORT_NAME, sizeof(vfd->name));
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               strlcat(vfd->name, "/", sizeof(vfd->name));
> +               if (vdev->slave[i] == v4l2_int_device_dummy())
> +                       continue;
> +               strlcat(vfd->name, vdev->slave[i]->name,
> sizeof(vfd->name)); +       }
> +       dev_info(vdev->cam->dev, "video%d is now %s\n", vfd->minor,
> vfd->name); +}
> +
> +/**
> + * omap34xxcam_device_unregister - V4L2 detach handler
> + * @s: ptr. to standard V4L2 device information structure
> + *
> + * Detach sensor and unregister and release the video device.
> + */
> +static void omap34xxcam_device_unregister(struct v4l2_int_device *s)
> +{
> +       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
> +       struct omap34xxcam_hw_config hwc;
> +
> +       BUG_ON(vidioc_int_g_priv(s, &hwc) < 0);
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy()) {
> +               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +               vdev->slaves--;
> +               omap34xxcam_vfd_name_update(vdev);
> +       }
> +
> +       if (vdev->slaves == 0 && vdev->vfd) {
> +               if (vdev->vfd->minor == -1) {
> +                       /*
> +                        * The device was never registered, so
> release the +                        * video_device struct directly.
> +                        */
> +                       video_device_release(vdev->vfd);
> +               } else {
> +                       /*
> +                        * The unregister function will release the
> +                        * video_device struct as well as
> +                        * unregistering it.
> +                        */
> +                       video_unregister_device(vdev->vfd);
> +               }
> +               vdev->vfd = NULL;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +}
> +
> +static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = {
> +       .vidioc_querycap         = vidioc_querycap,
> +       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
> +       .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
> +       .vidioc_s_fmt_vid_cap    = vidioc_s_fmt_vid_cap,
> +       .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,
> +       .vidioc_reqbufs          = vidioc_reqbufs,
> +       .vidioc_querybuf         = vidioc_querybuf,
> +       .vidioc_qbuf             = vidioc_qbuf,
> +       .vidioc_dqbuf            = vidioc_dqbuf,
> +       .vidioc_streamon         = vidioc_streamon,
> +       .vidioc_streamoff        = vidioc_streamoff,
> +       .vidioc_enum_input       = vidioc_enum_input,
> +       .vidioc_g_input          = vidioc_g_input,
> +       .vidioc_s_input          = vidioc_s_input,
> +       .vidioc_queryctrl        = vidioc_queryctrl,
> +       .vidioc_querymenu        = vidioc_querymenu,
> +       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
> +       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
> +       .vidioc_g_parm           = vidioc_g_parm,
> +       .vidioc_s_parm           = vidioc_s_parm,
> +       .vidioc_cropcap          = vidioc_cropcap,
> +       .vidioc_g_crop           = vidioc_g_crop,
> +       .vidioc_s_crop           = vidioc_s_crop,
> +       .vidioc_default          = vidioc_default,
> +};
> +
> +/**
> + * omap34xxcam_device_register - V4L2 attach handler
> + * @s: ptr. to standard V4L2 device information structure
> + *
> + * Allocates and initializes the V4L2 video_device structure,
> initializes + * the sensor, and finally
> + registers the device with V4L2 based on the
> + * video_device structure.
> + *
> + * Returns 0 on success, otherwise an appropriate error code on
> + * failure.
> + */
> +static int omap34xxcam_device_register(struct v4l2_int_device *s)
> +{
> +       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
> +       struct omap34xxcam_device *cam = vdev->cam;
> +       struct omap34xxcam_hw_config hwc;
> +       struct video_device *vfd;
> +       int rval;
> +
> +       /* We need to check rval just once. The place is here. */
> +       if (vidioc_int_g_priv(s, &hwc))
> +               return -ENODEV;
> +
> +       if (vdev->index != hwc.dev_index)
> +               return -ENODEV;
> +
> +       if (hwc.dev_type < 0 || hwc.dev_type >
> OMAP34XXCAM_SLAVE_FLASH) +               return -EINVAL;
> +
> +       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy())
> +               return -EBUSY;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (atomic_read(&vdev->users)) {
> +               dev_err(cam->dev, "we're open (%d), can't
> register\n", +                       atomic_read(&vdev->users));
> +               mutex_unlock(&vdev->mutex);
> +               return -EBUSY;
> +       }
> +
> +       vdev->slaves++;
> +       vdev->slave[hwc.dev_type] = s;
> +       vdev->slave_config[hwc.dev_type] = hwc;
> +
> +       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +               isp_get();
> +       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                          1 << hwc.dev_type);
> +       if (!rval && hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
> +               struct v4l2_format format;
> +               struct v4l2_streamparm a;
> +
> +               format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor,
> &format); +
> +               a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval |= vidioc_int_g_parm(vdev->vdev_sensor, &a);
> +               if (rval)
> +                       rval = -EBUSY;
> +
> +               vdev->want_pix = format.fmt.pix;
> +               vdev->want_timeperframe =
> a.parm.capture.timeperframe; +       }
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF, 1 <<
> hwc.dev_type); +       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +               isp_put();
> +
> +       if (rval)
> +               goto err;
> +
> +       /* Are we the first slave? */
> +       if (vdev->slaves == 1) {
> +               /* initialize the video_device struct */
> +               vdev->vfd = video_device_alloc();
> +               vfd = vdev->vfd;
> +               if (!vfd) {
> +                       dev_err(cam->dev,
> +                               "could not allocate video device
> struct\n"); +                       return -ENOMEM;
> +               }
> +               vfd->release    = video_device_release;
> +               vfd->minor      = -1;
> +               vfd->fops       = &omap34xxcam_fops;
> +               vfd->ioctl_ops  = &omap34xxcam_ioctl_ops;
> +               video_set_drvdata(vfd, vdev);
> +
> +               if (video_register_device(vfd, VFL_TYPE_GRABBER,
> +                                         hwc.dev_minor) < 0) {
> +                       dev_err(cam->dev,
> +                               "could not register V4L device\n");
> +                       vfd->minor = -1;
> +                       rval = -EBUSY;
> +                       goto err;
> +               }
> +       } else {
> +               vfd = vdev->vfd;
> +       }
> +
> +       omap34xxcam_vfd_name_update(vdev);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return 0;
> +
> +err:
> +       if (s == vdev->slave[hwc.dev_type]) {
> +               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +               vdev->slaves--;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +       omap34xxcam_device_unregister(s);
> +
> +       return rval;
> +}
> +
> +static struct v4l2_int_master omap34xxcam_master = {
> +       .attach = omap34xxcam_device_register,
> +       .detach = omap34xxcam_device_unregister,
> +};
> +
> +/*
> + *
> + * Driver Suspend/Resume
> + *
> + */
> +
> +#ifdef CONFIG_PM
> +/**
> + * omap34xxcam_suspend - platform driver PM suspend handler
> + * @pdev: ptr. to platform level device information structure
> + * @state: power state
> + *
> + * If applicable, stop capture and disable sensor.
> + *
> + * Returns 0 always
> + */
> +static int omap34xxcam_suspend(struct platform_device *pdev,
> pm_message_t state) +{
> +       struct omap34xxcam_videodev *vdev =
> platform_get_drvdata(pdev); +
> +       if (atomic_read(&vdev->users) == 0)
> +               return 0;
> +
> +       if (vdev->streaming) {
> +               isp_stop();
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                          
> OMAP34XXCAM_SLAVE_POWER_ALL); +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_resume - platform driver PM resume handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * If applicable, resume capture and enable sensor.
> + *
> + * Returns 0 always
> + */
> +static int omap34xxcam_resume(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_videodev *vdev =
> platform_get_drvdata(pdev); +
> +       if (atomic_read(&vdev->users) == 0)
> +               return 0;
> +
> +       if (vdev->streaming) {
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                          
> OMAP34XXCAM_SLAVE_POWER_ALL); +               isp_start();
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
> +/*
> + *
> + * Driver initialisation and deinitialisation.
> + *
> + */
> +
> +/**
> + * omap34xxcam_remove - platform driver remove handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * Unregister device with V4L2, unmap camera registers, and
> + * free camera device information structure (omap34xxcam_device).
> + *
> + * Returns 0 always.
> + */
> +static int omap34xxcam_remove(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_device *cam = platform_get_drvdata(pdev);
> +       int i;
> +
> +       if (!cam)
> +               return 0;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               if (cam->vdevs[i].cam == NULL)
> +                       continue;
> +
> +               v4l2_int_device_unregister(&cam->vdevs[i].master);
> +               cam->vdevs[i].cam = NULL;
> +       }
> +
> +       omap34xxcam = NULL;
> +
> +       kfree(cam);
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_probe - platform driver probe handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * Allocates and initializes camera device information structure
> + * (omap34xxcam_device), maps the device registers and gets the
> + * device IRQ.  Registers the device as a V4L2 client.
> + *
> + * Returns 0 on success or -ENODEV on failure.
> + */
> +static int omap34xxcam_probe(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_device *cam;
> +       struct isp_sysc isp_sysconfig;
> +       int i;
> +
> +       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
> +       if (!cam) {
> +               dev_err(&pdev->dev, "could not allocate memory\n");
> +               goto err;
> +       }
> +
> +       platform_set_drvdata(pdev, cam);
> +
> +       cam->dev = &pdev->dev;
> +
> +       isp_get();
> +       isp_sysconfig.reset = 0;
> +       isp_sysconfig.idle_mode = 1;
> +       isp_power_settings(isp_sysconfig);
> +       isp_put();
> +
> +       omap34xxcam = cam;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               struct omap34xxcam_videodev *vdev = &cam->vdevs[i];
> +               struct v4l2_int_device *m = &vdev->master;
> +
> +               m->module       = THIS_MODULE;
> +               strlcpy(m->name, CAM_NAME, sizeof(m->name));
> +               m->type         = v4l2_int_type_master;
> +               m->u.master     = &omap34xxcam_master;
> +               m->priv         = vdev;
> +
> +               mutex_init(&vdev->mutex);
> +               vdev->index             = i;
> +               vdev->cam               = cam;
> +               vdev->vdev_sensor =
> +                       vdev->vdev_lens =
> +                       vdev->vdev_flash = v4l2_int_device_dummy();
> +               setup_timer(&vdev->poweroff_timer,
> +                           omap34xxcam_slave_power_timer, (unsigned
> long)vdev); +               INIT_WORK(&vdev->poweroff_work,
> omap34xxcam_slave_power_work); +
> +               if (v4l2_int_device_register(m))
> +                       goto err;
> +       }
> +
> +       return 0;
> +
> +err:
> +       omap34xxcam_remove(pdev);
> +       return -ENODEV;
> +}
> +
> +static struct platform_driver omap34xxcam_driver = {
> +       .probe = omap34xxcam_probe,
> +       .remove = omap34xxcam_remove,
> +#ifdef CONFIG_PM
> +       .suspend = omap34xxcam_suspend,
> +       .resume = omap34xxcam_resume,
> +#endif
> +       .driver = {
> +                  .name = CAM_NAME,
> +                  },
> +};
> +
> +/*
> + *
> + * Module initialisation and deinitialisation
> + *
> + */
> +
> +/**
> + * omap34xxcam_init - module_init function
> + *
> + * Calls platfrom driver to register probe, remove,
> + * suspend and resume functions.
> + *
> + */
> +static int __init omap34xxcam_init(void)
> +{
> +       return platform_driver_register(&omap34xxcam_driver);
> +}
> +
> +/**
> + * omap34xxcam_cleanup - module_exit function
> + *
> + * Calls platfrom driver to unregister probe, remove,
> + * suspend and resume functions.
> + *
> + */
> +static void __exit omap34xxcam_cleanup(void)
> +{
> +       platform_driver_unregister(&omap34xxcam_driver);
> +}
> +
> +MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com");
> +MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
> +MODULE_LICENSE("GPL");
> +
> +late_initcall(omap34xxcam_init);
> +module_exit(omap34xxcam_cleanup);
> diff --git a/drivers/media/video/omap34xxcam.h
> b/drivers/media/video/omap34xxcam.h new file mode 100644
> index 0000000..cc024eb
> --- /dev/null
> +++ b/drivers/media/video/omap34xxcam.h
> @@ -0,0 +1,215 @@
> +/*
> + * drivers/media/video/omap34xxcam.c
> + *
> + * Copyright (C) 2006--2008 Nokia Corporation
> + * Copyright (C) 2007, 2008 Texas Instruments
> + *
> + * Contact: Sakari Ailus <sakari.ailus@nokia.com>
> + *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *
> + * Originally based on the OMAP 2 camera driver.
> + *
> + * Written by Sakari Ailus <sakari.ailus@nokia.com>
> + *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *            Sergio Aguirre <saaguirre@ti.com>
> + *            Mohit Jalori
> + *            Sameer Venkatraman
> + *            Leonides Martinez
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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 St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef OMAP34XXCAM_H
> +#define OMAP34XXCAM_H
> +
> +#include <media/v4l2-int-device.h>
> +#include "isp/isp.h"
> +
> +#define CAM_NAME                       "omap34xxcam"
> +#define CAM_SHORT_NAME                 "omap3"
> +
> +#define OMAP_ISP_AF            (1 << 4)
> +#define OMAP_ISP_HIST          (1 << 5)
> +#define OMAP34XXCAM_XCLK_NONE  -1
> +#define OMAP34XXCAM_XCLK_A     0
> +#define OMAP34XXCAM_XCLK_B     1
> +
> +#define OMAP34XXCAM_SLAVE_SENSOR       0
> +#define OMAP34XXCAM_SLAVE_LENS         1
> +#define OMAP34XXCAM_SLAVE_FLASH                2 /* This is the last
> slave! */ +
> +/* mask for omap34xxcam_slave_power_set */
> +#define OMAP34XXCAM_SLAVE_POWER_SENSOR (1 <<
> OMAP34XXCAM_SLAVE_SENSOR) +#define OMAP34XXCAM_SLAVE_POWER_LENS   (1
> << OMAP34XXCAM_SLAVE_LENS) +#define
> OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS \
> +       (OMAP34XXCAM_SLAVE_POWER_SENSOR |
> OMAP34XXCAM_SLAVE_POWER_LENS) +#define OMAP34XXCAM_SLAVE_POWER_FLASH 
> (1 << OMAP34XXCAM_SLAVE_FLASH) +#define OMAP34XXCAM_SLAVE_POWER_ALL  
>  -1
> +
> +#define OMAP34XXCAM_VIDEODEVS          4
> +
> +struct omap34xxcam_device;
> +struct omap34xxcam_videodev;
> +
> +struct omap34xxcam_sensor_config {
> +       int xclk;
> +       int sensor_isp;
> +       u32 capture_mem;
> +};
> +
> +struct omap34xxcam_lens_config {
> +};
> +
> +struct omap34xxcam_flash_config {
> +};
> +
> +/**
> + * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
> + * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
> + * @sensor_isp: Is sensor smart/SOC or raw
> + * @s_pix_sparm: Access function to set pix and sparm.
> + * Pix will override sparm
> + */
> +struct omap34xxcam_hw_config {
> +       int dev_index; /* Index in omap34xxcam_sensors */
> +       int dev_minor; /* Video device minor number */
> +       int dev_type; /* OMAP34XXCAM_SLAVE_* */
> +       union {
> +               struct omap34xxcam_sensor_config sensor;
> +               struct omap34xxcam_lens_config lens;
> +               struct omap34xxcam_flash_config flash;
> +       } u;
> +};
> +
> +/**
> + * struct omap34xxcam_videodev - per /dev/video* structure
> + * @mutex: serialises access to this structure
> + * @cam: pointer to cam hw structure
> + * @master: we are v4l2_int_device master
> + * @sensor: sensor device
> + * @lens: lens device
> + * @flash: flash device
> + * @slaves: how many slaves we have at the moment
> + * @vfd: our video device
> + * @capture_mem: maximum kernel-allocated capture memory
> + * @if_u: sensor interface stuff
> + * @index: index of this structure in cam->vdevs
> + * @users: how many users we have
> + * @power_state: Current power state
> + * @power_state_wish: New power state when poweroff_timer expires
> + * @power_state_mask: Bitmask of devices to set the new power state
> + * @poweroff_timer: Timer for dispatching poweroff_work
> + * @poweroff_work: Work for slave power state change
> + * @sensor_config: ISP-speicific sensor configuration
> + * @lens_config: ISP-speicific lens configuration
> + * @flash_config: ISP-speicific flash configuration
> + * @streaming: streaming file handle, if streaming is enabled
> + */
> +struct omap34xxcam_videodev {
> +       struct mutex mutex; /* serialises access to this structure */
> +
> +       struct omap34xxcam_device *cam;
> +       struct v4l2_int_device master;
> +
> +#define vdev_sensor slave[OMAP34XXCAM_SLAVE_SENSOR]
> +#define vdev_lens slave[OMAP34XXCAM_SLAVE_LENS]
> +#define vdev_flash slave[OMAP34XXCAM_SLAVE_FLASH]
> +       struct v4l2_int_device *slave[OMAP34XXCAM_SLAVE_FLASH + 1];
> +
> +       /* number of slaves attached */
> +       int slaves;
> +
> +       /*** video device parameters ***/
> +       struct video_device *vfd;
> +       int capture_mem;
> +
> +       /*** general driver state information ***/
> +       /*
> +        * Sensor interface parameters: interface type, CC_CTRL
> +        * register value and interface specific data.
> +        */
> +       u32 xclk;
> +       /* index to omap34xxcam_videodevs of this structure */
> +       int index;
> +       atomic_t users;
> +       enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
> +       enum v4l2_power power_state_wish;
> +       int power_state_mask;
> +       struct timer_list poweroff_timer;
> +       struct work_struct poweroff_work;
> +
> +#define vdev_sensor_config
> slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor +#define
> vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens +#define
> vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash +    
>   struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH +
> 1]; +
> +       /*** capture data ***/
> +       struct v4l2_fract want_timeperframe;
> +       struct v4l2_pix_format want_pix;
> +       /* file handle, if streaming is on */
> +       struct file *streaming;
> +};
> +
> +/**
> + * struct omap34xxcam_device - per-device data structure
> + * @mutex: mutex serialises access to this structure
> + * @sgdma_in_queue: Number or sgdma requests in scatter-gather
> queue, + * protected by the lock above.
> + * @sgdma: ISP sgdma subsystem information structure
> + * @dma_notify: DMA notify flag
> + * @irq: irq number platform HW resource
> + * @mmio_base: register map memory base (platform HW resource)
> + * @mmio_base_phys: register map memory base physical address
> + * @mmio_size: register map memory size
> + * @dev: device structure
> + * @vdevs: /dev/video specific structures
> + * @fck: camera module fck clock information
> + * @ick: camera module ick clock information
> + */
> +struct omap34xxcam_device {
> +       struct mutex mutex; /* serialises access to this structure */
> +       int sgdma_in_queue;
> +       struct isp_sgdma sgdma;
> +       int dma_notify;
> +
> +       /*** interfaces and device ***/
> +       struct device *dev;
> +       struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
> +
> +       /*** camera module clocks ***/
> +       struct clk *fck;
> +       struct clk *ick;
> +       bool sensor_if_enabled;
> +};
> +
> +/**
> + * struct omap34xxcam_fh - per-filehandle data structure
> + * @vbq_lock: spinlock for the videobuf queue
> + * @vbq: V4L2 video buffer queue structure
> + * @pix: V4L2 pixel format structure (serialise pix by vbq->lock)
> + * @field_count: field counter for videobuf_buffer
> + * @vdev: our /dev/video specific structure
> + */
> +struct omap34xxcam_fh {
> +       spinlock_t vbq_lock; /* spinlock for the videobuf queue */
> +       struct videobuf_queue vbq;
> +       struct v4l2_pix_format pix;
> +       atomic_t field_count;
> +       /* accessing cam here doesn't need serialisation: it's
> constant */ +       struct omap34xxcam_videodev *vdev;
> +};
> +
> +#endif /* ifndef OMAP34XXCAM_H */

Urgh. v4l2_pix_format is NOT filehandle-specific! It is device global and
should be part of omap34xxcam_device. The same should probably be true for
videobuf_queue.

I know that there is a bunch of other v4l drivers that do the same that
you are doing here, but these are all wrong and do not follow the v4l2
specification correctly. They are on my to do list to fix.

Also note that substantial changes were made in the v4l2 core for 2.6.29,
so this patch will not apply there. The file_operations struct is replaced
by a v4l2_file_operations struct and the inode pointer was dropped from
the various ops.

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-01-13  2:03   ` Aguirre Rodriguez, Sergio Alberto
  (?)
  (?)
@ 2009-02-06  2:26   ` DongSoo Kim
  -1 siblings, 0 replies; 43+ messages in thread
From: DongSoo Kim @ 2009-02-06  2:26 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto; +Cc: linux-media, linux-omap

Hello.

This could be something trivial.

On Tue, Jan 13, 2009 at 11:03 AM, Aguirre Rodriguez, Sergio Alberto
<saaguirre@ti.com> wrote:
> +/**
> + * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
> + * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
> + * @sensor_isp: Is sensor smart/SOC or raw
> + * @s_pix_sparm: Access function to set pix and sparm.
> + * Pix will override sparm
> + */
> +struct omap34xxcam_hw_config {
> +       int dev_index; /* Index in omap34xxcam_sensors */

I found "omap34xxcam_sensors" in your comment, but it couldn't found anywhere.
Let me guess that it means "omap34xxcam_videodev". Am I right?
Cheers.

Regards,
Nate

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-01-13  2:03   ` Aguirre Rodriguez, Sergio Alberto
                     ` (2 preceding siblings ...)
  (?)
@ 2009-02-11  4:00   ` DongSoo Kim
  2009-02-12  7:09     ` Sakari Ailus
  -1 siblings, 1 reply; 43+ messages in thread
From: DongSoo Kim @ 2009-02-11  4:00 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: linux-omap, video4linux-list, Nagalla, Hari, Sakari Ailus,
	Tuukka.O Toivonen, linux-media, kyungmin.park,
	형준 김,
	jongse.won

Hello.

+static int omap34xxcam_open(struct inode *inode, struct file *file)
+{

<snip>

+       if (atomic_inc_return(&vdev->users) == 1) {
+               isp_get();
+               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                               OMAP34XXCAM_SLAVE_POWER_ALL))
+                       goto out_slave_power_set_standby;
+               omap34xxcam_slave_power_set(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+               omap34xxcam_slave_power_suggest(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_LENS);
+       }


I'm wondering whether this V4L2_POWER_STANDBY operation for sensor
device is really necessary.

Because if that makes sensor device in standby mode, we do S_FMT and
bunch of V4L2 APIs while the camera module is in standby mode.

In most cases of "sensor + ISP" SOC camera modules, I2C command is not
working while the camera module is in standby mode.

Following the camera interface source code, sensor goes down to
standby mode until VIDIOC_STREAMON is called.

If this power up timing depends on sensor device, then I think we need
a conditional power on sequence.

As you defined slave devices as SENSOR, LENS, FLASH, then how about
making a new slave category like "ISP" for "sensor+ISP" SOC modules?

Then we could make slave devices with conditional cases.
Cheers.


Regards,
Nate

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-02-11  4:00   ` DongSoo Kim
@ 2009-02-12  7:09     ` Sakari Ailus
  2009-02-12  7:52       ` DongSoo Kim
  0 siblings, 1 reply; 43+ messages in thread
From: Sakari Ailus @ 2009-02-12  7:09 UTC (permalink / raw)
  To: DongSoo Kim
  Cc: Aguirre Rodriguez, Sergio Alberto, linux-omap, video4linux-list,
	Nagalla, Hari, Ailus Sakari (Nokia-D/Helsinki),
	Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-media, kyungmin.park, 형준 김,
	jongse.won

DongSoo Kim wrote:
> Hello.

Hi, and thanks for the comments!

> +static int omap34xxcam_open(struct inode *inode, struct file *file)
> +{
> 
> <snip>
> 
> +       if (atomic_inc_return(&vdev->users) == 1) {
> +               isp_get();
> +               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                               OMAP34XXCAM_SLAVE_POWER_ALL))
> +                       goto out_slave_power_set_standby;
> +               omap34xxcam_slave_power_set(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +               omap34xxcam_slave_power_suggest(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +       }
> 
> 
> I'm wondering whether this V4L2_POWER_STANDBY operation for sensor
> device is really necessary.
> 
> Because if that makes sensor device in standby mode, we do S_FMT and
> bunch of V4L2 APIs while the camera module is in standby mode.
> 
> In most cases of "sensor + ISP" SOC camera modules, I2C command is not
> working while the camera module is in standby mode.

I guess that applies to most sensors.

> Following the camera interface source code, sensor goes down to
> standby mode until VIDIOC_STREAMON is called.
> 
> If this power up timing depends on sensor device, then I think we need
> a conditional power on sequence.

You're right, there's something wrong with the slave power handling. :)

We were thinking that the sensor (or any slave) power management 
(current on, off and standby) could be replaced by four commands: open, 
close, streamon and streamoff. The slave could decide by itself what its 
real power state is. IMO direct power management doesn't belong to the 
camera driver which doesn't drive any hardware anyway.

> As you defined slave devices as SENSOR, LENS, FLASH, then how about
> making a new slave category like "ISP" for "sensor+ISP" SOC modules?

I currently have just raw sensors. It'd be nice to keep the interface 
for smart sensors the same, though. You still need for a receiver for 
the image data, sometimes called the camera controller. That would be 
the same than the ISP but without fancy features.

Cheers,

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-02-12  7:09     ` Sakari Ailus
@ 2009-02-12  7:52       ` DongSoo Kim
  2009-02-13  9:31         ` Arun KS
  2009-02-13 10:02         ` Sakari Ailus
  0 siblings, 2 replies; 43+ messages in thread
From: DongSoo Kim @ 2009-02-12  7:52 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Aguirre Rodriguez, Sergio Alberto, linux-omap, Nagalla, Hari,
	Ailus Sakari (Nokia-D/Helsinki), Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-media, kyungmin.park, 형준 김,
	jongse.won

Thank you for your comment.

BTW, what should I do if I would rather use external ISP device than
OMAP3 internal ISP feature?

You said that you just have raw sensors by now, so you mean this patch
is not verified working with some ISP modules?

I'm testing your patch on my own omap3 target board with NEC ISP...but
unfortunately not working yet ;(

I should try more harder. more research is needed :)

Cheers,


On Thu, Feb 12, 2009 at 4:09 PM, Sakari Ailus
<sakari.ailus@maxwell.research.nokia.com> wrote:
> DongSoo Kim wrote:
>>
>> Hello.
>
> Hi, and thanks for the comments!
>
>> +static int omap34xxcam_open(struct inode *inode, struct file *file)
>> +{
>>
>> <snip>
>>
>> +       if (atomic_inc_return(&vdev->users) == 1) {
>> +               isp_get();
>> +               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
>> +
>> OMAP34XXCAM_SLAVE_POWER_ALL))
>> +                       goto out_slave_power_set_standby;
>> +               omap34xxcam_slave_power_set(
>> +                       vdev, V4L2_POWER_STANDBY,
>> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
>> +               omap34xxcam_slave_power_suggest(
>> +                       vdev, V4L2_POWER_STANDBY,
>> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
>> +       }
>>
>>
>> I'm wondering whether this V4L2_POWER_STANDBY operation for sensor
>> device is really necessary.
>>
>> Because if that makes sensor device in standby mode, we do S_FMT and
>> bunch of V4L2 APIs while the camera module is in standby mode.
>>
>> In most cases of "sensor + ISP" SOC camera modules, I2C command is not
>> working while the camera module is in standby mode.
>
> I guess that applies to most sensors.
>
>> Following the camera interface source code, sensor goes down to
>> standby mode until VIDIOC_STREAMON is called.
>>
>> If this power up timing depends on sensor device, then I think we need
>> a conditional power on sequence.
>
> You're right, there's something wrong with the slave power handling. :)
>
> We were thinking that the sensor (or any slave) power management (current
> on, off and standby) could be replaced by four commands: open, close,
> streamon and streamoff. The slave could decide by itself what its real power
> state is. IMO direct power management doesn't belong to the camera driver
> which doesn't drive any hardware anyway.
>
>> As you defined slave devices as SENSOR, LENS, FLASH, then how about
>> making a new slave category like "ISP" for "sensor+ISP" SOC modules?
>
> I currently have just raw sensors. It'd be nice to keep the interface for
> smart sensors the same, though. You still need for a receiver for the image
> data, sometimes called the camera controller. That would be the same than
> the ISP but without fancy features.
>
> Cheers,
>
> --
> Sakari Ailus
> sakari.ailus@maxwell.research.nokia.com
>



-- 
========================================================
Dong Soo, Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
           dongsoo45.kim@samsung.com
========================================================

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-02-12  7:52       ` DongSoo Kim
@ 2009-02-13  9:31         ` Arun KS
  2009-02-13 10:04           ` DongSoo(Nathaniel) Kim
  2009-02-13 10:02         ` Sakari Ailus
  1 sibling, 1 reply; 43+ messages in thread
From: Arun KS @ 2009-02-13  9:31 UTC (permalink / raw)
  To: DongSoo Kim
  Cc: Sakari Ailus, Aguirre Rodriguez, Sergio Alberto, linux-omap,
	Nagalla, Hari, Ailus Sakari (Nokia-D/Helsinki),
	Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-media, kyungmin.park, 형준 김,
	jongse.won

On Thu, Feb 12, 2009 at 1:22 PM, DongSoo Kim <dongsoo.kim@gmail.com> wrote:
> Thank you for your comment.
>
> BTW, what should I do if I would rather use external ISP device than
> OMAP3 internal ISP feature?
>
> You said that you just have raw sensors by now, so you mean this patch
> is not verified working with some ISP modules?

Hi DongSoo,

          The driver is tested and working with sensors which have
inbuilt ISP modules.

Thanks,
Arun

>
> I'm testing your patch on my own omap3 target board with NEC ISP...but
> unfortunately not working yet ;(
>
> I should try more harder. more research is needed :)
>
> Cheers,
>
>
> On Thu, Feb 12, 2009 at 4:09 PM, Sakari Ailus
> <sakari.ailus@maxwell.research.nokia.com> wrote:
>> DongSoo Kim wrote:
>>>
>>> Hello.
>>
>> Hi, and thanks for the comments!
>>
>>> +static int omap34xxcam_open(struct inode *inode, struct file *file)
>>> +{
>>>
>>> <snip>
>>>
>>> +       if (atomic_inc_return(&vdev->users) == 1) {
>>> +               isp_get();
>>> +               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
>>> +
>>> OMAP34XXCAM_SLAVE_POWER_ALL))
>>> +                       goto out_slave_power_set_standby;
>>> +               omap34xxcam_slave_power_set(
>>> +                       vdev, V4L2_POWER_STANDBY,
>>> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
>>> +               omap34xxcam_slave_power_suggest(
>>> +                       vdev, V4L2_POWER_STANDBY,
>>> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
>>> +       }
>>>
>>>
>>> I'm wondering whether this V4L2_POWER_STANDBY operation for sensor
>>> device is really necessary.
>>>
>>> Because if that makes sensor device in standby mode, we do S_FMT and
>>> bunch of V4L2 APIs while the camera module is in standby mode.
>>>
>>> In most cases of "sensor + ISP" SOC camera modules, I2C command is not
>>> working while the camera module is in standby mode.
>>
>> I guess that applies to most sensors.
>>
>>> Following the camera interface source code, sensor goes down to
>>> standby mode until VIDIOC_STREAMON is called.
>>>
>>> If this power up timing depends on sensor device, then I think we need
>>> a conditional power on sequence.
>>
>> You're right, there's something wrong with the slave power handling. :)
>>
>> We were thinking that the sensor (or any slave) power management (current
>> on, off and standby) could be replaced by four commands: open, close,
>> streamon and streamoff. The slave could decide by itself what its real power
>> state is. IMO direct power management doesn't belong to the camera driver
>> which doesn't drive any hardware anyway.
>>
>>> As you defined slave devices as SENSOR, LENS, FLASH, then how about
>>> making a new slave category like "ISP" for "sensor+ISP" SOC modules?
>>
>> I currently have just raw sensors. It'd be nice to keep the interface for
>> smart sensors the same, though. You still need for a receiver for the image
>> data, sometimes called the camera controller. That would be the same than
>> the ISP but without fancy features.
>>
>> Cheers,
>>
>> --
>> Sakari Ailus
>> sakari.ailus@maxwell.research.nokia.com
>>
>
>
>
> --
> ========================================================
> Dong Soo, Kim
> Engineer
> Mobile S/W Platform Lab. S/W centre
> Telecommunication R&D Centre
> Samsung Electronics CO., LTD.
> e-mail : dongsoo.kim@gmail.com
>           dongsoo45.kim@samsung.com
> ========================================================
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-02-12  7:52       ` DongSoo Kim
  2009-02-13  9:31         ` Arun KS
@ 2009-02-13 10:02         ` Sakari Ailus
  2009-02-13 10:11           ` DongSoo(Nathaniel) Kim
  1 sibling, 1 reply; 43+ messages in thread
From: Sakari Ailus @ 2009-02-13 10:02 UTC (permalink / raw)
  To: DongSoo Kim
  Cc: Aguirre Rodriguez, Sergio Alberto, linux-omap, Nagalla, Hari,
	Ailus Sakari (Nokia-D/Helsinki), Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-media, kyungmin.park, 형준 김,
	jongse.won

DongSoo Kim wrote:
> Thank you for your comment.
> 
> BTW, what should I do if I would rather use external ISP device than
> OMAP3 internal ISP feature?
> 
> You said that you just have raw sensors by now, so you mean this patch
> is not verified working with some ISP modules?

I haven't verified it myself. Others might be using it.

> I'm testing your patch on my own omap3 target board with NEC ISP...but
> unfortunately not working yet ;(

NEC ISP? A sensor with NEC ISP integrated?

> I should try more harder. more research is needed :)

Thanks for the interest. :-)

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-02-13  9:31         ` Arun KS
@ 2009-02-13 10:04           ` DongSoo(Nathaniel) Kim
  0 siblings, 0 replies; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-02-13 10:04 UTC (permalink / raw)
  To: Arun KS
  Cc: Sakari Ailus, Aguirre Rodriguez, Sergio Alberto, linux-omap,
	Nagalla, Hari, Ailus Sakari (Nokia-D/Helsinki),
	Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-media, kyungmin.park, 형준 김,
	jongse.won

Hi Arun.

I appreciate your helpful words!
For the meantime, I need a concrete driver for my camera module first
and I'm still working on it.
I wish I could post my work as a patch ASAP :)
Wish me luck!
Cheers,

Nate


On Fri, Feb 13, 2009 at 6:31 PM, Arun KS <getarunks@gmail.com> wrote:
> On Thu, Feb 12, 2009 at 1:22 PM, DongSoo Kim <dongsoo.kim@gmail.com> wrote:
>> Thank you for your comment.
>>
>> BTW, what should I do if I would rather use external ISP device than
>> OMAP3 internal ISP feature?
>>
>> You said that you just have raw sensors by now, so you mean this patch
>> is not verified working with some ISP modules?
>
> Hi DongSoo,
>
>          The driver is tested and working with sensors which have
> inbuilt ISP modules.
>
> Thanks,
> Arun
>
>>
>> I'm testing your patch on my own omap3 target board with NEC ISP...but
>> unfortunately not working yet ;(
>>
>> I should try more harder. more research is needed :)
>>
>> Cheers,
>>
>>
>> On Thu, Feb 12, 2009 at 4:09 PM, Sakari Ailus
>> <sakari.ailus@maxwell.research.nokia.com> wrote:
>>> DongSoo Kim wrote:
>>>>
>>>> Hello.
>>>
>>> Hi, and thanks for the comments!
>>>
>>>> +static int omap34xxcam_open(struct inode *inode, struct file *file)
>>>> +{
>>>>
>>>> <snip>
>>>>
>>>> +       if (atomic_inc_return(&vdev->users) == 1) {
>>>> +               isp_get();
>>>> +               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
>>>> +
>>>> OMAP34XXCAM_SLAVE_POWER_ALL))
>>>> +                       goto out_slave_power_set_standby;
>>>> +               omap34xxcam_slave_power_set(
>>>> +                       vdev, V4L2_POWER_STANDBY,
>>>> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
>>>> +               omap34xxcam_slave_power_suggest(
>>>> +                       vdev, V4L2_POWER_STANDBY,
>>>> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
>>>> +       }
>>>>
>>>>
>>>> I'm wondering whether this V4L2_POWER_STANDBY operation for sensor
>>>> device is really necessary.
>>>>
>>>> Because if that makes sensor device in standby mode, we do S_FMT and
>>>> bunch of V4L2 APIs while the camera module is in standby mode.
>>>>
>>>> In most cases of "sensor + ISP" SOC camera modules, I2C command is not
>>>> working while the camera module is in standby mode.
>>>
>>> I guess that applies to most sensors.
>>>
>>>> Following the camera interface source code, sensor goes down to
>>>> standby mode until VIDIOC_STREAMON is called.
>>>>
>>>> If this power up timing depends on sensor device, then I think we need
>>>> a conditional power on sequence.
>>>
>>> You're right, there's something wrong with the slave power handling. :)
>>>
>>> We were thinking that the sensor (or any slave) power management (current
>>> on, off and standby) could be replaced by four commands: open, close,
>>> streamon and streamoff. The slave could decide by itself what its real power
>>> state is. IMO direct power management doesn't belong to the camera driver
>>> which doesn't drive any hardware anyway.
>>>
>>>> As you defined slave devices as SENSOR, LENS, FLASH, then how about
>>>> making a new slave category like "ISP" for "sensor+ISP" SOC modules?
>>>
>>> I currently have just raw sensors. It'd be nice to keep the interface for
>>> smart sensors the same, though. You still need for a receiver for the image
>>> data, sometimes called the camera controller. That would be the same than
>>> the ISP but without fancy features.
>>>
>>> Cheers,
>>>
>>> --
>>> Sakari Ailus
>>> sakari.ailus@maxwell.research.nokia.com
>>>
>>
>>
>>
>> --
>> ========================================================
>> Dong Soo, Kim
>> Engineer
>> Mobile S/W Platform Lab. S/W centre
>> Telecommunication R&D Centre
>> Samsung Electronics CO., LTD.
>> e-mail : dongsoo.kim@gmail.com
>>           dongsoo45.kim@samsung.com
>> ========================================================
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>



-- 
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
          dongsoo45.kim@samsung.com
========================================================

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-02-13 10:02         ` Sakari Ailus
@ 2009-02-13 10:11           ` DongSoo(Nathaniel) Kim
  0 siblings, 0 replies; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-02-13 10:11 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Aguirre Rodriguez, Sergio Alberto, linux-omap, Nagalla, Hari,
	Ailus Sakari (Nokia-D/Helsinki), Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-media, kyungmin.park, 형준 김,
	jongse.won

Hi! Sakari.

On Fri, Feb 13, 2009 at 7:02 PM, Sakari Ailus
<sakari.ailus@maxwell.research.nokia.com> wrote:
> DongSoo Kim wrote:
>>
>> Thank you for your comment.
>>
>> BTW, what should I do if I would rather use external ISP device than
>> OMAP3 internal ISP feature?
>>
>> You said that you just have raw sensors by now, so you mean this patch
>> is not verified working with some ISP modules?
>
> I haven't verified it myself. Others might be using it.

Some people using external ISP have informed me.
Thank you.

>
>> I'm testing your patch on my own omap3 target board with NEC ISP...but
>> unfortunately not working yet ;(
>
> NEC ISP? A sensor with NEC ISP integrated?

Yep. CE131 exactly.

>
>> I should try more harder. more research is needed :)
>
> Thanks for the interest. :-)

Thank you too :)
I wish I could send you my work as a patch ASAP.

Cheers,

Nate

>
> --
> Sakari Ailus
> sakari.ailus@maxwell.research.nokia.com
>



-- 
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
          dongsoo45.kim@samsung.com
========================================================

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2009-03-10 13:34 Hans Verkuil
  0 siblings, 0 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-03-10 13:34 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Aguirre Rodriguez, Sergio Alberto, DongSoo Kim, Hiremath,
	Vaibhav, Toivonen Tuukka.O, linux-omap, Nagalla, Hari,
	linux-media


> Hans Verkuil wrote:
>>> Sergio has posted earlier a patchset containing a driver for using the
>>> ISP to process images from memory to memory. The ISP driver is used
>>> roughly the same way as with the omap34xxcam and real sensors. The
>>> interface towards the userspace offered by the driver, however, is
>>> different, you probably saw it (preview and resizer wrappers).
>>>
>>> My opinion has been that the memory-to-memory operation of the ISP
>>> should also offer V4L2 interface. V4L2, however, doesn't support such
>>> devices at the moment. The only differences that I can see is that
>>>
>>> 1. the input is a video buffer instead of sensor and
>>>
>>> 2. the source format needs to be specified somehow since the ISP can
>>> also do format conversion. So it's output and input at the same time.
>>>
>>> But if we had one video device per ISP, then memory-to-memory operation
>>> would be just one... input or output or what? :)
>>>
>>> Earlier we were thinking of creating one device node for it.
>>
>> This sounds like a codec interface as 'described' here:
>>
>> http://www.xs4all.nl/~hverkuil/spec/v4l2.html#CODEC
>>
>> It would be a first for V4L2 to have a driver that can do this, but I
>> agree
>> that that would be a single device that has both 'output' and 'capture'.
>
> Ok. Although this work most probably will be left for future at this
> point.
>
>>> Currently you can have just one device node using the ISP open.
>>> omap34xxcam_open() calls isp_get() which fails if the ISP use count was
>>> non-zero (means one).
>>>
>>> Or did I misunderstood something?
>>
>> Oh dear. Please don't use 'use counts'. It is perfectly acceptable and
>> desirable to have multiple opens on the same video node. Only one file
>
>> Use counts are really bad and totally unnecessary. Only if another file
>> handle is in streaming mode (and when using VIDIOC_S_PRIORITY) does it
>> make
>> sense to return -EBUSY for certain ioctls or read/write operations.
>> Otherwise you shouldn't limit the user from opening the same device node
>> as
>> many times as he wants and use that to query the video device.
>
> ?
>
> Having a use count doesn't prevent multiple file handles nor otherwise
> artificially limit functionality. We need to be able to shut down the
> slaves when they are no longer needed. IMO having an use count to do
> this is fine (unless otherwise proven).

Yes, it is fine for such purposes. As long as it isn't abused to restrict
functionality on subsequent opens. Several drivers use it for that, and
that is NOT right. But it's OK for powersaving implementations. I should
have mentioned that.

> Also the camera driver does try_module_get() to the slaves when it's
> opened by the first user. module_put() is called on those when the last
> user goes away.

This is to allow those modules to be unloaded?

> We'd also like to get rid of the current way of directly telling the
> slaves what their power state should be. Rather we'd like to tell the
> slaves what's expected from them. This could translate to
> open/release/streamon/streamoff commands. To be able to do this, the use
> count is required --- unless this task is given to the slaves
> (v4l2_subdevs).

Sounds interesting. I would have to see a proposal or proof-of-concept
code to determine how useful it is. It's however better to do this after
the v4l2-subdev conversion.

>> BTW, I looked at omap24xxcam_open(): data like fh->pix does *not* belong
>> to
>> the filehandle struct, it should be part of the top-level data
>> structure.
>
> That's fixed in the omap34xxcam.c. :)

Yay!

>> You want to be able to do simple things like querying a video node for
>> the
>> currently selected format. You can't do that if the format is stored in
>> the
>> filehandle! E.g.: you are streaming and you want to run
>> v4l2-ctl --get-fmt-video to check what video format is being used.
>> Things
>> like this must be supported by a well-written v4l2 driver. Again, sadly
>> quite a few v4l2 drivers do this wrong as well :-(
>>
>> I also see that cam->users is not decreased by one if
>> omap24xxcam_sensor_enable() fails.
>>
>> Note that I'm looking at the code in the v4l-dvb repository, the
>> linux-omap
>> git tree might have fixed that already.
>
> I'm afraid it's still there. Will fix that.

OK.

Thanks,

       Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-05 21:24                             ` Hans Verkuil
@ 2009-03-10 12:14                               ` Sakari Ailus
  0 siblings, 0 replies; 43+ messages in thread
From: Sakari Ailus @ 2009-03-10 12:14 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Aguirre Rodriguez, Sergio Alberto, DongSoo(Nathaniel) Kim,
	Hiremath, Vaibhav, Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-omap, Nagalla, Hari, linux-media

Hans Verkuil wrote:
>> Sergio has posted earlier a patchset containing a driver for using the
>> ISP to process images from memory to memory. The ISP driver is used
>> roughly the same way as with the omap34xxcam and real sensors. The
>> interface towards the userspace offered by the driver, however, is
>> different, you probably saw it (preview and resizer wrappers).
>>
>> My opinion has been that the memory-to-memory operation of the ISP
>> should also offer V4L2 interface. V4L2, however, doesn't support such
>> devices at the moment. The only differences that I can see is that
>>
>> 1. the input is a video buffer instead of sensor and
>>
>> 2. the source format needs to be specified somehow since the ISP can
>> also do format conversion. So it's output and input at the same time.
>>
>> But if we had one video device per ISP, then memory-to-memory operation
>> would be just one... input or output or what? :)
>>
>> Earlier we were thinking of creating one device node for it.
> 
> This sounds like a codec interface as 'described' here:
> 
> http://www.xs4all.nl/~hverkuil/spec/v4l2.html#CODEC
> 
> It would be a first for V4L2 to have a driver that can do this, but I agree 
> that that would be a single device that has both 'output' and 'capture'.

Ok. Although this work most probably will be left for future at this point.

>> Currently you can have just one device node using the ISP open.
>> omap34xxcam_open() calls isp_get() which fails if the ISP use count was
>> non-zero (means one).
>>
>> Or did I misunderstood something?
> 
> Oh dear. Please don't use 'use counts'. It is perfectly acceptable and 
> desirable to have multiple opens on the same video node. Only one file 

> Use counts are really bad and totally unnecessary. Only if another file 
> handle is in streaming mode (and when using VIDIOC_S_PRIORITY) does it make 
> sense to return -EBUSY for certain ioctls or read/write operations. 
> Otherwise you shouldn't limit the user from opening the same device node as 
> many times as he wants and use that to query the video device.

?

Having a use count doesn't prevent multiple file handles nor otherwise 
artificially limit functionality. We need to be able to shut down the 
slaves when they are no longer needed. IMO having an use count to do 
this is fine (unless otherwise proven).

Also the camera driver does try_module_get() to the slaves when it's 
opened by the first user. module_put() is called on those when the last 
user goes away.

We'd also like to get rid of the current way of directly telling the 
slaves what their power state should be. Rather we'd like to tell the 
slaves what's expected from them. This could translate to 
open/release/streamon/streamoff commands. To be able to do this, the use 
count is required --- unless this task is given to the slaves 
(v4l2_subdevs).

> BTW, I looked at omap24xxcam_open(): data like fh->pix does *not* belong to 
> the filehandle struct, it should be part of the top-level data structure. 

That's fixed in the omap34xxcam.c. :)

> You want to be able to do simple things like querying a video node for the 
> currently selected format. You can't do that if the format is stored in the 
> filehandle! E.g.: you are streaming and you want to run 
> v4l2-ctl --get-fmt-video to check what video format is being used. Things 
> like this must be supported by a well-written v4l2 driver. Again, sadly 
> quite a few v4l2 drivers do this wrong as well :-(
> 
> I also see that cam->users is not decreased by one if 
> omap24xxcam_sensor_enable() fails.
> 
> Note that I'm looking at the code in the v4l-dvb repository, the linux-omap 
> git tree might have fixed that already.

I'm afraid it's still there. Will fix that.

Thanks.

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-05 20:11                           ` Sakari Ailus
@ 2009-03-05 21:24                             ` Hans Verkuil
  2009-03-10 12:14                               ` Sakari Ailus
  0 siblings, 1 reply; 43+ messages in thread
From: Hans Verkuil @ 2009-03-05 21:24 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Aguirre Rodriguez, Sergio Alberto, DongSoo(Nathaniel) Kim,
	Hiremath, Vaibhav, Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-omap, Nagalla, Hari, linux-media

On Thursday 05 March 2009 21:11:02 Sakari Ailus wrote:
> Hans Verkuil wrote:
> >> Situation 1
> >>  - Instance1: Select sensor 1, and Do queue/dequeue of buffers.
> >>  - Instance2: If sensor 1 is currently selected, Begin loop requesting
> >> internally collected OMAP3ISP statistics (with V4L2 private based
> >> IOCTLs) for performing user-side Auto-exposure, Auto White Balance,
> >> Auto Focus algorithms. And Adjust gains (with S_CTRL) accordingly on
> >> sensor as a result.
> >
> > Question: if you have multiple sensors, and sensor 1 is selected, can
> > you still get statistics from sensor 2? Or is all this still limited to
> > the selected sensor? Just want to make sure I understand it all.
>
> The ISP does have submodules and there are some ways of configuring the
> data path inside the ISP, but in general just one sensor can be used at
> a time in meaningful way.
>
> Sergio, please correct me if I'm wrong: the only case I know that you
> can do is to use the ISP normally (data flowing through pretty much all
> the ISP modules) with one sensor and write the output of another sensor
> directly to memory in one of the parallel/CCP2/CSI2 receivers.
>
> I guess there's no use case for this, however. So just one user at a
> time for the OMAP 3 ISP.
>
>
>
> Another thing comes to my mind, though.
>
> Sergio has posted earlier a patchset containing a driver for using the
> ISP to process images from memory to memory. The ISP driver is used
> roughly the same way as with the omap34xxcam and real sensors. The
> interface towards the userspace offered by the driver, however, is
> different, you probably saw it (preview and resizer wrappers).
>
> My opinion has been that the memory-to-memory operation of the ISP
> should also offer V4L2 interface. V4L2, however, doesn't support such
> devices at the moment. The only differences that I can see is that
>
> 1. the input is a video buffer instead of sensor and
>
> 2. the source format needs to be specified somehow since the ISP can
> also do format conversion. So it's output and input at the same time.
>
> But if we had one video device per ISP, then memory-to-memory operation
> would be just one... input or output or what? :)
>
> Earlier we were thinking of creating one device node for it.

This sounds like a codec interface as 'described' here:

http://www.xs4all.nl/~hverkuil/spec/v4l2.html#CODEC

It would be a first for V4L2 to have a driver that can do this, but I agree 
that that would be a single device that has both 'output' and 'capture'.

> > That is probably what the driver should do, yes. The V4L2 spec leaves
> > it up to the driver whether you can switch inputs while a capture is in
> > progress. In this case I think it is perfectly reasonably for the
> > driver to return -EBUSY.
>
> Ok.
>
> >> I'm not clear if this single-node idea is really helping the user to
> >> have a simpler usage in Situation 1, which I feel will become pretty
> >> common on this driver...
> >
> > The spec is pretty clear about this, and existing v4l2 applications
> > also expect this behavior. Also, suppose you have two video nodes, what
> > happens when you want to use the inactive node? How can you tell it is
> > inactive?
>
> open() succeeds.
>
> Currently you can have just one device node using the ISP open.
> omap34xxcam_open() calls isp_get() which fails if the ISP use count was
> non-zero (means one).
>
> Or did I misunderstood something?

Oh dear. Please don't use 'use counts'. It is perfectly acceptable and 
desirable to have multiple opens on the same video node. Only one file 
handle can do reading/writing/streaming, but others should be able to 
querying controls, set brightness, or whatever at the same time.

Use counts are really bad and totally unnecessary. Only if another file 
handle is in streaming mode (and when using VIDIOC_S_PRIORITY) does it make 
sense to return -EBUSY for certain ioctls or read/write operations. 
Otherwise you shouldn't limit the user from opening the same device node as 
many times as he wants and use that to query the video device.

There are unfortunately a whole bunch of existing v4l2 drivers that have 
this same limitation. These drivers are wrong. It is sadly not very easy to 
fix them, but I can try to prevent the same bug from appearing in new 
drivers.

BTW, I looked at omap24xxcam_open(): data like fh->pix does *not* belong to 
the filehandle struct, it should be part of the top-level data structure. 
You want to be able to do simple things like querying a video node for the 
currently selected format. You can't do that if the format is stored in the 
filehandle! E.g.: you are streaming and you want to run 
v4l2-ctl --get-fmt-video to check what video format is being used. Things 
like this must be supported by a well-written v4l2 driver. Again, sadly 
quite a few v4l2 drivers do this wrong as well :-(

I also see that cam->users is not decreased by one if 
omap24xxcam_sensor_enable() fails.

Note that I'm looking at the code in the v4l-dvb repository, the linux-omap 
git tree might have fixed that already.

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04 22:44                         ` Hans Verkuil
  2009-03-04 23:30                           ` Aguirre Rodriguez, Sergio Alberto
@ 2009-03-05 20:11                           ` Sakari Ailus
  2009-03-05 21:24                             ` Hans Verkuil
  1 sibling, 1 reply; 43+ messages in thread
From: Sakari Ailus @ 2009-03-05 20:11 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Aguirre Rodriguez, Sergio Alberto, DongSoo(Nathaniel) Kim,
	Hiremath, Vaibhav, Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-omap, Nagalla, Hari, linux-media

Hans Verkuil wrote:
>> Situation 1
>>  - Instance1: Select sensor 1, and Do queue/dequeue of buffers.
>>  - Instance2: If sensor 1 is currently selected, Begin loop requesting
>> internally collected OMAP3ISP statistics (with V4L2 private based IOCTLs)
>> for performing user-side Auto-exposure, Auto White Balance, Auto Focus
>> algorithms. And Adjust gains (with S_CTRL) accordingly on sensor as a
>> result.
> 
> Question: if you have multiple sensors, and sensor 1 is selected, can you 
> still get statistics from sensor 2? Or is all this still limited to the 
> selected sensor? Just want to make sure I understand it all.

The ISP does have submodules and there are some ways of configuring the
data path inside the ISP, but in general just one sensor can be used at
a time in meaningful way.

Sergio, please correct me if I'm wrong: the only case I know that you
can do is to use the ISP normally (data flowing through pretty much all
the ISP modules) with one sensor and write the output of another sensor
directly to memory in one of the parallel/CCP2/CSI2 receivers.

I guess there's no use case for this, however. So just one user at a 
time for the OMAP 3 ISP.



Another thing comes to my mind, though.

Sergio has posted earlier a patchset containing a driver for using the 
ISP to process images from memory to memory. The ISP driver is used 
roughly the same way as with the omap34xxcam and real sensors. The 
interface towards the userspace offered by the driver, however, is 
different, you probably saw it (preview and resizer wrappers).

My opinion has been that the memory-to-memory operation of the ISP 
should also offer V4L2 interface. V4L2, however, doesn't support such 
devices at the moment. The only differences that I can see is that

1. the input is a video buffer instead of sensor and

2. the source format needs to be specified somehow since the ISP can 
also do format conversion. So it's output and input at the same time.

But if we had one video device per ISP, then memory-to-memory operation 
would be just one... input or output or what? :)

Earlier we were thinking of creating one device node for it.

> That is probably what the driver should do, yes. The V4L2 spec leaves it up 
> to the driver whether you can switch inputs while a capture is in progress. 
> In this case I think it is perfectly reasonably for the driver to 
> return -EBUSY.

Ok.

>> I'm not clear if this single-node idea is really helping the user to have
>> a simpler usage in Situation 1, which I feel will become pretty common on
>> this driver...
> 
> The spec is pretty clear about this, and existing v4l2 applications also 
> expect this behavior. Also, suppose you have two video nodes, what happens 
> when you want to use the inactive node? How can you tell it is inactive?

open() succeeds.

Currently you can have just one device node using the ISP open. 
omap34xxcam_open() calls isp_get() which fails if the ISP use count was 
non-zero (means one).

Or did I misunderstood something?

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04 23:30                           ` Aguirre Rodriguez, Sergio Alberto
@ 2009-03-05  7:39                             ` Hans Verkuil
  0 siblings, 0 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-03-05  7:39 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: sakari.ailus, DongSoo(Nathaniel) Kim, Hiremath, Vaibhav,
	Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-omap, Nagalla, Hari, linux-media

On Thursday 05 March 2009 00:30:24 Aguirre Rodriguez, Sergio Alberto wrote:
> > -----Original Message-----
> > From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> > Sent: Wednesday, March 04, 2009 4:45 PM
> > To: Aguirre Rodriguez, Sergio Alberto
> > Cc: sakari.ailus@maxwell.research.nokia.com; DongSoo(Nathaniel) Kim;
> > Hiremath, Vaibhav; Toivonen Tuukka.O (Nokia-D/Oulu); linux-
> > omap@vger.kernel.org; Nagalla, Hari; linux-media@vger.kernel.org
> > Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> >
> > On Wednesday 04 March 2009 22:46:07 Aguirre Rodriguez, Sergio Alberto
> >
> > wrote:
> > > > -----Original Message-----
> > > > From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> > > > Sent: Wednesday, March 04, 2009 3:06 PM
> > > > To: sakari.ailus@maxwell.research.nokia.com
> > > > Cc: DongSoo(Nathaniel) Kim; Hiremath, Vaibhav; Toivonen Tuukka.O
> > > > (Nokia- D/Oulu); Aguirre Rodriguez, Sergio Alberto;
> > > > linux-omap@vger.kernel.org; Nagalla, Hari;
> > > > linux-media@vger.kernel.org Subject: Re: [REVIEW PATCH 11/14]
> > > > OMAP34XXCAM: Add driver
> > > >
> > > > On Wednesday 04 March 2009 20:22:04 Sakari Ailus wrote:
> > > > > Hans Verkuil wrote:
> > > > > > On Wednesday 04 March 2009 01:42:13 DongSoo(Nathaniel) Kim 
wrote:
> > > > > >> Thank you for your kind explanation Hans.
> > > > > >>
> > > > > >> Problem is omap3 camera subsystem is making device node for
> > > > > >> every int device attached to it.
> > > > > >
> > > > > > That's wrong. Multiple devices should only be created if they
> > > > > > can all be used at the same time. Otherwise there should be
> > > > > > just one device that uses S_INPUT et al to select between the
> > > > > > inputs.
> > > > >
> > > > > There might be situations where multiple device nodes would be
> > > > > beneficial even if they cannot be used simultaneously in all
> > > > > cases.
> > > > >
> > > > > Currently the omap34xxcam camera driver creates one device per
> > > > > camera. A camera in this case contains an isp (or camera
> > > > > controller), image sensor, lens and flash. The properties like
> > > > > maximum frame rate or resolution of a camera are usually (almost)
> > > > > completely defined by those of the sensor, lens and flash. This
> > > > > affects also cropping capabilities.
> > > > >
> > > > > Several programs can access video devices simultaneously. What
> > > > > happens if another program switches the input when the first one
> > > > > doesn't expect it? The original user won't notice the change,
> >
> > instead
> >
> > > > > of getting -EBUSY when trying to open the other video device.
> > > >
> > > > It is actually quite common to be able to switch inputs using one
> > > > program (e.g. v4l2-ctl) while another program also has the video
> > > > node open. This will typically be used for debugging or
> > > > experimenting. Depending on the hardware, switching inputs while
> > > > capturing is in progress may or may not be
> > > > allowed (the driver might just return -EBUSY in that case).
> > > >
> > > > In addition the application can also call VIDIOC_S_PRIORITY to
> > > > protect it against outside interference, provided the driver
> > > > supports this ioctl.
> > > >
> > > > As an aside: many applications don't use VIDIOC_S_PRIORITY since
> > > > whether a driver implements it is hit-and-miss. As part of the new
> >
> > v4l2
> >
> > > > framework I have a struct v4l2_fh planned that will integrate
> > > > support of this ioctl in the framework, thus making it generic for
> > > > all drivers. But this won't be available any time soon.
> > >
> > > As what I understand, we have 2 possible situations for multiple
> > > opens here:
> > >
> > > Situation 1
> > >  - Instance1: Select sensor 1, and Do queue/dequeue of buffers.
> > >  - Instance2: If sensor 1 is currently selected, Begin loop
> > > requesting internally collected OMAP3ISP statistics (with V4L2
> > > private based
> >
> > IOCTLs)
> >
> > > for performing user-side Auto-exposure, Auto White Balance, Auto
> > > Focus algorithms. And Adjust gains (with S_CTRL) accordingly on
> > > sensor as a result.
> >
> > Question: if you have multiple sensors, and sensor 1 is selected, can
> > you still get statistics from sensor 2? Or is all this still limited to
> > the selected sensor? Just want to make sure I understand it all.
>
> Everytime a RAW10 Bayer formatted frame is received on the OMAP3ISP,
> statistics are being generated and when done, stored in buffers allocated
> internally on the driver (last 5 frames only), marking every stats buffer
> with the frame number associated.
>
> When requesting stats, the user needs to specify the frame number (since
> last streamon call) to the which he needs the statistics. Receives in
> return the associated buffer.
>
> So, going back to answering directly your question, the stats are related
> to the frame_number since last stream on call, making it impossible to
> request from one specific sensor.
>
> > > Situation 2
> > >  - Instance1: Select sensor1 as input. Begin streaming.
> > >  - Instance2: Select sensor2 as input. Attempt to begin streaming.
> > >
> > > So, if I understood right, on Situation 2, if you attempt to do a
> >
> > S_INPUT
> >
> > > to sensor2 while capturing from sensor1, it should return a -EBUSY,
> > > right?
> >
> > That is probably what the driver should do, yes. The V4L2 spec leaves
> > it up
> > to the driver whether you can switch inputs while a capture is in
> > progress. In this case I think it is perfectly reasonably for the
> > driver to return -EBUSY.
>
> Ok, makes sense.
>
> > > I mean, the app should consciously make sure the input (sensor) is
> > > the correct one before performing any adjustments.
> >
> > Can you elaborate? I don't follow this, I'm afraid.
>
> Normally an app already knows what are the capabilities/limitations for
> /dev/video0, and that wont change in our current approach, right?
> (Because video0 node always points to the same sensor)
>
> But with your suggested approach, if a switching happens, the
> capabilities could vary between sensors, and the app should need to re
> request capabilities everytime it attempts to adjust something. So this
> is the _consciousness_ I'm talking about.. (Constantly making sure of
> sensor capabilities before sending S_CTRL calls)
>
> Did I made myself clear?
>
> > > I think our current approach avoids the user to be constantly
> > > checking
> >
> > if
> >
> > > the input is still the same before updating gains...
> >
> > If I understand it correctly, the normal approach would be one
> > application that might have a separate thread to do the gain
> > adjustments, etc. Or do it
> > all in the same thread, for example by doing the adjustments after
> > every X frames captured. Doing this in two separate applications seems
> > awkward to me. Usually the streaming thread and the adjustment thread
> > need to communicate with one another or be directed from some the main
> > application.
>
> Hmm... Ok, got your point.
>
> I guess we can leave all responsibility of correct
> settings<->sensor association to the user app threads then.
>
> > > I'm not clear if this single-node idea is really helping the user to
> >
> > have
> >
> > > a simpler usage in Situation 1, which I feel will become pretty
> > > common
> >
> > on
> >
> > > this driver...
> >
> > The spec is pretty clear about this, and existing v4l2 applications
> > also expect this behavior. Also, suppose you have two video nodes, what
> > happens when you want to use the inactive node? How can you tell it is
> > inactive?
>
> Sorry, I think I'm not very clear on your intention...
>
> You mean that how can an app know if streaming is ongoing in a device
> node?
>
> If that's the case, then I think we'll need to have an IOCTL for knowing
> if the node is streaming or not.
>
> Please clarify.

You have two video nodes, one for each sensor. But only one is 'active' at a 
time (i.e. is the current omap input). How do you determine which one that 
is? And what happens when you set a format or control on the inactive one? 
All this is much easier if you use S_INPUT to select between inputs.

Note that changing the input using S_INPUT will have side-effects that the 
application should consider. The spec mentions it in passing:

"To select a video input applications store the number of the desired input 
in an integer and call the VIDIOC_S_INPUT ioctl with a pointer to this 
integer. Side effects are possible. For example inputs may support 
different video standards, so the driver may implicitly switch the current 
standard. It is good practice to select an input before querying or 
negotiating any other parameters."

This should be more prominent, since if you are dealing with e.g. a camera 
input and a composite video input, then changing inputs will also change 
the available formats, resolutions, controls, etc.

I think all existing v4l drivers with multiple inputs just choose between 
tuner, composite and S-Video in. There are no side-effects to speak of in 
that case, so omap is probably the first driver that will have to deal with 
this.

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04 23:42                         ` Trent Piepho
@ 2009-03-05  2:25                           ` hermann pitton
  0 siblings, 0 replies; 43+ messages in thread
From: hermann pitton @ 2009-03-05  2:25 UTC (permalink / raw)
  To: Trent Piepho
  Cc: Aguirre Rodriguez, Sergio Alberto, Hans Verkuil, sakari.ailus,
	DongSoo(Nathaniel) Kim, Hiremath, Vaibhav,
	Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-omap, Nagalla, Hari, linux-media

Am Mittwoch, den 04.03.2009, 15:42 -0800 schrieb Trent Piepho:
> On Wed, 4 Mar 2009, Aguirre Rodriguez, Sergio Alberto wrote:
> > As what I understand, we have 2 possible situations for multiple opens here:
> >
> > Situation 1
> >  - Instance1: Select sensor 1, and Do queue/dequeue of buffers.
> >  - Instance2: If sensor 1 is currently selected, Begin loop requesting internally collected OMAP3ISP statistics (with V4L2 private based IOCTLs) for performing user-side Auto-exposure, Auto White Balance, Auto Focus algorithms. And Adjust gains (with S_CTRL) accordingly on sensor as a result.
> >
> > Situation 2
> >  - Instance1: Select sensor1 as input. Begin streaming.
> >  - Instance2: Select sensor2 as input. Attempt to begin streaming.
> >
> > So, if I understood right, on Situation 2, if you attempt to do a S_INPUT
> > to sensor2 while capturing from sensor1, it should return a -EBUSY,
> > right?  I mean, the app should consciously make sure the input (sensor)
> > is the correct one before performing any adjustments.
> 
> It's usually perfectly legal to change inputs from one file handle while
> another file handle is capturing.
> 
> If changing inputs while capturing is hard for your hardware and not
> supported, then S_INPUT could return EBUSY while capture is in progress.
> But in that case it doesn't matter which file descriptor is trying to
> change inputs.
> 
> v4l2 is designed to allow a device to be controlled from multiple open file
> descriptors.  Just like serial ports or audio mixers can be.
> 
> In general, an application should not worry about someone changing inputs
> or frequencies while it is running.  If using v4l2-ctl while and app is
> running leads to undesirable behavior there is a simple solution:  Don't do
> that.
> 
> If you want exclusive access you can use a solution external to v4l2.  For
> instance most apps that use serial ports (pppd, minicom, etc.) use lock
> files in /var/lock to control access.  V4L2 also gives you
> VIDIOC_[SG]_PRIORITY to do access control within v4l2, but it's not much
> used.  It has little use because exclusive access just isn't something that
> important.  In theory it seems important, but in practice no one seems to
> care much that it's missing.

Just a note.

All true, but if you fallback to a modem connection with kernel 2.6.22
on FC6 with at least one NIC and an external router/switch, the default
route will still be assigned to eth0 and you can configure kppp to what
ever you want, but it does not override it, but claims to do so at the
GUI. (OK, I'm eight years away from pppd, but ...)

You have to use "route del default" at first like in stoneage and I
suspect there is more of this stuff around.

To make more use of VIDIOC_S/G_PRIORITY I always did propagate :)

The first use case was to capture on /dev/videoN and at once get vbi EPG
data on /dev/vbiN.

Cheers,
Hermann





^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04 21:46                       ` Aguirre Rodriguez, Sergio Alberto
  2009-03-04 22:44                         ` Hans Verkuil
@ 2009-03-04 23:42                         ` Trent Piepho
  2009-03-05  2:25                           ` hermann pitton
  1 sibling, 1 reply; 43+ messages in thread
From: Trent Piepho @ 2009-03-04 23:42 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: Hans Verkuil, sakari.ailus, DongSoo(Nathaniel) Kim, Hiremath,
	Vaibhav, Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-omap, Nagalla, Hari, linux-media

On Wed, 4 Mar 2009, Aguirre Rodriguez, Sergio Alberto wrote:
> As what I understand, we have 2 possible situations for multiple opens here:
>
> Situation 1
>  - Instance1: Select sensor 1, and Do queue/dequeue of buffers.
>  - Instance2: If sensor 1 is currently selected, Begin loop requesting internally collected OMAP3ISP statistics (with V4L2 private based IOCTLs) for performing user-side Auto-exposure, Auto White Balance, Auto Focus algorithms. And Adjust gains (with S_CTRL) accordingly on sensor as a result.
>
> Situation 2
>  - Instance1: Select sensor1 as input. Begin streaming.
>  - Instance2: Select sensor2 as input. Attempt to begin streaming.
>
> So, if I understood right, on Situation 2, if you attempt to do a S_INPUT
> to sensor2 while capturing from sensor1, it should return a -EBUSY,
> right?  I mean, the app should consciously make sure the input (sensor)
> is the correct one before performing any adjustments.

It's usually perfectly legal to change inputs from one file handle while
another file handle is capturing.

If changing inputs while capturing is hard for your hardware and not
supported, then S_INPUT could return EBUSY while capture is in progress.
But in that case it doesn't matter which file descriptor is trying to
change inputs.

v4l2 is designed to allow a device to be controlled from multiple open file
descriptors.  Just like serial ports or audio mixers can be.

In general, an application should not worry about someone changing inputs
or frequencies while it is running.  If using v4l2-ctl while and app is
running leads to undesirable behavior there is a simple solution:  Don't do
that.

If you want exclusive access you can use a solution external to v4l2.  For
instance most apps that use serial ports (pppd, minicom, etc.) use lock
files in /var/lock to control access.  V4L2 also gives you
VIDIOC_[SG]_PRIORITY to do access control within v4l2, but it's not much
used.  It has little use because exclusive access just isn't something that
important.  In theory it seems important, but in practice no one seems to
care much that it's missing.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04 22:44                         ` Hans Verkuil
@ 2009-03-04 23:30                           ` Aguirre Rodriguez, Sergio Alberto
  2009-03-05  7:39                             ` Hans Verkuil
  2009-03-05 20:11                           ` Sakari Ailus
  1 sibling, 1 reply; 43+ messages in thread
From: Aguirre Rodriguez, Sergio Alberto @ 2009-03-04 23:30 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: sakari.ailus, DongSoo(Nathaniel) Kim, Hiremath, Vaibhav,
	Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-omap, Nagalla, Hari, linux-media



> -----Original Message-----
> From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> Sent: Wednesday, March 04, 2009 4:45 PM
> To: Aguirre Rodriguez, Sergio Alberto
> Cc: sakari.ailus@maxwell.research.nokia.com; DongSoo(Nathaniel) Kim;
> Hiremath, Vaibhav; Toivonen Tuukka.O (Nokia-D/Oulu); linux-
> omap@vger.kernel.org; Nagalla, Hari; linux-media@vger.kernel.org
> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> 
> On Wednesday 04 March 2009 22:46:07 Aguirre Rodriguez, Sergio Alberto
> wrote:
> > > -----Original Message-----
> > > From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> > > Sent: Wednesday, March 04, 2009 3:06 PM
> > > To: sakari.ailus@maxwell.research.nokia.com
> > > Cc: DongSoo(Nathaniel) Kim; Hiremath, Vaibhav; Toivonen Tuukka.O
> > > (Nokia- D/Oulu); Aguirre Rodriguez, Sergio Alberto;
> > > linux-omap@vger.kernel.org; Nagalla, Hari; linux-media@vger.kernel.org
> > > Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> > >
> > > On Wednesday 04 March 2009 20:22:04 Sakari Ailus wrote:
> > > > Hans Verkuil wrote:
> > > > > On Wednesday 04 March 2009 01:42:13 DongSoo(Nathaniel) Kim wrote:
> > > > >> Thank you for your kind explanation Hans.
> > > > >>
> > > > >> Problem is omap3 camera subsystem is making device node for every
> > > > >> int device attached to it.
> > > > >
> > > > > That's wrong. Multiple devices should only be created if they can
> > > > > all be used at the same time. Otherwise there should be just one
> > > > > device that uses S_INPUT et al to select between the inputs.
> > > >
> > > > There might be situations where multiple device nodes would be
> > > > beneficial even if they cannot be used simultaneously in all cases.
> > > >
> > > > Currently the omap34xxcam camera driver creates one device per
> > > > camera. A camera in this case contains an isp (or camera controller),
> > > > image sensor, lens and flash. The properties like maximum frame rate
> > > > or resolution of a camera are usually (almost) completely defined by
> > > > those of the sensor, lens and flash. This affects also cropping
> > > > capabilities.
> > > >
> > > > Several programs can access video devices simultaneously. What
> > > > happens if another program switches the input when the first one
> > > > doesn't expect it? The original user won't notice the change,
> instead
> > > > of getting -EBUSY when trying to open the other video device.
> > >
> > > It is actually quite common to be able to switch inputs using one
> > > program (e.g. v4l2-ctl) while another program also has the video node
> > > open. This will typically be used for debugging or experimenting.
> > > Depending on the hardware, switching inputs while capturing is in
> > > progress may or may not be
> > > allowed (the driver might just return -EBUSY in that case).
> > >
> > > In addition the application can also call VIDIOC_S_PRIORITY to protect
> > > it against outside interference, provided the driver supports this
> > > ioctl.
> > >
> > > As an aside: many applications don't use VIDIOC_S_PRIORITY since
> > > whether a driver implements it is hit-and-miss. As part of the new
> v4l2
> > > framework I have a struct v4l2_fh planned that will integrate support
> > > of this ioctl in the framework, thus making it generic for all drivers.
> > > But this won't be available any time soon.
> >
> > As what I understand, we have 2 possible situations for multiple opens
> > here:
> >
> > Situation 1
> >  - Instance1: Select sensor 1, and Do queue/dequeue of buffers.
> >  - Instance2: If sensor 1 is currently selected, Begin loop requesting
> > internally collected OMAP3ISP statistics (with V4L2 private based
> IOCTLs)
> > for performing user-side Auto-exposure, Auto White Balance, Auto Focus
> > algorithms. And Adjust gains (with S_CTRL) accordingly on sensor as a
> > result.
> 
> Question: if you have multiple sensors, and sensor 1 is selected, can you
> still get statistics from sensor 2? Or is all this still limited to the
> selected sensor? Just want to make sure I understand it all.

Everytime a RAW10 Bayer formatted frame is received on the OMAP3ISP, statistics are being generated and when done, stored in buffers allocated internally on the driver (last 5 frames only), marking every stats buffer with the frame number associated.

When requesting stats, the user needs to specify the frame number (since last streamon call) to the which he needs the statistics. Receives in return the associated buffer.

So, going back to answering directly your question, the stats are related to the frame_number since last stream on call, making it impossible to request from one specific sensor.

> 
> > Situation 2
> >  - Instance1: Select sensor1 as input. Begin streaming.
> >  - Instance2: Select sensor2 as input. Attempt to begin streaming.
> >
> > So, if I understood right, on Situation 2, if you attempt to do a
> S_INPUT
> > to sensor2 while capturing from sensor1, it should return a -EBUSY,
> > right?
> 
> That is probably what the driver should do, yes. The V4L2 spec leaves it
> up
> to the driver whether you can switch inputs while a capture is in progress.
> In this case I think it is perfectly reasonably for the driver to
> return -EBUSY.

Ok, makes sense.

> 
> > I mean, the app should consciously make sure the input (sensor) is
> > the correct one before performing any adjustments.
> 
> Can you elaborate? I don't follow this, I'm afraid.

Normally an app already knows what are the capabilities/limitations for /dev/video0, and that wont change in our current approach, right? (Because video0 node always points to the same sensor)

But with your suggested approach, if a switching happens, the capabilities could vary between sensors, and the app should need to re request capabilities everytime it attempts to adjust something. So this is the _consciousness_ I'm talking about.. (Constantly making sure of sensor capabilities before sending S_CTRL calls)

Did I made myself clear?

> 
> > I think our current approach avoids the user to be constantly checking
> if
> > the input is still the same before updating gains...
> 
> If I understand it correctly, the normal approach would be one application
> that might have a separate thread to do the gain adjustments, etc. Or do
> it
> all in the same thread, for example by doing the adjustments after every X
> frames captured. Doing this in two separate applications seems awkward to
> me. Usually the streaming thread and the adjustment thread need to
> communicate with one another or be directed from some the main application.

Hmm... Ok, got your point.

I guess we can leave all responsibility of correct
settings<->sensor association to the user app threads then.

> 
> > I'm not clear if this single-node idea is really helping the user to
> have
> > a simpler usage in Situation 1, which I feel will become pretty common
> on
> > this driver...
> 
> The spec is pretty clear about this, and existing v4l2 applications also
> expect this behavior. Also, suppose you have two video nodes, what happens
> when you want to use the inactive node? How can you tell it is inactive?

Sorry, I think I'm not very clear on your intention...

You mean that how can an app know if streaming is ongoing in a device node?

If that's the case, then I think we'll need to have an IOCTL for knowing if the node is streaming or not.

Please clarify.

> 
> Things might change, however, if statistics gathering can proceed on an
> inactive input. In that case I need to look into it more closely.
> 
> Regards,
> 
> 	Hans
> 
> --
> Hans Verkuil - video4linux developer - sponsored by TANDBERG


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04 21:46                       ` Aguirre Rodriguez, Sergio Alberto
@ 2009-03-04 22:44                         ` Hans Verkuil
  2009-03-04 23:30                           ` Aguirre Rodriguez, Sergio Alberto
  2009-03-05 20:11                           ` Sakari Ailus
  2009-03-04 23:42                         ` Trent Piepho
  1 sibling, 2 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-03-04 22:44 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: sakari.ailus, DongSoo(Nathaniel) Kim, Hiremath, Vaibhav,
	Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-omap, Nagalla, Hari, linux-media

On Wednesday 04 March 2009 22:46:07 Aguirre Rodriguez, Sergio Alberto wrote:
> > -----Original Message-----
> > From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> > Sent: Wednesday, March 04, 2009 3:06 PM
> > To: sakari.ailus@maxwell.research.nokia.com
> > Cc: DongSoo(Nathaniel) Kim; Hiremath, Vaibhav; Toivonen Tuukka.O
> > (Nokia- D/Oulu); Aguirre Rodriguez, Sergio Alberto;
> > linux-omap@vger.kernel.org; Nagalla, Hari; linux-media@vger.kernel.org
> > Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> >
> > On Wednesday 04 March 2009 20:22:04 Sakari Ailus wrote:
> > > Hans Verkuil wrote:
> > > > On Wednesday 04 March 2009 01:42:13 DongSoo(Nathaniel) Kim wrote:
> > > >> Thank you for your kind explanation Hans.
> > > >>
> > > >> Problem is omap3 camera subsystem is making device node for every
> > > >> int device attached to it.
> > > >
> > > > That's wrong. Multiple devices should only be created if they can
> > > > all be used at the same time. Otherwise there should be just one
> > > > device that uses S_INPUT et al to select between the inputs.
> > >
> > > There might be situations where multiple device nodes would be
> > > beneficial even if they cannot be used simultaneously in all cases.
> > >
> > > Currently the omap34xxcam camera driver creates one device per
> > > camera. A camera in this case contains an isp (or camera controller),
> > > image sensor, lens and flash. The properties like maximum frame rate
> > > or resolution of a camera are usually (almost) completely defined by
> > > those of the sensor, lens and flash. This affects also cropping
> > > capabilities.
> > >
> > > Several programs can access video devices simultaneously. What
> > > happens if another program switches the input when the first one
> > > doesn't expect it? The original user won't notice the change, instead
> > > of getting -EBUSY when trying to open the other video device.
> >
> > It is actually quite common to be able to switch inputs using one
> > program (e.g. v4l2-ctl) while another program also has the video node
> > open. This will typically be used for debugging or experimenting.
> > Depending on the hardware, switching inputs while capturing is in
> > progress may or may not be
> > allowed (the driver might just return -EBUSY in that case).
> >
> > In addition the application can also call VIDIOC_S_PRIORITY to protect
> > it against outside interference, provided the driver supports this
> > ioctl.
> >
> > As an aside: many applications don't use VIDIOC_S_PRIORITY since
> > whether a driver implements it is hit-and-miss. As part of the new v4l2
> > framework I have a struct v4l2_fh planned that will integrate support
> > of this ioctl in the framework, thus making it generic for all drivers.
> > But this won't be available any time soon.
>
> As what I understand, we have 2 possible situations for multiple opens
> here:
>
> Situation 1
>  - Instance1: Select sensor 1, and Do queue/dequeue of buffers.
>  - Instance2: If sensor 1 is currently selected, Begin loop requesting
> internally collected OMAP3ISP statistics (with V4L2 private based IOCTLs)
> for performing user-side Auto-exposure, Auto White Balance, Auto Focus
> algorithms. And Adjust gains (with S_CTRL) accordingly on sensor as a
> result.

Question: if you have multiple sensors, and sensor 1 is selected, can you 
still get statistics from sensor 2? Or is all this still limited to the 
selected sensor? Just want to make sure I understand it all.

> Situation 2
>  - Instance1: Select sensor1 as input. Begin streaming.
>  - Instance2: Select sensor2 as input. Attempt to begin streaming.
>
> So, if I understood right, on Situation 2, if you attempt to do a S_INPUT
> to sensor2 while capturing from sensor1, it should return a -EBUSY,
> right?

That is probably what the driver should do, yes. The V4L2 spec leaves it up 
to the driver whether you can switch inputs while a capture is in progress. 
In this case I think it is perfectly reasonably for the driver to 
return -EBUSY.

> I mean, the app should consciously make sure the input (sensor) is 
> the correct one before performing any adjustments.

Can you elaborate? I don't follow this, I'm afraid.

> I think our current approach avoids the user to be constantly checking if
> the input is still the same before updating gains...

If I understand it correctly, the normal approach would be one application 
that might have a separate thread to do the gain adjustments, etc. Or do it 
all in the same thread, for example by doing the adjustments after every X 
frames captured. Doing this in two separate applications seems awkward to 
me. Usually the streaming thread and the adjustment thread need to 
communicate with one another or be directed from some the main application.

> I'm not clear if this single-node idea is really helping the user to have
> a simpler usage in Situation 1, which I feel will become pretty common on
> this driver...

The spec is pretty clear about this, and existing v4l2 applications also 
expect this behavior. Also, suppose you have two video nodes, what happens 
when you want to use the inactive node? How can you tell it is inactive?

Things might change, however, if statistics gathering can proceed on an 
inactive input. In that case I need to look into it more closely.

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04 21:05                     ` Hans Verkuil
@ 2009-03-04 21:46                       ` Aguirre Rodriguez, Sergio Alberto
  2009-03-04 22:44                         ` Hans Verkuil
  2009-03-04 23:42                         ` Trent Piepho
  0 siblings, 2 replies; 43+ messages in thread
From: Aguirre Rodriguez, Sergio Alberto @ 2009-03-04 21:46 UTC (permalink / raw)
  To: Hans Verkuil, sakari.ailus
  Cc: DongSoo(Nathaniel) Kim, Hiremath, Vaibhav,
	Toivonen Tuukka.O (Nokia-D/Oulu),
	linux-omap, Nagalla, Hari, linux-media



> -----Original Message-----
> From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> Sent: Wednesday, March 04, 2009 3:06 PM
> To: sakari.ailus@maxwell.research.nokia.com
> Cc: DongSoo(Nathaniel) Kim; Hiremath, Vaibhav; Toivonen Tuukka.O (Nokia-
> D/Oulu); Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
> Nagalla, Hari; linux-media@vger.kernel.org
> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> 
> On Wednesday 04 March 2009 20:22:04 Sakari Ailus wrote:
> > Hans Verkuil wrote:
> > > On Wednesday 04 March 2009 01:42:13 DongSoo(Nathaniel) Kim wrote:
> > >> Thank you for your kind explanation Hans.
> > >>
> > >> Problem is omap3 camera subsystem is making device node for every int
> > >> device attached to it.
> > >
> > > That's wrong. Multiple devices should only be created if they can all
> > > be used at the same time. Otherwise there should be just one device
> > > that uses S_INPUT et al to select between the inputs.
> >
> > There might be situations where multiple device nodes would be
> > beneficial even if they cannot be used simultaneously in all cases.
> >
> > Currently the omap34xxcam camera driver creates one device per camera. A
> > camera in this case contains an isp (or camera controller), image
> > sensor, lens and flash. The properties like maximum frame rate or
> > resolution of a camera are usually (almost) completely defined by those
> > of the sensor, lens and flash. This affects also cropping capabilities.
> >
> > Several programs can access video devices simultaneously. What happens
> > if another program switches the input when the first one doesn't expect
> > it? The original user won't notice the change, instead of getting -EBUSY
> > when trying to open the other video device.
> 
> It is actually quite common to be able to switch inputs using one program
> (e.g. v4l2-ctl) while another program also has the video node open. This
> will typically be used for debugging or experimenting. Depending on the
> hardware, switching inputs while capturing is in progress may or may not
> be
> allowed (the driver might just return -EBUSY in that case).
> 
> In addition the application can also call VIDIOC_S_PRIORITY to protect it
> against outside interference, provided the driver supports this ioctl.
> 
> As an aside: many applications don't use VIDIOC_S_PRIORITY since whether a
> driver implements it is hit-and-miss. As part of the new v4l2 framework I
> have a struct v4l2_fh planned that will integrate support of this ioctl in
> the framework, thus making it generic for all drivers. But this won't be
> available any time soon.

As what I understand, we have 2 possible situations for multiple opens here:

Situation 1
 - Instance1: Select sensor 1, and Do queue/dequeue of buffers.
 - Instance2: If sensor 1 is currently selected, Begin loop requesting internally collected OMAP3ISP statistics (with V4L2 private based IOCTLs) for performing user-side Auto-exposure, Auto White Balance, Auto Focus algorithms. And Adjust gains (with S_CTRL) accordingly on sensor as a result.

Situation 2
 - Instance1: Select sensor1 as input. Begin streaming.
 - Instance2: Select sensor2 as input. Attempt to begin streaming.

So, if I understood right, on Situation 2, if you attempt to do a S_INPUT to sensor2 while capturing from sensor1, it should return a -EBUSY, right? I mean, the app should consciously make sure the input (sensor) is the correct one before performing any adjustments.

I think our current approach avoids the user to be constantly checking if the input is still the same before updating gains...

I'm not clear if this single-node idea is really helping the user to have a simpler usage in Situation 1, which I feel will become pretty common on this driver...

> 
> > In short, it's been just more clear to have one device per camera. There
> > may be other reasons but these come to mind this time.
> 
> I very much disagree here. Having multiple devices ONLY makes sense if you
> can capture from them in parallel. This situation is really just a
> straightforward case of multiple inputs you have to choose from.
> 
> > > BTW, do I understand correctly that e.g. lens drivers also get their
> > > own /dev/videoX node? Please tell me I'm mistaken! Since that would be
> > > so very wrong.
> >
> > Yes, you're mistaken this time. :)
> >
> > The contents of a video devices are defined in platform data.
> >
> > > I hope that the conversion to v4l2_subdev will take place soon. You
> are
> > > basically stuck in a technological dead-end :-(
> >
> > Making things working properly in camera and ISP drivers has taken much
> > more time than was anticipated and v4l2_subdev framework has developed a
> > lot during that time. You're right --- we'll start thinking of how and
> > when to move to v4l2_subdev.
> 
> Just contact me if you have any questions, I'll be happy to help. If you
> think there are missing bits in the framework, or find that you need to
> workaround some limitation, please contact me first. It might well be that
> I need to add something to support these devices, or that you should take
> a
> different approach instead. The sooner such issues are resolved, the less
> time you loose.
> 
> Regards,
> 
> 	Hans
> 
> --
> Hans Verkuil - video4linux developer - sponsored by TANDBERG


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04 19:22                   ` Sakari Ailus
@ 2009-03-04 21:05                     ` Hans Verkuil
  2009-03-04 21:46                       ` Aguirre Rodriguez, Sergio Alberto
  0 siblings, 1 reply; 43+ messages in thread
From: Hans Verkuil @ 2009-03-04 21:05 UTC (permalink / raw)
  To: sakari.ailus
  Cc: DongSoo(Nathaniel) Kim, Hiremath, Vaibhav,
	Toivonen Tuukka.O (Nokia-D/Oulu),
	Aguirre Rodriguez, Sergio Alberto, linux-omap, Nagalla, Hari,
	linux-media

On Wednesday 04 March 2009 20:22:04 Sakari Ailus wrote:
> Hans Verkuil wrote:
> > On Wednesday 04 March 2009 01:42:13 DongSoo(Nathaniel) Kim wrote:
> >> Thank you for your kind explanation Hans.
> >>
> >> Problem is omap3 camera subsystem is making device node for every int
> >> device attached to it.
> >
> > That's wrong. Multiple devices should only be created if they can all
> > be used at the same time. Otherwise there should be just one device
> > that uses S_INPUT et al to select between the inputs.
>
> There might be situations where multiple device nodes would be
> beneficial even if they cannot be used simultaneously in all cases.
>
> Currently the omap34xxcam camera driver creates one device per camera. A
> camera in this case contains an isp (or camera controller), image
> sensor, lens and flash. The properties like maximum frame rate or
> resolution of a camera are usually (almost) completely defined by those
> of the sensor, lens and flash. This affects also cropping capabilities.
>
> Several programs can access video devices simultaneously. What happens
> if another program switches the input when the first one doesn't expect
> it? The original user won't notice the change, instead of getting -EBUSY
> when trying to open the other video device.

It is actually quite common to be able to switch inputs using one program 
(e.g. v4l2-ctl) while another program also has the video node open. This 
will typically be used for debugging or experimenting. Depending on the 
hardware, switching inputs while capturing is in progress may or may not be 
allowed (the driver might just return -EBUSY in that case).

In addition the application can also call VIDIOC_S_PRIORITY to protect it 
against outside interference, provided the driver supports this ioctl.

As an aside: many applications don't use VIDIOC_S_PRIORITY since whether a 
driver implements it is hit-and-miss. As part of the new v4l2 framework I 
have a struct v4l2_fh planned that will integrate support of this ioctl in 
the framework, thus making it generic for all drivers. But this won't be 
available any time soon.

> In short, it's been just more clear to have one device per camera. There
> may be other reasons but these come to mind this time.

I very much disagree here. Having multiple devices ONLY makes sense if you 
can capture from them in parallel. This situation is really just a 
straightforward case of multiple inputs you have to choose from.

> > BTW, do I understand correctly that e.g. lens drivers also get their
> > own /dev/videoX node? Please tell me I'm mistaken! Since that would be
> > so very wrong.
>
> Yes, you're mistaken this time. :)
>
> The contents of a video devices are defined in platform data.
>
> > I hope that the conversion to v4l2_subdev will take place soon. You are
> > basically stuck in a technological dead-end :-(
>
> Making things working properly in camera and ISP drivers has taken much
> more time than was anticipated and v4l2_subdev framework has developed a
> lot during that time. You're right --- we'll start thinking of how and
> when to move to v4l2_subdev.

Just contact me if you have any questions, I'll be happy to help. If you 
think there are missing bits in the framework, or find that you need to 
workaround some limitation, please contact me first. It might well be that 
I need to add something to support these devices, or that you should take a 
different approach instead. The sooner such issues are resolved, the less 
time you loose.

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04  7:39                   ` Hans Verkuil
  (?)
  (?)
@ 2009-03-04 19:22                   ` Sakari Ailus
  2009-03-04 21:05                     ` Hans Verkuil
  -1 siblings, 1 reply; 43+ messages in thread
From: Sakari Ailus @ 2009-03-04 19:22 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: DongSoo(Nathaniel) Kim, Hiremath, Vaibhav,
	Toivonen Tuukka.O (Nokia-D/Oulu),
	Aguirre Rodriguez, Sergio Alberto, linux-omap, Nagalla, Hari,
	linux-media

Hans Verkuil wrote:
> On Wednesday 04 March 2009 01:42:13 DongSoo(Nathaniel) Kim wrote:
>> Thank you for your kind explanation Hans.
>>
>> Problem is omap3 camera subsystem is making device node for every int
>> device attached to it.
> 
> That's wrong. Multiple devices should only be created if they can all be 
> used at the same time. Otherwise there should be just one device that uses 
> S_INPUT et al to select between the inputs.

There might be situations where multiple device nodes would be 
beneficial even if they cannot be used simultaneously in all cases.

Currently the omap34xxcam camera driver creates one device per camera. A 
camera in this case contains an isp (or camera controller), image 
sensor, lens and flash. The properties like maximum frame rate or 
resolution of a camera are usually (almost) completely defined by those 
of the sensor, lens and flash. This affects also cropping capabilities.

Several programs can access video devices simultaneously. What happens 
if another program switches the input when the first one doesn't expect 
it? The original user won't notice the change, instead of getting -EBUSY 
when trying to open the other video device.

In short, it's been just more clear to have one device per camera. There 
may be other reasons but these come to mind this time.

> BTW, do I understand correctly that e.g. lens drivers also get their 
> own /dev/videoX node? Please tell me I'm mistaken! Since that would be so 
> very wrong.

Yes, you're mistaken this time. :)

The contents of a video devices are defined in platform data.

> I hope that the conversion to v4l2_subdev will take place soon. You are 
> basically stuck in a technological dead-end :-(

Making things working properly in camera and ISP drivers has taken much 
more time than was anticipated and v4l2_subdev framework has developed a 
lot during that time. You're right --- we'll start thinking of how and 
when to move to v4l2_subdev.

Thanks.

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2009-03-04  8:12 Hans Verkuil
  0 siblings, 0 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-03-04  8:12 UTC (permalink / raw)
  To: Tuukka.O Toivonen
  Cc: DongSoo Kim, Hiremath, Vaibhav, Aguirre Rodriguez,
	Sergio Alberto, linux-omap, Ailus Sakari, Nagalla, Hari,
	linux-media


> On Wednesday 04 March 2009 09:39:48 ext Hans Verkuil wrote:
>> BTW, do I understand correctly that e.g. lens drivers also get their
>> own /dev/videoX node? Please tell me I'm mistaken! Since that would be
>> so
>> very wrong.
>
> You're mistaken :)
>
> With the v4l2-int-interface/omap34xxcam camera driver one device
> node consists of all slaves (sensor, lens, flash, ...) making up
> the complete camera device.

Phew! That's a relief. I got scared there for a moment :-)

Regards,

         Hans

>> I hope that the conversion to v4l2_subdev will take place soon. You are
>> basically stuck in a technological dead-end :-(
>
> Ok :(
>
> - Tuukka
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04  7:39                   ` Hans Verkuil
  (?)
@ 2009-03-04  7:49                   ` Tuukka.O Toivonen
  -1 siblings, 0 replies; 43+ messages in thread
From: Tuukka.O Toivonen @ 2009-03-04  7:49 UTC (permalink / raw)
  To: ext Hans Verkuil
  Cc: DongSoo(Nathaniel) Kim, Hiremath, Vaibhav, Aguirre Rodriguez,
	Sergio Alberto, linux-omap, Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari, linux-media

On Wednesday 04 March 2009 09:39:48 ext Hans Verkuil wrote:
> BTW, do I understand correctly that e.g. lens drivers also get their 
> own /dev/videoX node? Please tell me I'm mistaken! Since that would be so 
> very wrong.

You're mistaken :)

With the v4l2-int-interface/omap34xxcam camera driver one device
node consists of all slaves (sensor, lens, flash, ...) making up
the complete camera device.

> I hope that the conversion to v4l2_subdev will take place soon. You are 
> basically stuck in a technological dead-end :-(

Ok :(

- Tuukka

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-04  0:42                 ` DongSoo(Nathaniel) Kim
@ 2009-03-04  7:39                   ` Hans Verkuil
  -1 siblings, 0 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-03-04  7:39 UTC (permalink / raw)
  To: DongSoo(Nathaniel) Kim
  Cc: Hiremath, Vaibhav, Tuukka.O Toivonen, Aguirre Rodriguez,
	Sergio Alberto, linux-omap, Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari, linux-media

On Wednesday 04 March 2009 01:42:13 DongSoo(Nathaniel) Kim wrote:
> Thank you for your kind explanation Hans.
>
> Problem is omap3 camera subsystem is making device node for every int
> device attached to it.

That's wrong. Multiple devices should only be created if they can all be 
used at the same time. Otherwise there should be just one device that uses 
S_INPUT et al to select between the inputs.

BTW, do I understand correctly that e.g. lens drivers also get their 
own /dev/videoX node? Please tell me I'm mistaken! Since that would be so 
very wrong.

> Before I have been using v4l2 int device, I implemented
> S_INPUT/G_INPUT/ENUMINPUT by my own for other CPUs like S3C64XX (just
> for demo..not opened on public domain yet)
> In that case, I considered camera interface as a capture device, and
> every camera devices as input devices for capture device. So using
> enuminput I could query how many devices do I have for input, and even
> camera device's name could be get.

This sort of information has to come from the platform, not from drivers. It 
is dangerous to rely on what i2c modules tell you what their inputs are. 
E.g. suppose you have two sensors whose input is combined by an FPGA into 
some sort of 3D format? Two sensors, but only one input.

The platform data is where such information should be stored since only at 
that level is the whole board layout known.

> I made only one device node for camera interface because it was
> exactly camera interface that I open, not camera module attached on
> it. Furthermore, CPU's camera video processing H/W cannot process data
> from multiple cameras at the same time. So no need to make device node
> for every single camera module attached on it.

Correct.

> For these kinds of reason, I think also omap3 camera subsystem should
> make only one device node for the same category of int device(or
> subdev for now?). I mean single device node for sensors, single device
> node for lens controllers, single device node for strobes.
> I hope I made myself clear. Honestly it is quite hard to explain (even
> in my language)

You are completely right, except that this info should come from the 
platform.

I hope that the conversion to v4l2_subdev will take place soon. You are 
basically stuck in a technological dead-end :-(

Regards,

	Hans

> Cheers,
>
> Nate
>
> On Tue, Mar 3, 2009 at 4:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> > On Tuesday 03 March 2009 06:13:11 DongSoo(Nathaniel) Kim wrote:
> >> Thank you for your reply.
> >>
> >> This is quite confusing because in case of mine, I wanna make
> >> switchable between different cameras attached to omap camera
> >> interface.
> >> Which idea do I have to follow? Comparing with multiple video input
> >> devices and multiple cameras attached to single camera interface is
> >> giving me no answer.
> >>
> >> Perhaps multiple cameras with single camera interface couldn't make
> >> sense at the first place because single camera interface can go with
> >> only one camera module at one time.
> >> But we are using like that. I mean dual cameras with single camera
> >> interface. There is no choice except that when we are using dual
> >> camera without stereo camera controller.
> >
> > If you have multiple inputs (cameras in this case) that the user can
> > choose from, then you need to implement S_INPUT/G_INPUT/ENUMINPUTS.
> > That's what they are there for. Any decent V4L2 app should support
> > these ioctls.
> >
> >> By the way, I cannot find any API documents about
> >> VIDIOC_INT_S_VIDEO_ROUTING but it seems to be all about "how to route
> >> between input device with output device".
> >
> > The description of this internal ioctl is in v4l2-common.h. It is used
> > to tell the i2c module how it is hooked up to the rest of the system.
> > I.e. what pin(s) is used for the input signal and what pin(s) is used
> > for the output signal.
> >
> > Typically the main v4l2 driver will map a user-level input (as set with
> > VIDIOC_S_INPUT) to the low-level routing information and pass that on
> > to the i2c device using VIDIOC_INT_S_VIDEO_ROUTING.
> >
> > Regards,
> >
> >        Hans
> >
> >> What exactly I need is "how to make switchable with multiple camera as
> >> an input for camera interface", which means just about an input
> >> device. In my opinion, those are different issues each other..(Am I
> >> right?)
> >> Cheers,
> >>
> >> Nate
> >>
> >> On Tue, Mar 3, 2009 at 12:53 PM, Hiremath, Vaibhav <hvaibhav@ti.com>
> >
> > wrote:
> >> > Thanks,
> >> > Vaibhav Hiremath
> >> >
> >> >> -----Original Message-----
> >> >> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> >> >> owner@vger.kernel.org] On Behalf Of DongSoo(Nathaniel) Kim
> >> >> Sent: Tuesday, March 03, 2009 8:18 AM
> >> >> To: Tuukka.O Toivonen
> >> >> Cc: Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
> >> >> Ailus Sakari (Nokia-D/Helsinki); Nagalla, Hari
> >> >> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> >> >>
> >> >> Hi Tuukka,
> >> >>
> >> >> I understand that it is a huge thing to support VIDIOC_S_INPUT.
> >> >> But without that, we don't have any proper "V4L2" api to get
> >> >> information about how many devices are attached to camera
> >> >> interface, and names of input devices...and so on. Because
> >> >> VIDIOC_ENUMINPUT and VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior.
> >> >> Of course we can refer
> >> >> to sysfs, but using only single set of APIs like V4L2 looks more
> >> >> decent.
> >> >>
> >> >> What do you think about this?
> >> >> If you think that it is a big burden, can I make a patch for this?
> >> >> Cheers,
> >> >
> >> > [Hiremath, Vaibhav] You may want to refer to the thread on this
> >> > subject.
> >> >
> >> > http://marc.info/?l=linux-omap&m=122772175002777&w=2
> >> > http://marc.info/?l=linux-omap&m=122823846806440&w=2
> >> >
> >> >> Nate
> >> >>
> >> >> On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
> >> >>
> >> >> <tuukka.o.toivonen@nokia.com> wrote:
> >> >> > On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim
> >> >>
> >> >> wrote:
> >> >> >> So, logically it does not make sense with making device nodes of
> >> >>
> >> >> every
> >> >>
> >> >> >> single slave attached with OMAP3camera interface. Because they
> >> >>
> >> >> can't
> >> >>
> >> >> >> be opened at the same time,even if it is possible it should not
> >> >>
> >> >> work
> >> >>
> >> >> >> properly.
> >> >> >>
> >> >> >> So.. how about making only single device node like /dev/video0
> >> >>
> >> >> for
> >> >>
> >> >> >> OMAP3 camera interface and make it switchable through V4L2 API.
> >> >>
> >> >> Like
> >> >>
> >> >> >> VIDIOC_S_INPUT?
> >> >> >
> >> >> > You are right that if the OMAP3 has several camera sensors
> >> >>
> >> >> attached
> >> >>
> >> >> > to its camera interface, generally just one can be used at once.
> >> >> >
> >> >> > However, from user's perspective those are still distinct
> >> >> > cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
> >> >> > or at least it will be more difficult to use than just pointing
> >> >> > an app to the correct video device. Logically they are two
> >> >> > independent cameras, which can't be used simultaneously
> >> >> > due to HW restrictions.
> >> >> >
> >> >> > - Tuukka
> >> >>
> >> >> --
> >> >> ========================================================
> >> >> DongSoo(Nathaniel), Kim
> >> >> Engineer
> >> >> Mobile S/W Platform Lab. S/W centre
> >> >> Telecommunication R&D Centre
> >> >> Samsung Electronics CO., LTD.
> >> >> e-mail : dongsoo.kim@gmail.com
> >> >>           dongsoo45.kim@samsung.com
> >> >> ========================================================
> >> >> --
> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
> >> >> omap" in
> >> >> the body of a message to majordomo@vger.kernel.org
> >> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> > --
> > Hans Verkuil - video4linux developer - sponsored by TANDBERG



-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2009-03-04  7:39                   ` Hans Verkuil
  0 siblings, 0 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-03-04  7:39 UTC (permalink / raw)
  To: DongSoo(Nathaniel) Kim
  Cc: Hiremath, Vaibhav, Tuukka.O Toivonen, Aguirre Rodriguez,
	Sergio Alberto, linux-omap, Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari, linux-media

On Wednesday 04 March 2009 01:42:13 DongSoo(Nathaniel) Kim wrote:
> Thank you for your kind explanation Hans.
>
> Problem is omap3 camera subsystem is making device node for every int
> device attached to it.

That's wrong. Multiple devices should only be created if they can all be 
used at the same time. Otherwise there should be just one device that uses 
S_INPUT et al to select between the inputs.

BTW, do I understand correctly that e.g. lens drivers also get their 
own /dev/videoX node? Please tell me I'm mistaken! Since that would be so 
very wrong.

> Before I have been using v4l2 int device, I implemented
> S_INPUT/G_INPUT/ENUMINPUT by my own for other CPUs like S3C64XX (just
> for demo..not opened on public domain yet)
> In that case, I considered camera interface as a capture device, and
> every camera devices as input devices for capture device. So using
> enuminput I could query how many devices do I have for input, and even
> camera device's name could be get.

This sort of information has to come from the platform, not from drivers. It 
is dangerous to rely on what i2c modules tell you what their inputs are. 
E.g. suppose you have two sensors whose input is combined by an FPGA into 
some sort of 3D format? Two sensors, but only one input.

The platform data is where such information should be stored since only at 
that level is the whole board layout known.

> I made only one device node for camera interface because it was
> exactly camera interface that I open, not camera module attached on
> it. Furthermore, CPU's camera video processing H/W cannot process data
> from multiple cameras at the same time. So no need to make device node
> for every single camera module attached on it.

Correct.

> For these kinds of reason, I think also omap3 camera subsystem should
> make only one device node for the same category of int device(or
> subdev for now?). I mean single device node for sensors, single device
> node for lens controllers, single device node for strobes.
> I hope I made myself clear. Honestly it is quite hard to explain (even
> in my language)

You are completely right, except that this info should come from the 
platform.

I hope that the conversion to v4l2_subdev will take place soon. You are 
basically stuck in a technological dead-end :-(

Regards,

	Hans

> Cheers,
>
> Nate
>
> On Tue, Mar 3, 2009 at 4:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> > On Tuesday 03 March 2009 06:13:11 DongSoo(Nathaniel) Kim wrote:
> >> Thank you for your reply.
> >>
> >> This is quite confusing because in case of mine, I wanna make
> >> switchable between different cameras attached to omap camera
> >> interface.
> >> Which idea do I have to follow? Comparing with multiple video input
> >> devices and multiple cameras attached to single camera interface is
> >> giving me no answer.
> >>
> >> Perhaps multiple cameras with single camera interface couldn't make
> >> sense at the first place because single camera interface can go with
> >> only one camera module at one time.
> >> But we are using like that. I mean dual cameras with single camera
> >> interface. There is no choice except that when we are using dual
> >> camera without stereo camera controller.
> >
> > If you have multiple inputs (cameras in this case) that the user can
> > choose from, then you need to implement S_INPUT/G_INPUT/ENUMINPUTS.
> > That's what they are there for. Any decent V4L2 app should support
> > these ioctls.
> >
> >> By the way, I cannot find any API documents about
> >> VIDIOC_INT_S_VIDEO_ROUTING but it seems to be all about "how to route
> >> between input device with output device".
> >
> > The description of this internal ioctl is in v4l2-common.h. It is used
> > to tell the i2c module how it is hooked up to the rest of the system.
> > I.e. what pin(s) is used for the input signal and what pin(s) is used
> > for the output signal.
> >
> > Typically the main v4l2 driver will map a user-level input (as set with
> > VIDIOC_S_INPUT) to the low-level routing information and pass that on
> > to the i2c device using VIDIOC_INT_S_VIDEO_ROUTING.
> >
> > Regards,
> >
> >        Hans
> >
> >> What exactly I need is "how to make switchable with multiple camera as
> >> an input for camera interface", which means just about an input
> >> device. In my opinion, those are different issues each other..(Am I
> >> right?)
> >> Cheers,
> >>
> >> Nate
> >>
> >> On Tue, Mar 3, 2009 at 12:53 PM, Hiremath, Vaibhav <hvaibhav@ti.com>
> >
> > wrote:
> >> > Thanks,
> >> > Vaibhav Hiremath
> >> >
> >> >> -----Original Message-----
> >> >> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> >> >> owner@vger.kernel.org] On Behalf Of DongSoo(Nathaniel) Kim
> >> >> Sent: Tuesday, March 03, 2009 8:18 AM
> >> >> To: Tuukka.O Toivonen
> >> >> Cc: Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
> >> >> Ailus Sakari (Nokia-D/Helsinki); Nagalla, Hari
> >> >> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> >> >>
> >> >> Hi Tuukka,
> >> >>
> >> >> I understand that it is a huge thing to support VIDIOC_S_INPUT.
> >> >> But without that, we don't have any proper "V4L2" api to get
> >> >> information about how many devices are attached to camera
> >> >> interface, and names of input devices...and so on. Because
> >> >> VIDIOC_ENUMINPUT and VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior.
> >> >> Of course we can refer
> >> >> to sysfs, but using only single set of APIs like V4L2 looks more
> >> >> decent.
> >> >>
> >> >> What do you think about this?
> >> >> If you think that it is a big burden, can I make a patch for this?
> >> >> Cheers,
> >> >
> >> > [Hiremath, Vaibhav] You may want to refer to the thread on this
> >> > subject.
> >> >
> >> > http://marc.info/?l=linux-omap&m=122772175002777&w=2
> >> > http://marc.info/?l=linux-omap&m=122823846806440&w=2
> >> >
> >> >> Nate
> >> >>
> >> >> On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
> >> >>
> >> >> <tuukka.o.toivonen@nokia.com> wrote:
> >> >> > On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim
> >> >>
> >> >> wrote:
> >> >> >> So, logically it does not make sense with making device nodes of
> >> >>
> >> >> every
> >> >>
> >> >> >> single slave attached with OMAP3camera interface. Because they
> >> >>
> >> >> can't
> >> >>
> >> >> >> be opened at the same time,even if it is possible it should not
> >> >>
> >> >> work
> >> >>
> >> >> >> properly.
> >> >> >>
> >> >> >> So.. how about making only single device node like /dev/video0
> >> >>
> >> >> for
> >> >>
> >> >> >> OMAP3 camera interface and make it switchable through V4L2 API.
> >> >>
> >> >> Like
> >> >>
> >> >> >> VIDIOC_S_INPUT?
> >> >> >
> >> >> > You are right that if the OMAP3 has several camera sensors
> >> >>
> >> >> attached
> >> >>
> >> >> > to its camera interface, generally just one can be used at once.
> >> >> >
> >> >> > However, from user's perspective those are still distinct
> >> >> > cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
> >> >> > or at least it will be more difficult to use than just pointing
> >> >> > an app to the correct video device. Logically they are two
> >> >> > independent cameras, which can't be used simultaneously
> >> >> > due to HW restrictions.
> >> >> >
> >> >> > - Tuukka
> >> >>
> >> >> --
> >> >> ========================================================
> >> >> DongSoo(Nathaniel), Kim
> >> >> Engineer
> >> >> Mobile S/W Platform Lab. S/W centre
> >> >> Telecommunication R&D Centre
> >> >> Samsung Electronics CO., LTD.
> >> >> e-mail : dongsoo.kim@gmail.com
> >> >>           dongsoo45.kim@samsung.com
> >> >> ========================================================
> >> >> --
> >> >> To unsubscribe from this list: send the line "unsubscribe linux-
> >> >> omap" in
> >> >> the body of a message to majordomo@vger.kernel.org
> >> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> > --
> > Hans Verkuil - video4linux developer - sponsored by TANDBERG



-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-03  7:36               ` Hans Verkuil
@ 2009-03-04  0:42                 ` DongSoo(Nathaniel) Kim
  -1 siblings, 0 replies; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-03-04  0:42 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Hiremath, Vaibhav, Tuukka.O Toivonen, Aguirre Rodriguez,
	Sergio Alberto, linux-omap, Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari, linux-media

Thank you for your kind explanation Hans.

Problem is omap3 camera subsystem is making device node for every int
device attached to it.
Before I have been using v4l2 int device, I implemented
S_INPUT/G_INPUT/ENUMINPUT by my own for other CPUs like S3C64XX (just
for demo..not opened on public domain yet)
In that case, I considered camera interface as a capture device, and
every camera devices as input devices for capture device. So using
enuminput I could query how many devices do I have for input, and even
camera device's name could be get.
I made only one device node for camera interface because it was
exactly camera interface that I open, not camera module attached on
it. Furthermore, CPU's camera video processing H/W cannot process data
from multiple cameras at the same time. So no need to make device node
for every single camera module attached on it.
For these kinds of reason, I think also omap3 camera subsystem should
make only one device node for the same category of int device(or
subdev for now?). I mean single device node for sensors, single device
node for lens controllers, single device node for strobes.
I hope I made myself clear. Honestly it is quite hard to explain (even
in my language)
Cheers,

Nate

On Tue, Mar 3, 2009 at 4:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On Tuesday 03 March 2009 06:13:11 DongSoo(Nathaniel) Kim wrote:
>> Thank you for your reply.
>>
>> This is quite confusing because in case of mine, I wanna make
>> switchable between different cameras attached to omap camera
>> interface.
>> Which idea do I have to follow? Comparing with multiple video input
>> devices and multiple cameras attached to single camera interface is
>> giving me no answer.
>>
>> Perhaps multiple cameras with single camera interface couldn't make
>> sense at the first place because single camera interface can go with
>> only one camera module at one time.
>> But we are using like that. I mean dual cameras with single camera
>> interface. There is no choice except that when we are using dual
>> camera without stereo camera controller.
>
> If you have multiple inputs (cameras in this case) that the user can choose
> from, then you need to implement S_INPUT/G_INPUT/ENUMINPUTS. That's what
> they are there for. Any decent V4L2 app should support these ioctls.
>
>> By the way, I cannot find any API documents about
>> VIDIOC_INT_S_VIDEO_ROUTING but it seems to be all about "how to route
>> between input device with output device".
>
> The description of this internal ioctl is in v4l2-common.h. It is used to
> tell the i2c module how it is hooked up to the rest of the system. I.e.
> what pin(s) is used for the input signal and what pin(s) is used for the
> output signal.
>
> Typically the main v4l2 driver will map a user-level input (as set with
> VIDIOC_S_INPUT) to the low-level routing information and pass that on to
> the i2c device using VIDIOC_INT_S_VIDEO_ROUTING.
>
> Regards,
>
>        Hans
>
>> What exactly I need is "how to make switchable with multiple camera as
>> an input for camera interface", which means just about an input
>> device. In my opinion, those are different issues each other..(Am I
>> right?)
>> Cheers,
>>
>> Nate
>>
>> On Tue, Mar 3, 2009 at 12:53 PM, Hiremath, Vaibhav <hvaibhav@ti.com>
> wrote:
>> > Thanks,
>> > Vaibhav Hiremath
>> >
>> >> -----Original Message-----
>> >> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>> >> owner@vger.kernel.org] On Behalf Of DongSoo(Nathaniel) Kim
>> >> Sent: Tuesday, March 03, 2009 8:18 AM
>> >> To: Tuukka.O Toivonen
>> >> Cc: Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
>> >> Ailus Sakari (Nokia-D/Helsinki); Nagalla, Hari
>> >> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
>> >>
>> >> Hi Tuukka,
>> >>
>> >> I understand that it is a huge thing to support VIDIOC_S_INPUT.
>> >> But without that, we don't have any proper "V4L2" api to get
>> >> information about how many devices are attached to camera interface,
>> >> and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
>> >> VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can
>> >> refer
>> >> to sysfs, but using only single set of APIs like V4L2 looks more
>> >> decent.
>> >>
>> >> What do you think about this?
>> >> If you think that it is a big burden, can I make a patch for this?
>> >> Cheers,
>> >
>> > [Hiremath, Vaibhav] You may want to refer to the thread on this
>> > subject.
>> >
>> > http://marc.info/?l=linux-omap&m=122772175002777&w=2
>> > http://marc.info/?l=linux-omap&m=122823846806440&w=2
>> >
>> >> Nate
>> >>
>> >> On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
>> >>
>> >> <tuukka.o.toivonen@nokia.com> wrote:
>> >> > On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim
>> >>
>> >> wrote:
>> >> >> So, logically it does not make sense with making device nodes of
>> >>
>> >> every
>> >>
>> >> >> single slave attached with OMAP3camera interface. Because they
>> >>
>> >> can't
>> >>
>> >> >> be opened at the same time,even if it is possible it should not
>> >>
>> >> work
>> >>
>> >> >> properly.
>> >> >>
>> >> >> So.. how about making only single device node like /dev/video0
>> >>
>> >> for
>> >>
>> >> >> OMAP3 camera interface and make it switchable through V4L2 API.
>> >>
>> >> Like
>> >>
>> >> >> VIDIOC_S_INPUT?
>> >> >
>> >> > You are right that if the OMAP3 has several camera sensors
>> >>
>> >> attached
>> >>
>> >> > to its camera interface, generally just one can be used at once.
>> >> >
>> >> > However, from user's perspective those are still distinct
>> >> > cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
>> >> > or at least it will be more difficult to use than just pointing
>> >> > an app to the correct video device. Logically they are two
>> >> > independent cameras, which can't be used simultaneously
>> >> > due to HW restrictions.
>> >> >
>> >> > - Tuukka
>> >>
>> >> --
>> >> ========================================================
>> >> DongSoo(Nathaniel), Kim
>> >> Engineer
>> >> Mobile S/W Platform Lab. S/W centre
>> >> Telecommunication R&D Centre
>> >> Samsung Electronics CO., LTD.
>> >> e-mail : dongsoo.kim@gmail.com
>> >>           dongsoo45.kim@samsung.com
>> >> ========================================================
>> >> --
>> >> To unsubscribe from this list: send the line "unsubscribe linux-
>> >> omap" in
>> >> the body of a message to majordomo@vger.kernel.org
>> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>
> --
> Hans Verkuil - video4linux developer - sponsored by TANDBERG
>



-- 
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
          dongsoo45.kim@samsung.com
========================================================

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2009-03-04  0:42                 ` DongSoo(Nathaniel) Kim
  0 siblings, 0 replies; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-03-04  0:42 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Hiremath, Vaibhav, Tuukka.O Toivonen, Aguirre Rodriguez,
	Sergio Alberto, linux-omap, Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari, linux-media

Thank you for your kind explanation Hans.

Problem is omap3 camera subsystem is making device node for every int
device attached to it.
Before I have been using v4l2 int device, I implemented
S_INPUT/G_INPUT/ENUMINPUT by my own for other CPUs like S3C64XX (just
for demo..not opened on public domain yet)
In that case, I considered camera interface as a capture device, and
every camera devices as input devices for capture device. So using
enuminput I could query how many devices do I have for input, and even
camera device's name could be get.
I made only one device node for camera interface because it was
exactly camera interface that I open, not camera module attached on
it. Furthermore, CPU's camera video processing H/W cannot process data
from multiple cameras at the same time. So no need to make device node
for every single camera module attached on it.
For these kinds of reason, I think also omap3 camera subsystem should
make only one device node for the same category of int device(or
subdev for now?). I mean single device node for sensors, single device
node for lens controllers, single device node for strobes.
I hope I made myself clear. Honestly it is quite hard to explain (even
in my language)
Cheers,

Nate

On Tue, Mar 3, 2009 at 4:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On Tuesday 03 March 2009 06:13:11 DongSoo(Nathaniel) Kim wrote:
>> Thank you for your reply.
>>
>> This is quite confusing because in case of mine, I wanna make
>> switchable between different cameras attached to omap camera
>> interface.
>> Which idea do I have to follow? Comparing with multiple video input
>> devices and multiple cameras attached to single camera interface is
>> giving me no answer.
>>
>> Perhaps multiple cameras with single camera interface couldn't make
>> sense at the first place because single camera interface can go with
>> only one camera module at one time.
>> But we are using like that. I mean dual cameras with single camera
>> interface. There is no choice except that when we are using dual
>> camera without stereo camera controller.
>
> If you have multiple inputs (cameras in this case) that the user can choose
> from, then you need to implement S_INPUT/G_INPUT/ENUMINPUTS. That's what
> they are there for. Any decent V4L2 app should support these ioctls.
>
>> By the way, I cannot find any API documents about
>> VIDIOC_INT_S_VIDEO_ROUTING but it seems to be all about "how to route
>> between input device with output device".
>
> The description of this internal ioctl is in v4l2-common.h. It is used to
> tell the i2c module how it is hooked up to the rest of the system. I.e.
> what pin(s) is used for the input signal and what pin(s) is used for the
> output signal.
>
> Typically the main v4l2 driver will map a user-level input (as set with
> VIDIOC_S_INPUT) to the low-level routing information and pass that on to
> the i2c device using VIDIOC_INT_S_VIDEO_ROUTING.
>
> Regards,
>
>        Hans
>
>> What exactly I need is "how to make switchable with multiple camera as
>> an input for camera interface", which means just about an input
>> device. In my opinion, those are different issues each other..(Am I
>> right?)
>> Cheers,
>>
>> Nate
>>
>> On Tue, Mar 3, 2009 at 12:53 PM, Hiremath, Vaibhav <hvaibhav@ti.com>
> wrote:
>> > Thanks,
>> > Vaibhav Hiremath
>> >
>> >> -----Original Message-----
>> >> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>> >> owner@vger.kernel.org] On Behalf Of DongSoo(Nathaniel) Kim
>> >> Sent: Tuesday, March 03, 2009 8:18 AM
>> >> To: Tuukka.O Toivonen
>> >> Cc: Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
>> >> Ailus Sakari (Nokia-D/Helsinki); Nagalla, Hari
>> >> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
>> >>
>> >> Hi Tuukka,
>> >>
>> >> I understand that it is a huge thing to support VIDIOC_S_INPUT.
>> >> But without that, we don't have any proper "V4L2" api to get
>> >> information about how many devices are attached to camera interface,
>> >> and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
>> >> VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can
>> >> refer
>> >> to sysfs, but using only single set of APIs like V4L2 looks more
>> >> decent.
>> >>
>> >> What do you think about this?
>> >> If you think that it is a big burden, can I make a patch for this?
>> >> Cheers,
>> >
>> > [Hiremath, Vaibhav] You may want to refer to the thread on this
>> > subject.
>> >
>> > http://marc.info/?l=linux-omap&m=122772175002777&w=2
>> > http://marc.info/?l=linux-omap&m=122823846806440&w=2
>> >
>> >> Nate
>> >>
>> >> On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
>> >>
>> >> <tuukka.o.toivonen@nokia.com> wrote:
>> >> > On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim
>> >>
>> >> wrote:
>> >> >> So, logically it does not make sense with making device nodes of
>> >>
>> >> every
>> >>
>> >> >> single slave attached with OMAP3camera interface. Because they
>> >>
>> >> can't
>> >>
>> >> >> be opened at the same time,even if it is possible it should not
>> >>
>> >> work
>> >>
>> >> >> properly.
>> >> >>
>> >> >> So.. how about making only single device node like /dev/video0
>> >>
>> >> for
>> >>
>> >> >> OMAP3 camera interface and make it switchable through V4L2 API.
>> >>
>> >> Like
>> >>
>> >> >> VIDIOC_S_INPUT?
>> >> >
>> >> > You are right that if the OMAP3 has several camera sensors
>> >>
>> >> attached
>> >>
>> >> > to its camera interface, generally just one can be used at once.
>> >> >
>> >> > However, from user's perspective those are still distinct
>> >> > cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
>> >> > or at least it will be more difficult to use than just pointing
>> >> > an app to the correct video device. Logically they are two
>> >> > independent cameras, which can't be used simultaneously
>> >> > due to HW restrictions.
>> >> >
>> >> > - Tuukka
>> >>
>> >> --
>> >> ========================================================
>> >> DongSoo(Nathaniel), Kim
>> >> Engineer
>> >> Mobile S/W Platform Lab. S/W centre
>> >> Telecommunication R&D Centre
>> >> Samsung Electronics CO., LTD.
>> >> e-mail : dongsoo.kim@gmail.com
>> >>           dongsoo45.kim@samsung.com
>> >> ========================================================
>> >> --
>> >> To unsubscribe from this list: send the line "unsubscribe linux-
>> >> omap" in
>> >> the body of a message to majordomo@vger.kernel.org
>> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>
> --
> Hans Verkuil - video4linux developer - sponsored by TANDBERG
>



-- 
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
          dongsoo45.kim@samsung.com
========================================================
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-03  7:25         ` Sakari Ailus
@ 2009-03-03  7:40           ` DongSoo(Nathaniel) Kim
  0 siblings, 0 replies; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-03-03  7:40 UTC (permalink / raw)
  To: sakari.ailus
  Cc: Toivonen Tuukka.O (Nokia-D/Oulu),
	Aguirre Rodriguez, Sergio Alberto, linux-omap, Nagalla, Hari

Hello Sakari,

Let me explain what I want to do.
First of all, I need to make it clear that I'm not using bare sensors
with omap3, but I'm using ISP included camera modules. To be more
clear I can take a 3G handset for instance, which has dual cameras on
it.
Each camera has their own ISP on them, and they share omap3 camera
data pins and clock/sync pins also.

So, I need a API to switch between two of them because OMAP3 can't
handle every data from each camera at once.

To be honest, I definitely thought that VIDIOC_S_INPUT is the proper
API for that ;(
But now I'm quite confused.

Regards,

Nate



On Tue, Mar 3, 2009 at 4:25 PM, Sakari Ailus <sakari.ailus@nokia.com> wrote:
> DongSoo(Nathaniel) Kim wrote:
>>
>> Hi Tuukka,
>>
>> I understand that it is a huge thing to support VIDIOC_S_INPUT.
>
> It might not be that much, in case it's supported by just one slave.
>
>> But without that, we don't have any proper "V4L2" api to get
>> information about how many devices are attached to camera interface,
>> and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
>> VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can refer
>> to sysfs, but using only single set of APIs like V4L2 looks more
>> decent.
>>
>> What do you think about this?
>> If you think that it is a big burden, can I make a patch for this?
>
> I'm just wondering the purpose --- as Tuukka explained, the ISP block
> doesn't make a camera, but a sensor essentially does. So for every sensor
> there's a video device, even if they are implemented by using just one ISP.
> How does this sound like?
>
> But for video decoders at least it's definitely meaningful to support
> VIDIOC_S_INPUT.
>
> --
> Sakari Ailus
> sakari.ailus@maxwell.research.nokia.com
>



-- 
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
          dongsoo45.kim@samsung.com
========================================================

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-03  5:13             ` DongSoo(Nathaniel) Kim
  (?)
  (?)
@ 2009-03-03  7:38             ` Sakari Ailus
  -1 siblings, 0 replies; 43+ messages in thread
From: Sakari Ailus @ 2009-03-03  7:38 UTC (permalink / raw)
  To: DongSoo(Nathaniel) Kim
  Cc: Hiremath, Vaibhav, Toivonen Tuukka.O (Nokia-D/Oulu),
	Aguirre Rodriguez, Sergio Alberto, linux-omap, Nagalla, Hari,
	linux-media

DongSoo(Nathaniel) Kim wrote:
> This is quite confusing because in case of mine, I wanna make
> switchable between different cameras attached to omap camera
> interface.

Currently the ISP doesn't have a very neat way of controlling its use. 
In the recent patches, there's a change that allows just one isp_get() 
--- subsequent calls return -EBUSY.

So in practice, if you open the first device, you can't open the second 
one before the first one is closed. That's not very elegant but at least 
it prevents problematic concurrent access to the ISP.

In theory (AFAIK) the ISP *can* be used to receive data from multiple 
sources at the same time, but there are limitations.

In practice, if you have a hardware mux, you can switch it to a specific 
sensor when the camera driver tells the slave to go to some state that's 
not V4L2_POWER_OFF.

> Which idea do I have to follow? Comparing with multiple video input
> devices and multiple cameras attached to single camera interface is
> giving me no answer.
> 
> Perhaps multiple cameras with single camera interface couldn't make
> sense at the first place because single camera interface can go with
> only one camera module at one time.
> But we are using like that. I mean dual cameras with single camera
> interface. There is no choice except that when we are using dual
> camera without stereo camera controller.

Yup, I know, some mobile devices have front and back cameras. :)

> By the way, I cannot find any API documents about
> VIDIOC_INT_S_VIDEO_ROUTING but it seems to be all about "how to route
> between input device with output device".

That, I guess, is meant for video output devices.

> What exactly I need is "how to make switchable with multiple camera as
> an input for camera interface", which means just about an input
> device. In my opinion, those are different issues each other..(Am I
> right?)
> Cheers,


-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-03  5:13             ` DongSoo(Nathaniel) Kim
@ 2009-03-03  7:36               ` Hans Verkuil
  -1 siblings, 0 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-03-03  7:36 UTC (permalink / raw)
  To: DongSoo(Nathaniel) Kim
  Cc: Hiremath, Vaibhav, Tuukka.O Toivonen, Aguirre Rodriguez,
	Sergio Alberto, linux-omap, Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari, linux-media

On Tuesday 03 March 2009 06:13:11 DongSoo(Nathaniel) Kim wrote:
> Thank you for your reply.
>
> This is quite confusing because in case of mine, I wanna make
> switchable between different cameras attached to omap camera
> interface.
> Which idea do I have to follow? Comparing with multiple video input
> devices and multiple cameras attached to single camera interface is
> giving me no answer.
>
> Perhaps multiple cameras with single camera interface couldn't make
> sense at the first place because single camera interface can go with
> only one camera module at one time.
> But we are using like that. I mean dual cameras with single camera
> interface. There is no choice except that when we are using dual
> camera without stereo camera controller.

If you have multiple inputs (cameras in this case) that the user can choose 
from, then you need to implement S_INPUT/G_INPUT/ENUMINPUTS. That's what 
they are there for. Any decent V4L2 app should support these ioctls.

> By the way, I cannot find any API documents about
> VIDIOC_INT_S_VIDEO_ROUTING but it seems to be all about "how to route
> between input device with output device".

The description of this internal ioctl is in v4l2-common.h. It is used to 
tell the i2c module how it is hooked up to the rest of the system. I.e. 
what pin(s) is used for the input signal and what pin(s) is used for the 
output signal.

Typically the main v4l2 driver will map a user-level input (as set with 
VIDIOC_S_INPUT) to the low-level routing information and pass that on to 
the i2c device using VIDIOC_INT_S_VIDEO_ROUTING.

Regards,

	Hans

> What exactly I need is "how to make switchable with multiple camera as
> an input for camera interface", which means just about an input
> device. In my opinion, those are different issues each other..(Am I
> right?)
> Cheers,
>
> Nate
>
> On Tue, Mar 3, 2009 at 12:53 PM, Hiremath, Vaibhav <hvaibhav@ti.com> 
wrote:
> > Thanks,
> > Vaibhav Hiremath
> >
> >> -----Original Message-----
> >> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> >> owner@vger.kernel.org] On Behalf Of DongSoo(Nathaniel) Kim
> >> Sent: Tuesday, March 03, 2009 8:18 AM
> >> To: Tuukka.O Toivonen
> >> Cc: Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
> >> Ailus Sakari (Nokia-D/Helsinki); Nagalla, Hari
> >> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> >>
> >> Hi Tuukka,
> >>
> >> I understand that it is a huge thing to support VIDIOC_S_INPUT.
> >> But without that, we don't have any proper "V4L2" api to get
> >> information about how many devices are attached to camera interface,
> >> and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
> >> VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can
> >> refer
> >> to sysfs, but using only single set of APIs like V4L2 looks more
> >> decent.
> >>
> >> What do you think about this?
> >> If you think that it is a big burden, can I make a patch for this?
> >> Cheers,
> >
> > [Hiremath, Vaibhav] You may want to refer to the thread on this
> > subject.
> >
> > http://marc.info/?l=linux-omap&m=122772175002777&w=2
> > http://marc.info/?l=linux-omap&m=122823846806440&w=2
> >
> >> Nate
> >>
> >> On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
> >>
> >> <tuukka.o.toivonen@nokia.com> wrote:
> >> > On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim
> >>
> >> wrote:
> >> >> So, logically it does not make sense with making device nodes of
> >>
> >> every
> >>
> >> >> single slave attached with OMAP3camera interface. Because they
> >>
> >> can't
> >>
> >> >> be opened at the same time,even if it is possible it should not
> >>
> >> work
> >>
> >> >> properly.
> >> >>
> >> >> So.. how about making only single device node like /dev/video0
> >>
> >> for
> >>
> >> >> OMAP3 camera interface and make it switchable through V4L2 API.
> >>
> >> Like
> >>
> >> >> VIDIOC_S_INPUT?
> >> >
> >> > You are right that if the OMAP3 has several camera sensors
> >>
> >> attached
> >>
> >> > to its camera interface, generally just one can be used at once.
> >> >
> >> > However, from user's perspective those are still distinct
> >> > cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
> >> > or at least it will be more difficult to use than just pointing
> >> > an app to the correct video device. Logically they are two
> >> > independent cameras, which can't be used simultaneously
> >> > due to HW restrictions.
> >> >
> >> > - Tuukka
> >>
> >> --
> >> ========================================================
> >> DongSoo(Nathaniel), Kim
> >> Engineer
> >> Mobile S/W Platform Lab. S/W centre
> >> Telecommunication R&D Centre
> >> Samsung Electronics CO., LTD.
> >> e-mail : dongsoo.kim@gmail.com
> >>           dongsoo45.kim@samsung.com
> >> ========================================================
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-
> >> omap" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2009-03-03  7:36               ` Hans Verkuil
  0 siblings, 0 replies; 43+ messages in thread
From: Hans Verkuil @ 2009-03-03  7:36 UTC (permalink / raw)
  To: DongSoo(Nathaniel) Kim
  Cc: Hiremath, Vaibhav, Tuukka.O Toivonen, Aguirre Rodriguez,
	Sergio Alberto, linux-omap, Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari, linux-media

On Tuesday 03 March 2009 06:13:11 DongSoo(Nathaniel) Kim wrote:
> Thank you for your reply.
>
> This is quite confusing because in case of mine, I wanna make
> switchable between different cameras attached to omap camera
> interface.
> Which idea do I have to follow? Comparing with multiple video input
> devices and multiple cameras attached to single camera interface is
> giving me no answer.
>
> Perhaps multiple cameras with single camera interface couldn't make
> sense at the first place because single camera interface can go with
> only one camera module at one time.
> But we are using like that. I mean dual cameras with single camera
> interface. There is no choice except that when we are using dual
> camera without stereo camera controller.

If you have multiple inputs (cameras in this case) that the user can choose 
from, then you need to implement S_INPUT/G_INPUT/ENUMINPUTS. That's what 
they are there for. Any decent V4L2 app should support these ioctls.

> By the way, I cannot find any API documents about
> VIDIOC_INT_S_VIDEO_ROUTING but it seems to be all about "how to route
> between input device with output device".

The description of this internal ioctl is in v4l2-common.h. It is used to 
tell the i2c module how it is hooked up to the rest of the system. I.e. 
what pin(s) is used for the input signal and what pin(s) is used for the 
output signal.

Typically the main v4l2 driver will map a user-level input (as set with 
VIDIOC_S_INPUT) to the low-level routing information and pass that on to 
the i2c device using VIDIOC_INT_S_VIDEO_ROUTING.

Regards,

	Hans

> What exactly I need is "how to make switchable with multiple camera as
> an input for camera interface", which means just about an input
> device. In my opinion, those are different issues each other..(Am I
> right?)
> Cheers,
>
> Nate
>
> On Tue, Mar 3, 2009 at 12:53 PM, Hiremath, Vaibhav <hvaibhav@ti.com> 
wrote:
> > Thanks,
> > Vaibhav Hiremath
> >
> >> -----Original Message-----
> >> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> >> owner@vger.kernel.org] On Behalf Of DongSoo(Nathaniel) Kim
> >> Sent: Tuesday, March 03, 2009 8:18 AM
> >> To: Tuukka.O Toivonen
> >> Cc: Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
> >> Ailus Sakari (Nokia-D/Helsinki); Nagalla, Hari
> >> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> >>
> >> Hi Tuukka,
> >>
> >> I understand that it is a huge thing to support VIDIOC_S_INPUT.
> >> But without that, we don't have any proper "V4L2" api to get
> >> information about how many devices are attached to camera interface,
> >> and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
> >> VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can
> >> refer
> >> to sysfs, but using only single set of APIs like V4L2 looks more
> >> decent.
> >>
> >> What do you think about this?
> >> If you think that it is a big burden, can I make a patch for this?
> >> Cheers,
> >
> > [Hiremath, Vaibhav] You may want to refer to the thread on this
> > subject.
> >
> > http://marc.info/?l=linux-omap&m=122772175002777&w=2
> > http://marc.info/?l=linux-omap&m=122823846806440&w=2
> >
> >> Nate
> >>
> >> On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
> >>
> >> <tuukka.o.toivonen@nokia.com> wrote:
> >> > On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim
> >>
> >> wrote:
> >> >> So, logically it does not make sense with making device nodes of
> >>
> >> every
> >>
> >> >> single slave attached with OMAP3camera interface. Because they
> >>
> >> can't
> >>
> >> >> be opened at the same time,even if it is possible it should not
> >>
> >> work
> >>
> >> >> properly.
> >> >>
> >> >> So.. how about making only single device node like /dev/video0
> >>
> >> for
> >>
> >> >> OMAP3 camera interface and make it switchable through V4L2 API.
> >>
> >> Like
> >>
> >> >> VIDIOC_S_INPUT?
> >> >
> >> > You are right that if the OMAP3 has several camera sensors
> >>
> >> attached
> >>
> >> > to its camera interface, generally just one can be used at once.
> >> >
> >> > However, from user's perspective those are still distinct
> >> > cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
> >> > or at least it will be more difficult to use than just pointing
> >> > an app to the correct video device. Logically they are two
> >> > independent cameras, which can't be used simultaneously
> >> > due to HW restrictions.
> >> >
> >> > - Tuukka
> >>
> >> --
> >> ========================================================
> >> DongSoo(Nathaniel), Kim
> >> Engineer
> >> Mobile S/W Platform Lab. S/W centre
> >> Telecommunication R&D Centre
> >> Samsung Electronics CO., LTD.
> >> e-mail : dongsoo.kim@gmail.com
> >>           dongsoo45.kim@samsung.com
> >> ========================================================
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-
> >> omap" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-03  2:48       ` DongSoo(Nathaniel) Kim
  2009-03-03  3:53         ` Hiremath, Vaibhav
@ 2009-03-03  7:25         ` Sakari Ailus
  2009-03-03  7:40           ` DongSoo(Nathaniel) Kim
  1 sibling, 1 reply; 43+ messages in thread
From: Sakari Ailus @ 2009-03-03  7:25 UTC (permalink / raw)
  To: DongSoo(Nathaniel) Kim
  Cc: Toivonen Tuukka.O (Nokia-D/Oulu),
	Aguirre Rodriguez, Sergio Alberto, linux-omap, Nagalla, Hari

DongSoo(Nathaniel) Kim wrote:
> Hi Tuukka,
> 
> I understand that it is a huge thing to support VIDIOC_S_INPUT.

It might not be that much, in case it's supported by just one slave.

> But without that, we don't have any proper "V4L2" api to get
> information about how many devices are attached to camera interface,
> and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
> VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can refer
> to sysfs, but using only single set of APIs like V4L2 looks more
> decent.
> 
> What do you think about this?
> If you think that it is a big burden, can I make a patch for this?

I'm just wondering the purpose --- as Tuukka explained, the ISP block 
doesn't make a camera, but a sensor essentially does. So for every 
sensor there's a video device, even if they are implemented by using 
just one ISP. How does this sound like?

But for video decoders at least it's definitely meaningful to support 
VIDIOC_S_INPUT.

-- 
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-03  3:53         ` Hiremath, Vaibhav
@ 2009-03-03  5:13             ` DongSoo(Nathaniel) Kim
  0 siblings, 0 replies; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-03-03  5:13 UTC (permalink / raw)
  To: Hiremath, Vaibhav
  Cc: Tuukka.O Toivonen, Aguirre Rodriguez, Sergio Alberto, linux-omap,
	Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari, linux-media

Thank you for your reply.

This is quite confusing because in case of mine, I wanna make
switchable between different cameras attached to omap camera
interface.
Which idea do I have to follow? Comparing with multiple video input
devices and multiple cameras attached to single camera interface is
giving me no answer.

Perhaps multiple cameras with single camera interface couldn't make
sense at the first place because single camera interface can go with
only one camera module at one time.
But we are using like that. I mean dual cameras with single camera
interface. There is no choice except that when we are using dual
camera without stereo camera controller.

By the way, I cannot find any API documents about
VIDIOC_INT_S_VIDEO_ROUTING but it seems to be all about "how to route
between input device with output device".
What exactly I need is "how to make switchable with multiple camera as
an input for camera interface", which means just about an input
device. In my opinion, those are different issues each other..(Am I
right?)
Cheers,

Nate


On Tue, Mar 3, 2009 at 12:53 PM, Hiremath, Vaibhav <hvaibhav@ti.com> wrote:
>
>
> Thanks,
> Vaibhav Hiremath
>
>> -----Original Message-----
>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>> owner@vger.kernel.org] On Behalf Of DongSoo(Nathaniel) Kim
>> Sent: Tuesday, March 03, 2009 8:18 AM
>> To: Tuukka.O Toivonen
>> Cc: Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
>> Ailus Sakari (Nokia-D/Helsinki); Nagalla, Hari
>> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
>>
>> Hi Tuukka,
>>
>> I understand that it is a huge thing to support VIDIOC_S_INPUT.
>> But without that, we don't have any proper "V4L2" api to get
>> information about how many devices are attached to camera interface,
>> and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
>> VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can
>> refer
>> to sysfs, but using only single set of APIs like V4L2 looks more
>> decent.
>>
>> What do you think about this?
>> If you think that it is a big burden, can I make a patch for this?
>> Cheers,
>>
> [Hiremath, Vaibhav] You may want to refer to the thread on this subject.
>
> http://marc.info/?l=linux-omap&m=122772175002777&w=2
> http://marc.info/?l=linux-omap&m=122823846806440&w=2
>
>> Nate
>>
>> On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
>> <tuukka.o.toivonen@nokia.com> wrote:
>> > On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim
>> wrote:
>> >> So, logically it does not make sense with making device nodes of
>> every
>> >> single slave attached with OMAP3camera interface. Because they
>> can't
>> >> be opened at the same time,even if it is possible it should not
>> work
>> >> properly.
>> >>
>> >> So.. how about making only single device node like /dev/video0
>> for
>> >> OMAP3 camera interface and make it switchable through V4L2 API.
>> Like
>> >> VIDIOC_S_INPUT?
>> >
>> > You are right that if the OMAP3 has several camera sensors
>> attached
>> > to its camera interface, generally just one can be used at once.
>> >
>> > However, from user's perspective those are still distinct
>> > cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
>> > or at least it will be more difficult to use than just pointing
>> > an app to the correct video device. Logically they are two
>> > independent cameras, which can't be used simultaneously
>> > due to HW restrictions.
>> >
>> > - Tuukka
>> >
>>
>>
>>
>> --
>> ========================================================
>> DongSoo(Nathaniel), Kim
>> Engineer
>> Mobile S/W Platform Lab. S/W centre
>> Telecommunication R&D Centre
>> Samsung Electronics CO., LTD.
>> e-mail : dongsoo.kim@gmail.com
>>           dongsoo45.kim@samsung.com
>> ========================================================
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-
>> omap" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>



-- 
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
          dongsoo45.kim@samsung.com
========================================================

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2009-03-03  5:13             ` DongSoo(Nathaniel) Kim
  0 siblings, 0 replies; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-03-03  5:13 UTC (permalink / raw)
  To: Hiremath, Vaibhav
  Cc: Tuukka.O Toivonen, Aguirre Rodriguez, Sergio Alberto, linux-omap,
	Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari, linux-media

Thank you for your reply.

This is quite confusing because in case of mine, I wanna make
switchable between different cameras attached to omap camera
interface.
Which idea do I have to follow? Comparing with multiple video input
devices and multiple cameras attached to single camera interface is
giving me no answer.

Perhaps multiple cameras with single camera interface couldn't make
sense at the first place because single camera interface can go with
only one camera module at one time.
But we are using like that. I mean dual cameras with single camera
interface. There is no choice except that when we are using dual
camera without stereo camera controller.

By the way, I cannot find any API documents about
VIDIOC_INT_S_VIDEO_ROUTING but it seems to be all about "how to route
between input device with output device".
What exactly I need is "how to make switchable with multiple camera as
an input for camera interface", which means just about an input
device. In my opinion, those are different issues each other..(Am I
right?)
Cheers,

Nate


On Tue, Mar 3, 2009 at 12:53 PM, Hiremath, Vaibhav <hvaibhav@ti.com> wrote:
>
>
> Thanks,
> Vaibhav Hiremath
>
>> -----Original Message-----
>> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
>> owner@vger.kernel.org] On Behalf Of DongSoo(Nathaniel) Kim
>> Sent: Tuesday, March 03, 2009 8:18 AM
>> To: Tuukka.O Toivonen
>> Cc: Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
>> Ailus Sakari (Nokia-D/Helsinki); Nagalla, Hari
>> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
>>
>> Hi Tuukka,
>>
>> I understand that it is a huge thing to support VIDIOC_S_INPUT.
>> But without that, we don't have any proper "V4L2" api to get
>> information about how many devices are attached to camera interface,
>> and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
>> VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can
>> refer
>> to sysfs, but using only single set of APIs like V4L2 looks more
>> decent.
>>
>> What do you think about this?
>> If you think that it is a big burden, can I make a patch for this?
>> Cheers,
>>
> [Hiremath, Vaibhav] You may want to refer to the thread on this subject.
>
> http://marc.info/?l=linux-omap&m=122772175002777&w=2
> http://marc.info/?l=linux-omap&m=122823846806440&w=2
>
>> Nate
>>
>> On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
>> <tuukka.o.toivonen@nokia.com> wrote:
>> > On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim
>> wrote:
>> >> So, logically it does not make sense with making device nodes of
>> every
>> >> single slave attached with OMAP3camera interface. Because they
>> can't
>> >> be opened at the same time,even if it is possible it should not
>> work
>> >> properly.
>> >>
>> >> So.. how about making only single device node like /dev/video0
>> for
>> >> OMAP3 camera interface and make it switchable through V4L2 API.
>> Like
>> >> VIDIOC_S_INPUT?
>> >
>> > You are right that if the OMAP3 has several camera sensors
>> attached
>> > to its camera interface, generally just one can be used at once.
>> >
>> > However, from user's perspective those are still distinct
>> > cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
>> > or at least it will be more difficult to use than just pointing
>> > an app to the correct video device. Logically they are two
>> > independent cameras, which can't be used simultaneously
>> > due to HW restrictions.
>> >
>> > - Tuukka
>> >
>>
>>
>>
>> --
>> ========================================================
>> DongSoo(Nathaniel), Kim
>> Engineer
>> Mobile S/W Platform Lab. S/W centre
>> Telecommunication R&D Centre
>> Samsung Electronics CO., LTD.
>> e-mail : dongsoo.kim@gmail.com
>>           dongsoo45.kim@samsung.com
>> ========================================================
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-
>> omap" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>



-- 
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
          dongsoo45.kim@samsung.com
========================================================
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-03-03  2:48       ` DongSoo(Nathaniel) Kim
@ 2009-03-03  3:53         ` Hiremath, Vaibhav
  2009-03-03  5:13             ` DongSoo(Nathaniel) Kim
  2009-03-03  7:25         ` Sakari Ailus
  1 sibling, 1 reply; 43+ messages in thread
From: Hiremath, Vaibhav @ 2009-03-03  3:53 UTC (permalink / raw)
  To: DongSoo(Nathaniel) Kim, Tuukka.O Toivonen
  Cc: Aguirre Rodriguez, Sergio Alberto, linux-omap,
	Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari



Thanks,
Vaibhav Hiremath

> -----Original Message-----
> From: linux-omap-owner@vger.kernel.org [mailto:linux-omap-
> owner@vger.kernel.org] On Behalf Of DongSoo(Nathaniel) Kim
> Sent: Tuesday, March 03, 2009 8:18 AM
> To: Tuukka.O Toivonen
> Cc: Aguirre Rodriguez, Sergio Alberto; linux-omap@vger.kernel.org;
> Ailus Sakari (Nokia-D/Helsinki); Nagalla, Hari
> Subject: Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
> 
> Hi Tuukka,
> 
> I understand that it is a huge thing to support VIDIOC_S_INPUT.
> But without that, we don't have any proper "V4L2" api to get
> information about how many devices are attached to camera interface,
> and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
> VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can
> refer
> to sysfs, but using only single set of APIs like V4L2 looks more
> decent.
> 
> What do you think about this?
> If you think that it is a big burden, can I make a patch for this?
> Cheers,
> 
[Hiremath, Vaibhav] You may want to refer to the thread on this subject.

http://marc.info/?l=linux-omap&m=122772175002777&w=2
http://marc.info/?l=linux-omap&m=122823846806440&w=2

> Nate
> 
> On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
> <tuukka.o.toivonen@nokia.com> wrote:
> > On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim
> wrote:
> >> So, logically it does not make sense with making device nodes of
> every
> >> single slave attached with OMAP3camera interface. Because they
> can't
> >> be opened at the same time,even if it is possible it should not
> work
> >> properly.
> >>
> >> So.. how about making only single device node like /dev/video0
> for
> >> OMAP3 camera interface and make it switchable through V4L2 API.
> Like
> >> VIDIOC_S_INPUT?
> >
> > You are right that if the OMAP3 has several camera sensors
> attached
> > to its camera interface, generally just one can be used at once.
> >
> > However, from user's perspective those are still distinct
> > cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
> > or at least it will be more difficult to use than just pointing
> > an app to the correct video device. Logically they are two
> > independent cameras, which can't be used simultaneously
> > due to HW restrictions.
> >
> > - Tuukka
> >
> 
> 
> 
> --
> ========================================================
> DongSoo(Nathaniel), Kim
> Engineer
> Mobile S/W Platform Lab. S/W centre
> Telecommunication R&D Centre
> Samsung Electronics CO., LTD.
> e-mail : dongsoo.kim@gmail.com
>           dongsoo45.kim@samsung.com
> ========================================================
> --
> To unsubscribe from this list: send the line "unsubscribe linux-
> omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-02-23  8:50     ` Tuukka.O Toivonen
@ 2009-03-03  2:48       ` DongSoo(Nathaniel) Kim
  2009-03-03  3:53         ` Hiremath, Vaibhav
  2009-03-03  7:25         ` Sakari Ailus
  0 siblings, 2 replies; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-03-03  2:48 UTC (permalink / raw)
  To: Tuukka.O Toivonen
  Cc: Aguirre Rodriguez, Sergio Alberto, linux-omap,
	Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari

Hi Tuukka,

I understand that it is a huge thing to support VIDIOC_S_INPUT.
But without that, we don't have any proper "V4L2" api to get
information about how many devices are attached to camera interface,
and names of input devices...and so on. Because VIDIOC_ENUMINPUT and
VIDIOC_G_INPUT needs VIDIOC_S_INPUT for prior. Of course we can refer
to sysfs, but using only single set of APIs like V4L2 looks more
decent.

What do you think about this?
If you think that it is a big burden, can I make a patch for this?
Cheers,

Nate

On Mon, Feb 23, 2009 at 5:50 PM, Tuukka.O Toivonen
<tuukka.o.toivonen@nokia.com> wrote:
> On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim wrote:
>> So, logically it does not make sense with making device nodes of every
>> single slave attached with OMAP3camera interface. Because they can't
>> be opened at the same time,even if it is possible it should not work
>> properly.
>>
>> So.. how about making only single device node like /dev/video0 for
>> OMAP3 camera interface and make it switchable through V4L2 API. Like
>> VIDIOC_S_INPUT?
>
> You are right that if the OMAP3 has several camera sensors attached
> to its camera interface, generally just one can be used at once.
>
> However, from user's perspective those are still distinct
> cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
> or at least it will be more difficult to use than just pointing
> an app to the correct video device. Logically they are two
> independent cameras, which can't be used simultaneously
> due to HW restrictions.
>
> - Tuukka
>



-- 
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
          dongsoo45.kim@samsung.com
========================================================

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2009-02-23  8:08   ` DongSoo(Nathaniel) Kim
@ 2009-02-23  8:50     ` Tuukka.O Toivonen
  2009-03-03  2:48       ` DongSoo(Nathaniel) Kim
  0 siblings, 1 reply; 43+ messages in thread
From: Tuukka.O Toivonen @ 2009-02-23  8:50 UTC (permalink / raw)
  To: ext DongSoo(Nathaniel) Kim
  Cc: Aguirre Rodriguez, Sergio Alberto, linux-omap,
	Ailus Sakari (Nokia-D/Helsinki),
	Nagalla, Hari

On Monday 23 February 2009 10:08:54 ext DongSoo(Nathaniel) Kim wrote:
> So, logically it does not make sense with making device nodes of every
> single slave attached with OMAP3camera interface. Because they can't
> be opened at the same time,even if it is possible it should not work
> properly.
> 
> So.. how about making only single device node like /dev/video0 for
> OMAP3 camera interface and make it switchable through V4L2 API. Like
> VIDIOC_S_INPUT?

You are right that if the OMAP3 has several camera sensors attached
to its camera interface, generally just one can be used at once.

However, from user's perspective those are still distinct
cameras. Many v4l2 applications don't support VIDIOC_S_INPUT
or at least it will be more difficult to use than just pointing
an app to the correct video device. Logically they are two
independent cameras, which can't be used simultaneously
due to HW restrictions.

- Tuukka

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2008-12-11 20:38 ` Aguirre Rodriguez, Sergio Alberto
  2009-02-23  8:08   ` DongSoo(Nathaniel) Kim
@ 2009-02-23  8:26   ` DongSoo(Nathaniel) Kim
  1 sibling, 0 replies; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-02-23  8:26 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: linux-omap, Sakari Ailus, Tuukka.O Toivonen, Nagalla, Hari, linux-media

Hello.

Sorry for double posting.

I've forgot adding linux-media list removing old v4l2 list.


On Fri, Dec 12, 2008 at 5:38 AM, Aguirre Rodriguez, Sergio Alberto
<saaguirre@ti.com> wrote:
> >From d5f4681ba9a74df4ea02332fe1aeccda2142a482 Mon Sep 17 00:00:00 2001
> From: Sergio Aguirre <saaguirre@ti.com>
> Date: Thu, 11 Dec 2008 13:35:47 -0600
> Subject: [PATCH] OMAP34XXCAM: Add driver
>
> Signed-off-by: Sakari Ailus <sakari.ailus@nokia.com>
> ---
>  drivers/media/video/Kconfig       |    8 +
>  drivers/media/video/Makefile      |    2 +
>  drivers/media/video/omap34xxcam.c | 2060 +++++++++++++++++++++++++++++++++++++
>  drivers/media/video/omap34xxcam.h |  221 ++++
>  4 files changed, 2291 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/video/omap34xxcam.c
>  create mode 100644 drivers/media/video/omap34xxcam.h
>
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index 6150d6f..a20a83b 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -702,6 +702,14 @@ config VIDEO_CAFE_CCIC
>
>  source "drivers/media/video/isp/Kconfig"
>
> +config VIDEO_OMAP3
> +        tristate "OMAP 3 Camera support"
> +       select VIDEOBUF_GEN
> +       select VIDEOBUF_DMA_SG
> +       depends on VIDEO_V4L2 && ARCH_OMAP34XX
> +       ---help---
> +         Driver for an OMAP 3 camera controller.
> +
>  config SOC_CAMERA
>        tristate "SoC camera support"
>        depends on VIDEO_V4L2 && HAS_DMA
> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
> index 16962f3..a2f73cf 100644
> --- a/drivers/media/video/Makefile
> +++ b/drivers/media/video/Makefile
> @@ -101,6 +101,8 @@ obj-$(CONFIG_VIDEO_OV7670)  += ov7670.o
>
>  obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
>
> +obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o isp/
> +
>  obj-$(CONFIG_USB_DABUSB)        += dabusb.o
>  obj-$(CONFIG_USB_OV511)         += ov511.o
>  obj-$(CONFIG_USB_SE401)         += se401.o
> diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
> new file mode 100644
> index 0000000..31b6b60
> --- /dev/null
> +++ b/drivers/media/video/omap34xxcam.c
> @@ -0,0 +1,2060 @@
> +/*
> + * drivers/media/video/omap34xxcam.c
> + *
> + * Copyright (C) 2006--2008 Nokia Corporation
> + * Copyright (C) 2007, 2008 Texas Instruments
> + *
> + * Contact: Sakari Ailus <sakari.ailus@nokia.com>
> + *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *
> + * Originally based on the OMAP 2 camera driver.
> + *
> + * Written by Sakari Ailus <sakari.ailus@nokia.com>
> + *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *            Sergio Aguirre <saaguirre@ti.com>
> + *            Mohit Jalori
> + *            Sameer Venkatraman
> + *            Leonides Martinez
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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 St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/pci.h>         /* needed for videobufs */
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/interrupt.h>
> +#include <linux/videodev2.h>
> +#include <linux/version.h>
> +#include <linux/platform_device.h>
> +
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-ioctl.h>
> +
> +#include "omap34xxcam.h"
> +#include "isp/isp.h"
> +#include "isp/ispmmu.h"
> +#include "isp/ispreg.h"
> +#include "isp/ispccdc.h"
> +#include "isp/isph3a.h"
> +#include "isp/isp_af.h"
> +#include "isp/isphist.h"
> +#include "isp/isppreview.h"
> +#include "isp/ispresizer.h"
> +
> +#define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
> +
> +/* global variables */
> +static struct omap34xxcam_device *omap34xxcam;
> +
> +struct omap34xxcam_fh *camfh_saved;
> +
> +#define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ)
> +
> +/*
> + *
> + * Sensor handling.
> + *
> + */
> +
> +/**
> + * omap34xxcam_slave_power_set - set slave power state
> + * @vdev: per-video device data structure
> + * @power: new power state
> + */
> +static int omap34xxcam_slave_power_set(struct omap34xxcam_videodev *vdev,
> +                                      enum v4l2_power power,
> +                                      int mask)
> +{
> +       int rval = 0, i = 0;
> +
> +       BUG_ON(!mutex_is_locked(&vdev->mutex));
> +
> +       vdev->power_state_wish = -1;
> +
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               if (vdev->slave[i] == v4l2_int_device_dummy())
> +                       continue;
> +
> +               if (!(mask & (1 << i))
> +                   || power == vdev->power_state[i])
> +                       continue;
> +
> +               rval = vidioc_int_s_power(vdev->slave[i], power);
> +
> +               if (rval && power != V4L2_POWER_OFF) {
> +                       power = V4L2_POWER_OFF;
> +                       goto out;
> +               }
> +
> +               vdev->power_state[i] = power;
> +       }
> +
> +       return 0;
> +
> +out:
> +       for (i--; i >= 0; i--) {
> +               if (vdev->slave[i] == v4l2_int_device_dummy())
> +                       continue;
> +
> +               if (!(mask & (1 << i)))
> +                       continue;
> +
> +               vidioc_int_s_power(vdev->slave[i], power);
> +               vdev->power_state[i] = power;
> +       }
> +
> +       return rval;
> +}
> +
> +static void omap34xxcam_slave_power_work(struct work_struct *work)
> +{
> +       struct omap34xxcam_videodev *vdev =
> +               container_of(work, struct omap34xxcam_videodev, poweroff_work);
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->power_state_wish != -1)
> +               omap34xxcam_slave_power_set(vdev, vdev->power_state_wish,
> +                                           vdev->power_state_mask);
> +
> +       mutex_unlock(&vdev->mutex);
> +}
> +
> +static void omap34xxcam_slave_power_timer(unsigned long ptr)
> +{
> +       struct omap34xxcam_videodev *vdev = (void *)ptr;
> +
> +       schedule_work(&vdev->poweroff_work);
> +}
> +
> +/**
> + * omap34xxcam_slave_power_suggest - delayed power state change
> + *
> + * @vdev: per-video device data structure
> + * @power: new power state
> + */
> +static void omap34xxcam_slave_power_suggest(struct omap34xxcam_videodev *vdev,
> +                                           enum v4l2_power power,
> +                                           int mask)
> +{
> +       BUG_ON(!mutex_is_locked(&vdev->mutex));
> +
> +       del_timer(&vdev->poweroff_timer);
> +
> +       vdev->power_state_wish = power;
> +       vdev->power_state_mask = mask;
> +
> +       mod_timer(&vdev->poweroff_timer, jiffies + OMAP34XXCAM_POWEROFF_DELAY);
> +}
> +
> +/**
> + * omap34xxcam_update_vbq - Updates VBQ with completed input buffer
> + * @vb: ptr. to standard V4L2 video buffer structure
> + *
> + * Updates video buffer queue with completed buffer passed as
> + * input parameter.  Also updates ISP H3A timestamp and field count
> + * statistics.
> + */
> +int omap34xxcam_update_vbq(struct videobuf_buffer *vb)
> +{
> +       struct omap34xxcam_fh *fh = camfh_saved;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       int rval = 0;
> +
> +       do_gettimeofday(&vb->ts);
> +       vb->field_count = atomic_add_return(2, &fh->field_count);
> +       vb->state = VIDEOBUF_DONE;
> +
> +       if (vdev->streaming)
> +               rval = 1;
> +
> +       wake_up(&vb->done);
> +
> +       return rval;
> +}
> +
> +/**
> + * omap34xxcam_vbq_setup - Calcs size and num of buffs allowed in queue
> + * @vbq: ptr. to standard V4L2 video buffer queue structure
> + * @cnt: ptr to location to hold the count of buffers to be in the queue
> + * @size: ptr to location to hold the size of a frame
> + *
> + * Calculates the number of buffers of current image size that can be
> + * supported by the available capture memory.
> + */
> +static int omap34xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
> +                                unsigned int *size)
> +{
> +       struct omap34xxcam_fh *fh = vbq->priv_data;
> +
> +       if (*cnt <= 0)
> +               *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
> +
> +       if (*cnt > VIDEO_MAX_FRAME)
> +               *cnt = VIDEO_MAX_FRAME;
> +
> +       *size = fh->pix.sizeimage;
> +
> +       while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
> +               (*cnt)--;
> +
> +       while ((*size * *cnt) > ispmmu_get_mapeable_space())
> +               (*cnt)--;
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_vbq_release - Free resources for input VBQ and VB
> + * @vbq: ptr. to standard V4L2 video buffer queue structure
> + * @vb: ptr to standard V4L2 video buffer structure
> + *
> + * Unmap and free all memory associated with input VBQ and VB, also
> + * unmap the address in ISP MMU.  Reset the VB state.
> + */
> +static void omap34xxcam_vbq_release(struct videobuf_queue *vbq,
> +                                   struct videobuf_buffer *vb)
> +{
> +       if (!vbq->streaming) {
> +               isp_vbq_release(vbq, vb);
> +               videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
> +               videobuf_dma_free(videobuf_to_dma(vb));
> +               vb->state = VIDEOBUF_NEEDS_INIT;
> +       }
> +       return;
> +}
> +
> +/**
> + * omap34xxcam_vbq_prepare - V4L2 video ops buf_prepare handler
> + * @vbq: ptr. to standard V4L2 video buffer queue structure
> + * @vb: ptr to standard V4L2 video buffer structure
> + * @field: standard V4L2 field enum
> + *
> + * Verifies there is sufficient locked memory for the requested
> + * buffer, or if there is not, allocates, locks and initializes
> + * it.
> + */
> +static int omap34xxcam_vbq_prepare(struct videobuf_queue *vbq,
> +                                  struct videobuf_buffer *vb,
> +                                  enum v4l2_field field)
> +{
> +       struct omap34xxcam_fh *fh = vbq->priv_data;
> +       int err = 0;
> +
> +       /*
> +        * Accessing pix here is okay since it's constant while
> +        * streaming is on (and we only get called then).
> +        */
> +       if (vb->baddr) {
> +               /* This is a userspace buffer. */
> +               if (fh->pix.sizeimage > vb->bsize)
> +                       /* The buffer isn't big enough. */
> +                       return -EINVAL;
> +       } else {
> +               if (vb->state != VIDEOBUF_NEEDS_INIT
> +                   && fh->pix.sizeimage > vb->bsize)
> +                       /*
> +                        * We have a kernel bounce buffer that has
> +                        * already been allocated.
> +                        */
> +                       omap34xxcam_vbq_release(vbq, vb);
> +       }
> +
> +       vb->size = fh->pix.bytesperline * fh->pix.height;
> +       vb->width = fh->pix.width;
> +       vb->height = fh->pix.height;
> +       vb->field = field;
> +
> +       if (vb->state == VIDEOBUF_NEEDS_INIT) {
> +               err = videobuf_iolock(vbq, vb, NULL);
> +               if (!err) {
> +                       /* isp_addr will be stored locally inside isp code */
> +                       err = isp_vbq_prepare(vbq, vb, field);
> +               }
> +       }
> +
> +       if (!err)
> +               vb->state = VIDEOBUF_PREPARED;
> +       else
> +               omap34xxcam_vbq_release(vbq, vb);
> +
> +       return err;
> +
> +}
> +
> +/**
> + * omap34xxcam_vbq_queue - V4L2 video ops buf_queue handler
> + * @vbq: ptr. to standard V4L2 video buffer queue structure
> + * @vb: ptr to standard V4L2 video buffer structure
> + *
> + * Maps the video buffer to sgdma and through the isp, sets
> + * the isp buffer done callback and sets the video buffer state
> + * to active.
> + */
> +static void omap34xxcam_vbq_queue(struct videobuf_queue *vbq,
> +                                 struct videobuf_buffer *vb)
> +{
> +       struct omap34xxcam_fh *fh = vbq->priv_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       enum videobuf_state state = vb->state;
> +       isp_vbq_callback_ptr func_ptr;
> +       int err = 0;
> +       camfh_saved = fh;
> +
> +       func_ptr = omap34xxcam_update_vbq;
> +       vb->state = VIDEOBUF_ACTIVE;
> +
> +       err = isp_sgdma_queue(videobuf_to_dma(vb),
> +                             vb, 0, &vdev->cam->dma_notify, func_ptr);
> +       if (err) {
> +               dev_dbg(vdev->cam->dev, "vbq queue failed\n");
> +               vb->state = state;
> +       }
> +
> +}
> +
> +static struct videobuf_queue_ops omap34xxcam_vbq_ops = {
> +       .buf_setup = omap34xxcam_vbq_setup,
> +       .buf_prepare = omap34xxcam_vbq_prepare,
> +       .buf_queue = omap34xxcam_vbq_queue,
> +       .buf_release = omap34xxcam_vbq_release,
> +};
> +
> +/*
> + *
> + * IOCTL interface.
> + *
> + */
> +
> +/**
> + * vidioc_querycap - V4L2 query capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @cap: ptr to standard V4L2 capability structure
> + *
> + * Fill in the V4L2 capabliity structure for the camera device
> + */
> +static int vidioc_querycap(struct file *file, void *fh,
> +                          struct v4l2_capability *cap)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +
> +       strlcpy(cap->driver, CAM_SHORT_NAME, sizeof(cap->driver));
> +       strlcpy(cap->card, vdev->vfd->name, sizeof(cap->card));
> +       cap->version = OMAP34XXCAM_VERSION;
> +       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
> +
> +       return 0;
> +}
> +
> +/**
> + * vidioc_enum_fmt_vid_cap - V4L2 enumerate format capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @f: ptr to standard V4L2 format description structure
> + *
> + * Fills in enumerate format capabilities information for sensor (if SOC
> + * sensor attached) or ISP (if raw sensor attached).
> + */
> +static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
> +                                  struct v4l2_fmtdesc *f)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, f);
> +       else
> +               rval = isp_enum_fmt_cap(f);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_g_fmt_vid_cap - V4L2 get format capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @f: ptr to standard V4L2 format structure
> + *
> + * Fills in format capabilities for sensor (if SOC sensor attached) or ISP
> + * (if raw sensor attached).
> + */
> +static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
> +                               struct v4l2_format *f)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +
> +       mutex_lock(&vdev->mutex);
> +       f->fmt.pix = ofh->pix;
> +       mutex_unlock(&vdev->mutex);
> +
> +       return 0;
> +}
> +
> +static int try_pix_parm(struct omap34xxcam_videodev *vdev,
> +                       struct v4l2_pix_format *best_pix_in,
> +                       struct v4l2_pix_format *wanted_pix_out,
> +                       struct v4l2_fract *best_ival)
> +{
> +       int fps;
> +       int rval;
> +       int size_index;
> +       struct v4l2_pix_format best_pix_out;
> +
> +       if (best_ival->numerator == 0
> +           || best_ival->denominator == 0)
> +               best_ival->denominator = 30, best_ival->numerator = 1;
> +
> +       fps = best_ival->denominator / best_ival->numerator;
> +
> +       best_ival->denominator = 0;
> +
> +       best_pix_out.height = INT_MAX >> 1;
> +       best_pix_out.width = best_pix_out.height;
> +
> +       /*
> +        * Get supported resolutions.
> +        */
> +       for (size_index = 0; ; size_index++) {
> +               struct v4l2_frmsizeenum frms;
> +               struct v4l2_pix_format pix_tmp_in, pix_tmp_out;
> +               int ival_index;
> +
> +               frms.index = size_index;
> +               frms.pixel_format = best_pix_in->pixelformat;
> +
> +               rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, &frms);
> +               if (rval) {
> +                       rval = 0;
> +                       break;
> +               }
> +
> +               pix_tmp_in.pixelformat = frms.pixel_format;
> +               pix_tmp_in.width = frms.discrete.width;
> +               pix_tmp_in.height = frms.discrete.height;
> +               pix_tmp_out = *wanted_pix_out;
> +               /* Don't do upscaling. */
> +               if (pix_tmp_out.width > pix_tmp_in.width)
> +                       pix_tmp_out.width = pix_tmp_in.width;
> +               if (pix_tmp_out.height > pix_tmp_in.height)
> +                       pix_tmp_out.height = pix_tmp_in.height;
> +               rval = isp_try_fmt_cap(&pix_tmp_in, &pix_tmp_out);
> +               if (rval)
> +                       return rval;
> +
> +#define IS_SMALLER_OR_EQUAL(pix1, pix2)                        \
> +               ((pix1)->width + (pix1)->height         \
> +                < (pix2)->width + (pix2)->height)
> +#define SIZE_DIFF(pix1, pix2)                                  \
> +               (abs((pix1)->width - (pix2)->width)             \
> +                + abs((pix1)->height - (pix2)->height))
> +
> +               /*
> +                * Don't use modes that are farther from wanted size
> +                * that what we already got.
> +                */
> +               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
> +                   > SIZE_DIFF(&best_pix_out, wanted_pix_out))
> +                       continue;
> +
> +               /*
> +                * There's an input mode that can provide output
> +                * closer to wanted.
> +                */
> +               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
> +                   < SIZE_DIFF(&best_pix_out, wanted_pix_out))
> +                       /* Force renegotation of fps etc. */
> +                       best_ival->denominator = 0;
> +
> +               for (ival_index = 0; ; ival_index++) {
> +                       struct v4l2_frmivalenum frmi;
> +
> +                       frmi.index = ival_index;
> +                       frmi.pixel_format = frms.pixel_format;
> +                       frmi.width = frms.discrete.width;
> +                       frmi.height = frms.discrete.height;
> +                       /* FIXME: try to fix standard... */
> +                       frmi.reserved[0] = 0xdeafbeef;
> +
> +                       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor,
> +                                                             &frmi);
> +                       if (rval) {
> +                               rval = 0;
> +                               break;
> +                       }
> +
> +                       if (best_ival->denominator == 0)
> +                               goto do_it_now;
> +
> +                       /*
> +                        * We aim to use maximum resolution from the
> +                        * sensor, provided that the fps is at least
> +                        * as close as on the current mode.
> +                        */
> +#define FPS_ABS_DIFF(fps, ival) abs(fps - (ival).denominator / (ival).numerator)
> +
> +                       /* Select mode with closest fps. */
> +                       if (FPS_ABS_DIFF(fps, frmi.discrete)
> +                           < FPS_ABS_DIFF(fps, *best_ival))
> +                               goto do_it_now;
> +
> +                       /*
> +                        * Select bigger resolution if it's available
> +                        * at same fps.
> +                        */
> +                       if (frmi.width > best_pix_in->width
> +                           && FPS_ABS_DIFF(fps, frmi.discrete)
> +                           <= FPS_ABS_DIFF(fps, *best_ival))
> +                               goto do_it_now;
> +
> +                       continue;
> +
> +do_it_now:
> +                       *best_ival = frmi.discrete;
> +                       best_pix_out = pix_tmp_out;
> +                       best_pix_in->width = frmi.width;
> +                       best_pix_in->height = frmi.height;
> +                       best_pix_in->pixelformat = frmi.pixel_format;
> +               }
> +       }
> +
> +       if (best_ival->denominator == 0)
> +               return -EINVAL;
> +
> +       *wanted_pix_out = best_pix_out;
> +
> +       dev_info(vdev->cam->dev, "w %d, h %d -> w %d, h %d\n",
> +                best_pix_in->width, best_pix_in->height,
> +                best_pix_out.width, best_pix_out.height);
> +
> +       return isp_try_fmt_cap(best_pix_in, wanted_pix_out);
> +}
> +
> +static int s_pix_parm(struct omap34xxcam_videodev *vdev,
> +                     struct v4l2_pix_format *best_pix,
> +                     struct v4l2_pix_format *pix,
> +                     struct v4l2_fract *best_ival)
> +{
> +       struct v4l2_streamparm a;
> +       struct v4l2_format fmt;
> +       int rval;
> +       int fmtd_index;
> +
> +       for (fmtd_index = 0; ; fmtd_index++) {
> +               struct v4l2_fmtdesc fmtd;
> +
> +               fmtd.index = fmtd_index;
> +               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
> +               if (rval)
> +                       return rval;
> +               best_pix->pixelformat = fmtd.pixelformat;
> +
> +               rval = try_pix_parm(vdev, best_pix, pix, best_ival);
> +               if (!rval)
> +                       break;
> +       }
> +
> +       rval = isp_s_fmt_cap(best_pix, pix);
> +       if (rval)
> +               return rval;
> +
> +       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +       fmt.fmt.pix = *best_pix;
> +       rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &fmt);
> +       if (rval)
> +               return rval;
> +
> +       a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +       a.parm.capture.timeperframe = *best_ival;
> +       rval = vidioc_int_s_parm(vdev->vdev_sensor, &a);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_s_fmt_vid_cap - V4L2 set format capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @f: ptr to standard V4L2 format structure
> + *
> + * Attempts to set input format with the sensor driver (first) and then the
> + * ISP.  Returns the return code from vidioc_g_fmt_vid_cap().
> + */
> +static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
> +                               struct v4l2_format *f)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_pix_format pix_tmp;
> +       struct v4l2_fract timeperframe;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming) {
> +               rval = -EBUSY;
> +               goto out;
> +       }
> +
> +       vdev->want_pix = f->fmt.pix;
> +
> +       timeperframe = vdev->want_timeperframe;
> +
> +       rval = s_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
> +       pix_tmp = f->fmt.pix;
> +
> +out:
> +       mutex_unlock(&vdev->mutex);
> +
> +       if (!rval) {
> +               mutex_lock(&ofh->vbq.vb_lock);
> +               ofh->pix = pix_tmp;
> +               mutex_unlock(&ofh->vbq.vb_lock);
> +       }
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_try_fmt_vid_cap - V4L2 try format capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @f: ptr to standard V4L2 format structure
> + *
> + * Checks if the given format is supported by the sensor driver and
> + * by the ISP.
> + */
> +static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
> +                                 struct v4l2_format *f)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_pix_format pix_tmp;
> +       struct v4l2_fract timeperframe;
> +       int rval;
> +       int fmtd_index;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +
> +       for (fmtd_index = 0; ; fmtd_index++) {
> +               struct v4l2_fmtdesc fmtd;
> +
> +               timeperframe = vdev->want_timeperframe;
> +
> +               fmtd.index = fmtd_index;
> +               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
> +               if (rval)
> +                       return rval;
> +               pix_tmp.pixelformat = fmtd.pixelformat;
> +
> +               rval = try_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
> +               if (!rval)
> +                       break;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_reqbufs - V4L2 request buffers IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @b: ptr to standard V4L2 request buffers structure
> + *
> + * Attempts to get a buffer from the buffer queue associated with the
> + * fh through the video buffer library API.
> + */
> +static int vidioc_reqbufs(struct file *file, void *fh,
> +                         struct v4l2_requestbuffers *b)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming) {
> +               mutex_unlock(&vdev->mutex);
> +               return -EBUSY;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       rval = videobuf_reqbufs(&ofh->vbq, b);
> +
> +       /*
> +        * Either videobuf_reqbufs failed or the buffers are not
> +        * memory-mapped (which would need special attention).
> +        */
> +       if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
> +               goto out;
> +
> +out:
> +       return rval;
> +}
> +
> +/**
> + * vidioc_querybuf - V4L2 query buffer IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @b: ptr to standard V4L2 buffer structure
> + *
> + * Attempts to fill in the v4l2_buffer structure for the buffer queue
> + * associated with the fh through the video buffer library API.
> + */
> +static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +
> +       return videobuf_querybuf(&ofh->vbq, b);
> +}
> +
> +/**
> + * vidioc_qbuf - V4L2 queue buffer IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @b: ptr to standard V4L2 buffer structure
> + *
> + * Attempts to queue the v4l2_buffer on the buffer queue
> + * associated with the fh through the video buffer library API.
> + */
> +static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +
> +       return videobuf_qbuf(&ofh->vbq, b);
> +}
> +
> +/**
> + * vidioc_dqbuf - V4L2 dequeue buffer IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @b: ptr to standard V4L2 buffer structure
> + *
> + * Attempts to dequeue the v4l2_buffer from the buffer queue
> + * associated with the fh through the video buffer library API.  If the
> + * buffer is a user space buffer, then this function will also requeue it,
> + * as user does not expect to do this.
> + */
> +static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +
> +       return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
> +}
> +
> +/**
> + * vidioc_streamon - V4L2 streamon IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @i: V4L2 buffer type
> + *
> + * Attempts to start streaming by enabling the sensor interface and turning
> + * on video buffer streaming through the video buffer library API.  Upon
> + * success the function returns 0, otherwise an error code is returned.
> + */
> +static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct omap34xxcam_device *cam = vdev->cam;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming) {
> +               rval = -EBUSY;
> +               goto out;
> +       }
> +
> +       cam->dma_notify = 1;
> +       isp_sgdma_init();
> +       rval = videobuf_streamon(&ofh->vbq);
> +       if (rval) {
> +               dev_dbg(vdev->cam->dev, "omap34xxcam_slave_power_set failed\n");
> +               goto out;
> +       }
> +
> +
> +       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                          OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
> +       if (!rval) {
> +               vdev->streaming = file;
> +       } else {
> +               isp_stop();
> +               videobuf_streamoff(&ofh->vbq);
> +       }
> +
> +out:
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_streamoff - V4L2 streamoff IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @i: V4L2 buffer type
> + *
> + * Attempts to stop streaming by flushing all scheduled work, waiting on
> + * any queued buffers to complete and then stopping the ISP and turning
> + * off video buffer streaming through the video buffer library API.  Upon
> + * success the function returns 0, otherwise an error code is returned.
> + */
> +static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct videobuf_queue *q = &ofh->vbq;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->streaming == file)
> +               isp_stop();
> +
> +       rval = videobuf_streamoff(q);
> +       if (!rval)
> +               vdev->streaming = NULL;
> +
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
> +                                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +       omap34xxcam_slave_power_suggest(vdev, V4L2_POWER_STANDBY,
> +                                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_enum_input - V4L2 enumerate input IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @inp: V4L2 input type information structure
> + *
> + * Fills in v4l2_input structure.  Returns 0.
> + */
> +static int vidioc_enum_input(struct file *file, void *fh,
> +                            struct v4l2_input *inp)
> +{
> +       if (inp->index > 0)
> +               return -EINVAL;
> +
> +       strlcpy(inp->name, "camera", sizeof(inp->name));
> +       inp->type = V4L2_INPUT_TYPE_CAMERA;
> +
> +       return 0;
> +}
> +
> +/**
> + * vidioc_g_input - V4L2 get input IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @i: address to hold index of input supported
> + *
> + * Sets index to 0.
> + */
> +static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
> +{
> +       *i = 0;
> +
> +       return 0;
> +}
> +
> +/**
> + * vidioc_s_input - V4L2 set input IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @i: index of input selected
> + *
> + * 0 is only index supported.
> + */
> +static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
> +{
> +       if (i > 0)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +/**
> + * vidioc_queryctrl - V4L2 query control IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 query control ioctl structure
> + *
> + * If the requested control is supported, returns the control information
> + * in the v4l2_queryctrl structure.  Otherwise, returns -EINVAL if the
> + * control is not supported.  If the sensor being used is a "smart sensor",
> + * this request is passed to the sensor driver, otherwise the ISP is
> + * queried and if it does not support the requested control, the request
> + * is forwarded to the "raw" sensor driver to see if it supports it.
> + */
> +static int vidioc_queryctrl(struct file *file, void *fh,
> +                           struct v4l2_queryctrl *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_queryctrl a_tmp;
> +       int best_slave = -1;
> +       u32 best_ctrl = (u32)-1;
> +       int i;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               return vidioc_int_queryctrl(vdev->vdev_sensor, a);
> +
> +       /* No next flags: try slaves directly. */
> +       if (!(a->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
> +               for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +                       if (!vidioc_int_queryctrl(vdev->slave[i], a))
> +                               return 0;
> +               }
> +               return isp_queryctrl(a);
> +       }
> +
> +       /* Find slave with smallest next control id. */
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               a_tmp = *a;
> +
> +               if (vidioc_int_queryctrl(vdev->slave[i], &a_tmp))
> +                       continue;
> +
> +               if (a_tmp.id < best_ctrl) {
> +                       best_slave = i;
> +                       best_ctrl = a_tmp.id;
> +               }
> +       }
> +
> +       a_tmp = *a;
> +       if (!isp_queryctrl(&a_tmp)) {
> +               if (a_tmp.id < best_ctrl) {
> +                       *a = a_tmp;
> +
> +                       return 0;
> +               }
> +       }
> +
> +       if (best_slave == -1)
> +               return -EINVAL;
> +
> +       a->id = best_ctrl;
> +       return vidioc_int_queryctrl(vdev->slave[best_slave], a);
> +}
> +
> +/**
> + * vidioc_querymenu - V4L2 query menu IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 query menu ioctl structure
> + *
> + * If the requested control is supported, returns the menu information
> + * in the v4l2_querymenu structure.  Otherwise, returns -EINVAL if the
> + * control is not supported or is not a menu.  If the sensor being used
> + * is a "smart sensor", this request is passed to the sensor driver,
> + * otherwise the ISP is queried and if it does not support the requested
> + * menu control, the request is forwarded to the "raw" sensor driver to
> + * see if it supports it.
> + */
> +static int vidioc_querymenu(struct file *file, void *fh,
> +                           struct v4l2_querymenu *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int i;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               return vidioc_int_querymenu(vdev->vdev_sensor, a);
> +
> +       /* Try slaves directly. */
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               if (!vidioc_int_querymenu(vdev->slave[i], a))
> +                       return 0;
> +       }
> +       return -EINVAL;                 /* There is not yet isp_querymenu() */
> +}
> +
> +static int vidioc_g_ext_ctrls(struct file *file, void *fh,
> +                             struct v4l2_ext_controls *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int i, ctrl_idx, rval = 0;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
> +               struct v4l2_control ctrl;
> +
> +               ctrl.id = a->controls[ctrl_idx].id;
> +
> +               if (vdev->vdev_sensor_config.sensor_isp) {
> +                       rval = vidioc_int_g_ctrl(vdev->vdev_sensor, &ctrl);
> +               } else {
> +                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +                               rval = vidioc_int_g_ctrl(vdev->slave[i], &ctrl);
> +                               if (!rval)
> +                                       break;
> +                       }
> +               }
> +
> +               if (rval)
> +                       rval = isp_g_ctrl(&ctrl);
> +
> +               if (rval) {
> +                       a->error_idx = ctrl_idx;
> +                       break;
> +               }
> +
> +               a->controls[ctrl_idx].value = ctrl.value;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +static int vidioc_s_ext_ctrls(struct file *file, void *fh,
> +                             struct v4l2_ext_controls *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int i, ctrl_idx, rval = 0;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
> +               struct v4l2_control ctrl;
> +
> +               ctrl.id = a->controls[ctrl_idx].id;
> +               ctrl.value = a->controls[ctrl_idx].value;
> +
> +               if (vdev->vdev_sensor_config.sensor_isp) {
> +                       rval = vidioc_int_s_ctrl(vdev->vdev_sensor, &ctrl);
> +               } else {
> +                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +                               rval = vidioc_int_s_ctrl(vdev->slave[i], &ctrl);
> +                               if (!rval)
> +                                       break;
> +                       }
> +               }
> +
> +               if (rval)
> +                       rval = isp_s_ctrl(&ctrl);
> +
> +               if (rval) {
> +                       a->error_idx = ctrl_idx;
> +                       break;
> +               }
> +
> +               a->controls[ctrl_idx].value = ctrl.value;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_g_parm - V4L2 get parameters IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 stream parameters structure
> + *
> + * If request is for video capture buffer type, handles request by
> + * forwarding to sensor driver.
> + */
> +static int vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +               return -EINVAL;
> +
> +       mutex_lock(&vdev->mutex);
> +       rval = vidioc_int_g_parm(vdev->vdev_sensor, a);
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_s_parm - V4L2 set parameters IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 stream parameters structure
> + *
> + * If request is for video capture buffer type, handles request by
> + * first getting current stream parameters from sensor, then forwarding
> + * request to set new parameters to sensor driver.  It then attempts to
> + * enable the sensor interface with the new parameters.  If this fails, it
> + * reverts back to the previous parameters.
> + */
> +static int vidioc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_pix_format pix_tmp_sensor, pix_tmp;
> +       int rval;
> +
> +       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +               return -EINVAL;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming) {
> +               rval = -EBUSY;
> +               goto out;
> +       }
> +
> +       vdev->want_timeperframe = a->parm.capture.timeperframe;
> +
> +       pix_tmp = vdev->want_pix;
> +
> +       rval = s_pix_parm(vdev, &pix_tmp_sensor, &pix_tmp,
> +                         &a->parm.capture.timeperframe);
> +
> +out:
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_cropcap - V4L2 crop capture IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 crop capture structure
> + *
> + * If using a "smart" sensor, just forwards request to the sensor driver,
> + * otherwise fills in the v4l2_cropcap values locally.
> + */
> +static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_cropcap *cropcap = a;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->vdev_sensor_config.sensor_isp) {
> +               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
> +       } else {
> +               struct v4l2_format f;
> +
> +               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
> +               if (!rval)
> +                       return rval;
> +
> +               /* cropcap failed, try to do this via g_fmt_cap */
> +               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &f);
> +               if (!rval) {
> +                       cropcap->bounds.top = 0;
> +                       cropcap->bounds.left = 0;
> +                       cropcap->bounds.width = f.fmt.pix.width;
> +                       cropcap->bounds.height = f.fmt.pix.height;
> +                       cropcap->defrect = cropcap->bounds;
> +                       cropcap->pixelaspect.numerator = 1;
> +                       cropcap->pixelaspect.denominator = 1;
> +               }
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_g_crop - V4L2 get capture crop IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 crop structure
> + *
> + * If using a "smart" sensor, just forwards request to the sensor driver,
> + * otherwise calls the isp functions to fill in current crop values.
> + */
> +static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval = 0;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
> +       else
> +               rval = isp_g_crop(a);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_s_crop - V4L2 set capture crop IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 crop structure
> + *
> + * If using a "smart" sensor, just forwards request to the sensor driver,
> + * otherwise calls the isp functions to set the current crop values.
> + */
> +static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_pix_format *pix = &ofh->pix;
> +       int rval = 0;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
> +       else
> +               rval = isp_s_crop(a, pix);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +static int vidioc_enum_framesizes(struct file *file, void *fh,
> +                                 struct v4l2_frmsizeenum *frms)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       u32 pixel_format;
> +       int rval;
> +
> +       pixel_format = frms->pixel_format;
> +       frms->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
> +
> +       mutex_lock(&vdev->mutex);
> +       rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
> +       mutex_unlock(&vdev->mutex);
> +
> +       frms->pixel_format = pixel_format;
> +
> +       return rval;
> +}
> +
> +static int vidioc_enum_frameintervals(struct file *file, void *fh,
> +                                     struct v4l2_frmivalenum *frmi)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       u32 pixel_format;
> +       int rval;
> +
> +       pixel_format = frmi->pixel_format;
> +       frmi->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
> +
> +       mutex_lock(&vdev->mutex);
> +       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
> +       mutex_unlock(&vdev->mutex);
> +
> +       frmi->pixel_format = pixel_format;
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_default - private IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @cmd: ioctl cmd value
> + * @arg: ioctl arg value
> + *
> + * If the sensor being used is a "smart sensor", this request is returned to
> + * caller with -EINVAL err code.  Otherwise if the control id is the private
> + * VIDIOC_PRIVATE_ISP_AEWB_REQ to update the analog gain or exposure,
> + * then this request is forwared directly to the sensor to incorporate the
> + * feedback. The request is then passed on to the ISP private IOCTL handler,
> + * isp_handle_private()
> + */
> +static int vidioc_default(struct file *file, void *fh, int cmd, void *arg)
> +{
> +       struct omap34xxcam_fh *ofh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp) {
> +               rval = -EINVAL;
> +       } else {
> +               switch (cmd) {
> +               case VIDIOC_ENUM_FRAMESIZES:
> +                       rval = vidioc_enum_framesizes(file, fh, arg);
> +                       goto out;
> +               case VIDIOC_ENUM_FRAMEINTERVALS:
> +                       rval = vidioc_enum_frameintervals(file, fh, arg);
> +                       goto out;
> +               case VIDIOC_PRIVATE_ISP_AEWB_REQ:
> +               {
> +                       /* Need to update sensor first */
> +                       struct isph3a_aewb_data *data;
> +                       struct v4l2_control vc;
> +
> +                       data = (struct isph3a_aewb_data *) arg;
> +                       if (data->update & SET_EXPOSURE) {
> +                               vc.id = V4L2_CID_EXPOSURE;
> +                               vc.value = data->shutter;
> +                               mutex_lock(&vdev->mutex);
> +                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
> +                                                        &vc);
> +                               mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +                       if (data->update & SET_ANALOG_GAIN) {
> +                               vc.id = V4L2_CID_GAIN;
> +                               vc.value = data->gain;
> +                               mutex_lock(&vdev->mutex);
> +                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
> +                                                        &vc);
> +                               mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +               }
> +               break;
> +               case VIDIOC_PRIVATE_ISP_AF_REQ: {
> +                       /* Need to update lens first */
> +                       struct isp_af_data *data;
> +                       struct v4l2_control vc;
> +
> +                       if (!vdev->vdev_lens) {
> +                               rval = -EINVAL;
> +                               goto out;
> +                       }
> +                       data = (struct isp_af_data *) arg;
> +                       if (data->update & LENS_DESIRED_POSITION) {
> +                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
> +                               vc.value = data->desired_lens_direction;
> +                               mutex_lock(&vdev->mutex);
> +                               rval = vidioc_int_s_ctrl(vdev->vdev_lens, &vc);
> +                               mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +                       if (data->update & REQUEST_STATISTICS) {
> +                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
> +                               mutex_lock(&vdev->mutex);
> +                               rval = vidioc_int_g_ctrl(vdev->vdev_lens, &vc);
> +                               mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                               data->xtrastats.lens_position = vc.value;
> +                       }
> +               }
> +                       break;
> +               }
> +
> +               mutex_lock(&vdev->mutex);
> +               rval = isp_handle_private(cmd, arg);
> +               mutex_unlock(&vdev->mutex);
> +       }
> +out:
> +       return rval;
> +}
> +
> +/*
> + *
> + * File operations.
> + *
> + */
> +
> +static long omap34xxcam_unlocked_ioctl(struct file *file, unsigned int cmd,
> +                                      unsigned long arg)
> +{
> +       return (long)video_ioctl2(file->f_dentry->d_inode, file, cmd, arg);
> +}
> +
> +/**
> + * omap34xxcam_poll - file operations poll handler
> + * @file: ptr. to system file structure
> + * @wait: system poll table structure
> + *
> + */
> +static unsigned int omap34xxcam_poll(struct file *file,
> +                                    struct poll_table_struct *wait)
> +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       struct videobuf_buffer *vb;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming != file) {
> +               mutex_unlock(&vdev->mutex);
> +               return POLLERR;
> +       }
> +       mutex_unlock(&vdev->mutex);
> +
> +       mutex_lock(&fh->vbq.vb_lock);
> +       if (list_empty(&fh->vbq.stream)) {
> +               mutex_unlock(&fh->vbq.vb_lock);
> +               return POLLERR;
> +       }
> +       vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
> +       mutex_unlock(&fh->vbq.vb_lock);
> +
> +       poll_wait(file, &vb->done, wait);
> +
> +       if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
> +               return POLLIN | POLLRDNORM;
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_mmap - file operations mmap handler
> + * @file: ptr. to system file structure
> + * @vma: system virt. mem. area structure
> + *
> + * Maps a virtual memory area via the video buffer API
> + */
> +static int omap34xxcam_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       return videobuf_mmap_mapper(&fh->vbq, vma);
> +}
> +
> +/**
> + * omap34xxcam_open - file operations open handler
> + * @inode: ptr. to system inode structure
> + * @file: ptr. to system file structure
> + *
> + * Allocates and initializes the per-filehandle data (omap34xxcam_fh),
> + * enables the sensor, opens/initializes the ISP interface and the
> + * video buffer queue.  Note that this function will allow multiple
> + * file handles to be open simultaneously, however only the first
> + * handle opened will initialize the ISP.  It is the application
> + * responsibility to only use one handle for streaming and the others
> + * for control only.
> + * This function returns 0 upon success and -ENODEV upon error.
> + */
> +static int omap34xxcam_open(struct inode *inode, struct file *file)
> +{
> +       struct omap34xxcam_videodev *vdev = NULL;
> +       struct omap34xxcam_device *cam = omap34xxcam;
> +       struct omap34xxcam_fh *fh;
> +       struct v4l2_format format;
> +       int i;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               if (cam->vdevs[i].vfd
> +                   && cam->vdevs[i].vfd->minor == iminor(inode)) {
> +                       vdev = &cam->vdevs[i];
> +                       break;
> +               }
> +       }
> +
> +       if (!vdev || !vdev->vfd)
> +               return -ENODEV;
> +
> +       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
> +       if (fh == NULL)
> +               return -ENOMEM;
> +
> +       mutex_lock(&vdev->mutex);
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               if (vdev->slave[i] != v4l2_int_device_dummy()
> +                   && !try_module_get(vdev->slave[i]->module)) {
> +                       mutex_unlock(&vdev->mutex);
> +                       goto out_try_module_get;
> +               }
> +       }
> +
> +       if (atomic_inc_return(&vdev->users) == 1) {
> +               isp_get();
> +               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                               OMAP34XXCAM_SLAVE_POWER_ALL))
> +                       goto out_slave_power_set_standby;
> +               omap34xxcam_slave_power_set(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +               omap34xxcam_slave_power_suggest(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +       }
> +
> +       fh->vdev = vdev;
> +
> +       /* FIXME: Check that we have sensor now... */
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
> +       else
> +               isp_g_fmt_cap(&format.fmt.pix);
> +
> +       mutex_unlock(&vdev->mutex);
> +       /* FIXME: how about fh->pix when there are more users? */
> +       fh->pix = format.fmt.pix;
> +
> +       file->private_data = fh;
> +
> +       spin_lock_init(&fh->vbq_lock);
> +
> +       videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
> +                               &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
> +                               V4L2_FIELD_NONE,
> +                               sizeof(struct videobuf_buffer), fh);
> +
> +       return 0;
> +
> +out_slave_power_set_standby:
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                   OMAP34XXCAM_SLAVE_POWER_ALL);
> +       isp_put();
> +       atomic_dec(&vdev->users);
> +       mutex_unlock(&vdev->mutex);
> +
> +out_try_module_get:
> +       for (i--; i >= 0; i--)
> +               if (vdev->slave[i] != v4l2_int_device_dummy())
> +                       module_put(vdev->slave[i]->module);
> +
> +       kfree(fh);
> +
> +       return -ENODEV;
> +}
> +
> +/**
> + * omap34xxcam_release - file operations release handler
> + * @inode: ptr. to system inode structure
> + * @file: ptr. to system file structure
> + *
> + * Complement of omap34xxcam_open.  This function will flush any scheduled
> + * work, disable the sensor, close the ISP interface, stop the
> + * video buffer queue from streaming and free the per-filehandle data
> + * (omap34xxcam_fh).  Note that because multiple open file handles
> + * are allowed, this function will only close the ISP and disable the
> + * sensor when the last open file handle (by count) is closed.
> + * This function returns 0.
> + */
> +static int omap34xxcam_release(struct inode *inode, struct file *file)
> +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       int i;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming == file) {
> +               isp_stop();
> +               videobuf_streamoff(&fh->vbq);
> +               omap34xxcam_slave_power_set(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +               omap34xxcam_slave_power_suggest(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +               vdev->streaming = NULL;
> +       }
> +
> +       if (atomic_dec_return(&vdev->users) == 0) {
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                           OMAP34XXCAM_SLAVE_POWER_ALL);
> +               isp_put();
> +       }
> +       mutex_unlock(&vdev->mutex);
> +
> +       file->private_data = NULL;
> +
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
> +               if (vdev->slave[i] != v4l2_int_device_dummy())
> +                       module_put(vdev->slave[i]->module);
> +
> +       kfree(fh);
> +
> +       return 0;
> +}
> +
> +static struct file_operations omap34xxcam_fops = {
> +       .owner = THIS_MODULE,
> +       .llseek = no_llseek,
> +       .unlocked_ioctl = omap34xxcam_unlocked_ioctl,
> +       .poll = omap34xxcam_poll,
> +       .mmap = omap34xxcam_mmap,
> +       .open = omap34xxcam_open,
> +       .release = omap34xxcam_release,
> +};
> +
> +static void omap34xxcam_vfd_name_update(struct omap34xxcam_videodev *vdev)
> +{
> +       struct video_device *vfd = vdev->vfd;
> +       int i;
> +
> +       strlcpy(vfd->name, CAM_SHORT_NAME, sizeof(vfd->name));
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               strlcat(vfd->name, "/", sizeof(vfd->name));
> +               if (vdev->slave[i] == v4l2_int_device_dummy())
> +                       continue;
> +               strlcat(vfd->name, vdev->slave[i]->name, sizeof(vfd->name));
> +       }
> +       dev_info(vdev->cam->dev, "video%d is now %s\n", vfd->minor, vfd->name);
> +}
> +
> +/**
> + * omap34xxcam_device_unregister - V4L2 detach handler
> + * @s: ptr. to standard V4L2 device information structure
> + *
> + * Detach sensor and unregister and release the video device.
> + */
> +static void omap34xxcam_device_unregister(struct v4l2_int_device *s)
> +{
> +       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
> +       struct omap34xxcam_hw_config hwc;
> +
> +       BUG_ON(vidioc_int_g_priv(s, &hwc) < 0);
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy()) {
> +               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +               vdev->slaves--;
> +               omap34xxcam_vfd_name_update(vdev);
> +       }
> +
> +       if (vdev->slaves == 0 && vdev->vfd) {
> +               if (vdev->vfd->minor == -1) {
> +                       /*
> +                        * The device was never registered, so release the
> +                        * video_device struct directly.
> +                        */
> +                       video_device_release(vdev->vfd);
> +               } else {
> +                       /*
> +                        * The unregister function will release the
> +                        * video_device struct as well as
> +                        * unregistering it.
> +                        */
> +                       video_unregister_device(vdev->vfd);
> +               }
> +               vdev->vfd = NULL;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +}
> +
> +static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = {
> +       .vidioc_querycap         = vidioc_querycap,
> +       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
> +       .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
> +       .vidioc_s_fmt_vid_cap    = vidioc_s_fmt_vid_cap,
> +       .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,
> +       .vidioc_reqbufs          = vidioc_reqbufs,
> +       .vidioc_querybuf         = vidioc_querybuf,
> +       .vidioc_qbuf             = vidioc_qbuf,
> +       .vidioc_dqbuf            = vidioc_dqbuf,
> +       .vidioc_streamon         = vidioc_streamon,
> +       .vidioc_streamoff        = vidioc_streamoff,
> +       .vidioc_enum_input       = vidioc_enum_input,
> +       .vidioc_g_input          = vidioc_g_input,
> +       .vidioc_s_input          = vidioc_s_input,
> +       .vidioc_queryctrl        = vidioc_queryctrl,
> +       .vidioc_querymenu        = vidioc_querymenu,
> +       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
> +       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
> +       .vidioc_g_parm           = vidioc_g_parm,
> +       .vidioc_s_parm           = vidioc_s_parm,
> +       .vidioc_cropcap          = vidioc_cropcap,
> +       .vidioc_g_crop           = vidioc_g_crop,
> +       .vidioc_s_crop           = vidioc_s_crop,
> +       .vidioc_default          = vidioc_default,
> +};
> +
> +/**
> + * omap34xxcam_device_register - V4L2 attach handler
> + * @s: ptr. to standard V4L2 device information structure
> + *
> + * Allocates and initializes the V4L2 video_device structure, initializes
> + * the sensor, and finally
> + registers the device with V4L2 based on the
> + * video_device structure.
> + *
> + * Returns 0 on success, otherwise an appropriate error code on
> + * failure.
> + */
> +static int omap34xxcam_device_register(struct v4l2_int_device *s)
> +{
> +       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
> +       struct omap34xxcam_device *cam = vdev->cam;
> +       struct omap34xxcam_hw_config hwc;
> +       struct video_device *vfd;
> +       int rval;
> +
> +       /* We need to check rval just once. The place is here. */
> +       if (vidioc_int_g_priv(s, &hwc))
> +               return -ENODEV;
> +
> +       if (vdev->index != hwc.dev_index)
> +               return -ENODEV;
> +
> +       if (hwc.dev_type < 0 || hwc.dev_type > OMAP34XXCAM_SLAVE_FLASH)
> +               return -EINVAL;
> +
> +       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy())
> +               return -EBUSY;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (atomic_read(&vdev->users)) {
> +               dev_err(cam->dev, "we're open (%d), can't register\n",
> +                       atomic_read(&vdev->users));
> +               mutex_unlock(&vdev->mutex);
> +               return -EBUSY;
> +       }
> +
> +       vdev->slaves++;
> +       vdev->slave[hwc.dev_type] = s;
> +       vdev->slave_config[hwc.dev_type] = hwc;
> +
> +       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +               isp_get();
> +       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                          1 << hwc.dev_type);
> +       if (!rval && hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
> +               struct v4l2_format format;
> +               struct v4l2_streamparm a;
> +
> +               format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
> +
> +               a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval |= vidioc_int_g_parm(vdev->vdev_sensor, &a);
> +               if (rval)
> +                       rval = -EBUSY;
> +
> +               vdev->want_pix = format.fmt.pix;
> +               vdev->want_timeperframe = a.parm.capture.timeperframe;
> +       }
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF, 1 << hwc.dev_type);
> +       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +               isp_put();
> +
> +       if (rval)
> +               goto err;
> +
> +       /* Are we the first slave? */
> +       if (vdev->slaves == 1) {
> +               /* initialize the video_device struct */
> +               vdev->vfd = video_device_alloc();
> +               vfd = vdev->vfd;
> +               if (!vfd) {
> +                       dev_err(cam->dev,
> +                               "could not allocate video device struct\n");
> +                       return -ENOMEM;
> +               }
> +               vfd->release    = video_device_release;
> +               vfd->minor      = -1;
> +               vfd->fops       = &omap34xxcam_fops;
> +               vfd->ioctl_ops  = &omap34xxcam_ioctl_ops;
> +               video_set_drvdata(vfd, vdev);
> +
> +               if (video_register_device(vfd, VFL_TYPE_GRABBER,
> +                                         hwc.dev_minor) < 0) {
> +                       dev_err(cam->dev,
> +                               "could not register V4L device\n");
> +                       vfd->minor = -1;
> +                       rval = -EBUSY;
> +                       goto err;
> +               }
> +       } else {
> +               vfd = vdev->vfd;
> +       }
> +

This part seems to be weird. Because following the codes, this device
registering routine just tries to attach all of the slave devices (AKA
v4l2 int device) connected with OMAP3 camera interface.

Here is an example which could be troubled.
Dual camera attached on OMAP3 like 3G handsets. In this case, we
should register two of sensors as v4l2 int devices.
As I'm understanding, OMAP3 can process only one camera image at a time.
Exceptional case like when we can attach a camera to parallel
interface and the other to MIPI interface, then we can turn on both of
the cameras at the same time. But also in this case OMAP3 could
process only one camera module at a time. (Am I right?)

So, logically it does not make sense with making device nodes of every
single slave attached with OMAP3camera interface. Because they can't
be opened at the same time,even if it is possible it should not work
properly.

So.. how about making only single device node like /dev/video0 for
OMAP3 camera interface and make it switchable through V4L2 API. Like
VIDIOC_S_INPUT?






> +       omap34xxcam_vfd_name_update(vdev);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return 0;
> +
> +err:
> +       if (s == vdev->slave[hwc.dev_type]) {
> +               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +               vdev->slaves--;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +       omap34xxcam_device_unregister(s);
> +
> +       return rval;
> +}
> +
> +static struct v4l2_int_master omap34xxcam_master = {
> +       .attach = omap34xxcam_device_register,
> +       .detach = omap34xxcam_device_unregister,
> +};
> +
> +/*
> + *
> + * Driver Suspend/Resume
> + *
> + */
> +
> +#ifdef CONFIG_PM
> +/**
> + * omap34xxcam_suspend - platform driver PM suspend handler
> + * @pdev: ptr. to platform level device information structure
> + * @state: power state
> + *
> + * If applicable, stop capture and disable sensor.
> + *
> + * Returns 0 always
> + */
> +static int omap34xxcam_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
> +
> +       if (atomic_read(&vdev->users) == 0)
> +               return 0;
> +
> +       if (vdev->streaming) {
> +               isp_stop();
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                           OMAP34XXCAM_SLAVE_POWER_ALL);
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_resume - platform driver PM resume handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * If applicable, resume capture and enable sensor.
> + *
> + * Returns 0 always
> + */
> +static int omap34xxcam_resume(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
> +
> +       if (atomic_read(&vdev->users) == 0)
> +               return 0;
> +
> +       if (vdev->streaming) {
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                           OMAP34XXCAM_SLAVE_POWER_ALL);
> +               isp_start();
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
> +/*
> + *
> + * Driver initialisation and deinitialisation.
> + *
> + */
> +
> +/**
> + * omap34xxcam_remove - platform driver remove handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * Unregister device with V4L2, unmap camera registers, and
> + * free camera device information structure (omap34xxcam_device).
> + *
> + * Returns 0 always.
> + */
> +static int omap34xxcam_remove(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_device *cam = platform_get_drvdata(pdev);
> +       int i;
> +
> +       if (!cam)
> +               return 0;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               if (cam->vdevs[i].cam == NULL)
> +                       continue;
> +
> +               v4l2_int_device_unregister(&cam->vdevs[i].master);
> +               cam->vdevs[i].cam = NULL;
> +       }
> +
> +       if (cam->mmio_base) {
> +               iounmap((void *)cam->mmio_base);
> +               cam->mmio_base = 0;
> +       }
> +
> +       if (cam->mmio_base_phys) {
> +               release_mem_region(cam->mmio_base_phys, cam->mmio_size);
> +               cam->mmio_base_phys = 0;
> +       }
> +
> +       omap34xxcam = NULL;
> +
> +       kfree(cam);
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_probe - platform driver probe handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * Allocates and initializes camera device information structure
> + * (omap34xxcam_device), maps the device registers and gets the
> + * device IRQ.  Registers the device as a V4L2 client.
> + *
> + * Returns 0 on success or -ENODEV on failure.
> + */
> +static int omap34xxcam_probe(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_device *cam;
> +       struct resource *mem;
> +       struct isp_sysc isp_sysconfig;
> +       int irq;
> +       int i;
> +
> +       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
> +       if (!cam) {
> +               dev_err(&pdev->dev, "could not allocate memory\n");
> +               goto err;
> +       }
> +
> +       platform_set_drvdata(pdev, cam);
> +
> +       cam->dev = &pdev->dev;
> +
> +       /* request the mem region for the camera registers */
> +       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!mem) {
> +               dev_err(cam->dev, "no mem resource?\n");
> +               goto err;
> +       }
> +
> +       if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
> +                               pdev->name)) {
> +               dev_err(cam->dev,
> +                       "cannot reserve camera register I/O region\n");
> +               goto err;
> +
> +       }
> +       cam->mmio_base_phys = mem->start;
> +       cam->mmio_size = (mem->end - mem->start) + 1;
> +
> +       /* map the region */
> +       cam->mmio_base = (unsigned long)
> +                       ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
> +       if (!cam->mmio_base) {
> +               dev_err(cam->dev, "cannot map camera register I/O region\n");
> +               goto err;
> +       }
> +
> +       irq = platform_get_irq(pdev, 0);
> +       if (irq <= 0) {
> +               dev_err(cam->dev, "no irq for camera?\n");
> +               goto err;
> +       }
> +
> +       isp_get();
> +       isp_sysconfig.reset = 0;
> +       isp_sysconfig.idle_mode = 1;
> +       isp_power_settings(isp_sysconfig);
> +       isp_put();
> +
> +       omap34xxcam = cam;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {

This routine depends on how many slave devices are connected with
omap3 camera interface.
Seems to be no problem.

> +               struct omap34xxcam_videodev *vdev = &cam->vdevs[i];
> +               struct v4l2_int_device *m = &vdev->master;
> +
> +               m->module       = THIS_MODULE;
> +               strlcpy(m->name, CAM_NAME, sizeof(m->name));
> +               m->type         = v4l2_int_type_master;
> +               m->u.master     = &omap34xxcam_master;
> +               m->priv         = vdev;
> +
> +               mutex_init(&vdev->mutex);
> +               vdev->index             = i;
> +               vdev->cam               = cam;
> +               vdev->vdev_sensor =
> +                       vdev->vdev_lens =
> +                       vdev->vdev_flash = v4l2_int_device_dummy();
> +               setup_timer(&vdev->poweroff_timer,
> +                           omap34xxcam_slave_power_timer, (unsigned long)vdev);
> +               INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
> +
> +               if (v4l2_int_device_register(m))

At this point, v4l2 int devices are being registered. Also makes sense.


> +                       goto err;
> +       }
> +
> +       return 0;
> +
> +err:
> +       omap34xxcam_remove(pdev);
> +       return -ENODEV;
> +}
> +
> +static struct platform_driver omap34xxcam_driver = {
> +       .probe = omap34xxcam_probe,
> +       .remove = omap34xxcam_remove,
> +#ifdef CONFIG_PM
> +       .suspend = omap34xxcam_suspend,
> +       .resume = omap34xxcam_resume,
> +#endif
> +       .driver = {
> +                  .name = CAM_NAME,
> +                  },
> +};
> +
> +/*
> + *
> + * Module initialisation and deinitialisation
> + *
> + */
> +
> +/**
> + * omap34xxcam_init - module_init function
> + *
> + * Calls platfrom driver to register probe, remove,
> + * suspend and resume functions.
> + *
> + */
> +static int __init omap34xxcam_init(void)
> +{
> +       return platform_driver_register(&omap34xxcam_driver);
> +}
> +
> +/**
> + * omap34xxcam_cleanup - module_exit function
> + *
> + * Calls platfrom driver to unregister probe, remove,
> + * suspend and resume functions.
> + *
> + */
> +static void __exit omap34xxcam_cleanup(void)
> +{
> +       platform_driver_unregister(&omap34xxcam_driver);
> +}
> +
> +MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com");
> +MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
> +MODULE_LICENSE("GPL");
> +
> +late_initcall(omap34xxcam_init);
> +module_exit(omap34xxcam_cleanup);
> diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
> new file mode 100644
> index 0000000..36f7fd5
> --- /dev/null
> +++ b/drivers/media/video/omap34xxcam.h
> @@ -0,0 +1,221 @@
> +/*
> + * drivers/media/video/omap34xxcam.c
> + *
> + * Copyright (C) 2006--2008 Nokia Corporation
> + * Copyright (C) 2007, 2008 Texas Instruments
> + *
> + * Contact: Sakari Ailus <sakari.ailus@nokia.com>
> + *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *
> + * Originally based on the OMAP 2 camera driver.
> + *
> + * Written by Sakari Ailus <sakari.ailus@nokia.com>
> + *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *            Sergio Aguirre <saaguirre@ti.com>
> + *            Mohit Jalori
> + *            Sameer Venkatraman
> + *            Leonides Martinez
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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 St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef OMAP34XXCAM_H
> +#define OMAP34XXCAM_H
> +
> +#include <media/v4l2-int-device.h>
> +#include "isp/isp.h"
> +
> +#define CAM_NAME                       "omap34xxcam"
> +#define CAM_SHORT_NAME                 "omap3"
> +
> +#define OMAP_ISP_AF            (1 << 4)
> +#define OMAP_ISP_HIST          (1 << 5)
> +#define OMAP34XXCAM_XCLK_NONE  -1
> +#define OMAP34XXCAM_XCLK_A     0
> +#define OMAP34XXCAM_XCLK_B     1
> +
> +#define OMAP34XXCAM_SLAVE_SENSOR       0
> +#define OMAP34XXCAM_SLAVE_LENS         1
> +#define OMAP34XXCAM_SLAVE_FLASH                2 /* This is the last slave! */
> +
> +/* mask for omap34xxcam_slave_power_set */
> +#define OMAP34XXCAM_SLAVE_POWER_SENSOR (1 << OMAP34XXCAM_SLAVE_SENSOR)
> +#define OMAP34XXCAM_SLAVE_POWER_LENS   (1 << OMAP34XXCAM_SLAVE_LENS)
> +#define OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS \
> +       (OMAP34XXCAM_SLAVE_POWER_SENSOR | OMAP34XXCAM_SLAVE_POWER_LENS)
> +#define OMAP34XXCAM_SLAVE_POWER_FLASH  (1 << OMAP34XXCAM_SLAVE_FLASH)
> +#define OMAP34XXCAM_SLAVE_POWER_ALL    -1
> +
> +#define OMAP34XXCAM_VIDEODEVS          4
> +
> +struct omap34xxcam_device;
> +struct omap34xxcam_videodev;
> +
> +struct omap34xxcam_sensor_config {
> +       int xclk;
> +       int sensor_isp;
> +       u32 capture_mem;
> +};
> +
> +struct omap34xxcam_lens_config {
> +};
> +
> +struct omap34xxcam_flash_config {
> +};
> +
> +/**
> + * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
> + * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
> + * @sensor_isp: Is sensor smart/SOC or raw
> + * @s_pix_sparm: Access function to set pix and sparm.
> + * Pix will override sparm
> + */
> +struct omap34xxcam_hw_config {
> +       int dev_index; /* Index in omap34xxcam_sensors */
> +       int dev_minor; /* Video device minor number */
> +       int dev_type; /* OMAP34XXCAM_SLAVE_* */
> +       union {
> +               struct omap34xxcam_sensor_config sensor;
> +               struct omap34xxcam_lens_config lens;
> +               struct omap34xxcam_flash_config flash;
> +       } u;
> +};
> +
> +/**
> + * struct omap34xxcam_videodev - per /dev/video* structure
> + * @mutex: serialises access to this structure
> + * @cam: pointer to cam hw structure
> + * @master: we are v4l2_int_device master
> + * @sensor: sensor device
> + * @lens: lens device
> + * @flash: flash device
> + * @slaves: how many slaves we have at the moment
> + * @vfd: our video device
> + * @capture_mem: maximum kernel-allocated capture memory
> + * @if_u: sensor interface stuff
> + * @index: index of this structure in cam->vdevs
> + * @users: how many users we have
> + * @power_state: Current power state
> + * @power_state_wish: New power state when poweroff_timer expires
> + * @power_state_mask: Bitmask of devices to set the new power state
> + * @poweroff_timer: Timer for dispatching poweroff_work
> + * @poweroff_work: Work for slave power state change
> + * @sensor_config: ISP-speicific sensor configuration
> + * @lens_config: ISP-speicific lens configuration
> + * @flash_config: ISP-speicific flash configuration
> + * @streaming: streaming file handle, if streaming is enabled
> + */
> +struct omap34xxcam_videodev {
> +       struct mutex mutex; /* serialises access to this structure */
> +
> +       struct omap34xxcam_device *cam;
> +       struct v4l2_int_device master;
> +
> +#define vdev_sensor slave[OMAP34XXCAM_SLAVE_SENSOR]
> +#define vdev_lens slave[OMAP34XXCAM_SLAVE_LENS]
> +#define vdev_flash slave[OMAP34XXCAM_SLAVE_FLASH]
> +       struct v4l2_int_device *slave[OMAP34XXCAM_SLAVE_FLASH + 1];
> +
> +       /* number of slaves attached */
> +       int slaves;
> +
> +       /*** video device parameters ***/
> +       struct video_device *vfd;
> +       int capture_mem;
> +
> +       /*** general driver state information ***/
> +       /*
> +        * Sensor interface parameters: interface type, CC_CTRL
> +        * register value and interface specific data.
> +        */
> +       u32 xclk;
> +       /* index to omap34xxcam_videodevs of this structure */
> +       int index;
> +       atomic_t users;
> +       enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
> +       enum v4l2_power power_state_wish;
> +       int power_state_mask;
> +       struct timer_list poweroff_timer;
> +       struct work_struct poweroff_work;
> +
> +#define vdev_sensor_config slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor
> +#define vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens
> +#define vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash
> +       struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH + 1];
> +
> +       /*** capture data ***/
> +       struct v4l2_fract want_timeperframe;
> +       struct v4l2_pix_format want_pix;
> +       /* file handle, if streaming is on */
> +       struct file *streaming;
> +};
> +
> +/**
> + * struct omap34xxcam_device - per-device data structure
> + * @mutex: mutex serialises access to this structure
> + * @sgdma_in_queue: Number or sgdma requests in scatter-gather queue,
> + * protected by the lock above.
> + * @sgdma: ISP sgdma subsystem information structure
> + * @dma_notify: DMA notify flag
> + * @irq: irq number platform HW resource
> + * @mmio_base: register map memory base (platform HW resource)
> + * @mmio_base_phys: register map memory base physical address
> + * @mmio_size: register map memory size
> + * @dev: device structure
> + * @vdevs: /dev/video specific structures
> + * @fck: camera module fck clock information
> + * @ick: camera module ick clock information
> + */
> +struct omap34xxcam_device {
> +       struct mutex mutex; /* serialises access to this structure */
> +       int sgdma_in_queue;
> +       struct isp_sgdma sgdma;
> +       int dma_notify;
> +
> +       /*** platform HW resource ***/
> +       unsigned int irq;
> +       unsigned long mmio_base;
> +       unsigned long mmio_base_phys;
> +       unsigned long mmio_size;
> +
> +       /*** interfaces and device ***/
> +       struct device *dev;
> +       struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
> +
> +       /*** camera module clocks ***/
> +       struct clk *fck;
> +       struct clk *ick;
> +       bool sensor_if_enabled;
> +};
> +
> +/**
> + * struct omap34xxcam_fh - per-filehandle data structure
> + * @vbq_lock: spinlock for the videobuf queue
> + * @vbq: V4L2 video buffer queue structure
> + * @pix: V4L2 pixel format structure (serialise pix by vbq->lock)
> + * @field_count: field counter for videobuf_buffer
> + * @vdev: our /dev/video specific structure
> + */
> +struct omap34xxcam_fh {
> +       spinlock_t vbq_lock; /* spinlock for the videobuf queue */
> +       struct videobuf_queue vbq;
> +       struct v4l2_pix_format pix;
> +       atomic_t field_count;
> +       /* accessing cam here doesn't need serialisation: it's constant */
> +       struct omap34xxcam_videodev *vdev;
> +};
> +
> +#endif /* ifndef OMAP34XXCAM_H */
> --
> 1.5.6.5
>
>
> --
> video4linux-list mailing list
> Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
> https://www.redhat.com/mailman/listinfo/video4linux-list
>


Cheers,

Nate

--
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
         dongsoo45.kim@samsung.com
========================================================

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
  2008-12-11 20:38 ` Aguirre Rodriguez, Sergio Alberto
@ 2009-02-23  8:08   ` DongSoo(Nathaniel) Kim
  2009-02-23  8:50     ` Tuukka.O Toivonen
  2009-02-23  8:26   ` DongSoo(Nathaniel) Kim
  1 sibling, 1 reply; 43+ messages in thread
From: DongSoo(Nathaniel) Kim @ 2009-02-23  8:08 UTC (permalink / raw)
  To: Aguirre Rodriguez, Sergio Alberto
  Cc: linux-omap, Sakari Ailus, Tuukka.O Toivonen, Nagalla, Hari

Hello.

First of all, I removed old video4linux list from Cc.



On Fri, Dec 12, 2008 at 5:38 AM, Aguirre Rodriguez, Sergio Alberto
<saaguirre@ti.com> wrote:
> >From d5f4681ba9a74df4ea02332fe1aeccda2142a482 Mon Sep 17 00:00:00 2001
> From: Sergio Aguirre <saaguirre@ti.com>
> Date: Thu, 11 Dec 2008 13:35:47 -0600
> Subject: [PATCH] OMAP34XXCAM: Add driver
>
> Signed-off-by: Sakari Ailus <sakari.ailus@nokia.com>
> ---
>  drivers/media/video/Kconfig       |    8 +
>  drivers/media/video/Makefile      |    2 +
>  drivers/media/video/omap34xxcam.c | 2060 +++++++++++++++++++++++++++++++++++++
>  drivers/media/video/omap34xxcam.h |  221 ++++
>  4 files changed, 2291 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/media/video/omap34xxcam.c
>  create mode 100644 drivers/media/video/omap34xxcam.h
>
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index 6150d6f..a20a83b 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -702,6 +702,14 @@ config VIDEO_CAFE_CCIC
>
>  source "drivers/media/video/isp/Kconfig"
>
> +config VIDEO_OMAP3
> +        tristate "OMAP 3 Camera support"
> +       select VIDEOBUF_GEN
> +       select VIDEOBUF_DMA_SG
> +       depends on VIDEO_V4L2 && ARCH_OMAP34XX
> +       ---help---
> +         Driver for an OMAP 3 camera controller.
> +
>  config SOC_CAMERA
>        tristate "SoC camera support"
>        depends on VIDEO_V4L2 && HAS_DMA
> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
> index 16962f3..a2f73cf 100644
> --- a/drivers/media/video/Makefile
> +++ b/drivers/media/video/Makefile
> @@ -101,6 +101,8 @@ obj-$(CONFIG_VIDEO_OV7670)  += ov7670.o
>
>  obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
>
> +obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o isp/
> +
>  obj-$(CONFIG_USB_DABUSB)        += dabusb.o
>  obj-$(CONFIG_USB_OV511)         += ov511.o
>  obj-$(CONFIG_USB_SE401)         += se401.o
> diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
> new file mode 100644
> index 0000000..31b6b60
> --- /dev/null
> +++ b/drivers/media/video/omap34xxcam.c
> @@ -0,0 +1,2060 @@
> +/*
> + * drivers/media/video/omap34xxcam.c
> + *
> + * Copyright (C) 2006--2008 Nokia Corporation
> + * Copyright (C) 2007, 2008 Texas Instruments
> + *
> + * Contact: Sakari Ailus <sakari.ailus@nokia.com>
> + *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *
> + * Originally based on the OMAP 2 camera driver.
> + *
> + * Written by Sakari Ailus <sakari.ailus@nokia.com>
> + *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *            Sergio Aguirre <saaguirre@ti.com>
> + *            Mohit Jalori
> + *            Sameer Venkatraman
> + *            Leonides Martinez
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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 St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/pci.h>         /* needed for videobufs */
> +#include <linux/delay.h>
> +#include <linux/kernel.h>
> +#include <linux/interrupt.h>
> +#include <linux/videodev2.h>
> +#include <linux/version.h>
> +#include <linux/platform_device.h>
> +
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-ioctl.h>
> +
> +#include "omap34xxcam.h"
> +#include "isp/isp.h"
> +#include "isp/ispmmu.h"
> +#include "isp/ispreg.h"
> +#include "isp/ispccdc.h"
> +#include "isp/isph3a.h"
> +#include "isp/isp_af.h"
> +#include "isp/isphist.h"
> +#include "isp/isppreview.h"
> +#include "isp/ispresizer.h"
> +
> +#define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
> +
> +/* global variables */
> +static struct omap34xxcam_device *omap34xxcam;
> +
> +struct omap34xxcam_fh *camfh_saved;
> +
> +#define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ)
> +
> +/*
> + *
> + * Sensor handling.
> + *
> + */
> +
> +/**
> + * omap34xxcam_slave_power_set - set slave power state
> + * @vdev: per-video device data structure
> + * @power: new power state
> + */
> +static int omap34xxcam_slave_power_set(struct omap34xxcam_videodev *vdev,
> +                                      enum v4l2_power power,
> +                                      int mask)
> +{
> +       int rval = 0, i = 0;
> +
> +       BUG_ON(!mutex_is_locked(&vdev->mutex));
> +
> +       vdev->power_state_wish = -1;
> +
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               if (vdev->slave[i] == v4l2_int_device_dummy())
> +                       continue;
> +
> +               if (!(mask & (1 << i))
> +                   || power == vdev->power_state[i])
> +                       continue;
> +
> +               rval = vidioc_int_s_power(vdev->slave[i], power);
> +
> +               if (rval && power != V4L2_POWER_OFF) {
> +                       power = V4L2_POWER_OFF;
> +                       goto out;
> +               }
> +
> +               vdev->power_state[i] = power;
> +       }
> +
> +       return 0;
> +
> +out:
> +       for (i--; i >= 0; i--) {
> +               if (vdev->slave[i] == v4l2_int_device_dummy())
> +                       continue;
> +
> +               if (!(mask & (1 << i)))
> +                       continue;
> +
> +               vidioc_int_s_power(vdev->slave[i], power);
> +               vdev->power_state[i] = power;
> +       }
> +
> +       return rval;
> +}
> +
> +static void omap34xxcam_slave_power_work(struct work_struct *work)
> +{
> +       struct omap34xxcam_videodev *vdev =
> +               container_of(work, struct omap34xxcam_videodev, poweroff_work);
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->power_state_wish != -1)
> +               omap34xxcam_slave_power_set(vdev, vdev->power_state_wish,
> +                                           vdev->power_state_mask);
> +
> +       mutex_unlock(&vdev->mutex);
> +}
> +
> +static void omap34xxcam_slave_power_timer(unsigned long ptr)
> +{
> +       struct omap34xxcam_videodev *vdev = (void *)ptr;
> +
> +       schedule_work(&vdev->poweroff_work);
> +}
> +
> +/**
> + * omap34xxcam_slave_power_suggest - delayed power state change
> + *
> + * @vdev: per-video device data structure
> + * @power: new power state
> + */
> +static void omap34xxcam_slave_power_suggest(struct omap34xxcam_videodev *vdev,
> +                                           enum v4l2_power power,
> +                                           int mask)
> +{
> +       BUG_ON(!mutex_is_locked(&vdev->mutex));
> +
> +       del_timer(&vdev->poweroff_timer);
> +
> +       vdev->power_state_wish = power;
> +       vdev->power_state_mask = mask;
> +
> +       mod_timer(&vdev->poweroff_timer, jiffies + OMAP34XXCAM_POWEROFF_DELAY);
> +}
> +
> +/**
> + * omap34xxcam_update_vbq - Updates VBQ with completed input buffer
> + * @vb: ptr. to standard V4L2 video buffer structure
> + *
> + * Updates video buffer queue with completed buffer passed as
> + * input parameter.  Also updates ISP H3A timestamp and field count
> + * statistics.
> + */
> +int omap34xxcam_update_vbq(struct videobuf_buffer *vb)
> +{
> +       struct omap34xxcam_fh *fh = camfh_saved;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       int rval = 0;
> +
> +       do_gettimeofday(&vb->ts);
> +       vb->field_count = atomic_add_return(2, &fh->field_count);
> +       vb->state = VIDEOBUF_DONE;
> +
> +       if (vdev->streaming)
> +               rval = 1;
> +
> +       wake_up(&vb->done);
> +
> +       return rval;
> +}
> +
> +/**
> + * omap34xxcam_vbq_setup - Calcs size and num of buffs allowed in queue
> + * @vbq: ptr. to standard V4L2 video buffer queue structure
> + * @cnt: ptr to location to hold the count of buffers to be in the queue
> + * @size: ptr to location to hold the size of a frame
> + *
> + * Calculates the number of buffers of current image size that can be
> + * supported by the available capture memory.
> + */
> +static int omap34xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
> +                                unsigned int *size)
> +{
> +       struct omap34xxcam_fh *fh = vbq->priv_data;
> +
> +       if (*cnt <= 0)
> +               *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
> +
> +       if (*cnt > VIDEO_MAX_FRAME)
> +               *cnt = VIDEO_MAX_FRAME;
> +
> +       *size = fh->pix.sizeimage;
> +
> +       while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
> +               (*cnt)--;
> +
> +       while ((*size * *cnt) > ispmmu_get_mapeable_space())
> +               (*cnt)--;
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_vbq_release - Free resources for input VBQ and VB
> + * @vbq: ptr. to standard V4L2 video buffer queue structure
> + * @vb: ptr to standard V4L2 video buffer structure
> + *
> + * Unmap and free all memory associated with input VBQ and VB, also
> + * unmap the address in ISP MMU.  Reset the VB state.
> + */
> +static void omap34xxcam_vbq_release(struct videobuf_queue *vbq,
> +                                   struct videobuf_buffer *vb)
> +{
> +       if (!vbq->streaming) {
> +               isp_vbq_release(vbq, vb);
> +               videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
> +               videobuf_dma_free(videobuf_to_dma(vb));
> +               vb->state = VIDEOBUF_NEEDS_INIT;
> +       }
> +       return;
> +}
> +
> +/**
> + * omap34xxcam_vbq_prepare - V4L2 video ops buf_prepare handler
> + * @vbq: ptr. to standard V4L2 video buffer queue structure
> + * @vb: ptr to standard V4L2 video buffer structure
> + * @field: standard V4L2 field enum
> + *
> + * Verifies there is sufficient locked memory for the requested
> + * buffer, or if there is not, allocates, locks and initializes
> + * it.
> + */
> +static int omap34xxcam_vbq_prepare(struct videobuf_queue *vbq,
> +                                  struct videobuf_buffer *vb,
> +                                  enum v4l2_field field)
> +{
> +       struct omap34xxcam_fh *fh = vbq->priv_data;
> +       int err = 0;
> +
> +       /*
> +        * Accessing pix here is okay since it's constant while
> +        * streaming is on (and we only get called then).
> +        */
> +       if (vb->baddr) {
> +               /* This is a userspace buffer. */
> +               if (fh->pix.sizeimage > vb->bsize)
> +                       /* The buffer isn't big enough. */
> +                       return -EINVAL;
> +       } else {
> +               if (vb->state != VIDEOBUF_NEEDS_INIT
> +                   && fh->pix.sizeimage > vb->bsize)
> +                       /*
> +                        * We have a kernel bounce buffer that has
> +                        * already been allocated.
> +                        */
> +                       omap34xxcam_vbq_release(vbq, vb);
> +       }
> +
> +       vb->size = fh->pix.bytesperline * fh->pix.height;
> +       vb->width = fh->pix.width;
> +       vb->height = fh->pix.height;
> +       vb->field = field;
> +
> +       if (vb->state == VIDEOBUF_NEEDS_INIT) {
> +               err = videobuf_iolock(vbq, vb, NULL);
> +               if (!err) {
> +                       /* isp_addr will be stored locally inside isp code */
> +                       err = isp_vbq_prepare(vbq, vb, field);
> +               }
> +       }
> +
> +       if (!err)
> +               vb->state = VIDEOBUF_PREPARED;
> +       else
> +               omap34xxcam_vbq_release(vbq, vb);
> +
> +       return err;
> +
> +}
> +
> +/**
> + * omap34xxcam_vbq_queue - V4L2 video ops buf_queue handler
> + * @vbq: ptr. to standard V4L2 video buffer queue structure
> + * @vb: ptr to standard V4L2 video buffer structure
> + *
> + * Maps the video buffer to sgdma and through the isp, sets
> + * the isp buffer done callback and sets the video buffer state
> + * to active.
> + */
> +static void omap34xxcam_vbq_queue(struct videobuf_queue *vbq,
> +                                 struct videobuf_buffer *vb)
> +{
> +       struct omap34xxcam_fh *fh = vbq->priv_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       enum videobuf_state state = vb->state;
> +       isp_vbq_callback_ptr func_ptr;
> +       int err = 0;
> +       camfh_saved = fh;
> +
> +       func_ptr = omap34xxcam_update_vbq;
> +       vb->state = VIDEOBUF_ACTIVE;
> +
> +       err = isp_sgdma_queue(videobuf_to_dma(vb),
> +                             vb, 0, &vdev->cam->dma_notify, func_ptr);
> +       if (err) {
> +               dev_dbg(vdev->cam->dev, "vbq queue failed\n");
> +               vb->state = state;
> +       }
> +
> +}
> +
> +static struct videobuf_queue_ops omap34xxcam_vbq_ops = {
> +       .buf_setup = omap34xxcam_vbq_setup,
> +       .buf_prepare = omap34xxcam_vbq_prepare,
> +       .buf_queue = omap34xxcam_vbq_queue,
> +       .buf_release = omap34xxcam_vbq_release,
> +};
> +
> +/*
> + *
> + * IOCTL interface.
> + *
> + */
> +
> +/**
> + * vidioc_querycap - V4L2 query capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @cap: ptr to standard V4L2 capability structure
> + *
> + * Fill in the V4L2 capabliity structure for the camera device
> + */
> +static int vidioc_querycap(struct file *file, void *fh,
> +                          struct v4l2_capability *cap)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +
> +       strlcpy(cap->driver, CAM_SHORT_NAME, sizeof(cap->driver));
> +       strlcpy(cap->card, vdev->vfd->name, sizeof(cap->card));
> +       cap->version = OMAP34XXCAM_VERSION;
> +       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
> +
> +       return 0;
> +}
> +
> +/**
> + * vidioc_enum_fmt_vid_cap - V4L2 enumerate format capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @f: ptr to standard V4L2 format description structure
> + *
> + * Fills in enumerate format capabilities information for sensor (if SOC
> + * sensor attached) or ISP (if raw sensor attached).
> + */
> +static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
> +                                  struct v4l2_fmtdesc *f)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, f);
> +       else
> +               rval = isp_enum_fmt_cap(f);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_g_fmt_vid_cap - V4L2 get format capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @f: ptr to standard V4L2 format structure
> + *
> + * Fills in format capabilities for sensor (if SOC sensor attached) or ISP
> + * (if raw sensor attached).
> + */
> +static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
> +                               struct v4l2_format *f)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +
> +       mutex_lock(&vdev->mutex);
> +       f->fmt.pix = ofh->pix;
> +       mutex_unlock(&vdev->mutex);
> +
> +       return 0;
> +}
> +
> +static int try_pix_parm(struct omap34xxcam_videodev *vdev,
> +                       struct v4l2_pix_format *best_pix_in,
> +                       struct v4l2_pix_format *wanted_pix_out,
> +                       struct v4l2_fract *best_ival)
> +{
> +       int fps;
> +       int rval;
> +       int size_index;
> +       struct v4l2_pix_format best_pix_out;
> +
> +       if (best_ival->numerator == 0
> +           || best_ival->denominator == 0)
> +               best_ival->denominator = 30, best_ival->numerator = 1;
> +
> +       fps = best_ival->denominator / best_ival->numerator;
> +
> +       best_ival->denominator = 0;
> +
> +       best_pix_out.height = INT_MAX >> 1;
> +       best_pix_out.width = best_pix_out.height;
> +
> +       /*
> +        * Get supported resolutions.
> +        */
> +       for (size_index = 0; ; size_index++) {
> +               struct v4l2_frmsizeenum frms;
> +               struct v4l2_pix_format pix_tmp_in, pix_tmp_out;
> +               int ival_index;
> +
> +               frms.index = size_index;
> +               frms.pixel_format = best_pix_in->pixelformat;
> +
> +               rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, &frms);
> +               if (rval) {
> +                       rval = 0;
> +                       break;
> +               }
> +
> +               pix_tmp_in.pixelformat = frms.pixel_format;
> +               pix_tmp_in.width = frms.discrete.width;
> +               pix_tmp_in.height = frms.discrete.height;
> +               pix_tmp_out = *wanted_pix_out;
> +               /* Don't do upscaling. */
> +               if (pix_tmp_out.width > pix_tmp_in.width)
> +                       pix_tmp_out.width = pix_tmp_in.width;
> +               if (pix_tmp_out.height > pix_tmp_in.height)
> +                       pix_tmp_out.height = pix_tmp_in.height;
> +               rval = isp_try_fmt_cap(&pix_tmp_in, &pix_tmp_out);
> +               if (rval)
> +                       return rval;
> +
> +#define IS_SMALLER_OR_EQUAL(pix1, pix2)                        \
> +               ((pix1)->width + (pix1)->height         \
> +                < (pix2)->width + (pix2)->height)
> +#define SIZE_DIFF(pix1, pix2)                                  \
> +               (abs((pix1)->width - (pix2)->width)             \
> +                + abs((pix1)->height - (pix2)->height))
> +
> +               /*
> +                * Don't use modes that are farther from wanted size
> +                * that what we already got.
> +                */
> +               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
> +                   > SIZE_DIFF(&best_pix_out, wanted_pix_out))
> +                       continue;
> +
> +               /*
> +                * There's an input mode that can provide output
> +                * closer to wanted.
> +                */
> +               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
> +                   < SIZE_DIFF(&best_pix_out, wanted_pix_out))
> +                       /* Force renegotation of fps etc. */
> +                       best_ival->denominator = 0;
> +
> +               for (ival_index = 0; ; ival_index++) {
> +                       struct v4l2_frmivalenum frmi;
> +
> +                       frmi.index = ival_index;
> +                       frmi.pixel_format = frms.pixel_format;
> +                       frmi.width = frms.discrete.width;
> +                       frmi.height = frms.discrete.height;
> +                       /* FIXME: try to fix standard... */
> +                       frmi.reserved[0] = 0xdeafbeef;
> +
> +                       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor,
> +                                                             &frmi);
> +                       if (rval) {
> +                               rval = 0;
> +                               break;
> +                       }
> +
> +                       if (best_ival->denominator == 0)
> +                               goto do_it_now;
> +
> +                       /*
> +                        * We aim to use maximum resolution from the
> +                        * sensor, provided that the fps is at least
> +                        * as close as on the current mode.
> +                        */
> +#define FPS_ABS_DIFF(fps, ival) abs(fps - (ival).denominator / (ival).numerator)
> +
> +                       /* Select mode with closest fps. */
> +                       if (FPS_ABS_DIFF(fps, frmi.discrete)
> +                           < FPS_ABS_DIFF(fps, *best_ival))
> +                               goto do_it_now;
> +
> +                       /*
> +                        * Select bigger resolution if it's available
> +                        * at same fps.
> +                        */
> +                       if (frmi.width > best_pix_in->width
> +                           && FPS_ABS_DIFF(fps, frmi.discrete)
> +                           <= FPS_ABS_DIFF(fps, *best_ival))
> +                               goto do_it_now;
> +
> +                       continue;
> +
> +do_it_now:
> +                       *best_ival = frmi.discrete;
> +                       best_pix_out = pix_tmp_out;
> +                       best_pix_in->width = frmi.width;
> +                       best_pix_in->height = frmi.height;
> +                       best_pix_in->pixelformat = frmi.pixel_format;
> +               }
> +       }
> +
> +       if (best_ival->denominator == 0)
> +               return -EINVAL;
> +
> +       *wanted_pix_out = best_pix_out;
> +
> +       dev_info(vdev->cam->dev, "w %d, h %d -> w %d, h %d\n",
> +                best_pix_in->width, best_pix_in->height,
> +                best_pix_out.width, best_pix_out.height);
> +
> +       return isp_try_fmt_cap(best_pix_in, wanted_pix_out);
> +}
> +
> +static int s_pix_parm(struct omap34xxcam_videodev *vdev,
> +                     struct v4l2_pix_format *best_pix,
> +                     struct v4l2_pix_format *pix,
> +                     struct v4l2_fract *best_ival)
> +{
> +       struct v4l2_streamparm a;
> +       struct v4l2_format fmt;
> +       int rval;
> +       int fmtd_index;
> +
> +       for (fmtd_index = 0; ; fmtd_index++) {
> +               struct v4l2_fmtdesc fmtd;
> +
> +               fmtd.index = fmtd_index;
> +               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
> +               if (rval)
> +                       return rval;
> +               best_pix->pixelformat = fmtd.pixelformat;
> +
> +               rval = try_pix_parm(vdev, best_pix, pix, best_ival);
> +               if (!rval)
> +                       break;
> +       }
> +
> +       rval = isp_s_fmt_cap(best_pix, pix);
> +       if (rval)
> +               return rval;
> +
> +       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +       fmt.fmt.pix = *best_pix;
> +       rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &fmt);
> +       if (rval)
> +               return rval;
> +
> +       a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +       a.parm.capture.timeperframe = *best_ival;
> +       rval = vidioc_int_s_parm(vdev->vdev_sensor, &a);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_s_fmt_vid_cap - V4L2 set format capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @f: ptr to standard V4L2 format structure
> + *
> + * Attempts to set input format with the sensor driver (first) and then the
> + * ISP.  Returns the return code from vidioc_g_fmt_vid_cap().
> + */
> +static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
> +                               struct v4l2_format *f)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_pix_format pix_tmp;
> +       struct v4l2_fract timeperframe;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming) {
> +               rval = -EBUSY;
> +               goto out;
> +       }
> +
> +       vdev->want_pix = f->fmt.pix;
> +
> +       timeperframe = vdev->want_timeperframe;
> +
> +       rval = s_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
> +       pix_tmp = f->fmt.pix;
> +
> +out:
> +       mutex_unlock(&vdev->mutex);
> +
> +       if (!rval) {
> +               mutex_lock(&ofh->vbq.vb_lock);
> +               ofh->pix = pix_tmp;
> +               mutex_unlock(&ofh->vbq.vb_lock);
> +       }
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_try_fmt_vid_cap - V4L2 try format capabilities IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @f: ptr to standard V4L2 format structure
> + *
> + * Checks if the given format is supported by the sensor driver and
> + * by the ISP.
> + */
> +static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
> +                                 struct v4l2_format *f)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_pix_format pix_tmp;
> +       struct v4l2_fract timeperframe;
> +       int rval;
> +       int fmtd_index;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +
> +       for (fmtd_index = 0; ; fmtd_index++) {
> +               struct v4l2_fmtdesc fmtd;
> +
> +               timeperframe = vdev->want_timeperframe;
> +
> +               fmtd.index = fmtd_index;
> +               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
> +               if (rval)
> +                       return rval;
> +               pix_tmp.pixelformat = fmtd.pixelformat;
> +
> +               rval = try_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
> +               if (!rval)
> +                       break;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_reqbufs - V4L2 request buffers IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @b: ptr to standard V4L2 request buffers structure
> + *
> + * Attempts to get a buffer from the buffer queue associated with the
> + * fh through the video buffer library API.
> + */
> +static int vidioc_reqbufs(struct file *file, void *fh,
> +                         struct v4l2_requestbuffers *b)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming) {
> +               mutex_unlock(&vdev->mutex);
> +               return -EBUSY;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       rval = videobuf_reqbufs(&ofh->vbq, b);
> +
> +       /*
> +        * Either videobuf_reqbufs failed or the buffers are not
> +        * memory-mapped (which would need special attention).
> +        */
> +       if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
> +               goto out;
> +
> +out:
> +       return rval;
> +}
> +
> +/**
> + * vidioc_querybuf - V4L2 query buffer IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @b: ptr to standard V4L2 buffer structure
> + *
> + * Attempts to fill in the v4l2_buffer structure for the buffer queue
> + * associated with the fh through the video buffer library API.
> + */
> +static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +
> +       return videobuf_querybuf(&ofh->vbq, b);
> +}
> +
> +/**
> + * vidioc_qbuf - V4L2 queue buffer IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @b: ptr to standard V4L2 buffer structure
> + *
> + * Attempts to queue the v4l2_buffer on the buffer queue
> + * associated with the fh through the video buffer library API.
> + */
> +static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +
> +       return videobuf_qbuf(&ofh->vbq, b);
> +}
> +
> +/**
> + * vidioc_dqbuf - V4L2 dequeue buffer IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @b: ptr to standard V4L2 buffer structure
> + *
> + * Attempts to dequeue the v4l2_buffer from the buffer queue
> + * associated with the fh through the video buffer library API.  If the
> + * buffer is a user space buffer, then this function will also requeue it,
> + * as user does not expect to do this.
> + */
> +static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +
> +       return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
> +}
> +
> +/**
> + * vidioc_streamon - V4L2 streamon IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @i: V4L2 buffer type
> + *
> + * Attempts to start streaming by enabling the sensor interface and turning
> + * on video buffer streaming through the video buffer library API.  Upon
> + * success the function returns 0, otherwise an error code is returned.
> + */
> +static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct omap34xxcam_device *cam = vdev->cam;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming) {
> +               rval = -EBUSY;
> +               goto out;
> +       }
> +
> +       cam->dma_notify = 1;
> +       isp_sgdma_init();
> +       rval = videobuf_streamon(&ofh->vbq);
> +       if (rval) {
> +               dev_dbg(vdev->cam->dev, "omap34xxcam_slave_power_set failed\n");
> +               goto out;
> +       }
> +
> +
> +       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                          OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
> +       if (!rval) {
> +               vdev->streaming = file;
> +       } else {
> +               isp_stop();
> +               videobuf_streamoff(&ofh->vbq);
> +       }
> +
> +out:
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_streamoff - V4L2 streamoff IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @i: V4L2 buffer type
> + *
> + * Attempts to stop streaming by flushing all scheduled work, waiting on
> + * any queued buffers to complete and then stopping the ISP and turning
> + * off video buffer streaming through the video buffer library API.  Upon
> + * success the function returns 0, otherwise an error code is returned.
> + */
> +static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct videobuf_queue *q = &ofh->vbq;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->streaming == file)
> +               isp_stop();
> +
> +       rval = videobuf_streamoff(q);
> +       if (!rval)
> +               vdev->streaming = NULL;
> +
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
> +                                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +       omap34xxcam_slave_power_suggest(vdev, V4L2_POWER_STANDBY,
> +                                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_enum_input - V4L2 enumerate input IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @inp: V4L2 input type information structure
> + *
> + * Fills in v4l2_input structure.  Returns 0.
> + */
> +static int vidioc_enum_input(struct file *file, void *fh,
> +                            struct v4l2_input *inp)
> +{
> +       if (inp->index > 0)
> +               return -EINVAL;
> +
> +       strlcpy(inp->name, "camera", sizeof(inp->name));
> +       inp->type = V4L2_INPUT_TYPE_CAMERA;
> +
> +       return 0;
> +}
> +
> +/**
> + * vidioc_g_input - V4L2 get input IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @i: address to hold index of input supported
> + *
> + * Sets index to 0.
> + */
> +static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
> +{
> +       *i = 0;
> +
> +       return 0;
> +}
> +
> +/**
> + * vidioc_s_input - V4L2 set input IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @i: index of input selected
> + *
> + * 0 is only index supported.
> + */
> +static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
> +{
> +       if (i > 0)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +/**
> + * vidioc_queryctrl - V4L2 query control IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 query control ioctl structure
> + *
> + * If the requested control is supported, returns the control information
> + * in the v4l2_queryctrl structure.  Otherwise, returns -EINVAL if the
> + * control is not supported.  If the sensor being used is a "smart sensor",
> + * this request is passed to the sensor driver, otherwise the ISP is
> + * queried and if it does not support the requested control, the request
> + * is forwarded to the "raw" sensor driver to see if it supports it.
> + */
> +static int vidioc_queryctrl(struct file *file, void *fh,
> +                           struct v4l2_queryctrl *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_queryctrl a_tmp;
> +       int best_slave = -1;
> +       u32 best_ctrl = (u32)-1;
> +       int i;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               return vidioc_int_queryctrl(vdev->vdev_sensor, a);
> +
> +       /* No next flags: try slaves directly. */
> +       if (!(a->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
> +               for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +                       if (!vidioc_int_queryctrl(vdev->slave[i], a))
> +                               return 0;
> +               }
> +               return isp_queryctrl(a);
> +       }
> +
> +       /* Find slave with smallest next control id. */
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               a_tmp = *a;
> +
> +               if (vidioc_int_queryctrl(vdev->slave[i], &a_tmp))
> +                       continue;
> +
> +               if (a_tmp.id < best_ctrl) {
> +                       best_slave = i;
> +                       best_ctrl = a_tmp.id;
> +               }
> +       }
> +
> +       a_tmp = *a;
> +       if (!isp_queryctrl(&a_tmp)) {
> +               if (a_tmp.id < best_ctrl) {
> +                       *a = a_tmp;
> +
> +                       return 0;
> +               }
> +       }
> +
> +       if (best_slave == -1)
> +               return -EINVAL;
> +
> +       a->id = best_ctrl;
> +       return vidioc_int_queryctrl(vdev->slave[best_slave], a);
> +}
> +
> +/**
> + * vidioc_querymenu - V4L2 query menu IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 query menu ioctl structure
> + *
> + * If the requested control is supported, returns the menu information
> + * in the v4l2_querymenu structure.  Otherwise, returns -EINVAL if the
> + * control is not supported or is not a menu.  If the sensor being used
> + * is a "smart sensor", this request is passed to the sensor driver,
> + * otherwise the ISP is queried and if it does not support the requested
> + * menu control, the request is forwarded to the "raw" sensor driver to
> + * see if it supports it.
> + */
> +static int vidioc_querymenu(struct file *file, void *fh,
> +                           struct v4l2_querymenu *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int i;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               return vidioc_int_querymenu(vdev->vdev_sensor, a);
> +
> +       /* Try slaves directly. */
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               if (!vidioc_int_querymenu(vdev->slave[i], a))
> +                       return 0;
> +       }
> +       return -EINVAL;                 /* There is not yet isp_querymenu() */
> +}
> +
> +static int vidioc_g_ext_ctrls(struct file *file, void *fh,
> +                             struct v4l2_ext_controls *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int i, ctrl_idx, rval = 0;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
> +               struct v4l2_control ctrl;
> +
> +               ctrl.id = a->controls[ctrl_idx].id;
> +
> +               if (vdev->vdev_sensor_config.sensor_isp) {
> +                       rval = vidioc_int_g_ctrl(vdev->vdev_sensor, &ctrl);
> +               } else {
> +                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +                               rval = vidioc_int_g_ctrl(vdev->slave[i], &ctrl);
> +                               if (!rval)
> +                                       break;
> +                       }
> +               }
> +
> +               if (rval)
> +                       rval = isp_g_ctrl(&ctrl);
> +
> +               if (rval) {
> +                       a->error_idx = ctrl_idx;
> +                       break;
> +               }
> +
> +               a->controls[ctrl_idx].value = ctrl.value;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +static int vidioc_s_ext_ctrls(struct file *file, void *fh,
> +                             struct v4l2_ext_controls *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int i, ctrl_idx, rval = 0;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
> +               struct v4l2_control ctrl;
> +
> +               ctrl.id = a->controls[ctrl_idx].id;
> +               ctrl.value = a->controls[ctrl_idx].value;
> +
> +               if (vdev->vdev_sensor_config.sensor_isp) {
> +                       rval = vidioc_int_s_ctrl(vdev->vdev_sensor, &ctrl);
> +               } else {
> +                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +                               rval = vidioc_int_s_ctrl(vdev->slave[i], &ctrl);
> +                               if (!rval)
> +                                       break;
> +                       }
> +               }
> +
> +               if (rval)
> +                       rval = isp_s_ctrl(&ctrl);
> +
> +               if (rval) {
> +                       a->error_idx = ctrl_idx;
> +                       break;
> +               }
> +
> +               a->controls[ctrl_idx].value = ctrl.value;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_g_parm - V4L2 get parameters IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 stream parameters structure
> + *
> + * If request is for video capture buffer type, handles request by
> + * forwarding to sensor driver.
> + */
> +static int vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +               return -EINVAL;
> +
> +       mutex_lock(&vdev->mutex);
> +       rval = vidioc_int_g_parm(vdev->vdev_sensor, a);
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_s_parm - V4L2 set parameters IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 stream parameters structure
> + *
> + * If request is for video capture buffer type, handles request by
> + * first getting current stream parameters from sensor, then forwarding
> + * request to set new parameters to sensor driver.  It then attempts to
> + * enable the sensor interface with the new parameters.  If this fails, it
> + * reverts back to the previous parameters.
> + */
> +static int vidioc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_pix_format pix_tmp_sensor, pix_tmp;
> +       int rval;
> +
> +       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> +               return -EINVAL;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming) {
> +               rval = -EBUSY;
> +               goto out;
> +       }
> +
> +       vdev->want_timeperframe = a->parm.capture.timeperframe;
> +
> +       pix_tmp = vdev->want_pix;
> +
> +       rval = s_pix_parm(vdev, &pix_tmp_sensor, &pix_tmp,
> +                         &a->parm.capture.timeperframe);
> +
> +out:
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_cropcap - V4L2 crop capture IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 crop capture structure
> + *
> + * If using a "smart" sensor, just forwards request to the sensor driver,
> + * otherwise fills in the v4l2_cropcap values locally.
> + */
> +static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_cropcap *cropcap = a;
> +       int rval;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->vdev_sensor_config.sensor_isp) {
> +               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
> +       } else {
> +               struct v4l2_format f;
> +
> +               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
> +               if (!rval)
> +                       return rval;
> +
> +               /* cropcap failed, try to do this via g_fmt_cap */
> +               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &f);
> +               if (!rval) {
> +                       cropcap->bounds.top = 0;
> +                       cropcap->bounds.left = 0;
> +                       cropcap->bounds.width = f.fmt.pix.width;
> +                       cropcap->bounds.height = f.fmt.pix.height;
> +                       cropcap->defrect = cropcap->bounds;
> +                       cropcap->pixelaspect.numerator = 1;
> +                       cropcap->pixelaspect.denominator = 1;
> +               }
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_g_crop - V4L2 get capture crop IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 crop structure
> + *
> + * If using a "smart" sensor, just forwards request to the sensor driver,
> + * otherwise calls the isp functions to fill in current crop values.
> + */
> +static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval = 0;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
> +       else
> +               rval = isp_g_crop(a);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_s_crop - V4L2 set capture crop IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @a: standard V4L2 crop structure
> + *
> + * If using a "smart" sensor, just forwards request to the sensor driver,
> + * otherwise calls the isp functions to set the current crop values.
> + */
> +static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       struct v4l2_pix_format *pix = &ofh->pix;
> +       int rval = 0;
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
> +       else
> +               rval = isp_s_crop(a, pix);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return rval;
> +}
> +
> +static int vidioc_enum_framesizes(struct file *file, void *fh,
> +                                 struct v4l2_frmsizeenum *frms)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       u32 pixel_format;
> +       int rval;
> +
> +       pixel_format = frms->pixel_format;
> +       frms->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
> +
> +       mutex_lock(&vdev->mutex);
> +       rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
> +       mutex_unlock(&vdev->mutex);
> +
> +       frms->pixel_format = pixel_format;
> +
> +       return rval;
> +}
> +
> +static int vidioc_enum_frameintervals(struct file *file, void *fh,
> +                                     struct v4l2_frmivalenum *frmi)
> +{
> +       struct omap34xxcam_fh *ofh = fh;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       u32 pixel_format;
> +       int rval;
> +
> +       pixel_format = frmi->pixel_format;
> +       frmi->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
> +
> +       mutex_lock(&vdev->mutex);
> +       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
> +       mutex_unlock(&vdev->mutex);
> +
> +       frmi->pixel_format = pixel_format;
> +
> +       return rval;
> +}
> +
> +/**
> + * vidioc_default - private IOCTL handler
> + * @file: ptr. to system file structure
> + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
> + * @cmd: ioctl cmd value
> + * @arg: ioctl arg value
> + *
> + * If the sensor being used is a "smart sensor", this request is returned to
> + * caller with -EINVAL err code.  Otherwise if the control id is the private
> + * VIDIOC_PRIVATE_ISP_AEWB_REQ to update the analog gain or exposure,
> + * then this request is forwared directly to the sensor to incorporate the
> + * feedback. The request is then passed on to the ISP private IOCTL handler,
> + * isp_handle_private()
> + */
> +static int vidioc_default(struct file *file, void *fh, int cmd, void *arg)
> +{
> +       struct omap34xxcam_fh *ofh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = ofh->vdev;
> +       int rval;
> +
> +       if (vdev->vdev_sensor_config.sensor_isp) {
> +               rval = -EINVAL;
> +       } else {
> +               switch (cmd) {
> +               case VIDIOC_ENUM_FRAMESIZES:
> +                       rval = vidioc_enum_framesizes(file, fh, arg);
> +                       goto out;
> +               case VIDIOC_ENUM_FRAMEINTERVALS:
> +                       rval = vidioc_enum_frameintervals(file, fh, arg);
> +                       goto out;
> +               case VIDIOC_PRIVATE_ISP_AEWB_REQ:
> +               {
> +                       /* Need to update sensor first */
> +                       struct isph3a_aewb_data *data;
> +                       struct v4l2_control vc;
> +
> +                       data = (struct isph3a_aewb_data *) arg;
> +                       if (data->update & SET_EXPOSURE) {
> +                               vc.id = V4L2_CID_EXPOSURE;
> +                               vc.value = data->shutter;
> +                               mutex_lock(&vdev->mutex);
> +                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
> +                                                        &vc);
> +                               mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +                       if (data->update & SET_ANALOG_GAIN) {
> +                               vc.id = V4L2_CID_GAIN;
> +                               vc.value = data->gain;
> +                               mutex_lock(&vdev->mutex);
> +                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
> +                                                        &vc);
> +                               mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +               }
> +               break;
> +               case VIDIOC_PRIVATE_ISP_AF_REQ: {
> +                       /* Need to update lens first */
> +                       struct isp_af_data *data;
> +                       struct v4l2_control vc;
> +
> +                       if (!vdev->vdev_lens) {
> +                               rval = -EINVAL;
> +                               goto out;
> +                       }
> +                       data = (struct isp_af_data *) arg;
> +                       if (data->update & LENS_DESIRED_POSITION) {
> +                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
> +                               vc.value = data->desired_lens_direction;
> +                               mutex_lock(&vdev->mutex);
> +                               rval = vidioc_int_s_ctrl(vdev->vdev_lens, &vc);
> +                               mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                       }
> +                       if (data->update & REQUEST_STATISTICS) {
> +                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
> +                               mutex_lock(&vdev->mutex);
> +                               rval = vidioc_int_g_ctrl(vdev->vdev_lens, &vc);
> +                               mutex_unlock(&vdev->mutex);
> +                               if (rval)
> +                                       goto out;
> +                               data->xtrastats.lens_position = vc.value;
> +                       }
> +               }
> +                       break;
> +               }
> +
> +               mutex_lock(&vdev->mutex);
> +               rval = isp_handle_private(cmd, arg);
> +               mutex_unlock(&vdev->mutex);
> +       }
> +out:
> +       return rval;
> +}
> +
> +/*
> + *
> + * File operations.
> + *
> + */
> +
> +static long omap34xxcam_unlocked_ioctl(struct file *file, unsigned int cmd,
> +                                      unsigned long arg)
> +{
> +       return (long)video_ioctl2(file->f_dentry->d_inode, file, cmd, arg);
> +}
> +
> +/**
> + * omap34xxcam_poll - file operations poll handler
> + * @file: ptr. to system file structure
> + * @wait: system poll table structure
> + *
> + */
> +static unsigned int omap34xxcam_poll(struct file *file,
> +                                    struct poll_table_struct *wait)
> +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       struct videobuf_buffer *vb;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming != file) {
> +               mutex_unlock(&vdev->mutex);
> +               return POLLERR;
> +       }
> +       mutex_unlock(&vdev->mutex);
> +
> +       mutex_lock(&fh->vbq.vb_lock);
> +       if (list_empty(&fh->vbq.stream)) {
> +               mutex_unlock(&fh->vbq.vb_lock);
> +               return POLLERR;
> +       }
> +       vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
> +       mutex_unlock(&fh->vbq.vb_lock);
> +
> +       poll_wait(file, &vb->done, wait);
> +
> +       if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
> +               return POLLIN | POLLRDNORM;
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_mmap - file operations mmap handler
> + * @file: ptr. to system file structure
> + * @vma: system virt. mem. area structure
> + *
> + * Maps a virtual memory area via the video buffer API
> + */
> +static int omap34xxcam_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       return videobuf_mmap_mapper(&fh->vbq, vma);
> +}
> +
> +/**
> + * omap34xxcam_open - file operations open handler
> + * @inode: ptr. to system inode structure
> + * @file: ptr. to system file structure
> + *
> + * Allocates and initializes the per-filehandle data (omap34xxcam_fh),
> + * enables the sensor, opens/initializes the ISP interface and the
> + * video buffer queue.  Note that this function will allow multiple
> + * file handles to be open simultaneously, however only the first
> + * handle opened will initialize the ISP.  It is the application
> + * responsibility to only use one handle for streaming and the others
> + * for control only.
> + * This function returns 0 upon success and -ENODEV upon error.
> + */
> +static int omap34xxcam_open(struct inode *inode, struct file *file)
> +{
> +       struct omap34xxcam_videodev *vdev = NULL;
> +       struct omap34xxcam_device *cam = omap34xxcam;
> +       struct omap34xxcam_fh *fh;
> +       struct v4l2_format format;
> +       int i;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               if (cam->vdevs[i].vfd
> +                   && cam->vdevs[i].vfd->minor == iminor(inode)) {
> +                       vdev = &cam->vdevs[i];
> +                       break;
> +               }
> +       }
> +
> +       if (!vdev || !vdev->vfd)
> +               return -ENODEV;
> +
> +       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
> +       if (fh == NULL)
> +               return -ENOMEM;
> +
> +       mutex_lock(&vdev->mutex);
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               if (vdev->slave[i] != v4l2_int_device_dummy()
> +                   && !try_module_get(vdev->slave[i]->module)) {
> +                       mutex_unlock(&vdev->mutex);
> +                       goto out_try_module_get;
> +               }
> +       }
> +
> +       if (atomic_inc_return(&vdev->users) == 1) {
> +               isp_get();
> +               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                               OMAP34XXCAM_SLAVE_POWER_ALL))
> +                       goto out_slave_power_set_standby;
> +               omap34xxcam_slave_power_set(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +               omap34xxcam_slave_power_suggest(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +       }
> +
> +       fh->vdev = vdev;
> +
> +       /* FIXME: Check that we have sensor now... */
> +       if (vdev->vdev_sensor_config.sensor_isp)
> +               vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
> +       else
> +               isp_g_fmt_cap(&format.fmt.pix);
> +
> +       mutex_unlock(&vdev->mutex);
> +       /* FIXME: how about fh->pix when there are more users? */
> +       fh->pix = format.fmt.pix;
> +
> +       file->private_data = fh;
> +
> +       spin_lock_init(&fh->vbq_lock);
> +
> +       videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
> +                               &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
> +                               V4L2_FIELD_NONE,
> +                               sizeof(struct videobuf_buffer), fh);
> +
> +       return 0;
> +
> +out_slave_power_set_standby:
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                   OMAP34XXCAM_SLAVE_POWER_ALL);
> +       isp_put();
> +       atomic_dec(&vdev->users);
> +       mutex_unlock(&vdev->mutex);
> +
> +out_try_module_get:
> +       for (i--; i >= 0; i--)
> +               if (vdev->slave[i] != v4l2_int_device_dummy())
> +                       module_put(vdev->slave[i]->module);
> +
> +       kfree(fh);
> +
> +       return -ENODEV;
> +}
> +
> +/**
> + * omap34xxcam_release - file operations release handler
> + * @inode: ptr. to system inode structure
> + * @file: ptr. to system file structure
> + *
> + * Complement of omap34xxcam_open.  This function will flush any scheduled
> + * work, disable the sensor, close the ISP interface, stop the
> + * video buffer queue from streaming and free the per-filehandle data
> + * (omap34xxcam_fh).  Note that because multiple open file handles
> + * are allowed, this function will only close the ISP and disable the
> + * sensor when the last open file handle (by count) is closed.
> + * This function returns 0.
> + */
> +static int omap34xxcam_release(struct inode *inode, struct file *file)
> +{
> +       struct omap34xxcam_fh *fh = file->private_data;
> +       struct omap34xxcam_videodev *vdev = fh->vdev;
> +       int i;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (vdev->streaming == file) {
> +               isp_stop();
> +               videobuf_streamoff(&fh->vbq);
> +               omap34xxcam_slave_power_set(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
> +               omap34xxcam_slave_power_suggest(
> +                       vdev, V4L2_POWER_STANDBY,
> +                       OMAP34XXCAM_SLAVE_POWER_LENS);
> +               vdev->streaming = NULL;
> +       }
> +
> +       if (atomic_dec_return(&vdev->users) == 0) {
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                           OMAP34XXCAM_SLAVE_POWER_ALL);
> +               isp_put();
> +       }
> +       mutex_unlock(&vdev->mutex);
> +
> +       file->private_data = NULL;
> +
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
> +               if (vdev->slave[i] != v4l2_int_device_dummy())
> +                       module_put(vdev->slave[i]->module);
> +
> +       kfree(fh);
> +
> +       return 0;
> +}
> +
> +static struct file_operations omap34xxcam_fops = {
> +       .owner = THIS_MODULE,
> +       .llseek = no_llseek,
> +       .unlocked_ioctl = omap34xxcam_unlocked_ioctl,
> +       .poll = omap34xxcam_poll,
> +       .mmap = omap34xxcam_mmap,
> +       .open = omap34xxcam_open,
> +       .release = omap34xxcam_release,
> +};
> +
> +static void omap34xxcam_vfd_name_update(struct omap34xxcam_videodev *vdev)
> +{
> +       struct video_device *vfd = vdev->vfd;
> +       int i;
> +
> +       strlcpy(vfd->name, CAM_SHORT_NAME, sizeof(vfd->name));
> +       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
> +               strlcat(vfd->name, "/", sizeof(vfd->name));
> +               if (vdev->slave[i] == v4l2_int_device_dummy())
> +                       continue;
> +               strlcat(vfd->name, vdev->slave[i]->name, sizeof(vfd->name));
> +       }
> +       dev_info(vdev->cam->dev, "video%d is now %s\n", vfd->minor, vfd->name);
> +}
> +
> +/**
> + * omap34xxcam_device_unregister - V4L2 detach handler
> + * @s: ptr. to standard V4L2 device information structure
> + *
> + * Detach sensor and unregister and release the video device.
> + */
> +static void omap34xxcam_device_unregister(struct v4l2_int_device *s)
> +{
> +       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
> +       struct omap34xxcam_hw_config hwc;
> +
> +       BUG_ON(vidioc_int_g_priv(s, &hwc) < 0);
> +
> +       mutex_lock(&vdev->mutex);
> +
> +       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy()) {
> +               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +               vdev->slaves--;
> +               omap34xxcam_vfd_name_update(vdev);
> +       }
> +
> +       if (vdev->slaves == 0 && vdev->vfd) {
> +               if (vdev->vfd->minor == -1) {
> +                       /*
> +                        * The device was never registered, so release the
> +                        * video_device struct directly.
> +                        */
> +                       video_device_release(vdev->vfd);
> +               } else {
> +                       /*
> +                        * The unregister function will release the
> +                        * video_device struct as well as
> +                        * unregistering it.
> +                        */
> +                       video_unregister_device(vdev->vfd);
> +               }
> +               vdev->vfd = NULL;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +}
> +
> +static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = {
> +       .vidioc_querycap         = vidioc_querycap,
> +       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
> +       .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
> +       .vidioc_s_fmt_vid_cap    = vidioc_s_fmt_vid_cap,
> +       .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,
> +       .vidioc_reqbufs          = vidioc_reqbufs,
> +       .vidioc_querybuf         = vidioc_querybuf,
> +       .vidioc_qbuf             = vidioc_qbuf,
> +       .vidioc_dqbuf            = vidioc_dqbuf,
> +       .vidioc_streamon         = vidioc_streamon,
> +       .vidioc_streamoff        = vidioc_streamoff,
> +       .vidioc_enum_input       = vidioc_enum_input,
> +       .vidioc_g_input          = vidioc_g_input,
> +       .vidioc_s_input          = vidioc_s_input,
> +       .vidioc_queryctrl        = vidioc_queryctrl,
> +       .vidioc_querymenu        = vidioc_querymenu,
> +       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
> +       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
> +       .vidioc_g_parm           = vidioc_g_parm,
> +       .vidioc_s_parm           = vidioc_s_parm,
> +       .vidioc_cropcap          = vidioc_cropcap,
> +       .vidioc_g_crop           = vidioc_g_crop,
> +       .vidioc_s_crop           = vidioc_s_crop,
> +       .vidioc_default          = vidioc_default,
> +};
> +
> +/**
> + * omap34xxcam_device_register - V4L2 attach handler
> + * @s: ptr. to standard V4L2 device information structure
> + *
> + * Allocates and initializes the V4L2 video_device structure, initializes
> + * the sensor, and finally
> + registers the device with V4L2 based on the
> + * video_device structure.
> + *
> + * Returns 0 on success, otherwise an appropriate error code on
> + * failure.
> + */
> +static int omap34xxcam_device_register(struct v4l2_int_device *s)
> +{
> +       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
> +       struct omap34xxcam_device *cam = vdev->cam;
> +       struct omap34xxcam_hw_config hwc;
> +       struct video_device *vfd;
> +       int rval;
> +
> +       /* We need to check rval just once. The place is here. */
> +       if (vidioc_int_g_priv(s, &hwc))
> +               return -ENODEV;
> +
> +       if (vdev->index != hwc.dev_index)
> +               return -ENODEV;
> +
> +       if (hwc.dev_type < 0 || hwc.dev_type > OMAP34XXCAM_SLAVE_FLASH)
> +               return -EINVAL;
> +
> +       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy())
> +               return -EBUSY;
> +
> +       mutex_lock(&vdev->mutex);
> +       if (atomic_read(&vdev->users)) {
> +               dev_err(cam->dev, "we're open (%d), can't register\n",
> +                       atomic_read(&vdev->users));
> +               mutex_unlock(&vdev->mutex);
> +               return -EBUSY;
> +       }
> +
> +       vdev->slaves++;
> +       vdev->slave[hwc.dev_type] = s;
> +       vdev->slave_config[hwc.dev_type] = hwc;
> +
> +       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +               isp_get();
> +       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                          1 << hwc.dev_type);
> +       if (!rval && hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
> +               struct v4l2_format format;
> +               struct v4l2_streamparm a;
> +
> +               format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
> +
> +               a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +               rval |= vidioc_int_g_parm(vdev->vdev_sensor, &a);
> +               if (rval)
> +                       rval = -EBUSY;
> +
> +               vdev->want_pix = format.fmt.pix;
> +               vdev->want_timeperframe = a.parm.capture.timeperframe;
> +       }
> +       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF, 1 << hwc.dev_type);
> +       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
> +               isp_put();
> +
> +       if (rval)
> +               goto err;
> +
> +       /* Are we the first slave? */
> +       if (vdev->slaves == 1) {
> +               /* initialize the video_device struct */
> +               vdev->vfd = video_device_alloc();
> +               vfd = vdev->vfd;
> +               if (!vfd) {
> +                       dev_err(cam->dev,
> +                               "could not allocate video device struct\n");
> +                       return -ENOMEM;
> +               }
> +               vfd->release    = video_device_release;
> +               vfd->minor      = -1;
> +               vfd->fops       = &omap34xxcam_fops;
> +               vfd->ioctl_ops  = &omap34xxcam_ioctl_ops;
> +               video_set_drvdata(vfd, vdev);
> +
> +               if (video_register_device(vfd, VFL_TYPE_GRABBER,
> +                                         hwc.dev_minor) < 0) {
> +                       dev_err(cam->dev,
> +                               "could not register V4L device\n");
> +                       vfd->minor = -1;
> +                       rval = -EBUSY;
> +                       goto err;
> +               }
> +       } else {
> +               vfd = vdev->vfd;
> +       }
> +

This part seems to be weird. Because following the codes, this device
registering routine just tries to attach all of the slave devices (AKA
v4l2 int device) connected with OMAP3 camera interface.

Here is an example which could be troubled.
Dual camera attached on OMAP3 like 3G handsets. In this case, we
should register two of sensors as v4l2 int devices.
As I'm understanding, OMAP3 can process only one camera image at a time.
Exceptional case like when we can attach a camera to parallel
interface and the other to MIPI interface, then we can turn on both of
the cameras at the same time. But also in this case OMAP3 could
process only one camera module at a time. (Am I right?)

So, logically it does not make sense with making device nodes of every
single slave attached with OMAP3camera interface. Because they can't
be opened at the same time,even if it is possible it should not work
properly.

So.. how about making only single device node like /dev/video0 for
OMAP3 camera interface and make it switchable through V4L2 API. Like
VIDIOC_S_INPUT?





> +       omap34xxcam_vfd_name_update(vdev);
> +
> +       mutex_unlock(&vdev->mutex);
> +
> +       return 0;
> +
> +err:
> +       if (s == vdev->slave[hwc.dev_type]) {
> +               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
> +               vdev->slaves--;
> +       }
> +
> +       mutex_unlock(&vdev->mutex);
> +       omap34xxcam_device_unregister(s);
> +
> +       return rval;
> +}
> +
> +static struct v4l2_int_master omap34xxcam_master = {
> +       .attach = omap34xxcam_device_register,
> +       .detach = omap34xxcam_device_unregister,
> +};
> +
> +/*
> + *
> + * Driver Suspend/Resume
> + *
> + */
> +
> +#ifdef CONFIG_PM
> +/**
> + * omap34xxcam_suspend - platform driver PM suspend handler
> + * @pdev: ptr. to platform level device information structure
> + * @state: power state
> + *
> + * If applicable, stop capture and disable sensor.
> + *
> + * Returns 0 always
> + */
> +static int omap34xxcam_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
> +
> +       if (atomic_read(&vdev->users) == 0)
> +               return 0;
> +
> +       if (vdev->streaming) {
> +               isp_stop();
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
> +                                           OMAP34XXCAM_SLAVE_POWER_ALL);
> +       }
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_resume - platform driver PM resume handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * If applicable, resume capture and enable sensor.
> + *
> + * Returns 0 always
> + */
> +static int omap34xxcam_resume(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
> +
> +       if (atomic_read(&vdev->users) == 0)
> +               return 0;
> +
> +       if (vdev->streaming) {
> +               omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
> +                                           OMAP34XXCAM_SLAVE_POWER_ALL);
> +               isp_start();
> +       }
> +
> +       return 0;
> +}
> +#endif
> +
> +/*
> + *
> + * Driver initialisation and deinitialisation.
> + *
> + */
> +
> +/**
> + * omap34xxcam_remove - platform driver remove handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * Unregister device with V4L2, unmap camera registers, and
> + * free camera device information structure (omap34xxcam_device).
> + *
> + * Returns 0 always.
> + */
> +static int omap34xxcam_remove(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_device *cam = platform_get_drvdata(pdev);
> +       int i;
> +
> +       if (!cam)
> +               return 0;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
> +               if (cam->vdevs[i].cam == NULL)
> +                       continue;
> +
> +               v4l2_int_device_unregister(&cam->vdevs[i].master);
> +               cam->vdevs[i].cam = NULL;
> +       }
> +
> +       if (cam->mmio_base) {
> +               iounmap((void *)cam->mmio_base);
> +               cam->mmio_base = 0;
> +       }
> +
> +       if (cam->mmio_base_phys) {
> +               release_mem_region(cam->mmio_base_phys, cam->mmio_size);
> +               cam->mmio_base_phys = 0;
> +       }
> +
> +       omap34xxcam = NULL;
> +
> +       kfree(cam);
> +
> +       return 0;
> +}
> +
> +/**
> + * omap34xxcam_probe - platform driver probe handler
> + * @pdev: ptr. to platform level device information structure
> + *
> + * Allocates and initializes camera device information structure
> + * (omap34xxcam_device), maps the device registers and gets the
> + * device IRQ.  Registers the device as a V4L2 client.
> + *
> + * Returns 0 on success or -ENODEV on failure.
> + */
> +static int omap34xxcam_probe(struct platform_device *pdev)
> +{
> +       struct omap34xxcam_device *cam;
> +       struct resource *mem;
> +       struct isp_sysc isp_sysconfig;
> +       int irq;
> +       int i;
> +
> +       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
> +       if (!cam) {
> +               dev_err(&pdev->dev, "could not allocate memory\n");
> +               goto err;
> +       }
> +
> +       platform_set_drvdata(pdev, cam);
> +
> +       cam->dev = &pdev->dev;
> +
> +       /* request the mem region for the camera registers */
> +       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!mem) {
> +               dev_err(cam->dev, "no mem resource?\n");
> +               goto err;
> +       }
> +
> +       if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
> +                               pdev->name)) {
> +               dev_err(cam->dev,
> +                       "cannot reserve camera register I/O region\n");
> +               goto err;
> +
> +       }
> +       cam->mmio_base_phys = mem->start;
> +       cam->mmio_size = (mem->end - mem->start) + 1;
> +
> +       /* map the region */
> +       cam->mmio_base = (unsigned long)
> +                       ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
> +       if (!cam->mmio_base) {
> +               dev_err(cam->dev, "cannot map camera register I/O region\n");
> +               goto err;
> +       }
> +
> +       irq = platform_get_irq(pdev, 0);
> +       if (irq <= 0) {
> +               dev_err(cam->dev, "no irq for camera?\n");
> +               goto err;
> +       }
> +
> +       isp_get();
> +       isp_sysconfig.reset = 0;
> +       isp_sysconfig.idle_mode = 1;
> +       isp_power_settings(isp_sysconfig);
> +       isp_put();
> +
> +       omap34xxcam = cam;
> +
> +       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {

This routine depends on how many slave devices are connected with
omap3 camera interface.
Seems to be no problem.

> +               struct omap34xxcam_videodev *vdev = &cam->vdevs[i];
> +               struct v4l2_int_device *m = &vdev->master;
> +
> +               m->module       = THIS_MODULE;
> +               strlcpy(m->name, CAM_NAME, sizeof(m->name));
> +               m->type         = v4l2_int_type_master;
> +               m->u.master     = &omap34xxcam_master;
> +               m->priv         = vdev;
> +
> +               mutex_init(&vdev->mutex);
> +               vdev->index             = i;
> +               vdev->cam               = cam;
> +               vdev->vdev_sensor =
> +                       vdev->vdev_lens =
> +                       vdev->vdev_flash = v4l2_int_device_dummy();
> +               setup_timer(&vdev->poweroff_timer,
> +                           omap34xxcam_slave_power_timer, (unsigned long)vdev);
> +               INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
> +
> +               if (v4l2_int_device_register(m))

At this point, v4l2 int devices are being registered. Also makes sense.

> +                       goto err;
> +       }
> +
> +       return 0;
> +
> +err:
> +       omap34xxcam_remove(pdev);
> +       return -ENODEV;
> +}
> +
> +static struct platform_driver omap34xxcam_driver = {
> +       .probe = omap34xxcam_probe,
> +       .remove = omap34xxcam_remove,
> +#ifdef CONFIG_PM
> +       .suspend = omap34xxcam_suspend,
> +       .resume = omap34xxcam_resume,
> +#endif
> +       .driver = {
> +                  .name = CAM_NAME,
> +                  },
> +};
> +
> +/*
> + *
> + * Module initialisation and deinitialisation
> + *
> + */
> +
> +/**
> + * omap34xxcam_init - module_init function
> + *
> + * Calls platfrom driver to register probe, remove,
> + * suspend and resume functions.
> + *
> + */
> +static int __init omap34xxcam_init(void)
> +{
> +       return platform_driver_register(&omap34xxcam_driver);
> +}
> +
> +/**
> + * omap34xxcam_cleanup - module_exit function
> + *
> + * Calls platfrom driver to unregister probe, remove,
> + * suspend and resume functions.
> + *
> + */
> +static void __exit omap34xxcam_cleanup(void)
> +{
> +       platform_driver_unregister(&omap34xxcam_driver);
> +}
> +
> +MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com");
> +MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
> +MODULE_LICENSE("GPL");
> +
> +late_initcall(omap34xxcam_init);
> +module_exit(omap34xxcam_cleanup);
> diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
> new file mode 100644
> index 0000000..36f7fd5
> --- /dev/null
> +++ b/drivers/media/video/omap34xxcam.h
> @@ -0,0 +1,221 @@
> +/*
> + * drivers/media/video/omap34xxcam.c
> + *
> + * Copyright (C) 2006--2008 Nokia Corporation
> + * Copyright (C) 2007, 2008 Texas Instruments
> + *
> + * Contact: Sakari Ailus <sakari.ailus@nokia.com>
> + *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *
> + * Originally based on the OMAP 2 camera driver.
> + *
> + * Written by Sakari Ailus <sakari.ailus@nokia.com>
> + *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
> + *            Sergio Aguirre <saaguirre@ti.com>
> + *            Mohit Jalori
> + *            Sameer Venkatraman
> + *            Leonides Martinez
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * 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 St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef OMAP34XXCAM_H
> +#define OMAP34XXCAM_H
> +
> +#include <media/v4l2-int-device.h>
> +#include "isp/isp.h"
> +
> +#define CAM_NAME                       "omap34xxcam"
> +#define CAM_SHORT_NAME                 "omap3"
> +
> +#define OMAP_ISP_AF            (1 << 4)
> +#define OMAP_ISP_HIST          (1 << 5)
> +#define OMAP34XXCAM_XCLK_NONE  -1
> +#define OMAP34XXCAM_XCLK_A     0
> +#define OMAP34XXCAM_XCLK_B     1
> +
> +#define OMAP34XXCAM_SLAVE_SENSOR       0
> +#define OMAP34XXCAM_SLAVE_LENS         1
> +#define OMAP34XXCAM_SLAVE_FLASH                2 /* This is the last slave! */
> +
> +/* mask for omap34xxcam_slave_power_set */
> +#define OMAP34XXCAM_SLAVE_POWER_SENSOR (1 << OMAP34XXCAM_SLAVE_SENSOR)
> +#define OMAP34XXCAM_SLAVE_POWER_LENS   (1 << OMAP34XXCAM_SLAVE_LENS)
> +#define OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS \
> +       (OMAP34XXCAM_SLAVE_POWER_SENSOR | OMAP34XXCAM_SLAVE_POWER_LENS)
> +#define OMAP34XXCAM_SLAVE_POWER_FLASH  (1 << OMAP34XXCAM_SLAVE_FLASH)
> +#define OMAP34XXCAM_SLAVE_POWER_ALL    -1
> +
> +#define OMAP34XXCAM_VIDEODEVS          4
> +
> +struct omap34xxcam_device;
> +struct omap34xxcam_videodev;
> +
> +struct omap34xxcam_sensor_config {
> +       int xclk;
> +       int sensor_isp;
> +       u32 capture_mem;
> +};
> +
> +struct omap34xxcam_lens_config {
> +};
> +
> +struct omap34xxcam_flash_config {
> +};
> +
> +/**
> + * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
> + * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
> + * @sensor_isp: Is sensor smart/SOC or raw
> + * @s_pix_sparm: Access function to set pix and sparm.
> + * Pix will override sparm
> + */
> +struct omap34xxcam_hw_config {
> +       int dev_index; /* Index in omap34xxcam_sensors */
> +       int dev_minor; /* Video device minor number */
> +       int dev_type; /* OMAP34XXCAM_SLAVE_* */
> +       union {
> +               struct omap34xxcam_sensor_config sensor;
> +               struct omap34xxcam_lens_config lens;
> +               struct omap34xxcam_flash_config flash;
> +       } u;
> +};
> +
> +/**
> + * struct omap34xxcam_videodev - per /dev/video* structure
> + * @mutex: serialises access to this structure
> + * @cam: pointer to cam hw structure
> + * @master: we are v4l2_int_device master
> + * @sensor: sensor device
> + * @lens: lens device
> + * @flash: flash device
> + * @slaves: how many slaves we have at the moment
> + * @vfd: our video device
> + * @capture_mem: maximum kernel-allocated capture memory
> + * @if_u: sensor interface stuff
> + * @index: index of this structure in cam->vdevs
> + * @users: how many users we have
> + * @power_state: Current power state
> + * @power_state_wish: New power state when poweroff_timer expires
> + * @power_state_mask: Bitmask of devices to set the new power state
> + * @poweroff_timer: Timer for dispatching poweroff_work
> + * @poweroff_work: Work for slave power state change
> + * @sensor_config: ISP-speicific sensor configuration
> + * @lens_config: ISP-speicific lens configuration
> + * @flash_config: ISP-speicific flash configuration
> + * @streaming: streaming file handle, if streaming is enabled
> + */
> +struct omap34xxcam_videodev {
> +       struct mutex mutex; /* serialises access to this structure */
> +
> +       struct omap34xxcam_device *cam;
> +       struct v4l2_int_device master;
> +
> +#define vdev_sensor slave[OMAP34XXCAM_SLAVE_SENSOR]
> +#define vdev_lens slave[OMAP34XXCAM_SLAVE_LENS]
> +#define vdev_flash slave[OMAP34XXCAM_SLAVE_FLASH]
> +       struct v4l2_int_device *slave[OMAP34XXCAM_SLAVE_FLASH + 1];
> +
> +       /* number of slaves attached */
> +       int slaves;
> +
> +       /*** video device parameters ***/
> +       struct video_device *vfd;
> +       int capture_mem;
> +
> +       /*** general driver state information ***/
> +       /*
> +        * Sensor interface parameters: interface type, CC_CTRL
> +        * register value and interface specific data.
> +        */
> +       u32 xclk;
> +       /* index to omap34xxcam_videodevs of this structure */
> +       int index;
> +       atomic_t users;
> +       enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
> +       enum v4l2_power power_state_wish;
> +       int power_state_mask;
> +       struct timer_list poweroff_timer;
> +       struct work_struct poweroff_work;
> +
> +#define vdev_sensor_config slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor
> +#define vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens
> +#define vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash
> +       struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH + 1];
> +
> +       /*** capture data ***/
> +       struct v4l2_fract want_timeperframe;
> +       struct v4l2_pix_format want_pix;
> +       /* file handle, if streaming is on */
> +       struct file *streaming;
> +};
> +
> +/**
> + * struct omap34xxcam_device - per-device data structure
> + * @mutex: mutex serialises access to this structure
> + * @sgdma_in_queue: Number or sgdma requests in scatter-gather queue,
> + * protected by the lock above.
> + * @sgdma: ISP sgdma subsystem information structure
> + * @dma_notify: DMA notify flag
> + * @irq: irq number platform HW resource
> + * @mmio_base: register map memory base (platform HW resource)
> + * @mmio_base_phys: register map memory base physical address
> + * @mmio_size: register map memory size
> + * @dev: device structure
> + * @vdevs: /dev/video specific structures
> + * @fck: camera module fck clock information
> + * @ick: camera module ick clock information
> + */
> +struct omap34xxcam_device {
> +       struct mutex mutex; /* serialises access to this structure */
> +       int sgdma_in_queue;
> +       struct isp_sgdma sgdma;
> +       int dma_notify;
> +
> +       /*** platform HW resource ***/
> +       unsigned int irq;
> +       unsigned long mmio_base;
> +       unsigned long mmio_base_phys;
> +       unsigned long mmio_size;
> +
> +       /*** interfaces and device ***/
> +       struct device *dev;
> +       struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
> +
> +       /*** camera module clocks ***/
> +       struct clk *fck;
> +       struct clk *ick;
> +       bool sensor_if_enabled;
> +};
> +
> +/**
> + * struct omap34xxcam_fh - per-filehandle data structure
> + * @vbq_lock: spinlock for the videobuf queue
> + * @vbq: V4L2 video buffer queue structure
> + * @pix: V4L2 pixel format structure (serialise pix by vbq->lock)
> + * @field_count: field counter for videobuf_buffer
> + * @vdev: our /dev/video specific structure
> + */
> +struct omap34xxcam_fh {
> +       spinlock_t vbq_lock; /* spinlock for the videobuf queue */
> +       struct videobuf_queue vbq;
> +       struct v4l2_pix_format pix;
> +       atomic_t field_count;
> +       /* accessing cam here doesn't need serialisation: it's constant */
> +       struct omap34xxcam_videodev *vdev;
> +};
> +
> +#endif /* ifndef OMAP34XXCAM_H */
> --
> 1.5.6.5
>
>
> --
> video4linux-list mailing list
> Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
> https://www.redhat.com/mailman/listinfo/video4linux-list
>


Cheers,

Nate

-- 
========================================================
DongSoo(Nathaniel), Kim
Engineer
Mobile S/W Platform Lab. S/W centre
Telecommunication R&D Centre
Samsung Electronics CO., LTD.
e-mail : dongsoo.kim@gmail.com
          dongsoo45.kim@samsung.com
========================================================

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver
@ 2008-12-11 20:38 ` Aguirre Rodriguez, Sergio Alberto
  2009-02-23  8:08   ` DongSoo(Nathaniel) Kim
  2009-02-23  8:26   ` DongSoo(Nathaniel) Kim
  0 siblings, 2 replies; 43+ messages in thread
From: Aguirre Rodriguez, Sergio Alberto @ 2008-12-11 20:38 UTC (permalink / raw)
  To: linux-omap, video4linux-list
  Cc: Sakari Ailus, Tuukka.O Toivonen, Nagalla, Hari

>From d5f4681ba9a74df4ea02332fe1aeccda2142a482 Mon Sep 17 00:00:00 2001
From: Sergio Aguirre <saaguirre@ti.com>
Date: Thu, 11 Dec 2008 13:35:47 -0600
Subject: [PATCH] OMAP34XXCAM: Add driver

Signed-off-by: Sakari Ailus <sakari.ailus@nokia.com>
---
 drivers/media/video/Kconfig       |    8 +
 drivers/media/video/Makefile      |    2 +
 drivers/media/video/omap34xxcam.c | 2060 +++++++++++++++++++++++++++++++++++++
 drivers/media/video/omap34xxcam.h |  221 ++++
 4 files changed, 2291 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/omap34xxcam.c
 create mode 100644 drivers/media/video/omap34xxcam.h

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 6150d6f..a20a83b 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -702,6 +702,14 @@ config VIDEO_CAFE_CCIC

 source "drivers/media/video/isp/Kconfig"

+config VIDEO_OMAP3
+        tristate "OMAP 3 Camera support"
+       select VIDEOBUF_GEN
+       select VIDEOBUF_DMA_SG
+       depends on VIDEO_V4L2 && ARCH_OMAP34XX
+       ---help---
+         Driver for an OMAP 3 camera controller.
+
 config SOC_CAMERA
        tristate "SoC camera support"
        depends on VIDEO_V4L2 && HAS_DMA
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 16962f3..a2f73cf 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -101,6 +101,8 @@ obj-$(CONFIG_VIDEO_OV7670)  += ov7670.o

 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o

+obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o isp/
+
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_SE401)         += se401.o
diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
new file mode 100644
index 0000000..31b6b60
--- /dev/null
+++ b/drivers/media/video/omap34xxcam.c
@@ -0,0 +1,2060 @@
+/*
+ * drivers/media/video/omap34xxcam.c
+ *
+ * Copyright (C) 2006--2008 Nokia Corporation
+ * Copyright (C) 2007, 2008 Texas Instruments
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *
+ * Originally based on the OMAP 2 camera driver.
+ *
+ * Written by Sakari Ailus <sakari.ailus@nokia.com>
+ *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *            Sergio Aguirre <saaguirre@ti.com>
+ *            Mohit Jalori
+ *            Sameer Venkatraman
+ *            Leonides Martinez
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/pci.h>         /* needed for videobufs */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "omap34xxcam.h"
+#include "isp/isp.h"
+#include "isp/ispmmu.h"
+#include "isp/ispreg.h"
+#include "isp/ispccdc.h"
+#include "isp/isph3a.h"
+#include "isp/isp_af.h"
+#include "isp/isphist.h"
+#include "isp/isppreview.h"
+#include "isp/ispresizer.h"
+
+#define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+/* global variables */
+static struct omap34xxcam_device *omap34xxcam;
+
+struct omap34xxcam_fh *camfh_saved;
+
+#define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ)
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/**
+ * omap34xxcam_slave_power_set - set slave power state
+ * @vdev: per-video device data structure
+ * @power: new power state
+ */
+static int omap34xxcam_slave_power_set(struct omap34xxcam_videodev *vdev,
+                                      enum v4l2_power power,
+                                      int mask)
+{
+       int rval = 0, i = 0;
+
+       BUG_ON(!mutex_is_locked(&vdev->mutex));
+
+       vdev->power_state_wish = -1;
+
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               if (vdev->slave[i] == v4l2_int_device_dummy())
+                       continue;
+
+               if (!(mask & (1 << i))
+                   || power == vdev->power_state[i])
+                       continue;
+
+               rval = vidioc_int_s_power(vdev->slave[i], power);
+
+               if (rval && power != V4L2_POWER_OFF) {
+                       power = V4L2_POWER_OFF;
+                       goto out;
+               }
+
+               vdev->power_state[i] = power;
+       }
+
+       return 0;
+
+out:
+       for (i--; i >= 0; i--) {
+               if (vdev->slave[i] == v4l2_int_device_dummy())
+                       continue;
+
+               if (!(mask & (1 << i)))
+                       continue;
+
+               vidioc_int_s_power(vdev->slave[i], power);
+               vdev->power_state[i] = power;
+       }
+
+       return rval;
+}
+
+static void omap34xxcam_slave_power_work(struct work_struct *work)
+{
+       struct omap34xxcam_videodev *vdev =
+               container_of(work, struct omap34xxcam_videodev, poweroff_work);
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->power_state_wish != -1)
+               omap34xxcam_slave_power_set(vdev, vdev->power_state_wish,
+                                           vdev->power_state_mask);
+
+       mutex_unlock(&vdev->mutex);
+}
+
+static void omap34xxcam_slave_power_timer(unsigned long ptr)
+{
+       struct omap34xxcam_videodev *vdev = (void *)ptr;
+
+       schedule_work(&vdev->poweroff_work);
+}
+
+/**
+ * omap34xxcam_slave_power_suggest - delayed power state change
+ *
+ * @vdev: per-video device data structure
+ * @power: new power state
+ */
+static void omap34xxcam_slave_power_suggest(struct omap34xxcam_videodev *vdev,
+                                           enum v4l2_power power,
+                                           int mask)
+{
+       BUG_ON(!mutex_is_locked(&vdev->mutex));
+
+       del_timer(&vdev->poweroff_timer);
+
+       vdev->power_state_wish = power;
+       vdev->power_state_mask = mask;
+
+       mod_timer(&vdev->poweroff_timer, jiffies + OMAP34XXCAM_POWEROFF_DELAY);
+}
+
+/**
+ * omap34xxcam_update_vbq - Updates VBQ with completed input buffer
+ * @vb: ptr. to standard V4L2 video buffer structure
+ *
+ * Updates video buffer queue with completed buffer passed as
+ * input parameter.  Also updates ISP H3A timestamp and field count
+ * statistics.
+ */
+int omap34xxcam_update_vbq(struct videobuf_buffer *vb)
+{
+       struct omap34xxcam_fh *fh = camfh_saved;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       int rval = 0;
+
+       do_gettimeofday(&vb->ts);
+       vb->field_count = atomic_add_return(2, &fh->field_count);
+       vb->state = VIDEOBUF_DONE;
+
+       if (vdev->streaming)
+               rval = 1;
+
+       wake_up(&vb->done);
+
+       return rval;
+}
+
+/**
+ * omap34xxcam_vbq_setup - Calcs size and num of buffs allowed in queue
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @cnt: ptr to location to hold the count of buffers to be in the queue
+ * @size: ptr to location to hold the size of a frame
+ *
+ * Calculates the number of buffers of current image size that can be
+ * supported by the available capture memory.
+ */
+static int omap34xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+                                unsigned int *size)
+{
+       struct omap34xxcam_fh *fh = vbq->priv_data;
+
+       if (*cnt <= 0)
+               *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+       if (*cnt > VIDEO_MAX_FRAME)
+               *cnt = VIDEO_MAX_FRAME;
+
+       *size = fh->pix.sizeimage;
+
+       while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
+               (*cnt)--;
+
+       while ((*size * *cnt) > ispmmu_get_mapeable_space())
+               (*cnt)--;
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_vbq_release - Free resources for input VBQ and VB
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ *
+ * Unmap and free all memory associated with input VBQ and VB, also
+ * unmap the address in ISP MMU.  Reset the VB state.
+ */
+static void omap34xxcam_vbq_release(struct videobuf_queue *vbq,
+                                   struct videobuf_buffer *vb)
+{
+       if (!vbq->streaming) {
+               isp_vbq_release(vbq, vb);
+               videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+               videobuf_dma_free(videobuf_to_dma(vb));
+               vb->state = VIDEOBUF_NEEDS_INIT;
+       }
+       return;
+}
+
+/**
+ * omap34xxcam_vbq_prepare - V4L2 video ops buf_prepare handler
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ * @field: standard V4L2 field enum
+ *
+ * Verifies there is sufficient locked memory for the requested
+ * buffer, or if there is not, allocates, locks and initializes
+ * it.
+ */
+static int omap34xxcam_vbq_prepare(struct videobuf_queue *vbq,
+                                  struct videobuf_buffer *vb,
+                                  enum v4l2_field field)
+{
+       struct omap34xxcam_fh *fh = vbq->priv_data;
+       int err = 0;
+
+       /*
+        * Accessing pix here is okay since it's constant while
+        * streaming is on (and we only get called then).
+        */
+       if (vb->baddr) {
+               /* This is a userspace buffer. */
+               if (fh->pix.sizeimage > vb->bsize)
+                       /* The buffer isn't big enough. */
+                       return -EINVAL;
+       } else {
+               if (vb->state != VIDEOBUF_NEEDS_INIT
+                   && fh->pix.sizeimage > vb->bsize)
+                       /*
+                        * We have a kernel bounce buffer that has
+                        * already been allocated.
+                        */
+                       omap34xxcam_vbq_release(vbq, vb);
+       }
+
+       vb->size = fh->pix.bytesperline * fh->pix.height;
+       vb->width = fh->pix.width;
+       vb->height = fh->pix.height;
+       vb->field = field;
+
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               err = videobuf_iolock(vbq, vb, NULL);
+               if (!err) {
+                       /* isp_addr will be stored locally inside isp code */
+                       err = isp_vbq_prepare(vbq, vb, field);
+               }
+       }
+
+       if (!err)
+               vb->state = VIDEOBUF_PREPARED;
+       else
+               omap34xxcam_vbq_release(vbq, vb);
+
+       return err;
+
+}
+
+/**
+ * omap34xxcam_vbq_queue - V4L2 video ops buf_queue handler
+ * @vbq: ptr. to standard V4L2 video buffer queue structure
+ * @vb: ptr to standard V4L2 video buffer structure
+ *
+ * Maps the video buffer to sgdma and through the isp, sets
+ * the isp buffer done callback and sets the video buffer state
+ * to active.
+ */
+static void omap34xxcam_vbq_queue(struct videobuf_queue *vbq,
+                                 struct videobuf_buffer *vb)
+{
+       struct omap34xxcam_fh *fh = vbq->priv_data;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       enum videobuf_state state = vb->state;
+       isp_vbq_callback_ptr func_ptr;
+       int err = 0;
+       camfh_saved = fh;
+
+       func_ptr = omap34xxcam_update_vbq;
+       vb->state = VIDEOBUF_ACTIVE;
+
+       err = isp_sgdma_queue(videobuf_to_dma(vb),
+                             vb, 0, &vdev->cam->dma_notify, func_ptr);
+       if (err) {
+               dev_dbg(vdev->cam->dev, "vbq queue failed\n");
+               vb->state = state;
+       }
+
+}
+
+static struct videobuf_queue_ops omap34xxcam_vbq_ops = {
+       .buf_setup = omap34xxcam_vbq_setup,
+       .buf_prepare = omap34xxcam_vbq_prepare,
+       .buf_queue = omap34xxcam_vbq_queue,
+       .buf_release = omap34xxcam_vbq_release,
+};
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+/**
+ * vidioc_querycap - V4L2 query capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @cap: ptr to standard V4L2 capability structure
+ *
+ * Fill in the V4L2 capabliity structure for the camera device
+ */
+static int vidioc_querycap(struct file *file, void *fh,
+                          struct v4l2_capability *cap)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+
+       strlcpy(cap->driver, CAM_SHORT_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, vdev->vfd->name, sizeof(cap->card));
+       cap->version = OMAP34XXCAM_VERSION;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+/**
+ * vidioc_enum_fmt_vid_cap - V4L2 enumerate format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format description structure
+ *
+ * Fills in enumerate format capabilities information for sensor (if SOC
+ * sensor attached) or ISP (if raw sensor attached).
+ */
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+                                  struct v4l2_fmtdesc *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, f);
+       else
+               rval = isp_enum_fmt_cap(f);
+
+       return rval;
+}
+
+/**
+ * vidioc_g_fmt_vid_cap - V4L2 get format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Fills in format capabilities for sensor (if SOC sensor attached) or ISP
+ * (if raw sensor attached).
+ */
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+
+       mutex_lock(&vdev->mutex);
+       f->fmt.pix = ofh->pix;
+       mutex_unlock(&vdev->mutex);
+
+       return 0;
+}
+
+static int try_pix_parm(struct omap34xxcam_videodev *vdev,
+                       struct v4l2_pix_format *best_pix_in,
+                       struct v4l2_pix_format *wanted_pix_out,
+                       struct v4l2_fract *best_ival)
+{
+       int fps;
+       int rval;
+       int size_index;
+       struct v4l2_pix_format best_pix_out;
+
+       if (best_ival->numerator == 0
+           || best_ival->denominator == 0)
+               best_ival->denominator = 30, best_ival->numerator = 1;
+
+       fps = best_ival->denominator / best_ival->numerator;
+
+       best_ival->denominator = 0;
+
+       best_pix_out.height = INT_MAX >> 1;
+       best_pix_out.width = best_pix_out.height;
+
+       /*
+        * Get supported resolutions.
+        */
+       for (size_index = 0; ; size_index++) {
+               struct v4l2_frmsizeenum frms;
+               struct v4l2_pix_format pix_tmp_in, pix_tmp_out;
+               int ival_index;
+
+               frms.index = size_index;
+               frms.pixel_format = best_pix_in->pixelformat;
+
+               rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, &frms);
+               if (rval) {
+                       rval = 0;
+                       break;
+               }
+
+               pix_tmp_in.pixelformat = frms.pixel_format;
+               pix_tmp_in.width = frms.discrete.width;
+               pix_tmp_in.height = frms.discrete.height;
+               pix_tmp_out = *wanted_pix_out;
+               /* Don't do upscaling. */
+               if (pix_tmp_out.width > pix_tmp_in.width)
+                       pix_tmp_out.width = pix_tmp_in.width;
+               if (pix_tmp_out.height > pix_tmp_in.height)
+                       pix_tmp_out.height = pix_tmp_in.height;
+               rval = isp_try_fmt_cap(&pix_tmp_in, &pix_tmp_out);
+               if (rval)
+                       return rval;
+
+#define IS_SMALLER_OR_EQUAL(pix1, pix2)                        \
+               ((pix1)->width + (pix1)->height         \
+                < (pix2)->width + (pix2)->height)
+#define SIZE_DIFF(pix1, pix2)                                  \
+               (abs((pix1)->width - (pix2)->width)             \
+                + abs((pix1)->height - (pix2)->height))
+
+               /*
+                * Don't use modes that are farther from wanted size
+                * that what we already got.
+                */
+               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
+                   > SIZE_DIFF(&best_pix_out, wanted_pix_out))
+                       continue;
+
+               /*
+                * There's an input mode that can provide output
+                * closer to wanted.
+                */
+               if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
+                   < SIZE_DIFF(&best_pix_out, wanted_pix_out))
+                       /* Force renegotation of fps etc. */
+                       best_ival->denominator = 0;
+
+               for (ival_index = 0; ; ival_index++) {
+                       struct v4l2_frmivalenum frmi;
+
+                       frmi.index = ival_index;
+                       frmi.pixel_format = frms.pixel_format;
+                       frmi.width = frms.discrete.width;
+                       frmi.height = frms.discrete.height;
+                       /* FIXME: try to fix standard... */
+                       frmi.reserved[0] = 0xdeafbeef;
+
+                       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor,
+                                                             &frmi);
+                       if (rval) {
+                               rval = 0;
+                               break;
+                       }
+
+                       if (best_ival->denominator == 0)
+                               goto do_it_now;
+
+                       /*
+                        * We aim to use maximum resolution from the
+                        * sensor, provided that the fps is at least
+                        * as close as on the current mode.
+                        */
+#define FPS_ABS_DIFF(fps, ival) abs(fps - (ival).denominator / (ival).numerator)
+
+                       /* Select mode with closest fps. */
+                       if (FPS_ABS_DIFF(fps, frmi.discrete)
+                           < FPS_ABS_DIFF(fps, *best_ival))
+                               goto do_it_now;
+
+                       /*
+                        * Select bigger resolution if it's available
+                        * at same fps.
+                        */
+                       if (frmi.width > best_pix_in->width
+                           && FPS_ABS_DIFF(fps, frmi.discrete)
+                           <= FPS_ABS_DIFF(fps, *best_ival))
+                               goto do_it_now;
+
+                       continue;
+
+do_it_now:
+                       *best_ival = frmi.discrete;
+                       best_pix_out = pix_tmp_out;
+                       best_pix_in->width = frmi.width;
+                       best_pix_in->height = frmi.height;
+                       best_pix_in->pixelformat = frmi.pixel_format;
+               }
+       }
+
+       if (best_ival->denominator == 0)
+               return -EINVAL;
+
+       *wanted_pix_out = best_pix_out;
+
+       dev_info(vdev->cam->dev, "w %d, h %d -> w %d, h %d\n",
+                best_pix_in->width, best_pix_in->height,
+                best_pix_out.width, best_pix_out.height);
+
+       return isp_try_fmt_cap(best_pix_in, wanted_pix_out);
+}
+
+static int s_pix_parm(struct omap34xxcam_videodev *vdev,
+                     struct v4l2_pix_format *best_pix,
+                     struct v4l2_pix_format *pix,
+                     struct v4l2_fract *best_ival)
+{
+       struct v4l2_streamparm a;
+       struct v4l2_format fmt;
+       int rval;
+       int fmtd_index;
+
+       for (fmtd_index = 0; ; fmtd_index++) {
+               struct v4l2_fmtdesc fmtd;
+
+               fmtd.index = fmtd_index;
+               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
+               if (rval)
+                       return rval;
+               best_pix->pixelformat = fmtd.pixelformat;
+
+               rval = try_pix_parm(vdev, best_pix, pix, best_ival);
+               if (!rval)
+                       break;
+       }
+
+       rval = isp_s_fmt_cap(best_pix, pix);
+       if (rval)
+               return rval;
+
+       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt.fmt.pix = *best_pix;
+       rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &fmt);
+       if (rval)
+               return rval;
+
+       a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a.parm.capture.timeperframe = *best_ival;
+       rval = vidioc_int_s_parm(vdev->vdev_sensor, &a);
+
+       return rval;
+}
+
+/**
+ * vidioc_s_fmt_vid_cap - V4L2 set format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Attempts to set input format with the sensor driver (first) and then the
+ * ISP.  Returns the return code from vidioc_g_fmt_vid_cap().
+ */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format pix_tmp;
+       struct v4l2_fract timeperframe;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       vdev->want_pix = f->fmt.pix;
+
+       timeperframe = vdev->want_timeperframe;
+
+       rval = s_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
+       pix_tmp = f->fmt.pix;
+
+out:
+       mutex_unlock(&vdev->mutex);
+
+       if (!rval) {
+               mutex_lock(&ofh->vbq.vb_lock);
+               ofh->pix = pix_tmp;
+               mutex_unlock(&ofh->vbq.vb_lock);
+       }
+
+       return rval;
+}
+
+/**
+ * vidioc_try_fmt_vid_cap - V4L2 try format capabilities IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @f: ptr to standard V4L2 format structure
+ *
+ * Checks if the given format is supported by the sensor driver and
+ * by the ISP.
+ */
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+                                 struct v4l2_format *f)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format pix_tmp;
+       struct v4l2_fract timeperframe;
+       int rval;
+       int fmtd_index;
+
+       mutex_lock(&vdev->mutex);
+
+
+       for (fmtd_index = 0; ; fmtd_index++) {
+               struct v4l2_fmtdesc fmtd;
+
+               timeperframe = vdev->want_timeperframe;
+
+               fmtd.index = fmtd_index;
+               fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
+               if (rval)
+                       return rval;
+               pix_tmp.pixelformat = fmtd.pixelformat;
+
+               rval = try_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
+               if (!rval)
+                       break;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_reqbufs - V4L2 request buffers IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 request buffers structure
+ *
+ * Attempts to get a buffer from the buffer queue associated with the
+ * fh through the video buffer library API.
+ */
+static int vidioc_reqbufs(struct file *file, void *fh,
+                         struct v4l2_requestbuffers *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               mutex_unlock(&vdev->mutex);
+               return -EBUSY;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       rval = videobuf_reqbufs(&ofh->vbq, b);
+
+       /*
+        * Either videobuf_reqbufs failed or the buffers are not
+        * memory-mapped (which would need special attention).
+        */
+       if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+               goto out;
+
+out:
+       return rval;
+}
+
+/**
+ * vidioc_querybuf - V4L2 query buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to fill in the v4l2_buffer structure for the buffer queue
+ * associated with the fh through the video buffer library API.
+ */
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+
+       return videobuf_querybuf(&ofh->vbq, b);
+}
+
+/**
+ * vidioc_qbuf - V4L2 queue buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to queue the v4l2_buffer on the buffer queue
+ * associated with the fh through the video buffer library API.
+ */
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+
+       return videobuf_qbuf(&ofh->vbq, b);
+}
+
+/**
+ * vidioc_dqbuf - V4L2 dequeue buffer IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @b: ptr to standard V4L2 buffer structure
+ *
+ * Attempts to dequeue the v4l2_buffer from the buffer queue
+ * associated with the fh through the video buffer library API.  If the
+ * buffer is a user space buffer, then this function will also requeue it,
+ * as user does not expect to do this.
+ */
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap34xxcam_fh *ofh = fh;
+
+       return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vidioc_streamon - V4L2 streamon IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: V4L2 buffer type
+ *
+ * Attempts to start streaming by enabling the sensor interface and turning
+ * on video buffer streaming through the video buffer library API.  Upon
+ * success the function returns 0, otherwise an error code is returned.
+ */
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct omap34xxcam_device *cam = vdev->cam;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       cam->dma_notify = 1;
+       isp_sgdma_init();
+       rval = videobuf_streamon(&ofh->vbq);
+       if (rval) {
+               dev_dbg(vdev->cam->dev, "omap34xxcam_slave_power_set failed\n");
+               goto out;
+       }
+
+
+       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                          OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
+       if (!rval) {
+               vdev->streaming = file;
+       } else {
+               isp_stop();
+               videobuf_streamoff(&ofh->vbq);
+       }
+
+out:
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_streamoff - V4L2 streamoff IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: V4L2 buffer type
+ *
+ * Attempts to stop streaming by flushing all scheduled work, waiting on
+ * any queued buffers to complete and then stopping the ISP and turning
+ * off video buffer streaming through the video buffer library API.  Upon
+ * success the function returns 0, otherwise an error code is returned.
+ */
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct videobuf_queue *q = &ofh->vbq;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->streaming == file)
+               isp_stop();
+
+       rval = videobuf_streamoff(q);
+       if (!rval)
+               vdev->streaming = NULL;
+
+       omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
+                                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+       omap34xxcam_slave_power_suggest(vdev, V4L2_POWER_STANDBY,
+                                       OMAP34XXCAM_SLAVE_POWER_LENS);
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_enum_input - V4L2 enumerate input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @inp: V4L2 input type information structure
+ *
+ * Fills in v4l2_input structure.  Returns 0.
+ */
+static int vidioc_enum_input(struct file *file, void *fh,
+                            struct v4l2_input *inp)
+{
+       if (inp->index > 0)
+               return -EINVAL;
+
+       strlcpy(inp->name, "camera", sizeof(inp->name));
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+/**
+ * vidioc_g_input - V4L2 get input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: address to hold index of input supported
+ *
+ * Sets index to 0.
+ */
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       *i = 0;
+
+       return 0;
+}
+
+/**
+ * vidioc_s_input - V4L2 set input IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @i: index of input selected
+ *
+ * 0 is only index supported.
+ */
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+       if (i > 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * vidioc_queryctrl - V4L2 query control IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 query control ioctl structure
+ *
+ * If the requested control is supported, returns the control information
+ * in the v4l2_queryctrl structure.  Otherwise, returns -EINVAL if the
+ * control is not supported.  If the sensor being used is a "smart sensor",
+ * this request is passed to the sensor driver, otherwise the ISP is
+ * queried and if it does not support the requested control, the request
+ * is forwarded to the "raw" sensor driver to see if it supports it.
+ */
+static int vidioc_queryctrl(struct file *file, void *fh,
+                           struct v4l2_queryctrl *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_queryctrl a_tmp;
+       int best_slave = -1;
+       u32 best_ctrl = (u32)-1;
+       int i;
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               return vidioc_int_queryctrl(vdev->vdev_sensor, a);
+
+       /* No next flags: try slaves directly. */
+       if (!(a->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
+               for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+                       if (!vidioc_int_queryctrl(vdev->slave[i], a))
+                               return 0;
+               }
+               return isp_queryctrl(a);
+       }
+
+       /* Find slave with smallest next control id. */
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               a_tmp = *a;
+
+               if (vidioc_int_queryctrl(vdev->slave[i], &a_tmp))
+                       continue;
+
+               if (a_tmp.id < best_ctrl) {
+                       best_slave = i;
+                       best_ctrl = a_tmp.id;
+               }
+       }
+
+       a_tmp = *a;
+       if (!isp_queryctrl(&a_tmp)) {
+               if (a_tmp.id < best_ctrl) {
+                       *a = a_tmp;
+
+                       return 0;
+               }
+       }
+
+       if (best_slave == -1)
+               return -EINVAL;
+
+       a->id = best_ctrl;
+       return vidioc_int_queryctrl(vdev->slave[best_slave], a);
+}
+
+/**
+ * vidioc_querymenu - V4L2 query menu IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 query menu ioctl structure
+ *
+ * If the requested control is supported, returns the menu information
+ * in the v4l2_querymenu structure.  Otherwise, returns -EINVAL if the
+ * control is not supported or is not a menu.  If the sensor being used
+ * is a "smart sensor", this request is passed to the sensor driver,
+ * otherwise the ISP is queried and if it does not support the requested
+ * menu control, the request is forwarded to the "raw" sensor driver to
+ * see if it supports it.
+ */
+static int vidioc_querymenu(struct file *file, void *fh,
+                           struct v4l2_querymenu *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int i;
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               return vidioc_int_querymenu(vdev->vdev_sensor, a);
+
+       /* Try slaves directly. */
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               if (!vidioc_int_querymenu(vdev->slave[i], a))
+                       return 0;
+       }
+       return -EINVAL;                 /* There is not yet isp_querymenu() */
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *fh,
+                             struct v4l2_ext_controls *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int i, ctrl_idx, rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
+               struct v4l2_control ctrl;
+
+               ctrl.id = a->controls[ctrl_idx].id;
+
+               if (vdev->vdev_sensor_config.sensor_isp) {
+                       rval = vidioc_int_g_ctrl(vdev->vdev_sensor, &ctrl);
+               } else {
+                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+                               rval = vidioc_int_g_ctrl(vdev->slave[i], &ctrl);
+                               if (!rval)
+                                       break;
+                       }
+               }
+
+               if (rval)
+                       rval = isp_g_ctrl(&ctrl);
+
+               if (rval) {
+                       a->error_idx = ctrl_idx;
+                       break;
+               }
+
+               a->controls[ctrl_idx].value = ctrl.value;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *fh,
+                             struct v4l2_ext_controls *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int i, ctrl_idx, rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       for (ctrl_idx = 0; ctrl_idx < a->count; ctrl_idx++) {
+               struct v4l2_control ctrl;
+
+               ctrl.id = a->controls[ctrl_idx].id;
+               ctrl.value = a->controls[ctrl_idx].value;
+
+               if (vdev->vdev_sensor_config.sensor_isp) {
+                       rval = vidioc_int_s_ctrl(vdev->vdev_sensor, &ctrl);
+               } else {
+                       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+                               rval = vidioc_int_s_ctrl(vdev->slave[i], &ctrl);
+                               if (!rval)
+                                       break;
+                       }
+               }
+
+               if (rval)
+                       rval = isp_s_ctrl(&ctrl);
+
+               if (rval) {
+                       a->error_idx = ctrl_idx;
+                       break;
+               }
+
+               a->controls[ctrl_idx].value = ctrl.value;
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_g_parm - V4L2 get parameters IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 stream parameters structure
+ *
+ * If request is for video capture buffer type, handles request by
+ * forwarding to sensor driver.
+ */
+static int vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&vdev->mutex);
+       rval = vidioc_int_g_parm(vdev->vdev_sensor, a);
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_s_parm - V4L2 set parameters IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 stream parameters structure
+ *
+ * If request is for video capture buffer type, handles request by
+ * first getting current stream parameters from sensor, then forwarding
+ * request to set new parameters to sensor driver.  It then attempts to
+ * enable the sensor interface with the new parameters.  If this fails, it
+ * reverts back to the previous parameters.
+ */
+static int vidioc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format pix_tmp_sensor, pix_tmp;
+       int rval;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       vdev->want_timeperframe = a->parm.capture.timeperframe;
+
+       pix_tmp = vdev->want_pix;
+
+       rval = s_pix_parm(vdev, &pix_tmp_sensor, &pix_tmp,
+                         &a->parm.capture.timeperframe);
+
+out:
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_cropcap - V4L2 crop capture IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop capture structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise fills in the v4l2_cropcap values locally.
+ */
+static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_cropcap *cropcap = a;
+       int rval;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->vdev_sensor_config.sensor_isp) {
+               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
+       } else {
+               struct v4l2_format f;
+
+               rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
+               if (!rval)
+                       return rval;
+
+               /* cropcap failed, try to do this via g_fmt_cap */
+               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &f);
+               if (!rval) {
+                       cropcap->bounds.top = 0;
+                       cropcap->bounds.left = 0;
+                       cropcap->bounds.width = f.fmt.pix.width;
+                       cropcap->bounds.height = f.fmt.pix.height;
+                       cropcap->defrect = cropcap->bounds;
+                       cropcap->pixelaspect.numerator = 1;
+                       cropcap->pixelaspect.denominator = 1;
+               }
+       }
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_g_crop - V4L2 get capture crop IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise calls the isp functions to fill in current crop values.
+ */
+static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
+       else
+               rval = isp_g_crop(a);
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+/**
+ * vidioc_s_crop - V4L2 set capture crop IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @a: standard V4L2 crop structure
+ *
+ * If using a "smart" sensor, just forwards request to the sensor driver,
+ * otherwise calls the isp functions to set the current crop values.
+ */
+static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       struct v4l2_pix_format *pix = &ofh->pix;
+       int rval = 0;
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->vdev_sensor_config.sensor_isp)
+               rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
+       else
+               rval = isp_s_crop(a, pix);
+
+       mutex_unlock(&vdev->mutex);
+
+       return rval;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+                                 struct v4l2_frmsizeenum *frms)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       u32 pixel_format;
+       int rval;
+
+       pixel_format = frms->pixel_format;
+       frms->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
+
+       mutex_lock(&vdev->mutex);
+       rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
+       mutex_unlock(&vdev->mutex);
+
+       frms->pixel_format = pixel_format;
+
+       return rval;
+}
+
+static int vidioc_enum_frameintervals(struct file *file, void *fh,
+                                     struct v4l2_frmivalenum *frmi)
+{
+       struct omap34xxcam_fh *ofh = fh;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       u32 pixel_format;
+       int rval;
+
+       pixel_format = frmi->pixel_format;
+       frmi->pixel_format = V4L2_PIX_FMT_SGRBG10; /* We can accept any. */
+
+       mutex_lock(&vdev->mutex);
+       rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
+       mutex_unlock(&vdev->mutex);
+
+       frmi->pixel_format = pixel_format;
+
+       return rval;
+}
+
+/**
+ * vidioc_default - private IOCTL handler
+ * @file: ptr. to system file structure
+ * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data)
+ * @cmd: ioctl cmd value
+ * @arg: ioctl arg value
+ *
+ * If the sensor being used is a "smart sensor", this request is returned to
+ * caller with -EINVAL err code.  Otherwise if the control id is the private
+ * VIDIOC_PRIVATE_ISP_AEWB_REQ to update the analog gain or exposure,
+ * then this request is forwared directly to the sensor to incorporate the
+ * feedback. The request is then passed on to the ISP private IOCTL handler,
+ * isp_handle_private()
+ */
+static int vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+{
+       struct omap34xxcam_fh *ofh = file->private_data;
+       struct omap34xxcam_videodev *vdev = ofh->vdev;
+       int rval;
+
+       if (vdev->vdev_sensor_config.sensor_isp) {
+               rval = -EINVAL;
+       } else {
+               switch (cmd) {
+               case VIDIOC_ENUM_FRAMESIZES:
+                       rval = vidioc_enum_framesizes(file, fh, arg);
+                       goto out;
+               case VIDIOC_ENUM_FRAMEINTERVALS:
+                       rval = vidioc_enum_frameintervals(file, fh, arg);
+                       goto out;
+               case VIDIOC_PRIVATE_ISP_AEWB_REQ:
+               {
+                       /* Need to update sensor first */
+                       struct isph3a_aewb_data *data;
+                       struct v4l2_control vc;
+
+                       data = (struct isph3a_aewb_data *) arg;
+                       if (data->update & SET_EXPOSURE) {
+                               vc.id = V4L2_CID_EXPOSURE;
+                               vc.value = data->shutter;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
+                                                        &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                       }
+                       if (data->update & SET_ANALOG_GAIN) {
+                               vc.id = V4L2_CID_GAIN;
+                               vc.value = data->gain;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_s_ctrl(vdev->vdev_sensor,
+                                                        &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                       }
+               }
+               break;
+               case VIDIOC_PRIVATE_ISP_AF_REQ: {
+                       /* Need to update lens first */
+                       struct isp_af_data *data;
+                       struct v4l2_control vc;
+
+                       if (!vdev->vdev_lens) {
+                               rval = -EINVAL;
+                               goto out;
+                       }
+                       data = (struct isp_af_data *) arg;
+                       if (data->update & LENS_DESIRED_POSITION) {
+                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
+                               vc.value = data->desired_lens_direction;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_s_ctrl(vdev->vdev_lens, &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                       }
+                       if (data->update & REQUEST_STATISTICS) {
+                               vc.id = V4L2_CID_FOCUS_ABSOLUTE;
+                               mutex_lock(&vdev->mutex);
+                               rval = vidioc_int_g_ctrl(vdev->vdev_lens, &vc);
+                               mutex_unlock(&vdev->mutex);
+                               if (rval)
+                                       goto out;
+                               data->xtrastats.lens_position = vc.value;
+                       }
+               }
+                       break;
+               }
+
+               mutex_lock(&vdev->mutex);
+               rval = isp_handle_private(cmd, arg);
+               mutex_unlock(&vdev->mutex);
+       }
+out:
+       return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+static long omap34xxcam_unlocked_ioctl(struct file *file, unsigned int cmd,
+                                      unsigned long arg)
+{
+       return (long)video_ioctl2(file->f_dentry->d_inode, file, cmd, arg);
+}
+
+/**
+ * omap34xxcam_poll - file operations poll handler
+ * @file: ptr. to system file structure
+ * @wait: system poll table structure
+ *
+ */
+static unsigned int omap34xxcam_poll(struct file *file,
+                                    struct poll_table_struct *wait)
+{
+       struct omap34xxcam_fh *fh = file->private_data;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       struct videobuf_buffer *vb;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming != file) {
+               mutex_unlock(&vdev->mutex);
+               return POLLERR;
+       }
+       mutex_unlock(&vdev->mutex);
+
+       mutex_lock(&fh->vbq.vb_lock);
+       if (list_empty(&fh->vbq.stream)) {
+               mutex_unlock(&fh->vbq.vb_lock);
+               return POLLERR;
+       }
+       vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+       mutex_unlock(&fh->vbq.vb_lock);
+
+       poll_wait(file, &vb->done, wait);
+
+       if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_mmap - file operations mmap handler
+ * @file: ptr. to system file structure
+ * @vma: system virt. mem. area structure
+ *
+ * Maps a virtual memory area via the video buffer API
+ */
+static int omap34xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct omap34xxcam_fh *fh = file->private_data;
+       return videobuf_mmap_mapper(&fh->vbq, vma);
+}
+
+/**
+ * omap34xxcam_open - file operations open handler
+ * @inode: ptr. to system inode structure
+ * @file: ptr. to system file structure
+ *
+ * Allocates and initializes the per-filehandle data (omap34xxcam_fh),
+ * enables the sensor, opens/initializes the ISP interface and the
+ * video buffer queue.  Note that this function will allow multiple
+ * file handles to be open simultaneously, however only the first
+ * handle opened will initialize the ISP.  It is the application
+ * responsibility to only use one handle for streaming and the others
+ * for control only.
+ * This function returns 0 upon success and -ENODEV upon error.
+ */
+static int omap34xxcam_open(struct inode *inode, struct file *file)
+{
+       struct omap34xxcam_videodev *vdev = NULL;
+       struct omap34xxcam_device *cam = omap34xxcam;
+       struct omap34xxcam_fh *fh;
+       struct v4l2_format format;
+       int i;
+
+       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+               if (cam->vdevs[i].vfd
+                   && cam->vdevs[i].vfd->minor == iminor(inode)) {
+                       vdev = &cam->vdevs[i];
+                       break;
+               }
+       }
+
+       if (!vdev || !vdev->vfd)
+               return -ENODEV;
+
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (fh == NULL)
+               return -ENOMEM;
+
+       mutex_lock(&vdev->mutex);
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               if (vdev->slave[i] != v4l2_int_device_dummy()
+                   && !try_module_get(vdev->slave[i]->module)) {
+                       mutex_unlock(&vdev->mutex);
+                       goto out_try_module_get;
+               }
+       }
+
+       if (atomic_inc_return(&vdev->users) == 1) {
+               isp_get();
+               if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                               OMAP34XXCAM_SLAVE_POWER_ALL))
+                       goto out_slave_power_set_standby;
+               omap34xxcam_slave_power_set(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+               omap34xxcam_slave_power_suggest(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_LENS);
+       }
+
+       fh->vdev = vdev;
+
+       /* FIXME: Check that we have sensor now... */
+       if (vdev->vdev_sensor_config.sensor_isp)
+               vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
+       else
+               isp_g_fmt_cap(&format.fmt.pix);
+
+       mutex_unlock(&vdev->mutex);
+       /* FIXME: how about fh->pix when there are more users? */
+       fh->pix = format.fmt.pix;
+
+       file->private_data = fh;
+
+       spin_lock_init(&fh->vbq_lock);
+
+       videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
+                               &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                               V4L2_FIELD_NONE,
+                               sizeof(struct videobuf_buffer), fh);
+
+       return 0;
+
+out_slave_power_set_standby:
+       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+                                   OMAP34XXCAM_SLAVE_POWER_ALL);
+       isp_put();
+       atomic_dec(&vdev->users);
+       mutex_unlock(&vdev->mutex);
+
+out_try_module_get:
+       for (i--; i >= 0; i--)
+               if (vdev->slave[i] != v4l2_int_device_dummy())
+                       module_put(vdev->slave[i]->module);
+
+       kfree(fh);
+
+       return -ENODEV;
+}
+
+/**
+ * omap34xxcam_release - file operations release handler
+ * @inode: ptr. to system inode structure
+ * @file: ptr. to system file structure
+ *
+ * Complement of omap34xxcam_open.  This function will flush any scheduled
+ * work, disable the sensor, close the ISP interface, stop the
+ * video buffer queue from streaming and free the per-filehandle data
+ * (omap34xxcam_fh).  Note that because multiple open file handles
+ * are allowed, this function will only close the ISP and disable the
+ * sensor when the last open file handle (by count) is closed.
+ * This function returns 0.
+ */
+static int omap34xxcam_release(struct inode *inode, struct file *file)
+{
+       struct omap34xxcam_fh *fh = file->private_data;
+       struct omap34xxcam_videodev *vdev = fh->vdev;
+       int i;
+
+       mutex_lock(&vdev->mutex);
+       if (vdev->streaming == file) {
+               isp_stop();
+               videobuf_streamoff(&fh->vbq);
+               omap34xxcam_slave_power_set(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_SENSOR);
+               omap34xxcam_slave_power_suggest(
+                       vdev, V4L2_POWER_STANDBY,
+                       OMAP34XXCAM_SLAVE_POWER_LENS);
+               vdev->streaming = NULL;
+       }
+
+       if (atomic_dec_return(&vdev->users) == 0) {
+               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+                                           OMAP34XXCAM_SLAVE_POWER_ALL);
+               isp_put();
+       }
+       mutex_unlock(&vdev->mutex);
+
+       file->private_data = NULL;
+
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++)
+               if (vdev->slave[i] != v4l2_int_device_dummy())
+                       module_put(vdev->slave[i]->module);
+
+       kfree(fh);
+
+       return 0;
+}
+
+static struct file_operations omap34xxcam_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .unlocked_ioctl = omap34xxcam_unlocked_ioctl,
+       .poll = omap34xxcam_poll,
+       .mmap = omap34xxcam_mmap,
+       .open = omap34xxcam_open,
+       .release = omap34xxcam_release,
+};
+
+static void omap34xxcam_vfd_name_update(struct omap34xxcam_videodev *vdev)
+{
+       struct video_device *vfd = vdev->vfd;
+       int i;
+
+       strlcpy(vfd->name, CAM_SHORT_NAME, sizeof(vfd->name));
+       for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+               strlcat(vfd->name, "/", sizeof(vfd->name));
+               if (vdev->slave[i] == v4l2_int_device_dummy())
+                       continue;
+               strlcat(vfd->name, vdev->slave[i]->name, sizeof(vfd->name));
+       }
+       dev_info(vdev->cam->dev, "video%d is now %s\n", vfd->minor, vfd->name);
+}
+
+/**
+ * omap34xxcam_device_unregister - V4L2 detach handler
+ * @s: ptr. to standard V4L2 device information structure
+ *
+ * Detach sensor and unregister and release the video device.
+ */
+static void omap34xxcam_device_unregister(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct omap34xxcam_hw_config hwc;
+
+       BUG_ON(vidioc_int_g_priv(s, &hwc) < 0);
+
+       mutex_lock(&vdev->mutex);
+
+       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy()) {
+               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
+               vdev->slaves--;
+               omap34xxcam_vfd_name_update(vdev);
+       }
+
+       if (vdev->slaves == 0 && vdev->vfd) {
+               if (vdev->vfd->minor == -1) {
+                       /*
+                        * The device was never registered, so release the
+                        * video_device struct directly.
+                        */
+                       video_device_release(vdev->vfd);
+               } else {
+                       /*
+                        * The unregister function will release the
+                        * video_device struct as well as
+                        * unregistering it.
+                        */
+                       video_unregister_device(vdev->vfd);
+               }
+               vdev->vfd = NULL;
+       }
+
+       mutex_unlock(&vdev->mutex);
+}
+
+static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = {
+       .vidioc_querycap         = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap    = vidioc_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,
+       .vidioc_reqbufs          = vidioc_reqbufs,
+       .vidioc_querybuf         = vidioc_querybuf,
+       .vidioc_qbuf             = vidioc_qbuf,
+       .vidioc_dqbuf            = vidioc_dqbuf,
+       .vidioc_streamon         = vidioc_streamon,
+       .vidioc_streamoff        = vidioc_streamoff,
+       .vidioc_enum_input       = vidioc_enum_input,
+       .vidioc_g_input          = vidioc_g_input,
+       .vidioc_s_input          = vidioc_s_input,
+       .vidioc_queryctrl        = vidioc_queryctrl,
+       .vidioc_querymenu        = vidioc_querymenu,
+       .vidioc_g_ext_ctrls      = vidioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls      = vidioc_s_ext_ctrls,
+       .vidioc_g_parm           = vidioc_g_parm,
+       .vidioc_s_parm           = vidioc_s_parm,
+       .vidioc_cropcap          = vidioc_cropcap,
+       .vidioc_g_crop           = vidioc_g_crop,
+       .vidioc_s_crop           = vidioc_s_crop,
+       .vidioc_default          = vidioc_default,
+};
+
+/**
+ * omap34xxcam_device_register - V4L2 attach handler
+ * @s: ptr. to standard V4L2 device information structure
+ *
+ * Allocates and initializes the V4L2 video_device structure, initializes
+ * the sensor, and finally
+ registers the device with V4L2 based on the
+ * video_device structure.
+ *
+ * Returns 0 on success, otherwise an appropriate error code on
+ * failure.
+ */
+static int omap34xxcam_device_register(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct omap34xxcam_device *cam = vdev->cam;
+       struct omap34xxcam_hw_config hwc;
+       struct video_device *vfd;
+       int rval;
+
+       /* We need to check rval just once. The place is here. */
+       if (vidioc_int_g_priv(s, &hwc))
+               return -ENODEV;
+
+       if (vdev->index != hwc.dev_index)
+               return -ENODEV;
+
+       if (hwc.dev_type < 0 || hwc.dev_type > OMAP34XXCAM_SLAVE_FLASH)
+               return -EINVAL;
+
+       if (vdev->slave[hwc.dev_type] != v4l2_int_device_dummy())
+               return -EBUSY;
+
+       mutex_lock(&vdev->mutex);
+       if (atomic_read(&vdev->users)) {
+               dev_err(cam->dev, "we're open (%d), can't register\n",
+                       atomic_read(&vdev->users));
+               mutex_unlock(&vdev->mutex);
+               return -EBUSY;
+       }
+
+       vdev->slaves++;
+       vdev->slave[hwc.dev_type] = s;
+       vdev->slave_config[hwc.dev_type] = hwc;
+
+       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
+               isp_get();
+       rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                          1 << hwc.dev_type);
+       if (!rval && hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
+               struct v4l2_format format;
+               struct v4l2_streamparm a;
+
+               format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
+
+               a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               rval |= vidioc_int_g_parm(vdev->vdev_sensor, &a);
+               if (rval)
+                       rval = -EBUSY;
+
+               vdev->want_pix = format.fmt.pix;
+               vdev->want_timeperframe = a.parm.capture.timeperframe;
+       }
+       omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF, 1 << hwc.dev_type);
+       if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
+               isp_put();
+
+       if (rval)
+               goto err;
+
+       /* Are we the first slave? */
+       if (vdev->slaves == 1) {
+               /* initialize the video_device struct */
+               vdev->vfd = video_device_alloc();
+               vfd = vdev->vfd;
+               if (!vfd) {
+                       dev_err(cam->dev,
+                               "could not allocate video device struct\n");
+                       return -ENOMEM;
+               }
+               vfd->release    = video_device_release;
+               vfd->minor      = -1;
+               vfd->fops       = &omap34xxcam_fops;
+               vfd->ioctl_ops  = &omap34xxcam_ioctl_ops;
+               video_set_drvdata(vfd, vdev);
+
+               if (video_register_device(vfd, VFL_TYPE_GRABBER,
+                                         hwc.dev_minor) < 0) {
+                       dev_err(cam->dev,
+                               "could not register V4L device\n");
+                       vfd->minor = -1;
+                       rval = -EBUSY;
+                       goto err;
+               }
+       } else {
+               vfd = vdev->vfd;
+       }
+
+       omap34xxcam_vfd_name_update(vdev);
+
+       mutex_unlock(&vdev->mutex);
+
+       return 0;
+
+err:
+       if (s == vdev->slave[hwc.dev_type]) {
+               vdev->slave[hwc.dev_type] = v4l2_int_device_dummy();
+               vdev->slaves--;
+       }
+
+       mutex_unlock(&vdev->mutex);
+       omap34xxcam_device_unregister(s);
+
+       return rval;
+}
+
+static struct v4l2_int_master omap34xxcam_master = {
+       .attach = omap34xxcam_device_register,
+       .detach = omap34xxcam_device_unregister,
+};
+
+/*
+ *
+ * Driver Suspend/Resume
+ *
+ */
+
+#ifdef CONFIG_PM
+/**
+ * omap34xxcam_suspend - platform driver PM suspend handler
+ * @pdev: ptr. to platform level device information structure
+ * @state: power state
+ *
+ * If applicable, stop capture and disable sensor.
+ *
+ * Returns 0 always
+ */
+static int omap34xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
+
+       if (atomic_read(&vdev->users) == 0)
+               return 0;
+
+       if (vdev->streaming) {
+               isp_stop();
+               omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
+                                           OMAP34XXCAM_SLAVE_POWER_ALL);
+       }
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_resume - platform driver PM resume handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * If applicable, resume capture and enable sensor.
+ *
+ * Returns 0 always
+ */
+static int omap34xxcam_resume(struct platform_device *pdev)
+{
+       struct omap34xxcam_videodev *vdev = platform_get_drvdata(pdev);
+
+       if (atomic_read(&vdev->users) == 0)
+               return 0;
+
+       if (vdev->streaming) {
+               omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+                                           OMAP34XXCAM_SLAVE_POWER_ALL);
+               isp_start();
+       }
+
+       return 0;
+}
+#endif
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+/**
+ * omap34xxcam_remove - platform driver remove handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * Unregister device with V4L2, unmap camera registers, and
+ * free camera device information structure (omap34xxcam_device).
+ *
+ * Returns 0 always.
+ */
+static int omap34xxcam_remove(struct platform_device *pdev)
+{
+       struct omap34xxcam_device *cam = platform_get_drvdata(pdev);
+       int i;
+
+       if (!cam)
+               return 0;
+
+       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+               if (cam->vdevs[i].cam == NULL)
+                       continue;
+
+               v4l2_int_device_unregister(&cam->vdevs[i].master);
+               cam->vdevs[i].cam = NULL;
+       }
+
+       if (cam->mmio_base) {
+               iounmap((void *)cam->mmio_base);
+               cam->mmio_base = 0;
+       }
+
+       if (cam->mmio_base_phys) {
+               release_mem_region(cam->mmio_base_phys, cam->mmio_size);
+               cam->mmio_base_phys = 0;
+       }
+
+       omap34xxcam = NULL;
+
+       kfree(cam);
+
+       return 0;
+}
+
+/**
+ * omap34xxcam_probe - platform driver probe handler
+ * @pdev: ptr. to platform level device information structure
+ *
+ * Allocates and initializes camera device information structure
+ * (omap34xxcam_device), maps the device registers and gets the
+ * device IRQ.  Registers the device as a V4L2 client.
+ *
+ * Returns 0 on success or -ENODEV on failure.
+ */
+static int omap34xxcam_probe(struct platform_device *pdev)
+{
+       struct omap34xxcam_device *cam;
+       struct resource *mem;
+       struct isp_sysc isp_sysconfig;
+       int irq;
+       int i;
+
+       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+       if (!cam) {
+               dev_err(&pdev->dev, "could not allocate memory\n");
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, cam);
+
+       cam->dev = &pdev->dev;
+
+       /* request the mem region for the camera registers */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(cam->dev, "no mem resource?\n");
+               goto err;
+       }
+
+       if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+                               pdev->name)) {
+               dev_err(cam->dev,
+                       "cannot reserve camera register I/O region\n");
+               goto err;
+
+       }
+       cam->mmio_base_phys = mem->start;
+       cam->mmio_size = (mem->end - mem->start) + 1;
+
+       /* map the region */
+       cam->mmio_base = (unsigned long)
+                       ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+       if (!cam->mmio_base) {
+               dev_err(cam->dev, "cannot map camera register I/O region\n");
+               goto err;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(cam->dev, "no irq for camera?\n");
+               goto err;
+       }
+
+       isp_get();
+       isp_sysconfig.reset = 0;
+       isp_sysconfig.idle_mode = 1;
+       isp_power_settings(isp_sysconfig);
+       isp_put();
+
+       omap34xxcam = cam;
+
+       for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
+               struct omap34xxcam_videodev *vdev = &cam->vdevs[i];
+               struct v4l2_int_device *m = &vdev->master;
+
+               m->module       = THIS_MODULE;
+               strlcpy(m->name, CAM_NAME, sizeof(m->name));
+               m->type         = v4l2_int_type_master;
+               m->u.master     = &omap34xxcam_master;
+               m->priv         = vdev;
+
+               mutex_init(&vdev->mutex);
+               vdev->index             = i;
+               vdev->cam               = cam;
+               vdev->vdev_sensor =
+                       vdev->vdev_lens =
+                       vdev->vdev_flash = v4l2_int_device_dummy();
+               setup_timer(&vdev->poweroff_timer,
+                           omap34xxcam_slave_power_timer, (unsigned long)vdev);
+               INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
+
+               if (v4l2_int_device_register(m))
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       omap34xxcam_remove(pdev);
+       return -ENODEV;
+}
+
+static struct platform_driver omap34xxcam_driver = {
+       .probe = omap34xxcam_probe,
+       .remove = omap34xxcam_remove,
+#ifdef CONFIG_PM
+       .suspend = omap34xxcam_suspend,
+       .resume = omap34xxcam_resume,
+#endif
+       .driver = {
+                  .name = CAM_NAME,
+                  },
+};
+
+/*
+ *
+ * Module initialisation and deinitialisation
+ *
+ */
+
+/**
+ * omap34xxcam_init - module_init function
+ *
+ * Calls platfrom driver to register probe, remove,
+ * suspend and resume functions.
+ *
+ */
+static int __init omap34xxcam_init(void)
+{
+       return platform_driver_register(&omap34xxcam_driver);
+}
+
+/**
+ * omap34xxcam_cleanup - module_exit function
+ *
+ * Calls platfrom driver to unregister probe, remove,
+ * suspend and resume functions.
+ *
+ */
+static void __exit omap34xxcam_cleanup(void)
+{
+       platform_driver_unregister(&omap34xxcam_driver);
+}
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com");
+MODULE_DESCRIPTION("OMAP34xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+
+late_initcall(omap34xxcam_init);
+module_exit(omap34xxcam_cleanup);
diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
new file mode 100644
index 0000000..36f7fd5
--- /dev/null
+++ b/drivers/media/video/omap34xxcam.h
@@ -0,0 +1,221 @@
+/*
+ * drivers/media/video/omap34xxcam.c
+ *
+ * Copyright (C) 2006--2008 Nokia Corporation
+ * Copyright (C) 2007, 2008 Texas Instruments
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *
+ * Originally based on the OMAP 2 camera driver.
+ *
+ * Written by Sakari Ailus <sakari.ailus@nokia.com>
+ *            Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *            Sergio Aguirre <saaguirre@ti.com>
+ *            Mohit Jalori
+ *            Sameer Venkatraman
+ *            Leonides Martinez
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef OMAP34XXCAM_H
+#define OMAP34XXCAM_H
+
+#include <media/v4l2-int-device.h>
+#include "isp/isp.h"
+
+#define CAM_NAME                       "omap34xxcam"
+#define CAM_SHORT_NAME                 "omap3"
+
+#define OMAP_ISP_AF            (1 << 4)
+#define OMAP_ISP_HIST          (1 << 5)
+#define OMAP34XXCAM_XCLK_NONE  -1
+#define OMAP34XXCAM_XCLK_A     0
+#define OMAP34XXCAM_XCLK_B     1
+
+#define OMAP34XXCAM_SLAVE_SENSOR       0
+#define OMAP34XXCAM_SLAVE_LENS         1
+#define OMAP34XXCAM_SLAVE_FLASH                2 /* This is the last slave! */
+
+/* mask for omap34xxcam_slave_power_set */
+#define OMAP34XXCAM_SLAVE_POWER_SENSOR (1 << OMAP34XXCAM_SLAVE_SENSOR)
+#define OMAP34XXCAM_SLAVE_POWER_LENS   (1 << OMAP34XXCAM_SLAVE_LENS)
+#define OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS \
+       (OMAP34XXCAM_SLAVE_POWER_SENSOR | OMAP34XXCAM_SLAVE_POWER_LENS)
+#define OMAP34XXCAM_SLAVE_POWER_FLASH  (1 << OMAP34XXCAM_SLAVE_FLASH)
+#define OMAP34XXCAM_SLAVE_POWER_ALL    -1
+
+#define OMAP34XXCAM_VIDEODEVS          4
+
+struct omap34xxcam_device;
+struct omap34xxcam_videodev;
+
+struct omap34xxcam_sensor_config {
+       int xclk;
+       int sensor_isp;
+       u32 capture_mem;
+};
+
+struct omap34xxcam_lens_config {
+};
+
+struct omap34xxcam_flash_config {
+};
+
+/**
+ * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
+ * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
+ * @sensor_isp: Is sensor smart/SOC or raw
+ * @s_pix_sparm: Access function to set pix and sparm.
+ * Pix will override sparm
+ */
+struct omap34xxcam_hw_config {
+       int dev_index; /* Index in omap34xxcam_sensors */
+       int dev_minor; /* Video device minor number */
+       int dev_type; /* OMAP34XXCAM_SLAVE_* */
+       union {
+               struct omap34xxcam_sensor_config sensor;
+               struct omap34xxcam_lens_config lens;
+               struct omap34xxcam_flash_config flash;
+       } u;
+};
+
+/**
+ * struct omap34xxcam_videodev - per /dev/video* structure
+ * @mutex: serialises access to this structure
+ * @cam: pointer to cam hw structure
+ * @master: we are v4l2_int_device master
+ * @sensor: sensor device
+ * @lens: lens device
+ * @flash: flash device
+ * @slaves: how many slaves we have at the moment
+ * @vfd: our video device
+ * @capture_mem: maximum kernel-allocated capture memory
+ * @if_u: sensor interface stuff
+ * @index: index of this structure in cam->vdevs
+ * @users: how many users we have
+ * @power_state: Current power state
+ * @power_state_wish: New power state when poweroff_timer expires
+ * @power_state_mask: Bitmask of devices to set the new power state
+ * @poweroff_timer: Timer for dispatching poweroff_work
+ * @poweroff_work: Work for slave power state change
+ * @sensor_config: ISP-speicific sensor configuration
+ * @lens_config: ISP-speicific lens configuration
+ * @flash_config: ISP-speicific flash configuration
+ * @streaming: streaming file handle, if streaming is enabled
+ */
+struct omap34xxcam_videodev {
+       struct mutex mutex; /* serialises access to this structure */
+
+       struct omap34xxcam_device *cam;
+       struct v4l2_int_device master;
+
+#define vdev_sensor slave[OMAP34XXCAM_SLAVE_SENSOR]
+#define vdev_lens slave[OMAP34XXCAM_SLAVE_LENS]
+#define vdev_flash slave[OMAP34XXCAM_SLAVE_FLASH]
+       struct v4l2_int_device *slave[OMAP34XXCAM_SLAVE_FLASH + 1];
+
+       /* number of slaves attached */
+       int slaves;
+
+       /*** video device parameters ***/
+       struct video_device *vfd;
+       int capture_mem;
+
+       /*** general driver state information ***/
+       /*
+        * Sensor interface parameters: interface type, CC_CTRL
+        * register value and interface specific data.
+        */
+       u32 xclk;
+       /* index to omap34xxcam_videodevs of this structure */
+       int index;
+       atomic_t users;
+       enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
+       enum v4l2_power power_state_wish;
+       int power_state_mask;
+       struct timer_list poweroff_timer;
+       struct work_struct poweroff_work;
+
+#define vdev_sensor_config slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor
+#define vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens
+#define vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash
+       struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH + 1];
+
+       /*** capture data ***/
+       struct v4l2_fract want_timeperframe;
+       struct v4l2_pix_format want_pix;
+       /* file handle, if streaming is on */
+       struct file *streaming;
+};
+
+/**
+ * struct omap34xxcam_device - per-device data structure
+ * @mutex: mutex serialises access to this structure
+ * @sgdma_in_queue: Number or sgdma requests in scatter-gather queue,
+ * protected by the lock above.
+ * @sgdma: ISP sgdma subsystem information structure
+ * @dma_notify: DMA notify flag
+ * @irq: irq number platform HW resource
+ * @mmio_base: register map memory base (platform HW resource)
+ * @mmio_base_phys: register map memory base physical address
+ * @mmio_size: register map memory size
+ * @dev: device structure
+ * @vdevs: /dev/video specific structures
+ * @fck: camera module fck clock information
+ * @ick: camera module ick clock information
+ */
+struct omap34xxcam_device {
+       struct mutex mutex; /* serialises access to this structure */
+       int sgdma_in_queue;
+       struct isp_sgdma sgdma;
+       int dma_notify;
+
+       /*** platform HW resource ***/
+       unsigned int irq;
+       unsigned long mmio_base;
+       unsigned long mmio_base_phys;
+       unsigned long mmio_size;
+
+       /*** interfaces and device ***/
+       struct device *dev;
+       struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
+
+       /*** camera module clocks ***/
+       struct clk *fck;
+       struct clk *ick;
+       bool sensor_if_enabled;
+};
+
+/**
+ * struct omap34xxcam_fh - per-filehandle data structure
+ * @vbq_lock: spinlock for the videobuf queue
+ * @vbq: V4L2 video buffer queue structure
+ * @pix: V4L2 pixel format structure (serialise pix by vbq->lock)
+ * @field_count: field counter for videobuf_buffer
+ * @vdev: our /dev/video specific structure
+ */
+struct omap34xxcam_fh {
+       spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+       struct videobuf_queue vbq;
+       struct v4l2_pix_format pix;
+       atomic_t field_count;
+       /* accessing cam here doesn't need serialisation: it's constant */
+       struct omap34xxcam_videodev *vdev;
+};
+
+#endif /* ifndef OMAP34XXCAM_H */
--
1.5.6.5


--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

^ permalink raw reply related	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2009-03-10 13:35 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <Acl1IyQQvIDQejCAQ5O/QnkHIBmt3w==>
2009-01-13  2:03 ` [REVIEW PATCH 11/14] OMAP34XXCAM: Add driver Aguirre Rodriguez, Sergio Alberto
2009-01-13  2:03   ` Aguirre Rodriguez, Sergio Alberto
2009-01-13  7:24   ` Hans Verkuil
2009-01-13  7:24     ` Hans Verkuil
2009-02-06  2:26   ` DongSoo Kim
2009-02-11  4:00   ` DongSoo Kim
2009-02-12  7:09     ` Sakari Ailus
2009-02-12  7:52       ` DongSoo Kim
2009-02-13  9:31         ` Arun KS
2009-02-13 10:04           ` DongSoo(Nathaniel) Kim
2009-02-13 10:02         ` Sakari Ailus
2009-02-13 10:11           ` DongSoo(Nathaniel) Kim
2009-03-10 13:34 Hans Verkuil
  -- strict thread matches above, loose matches on Subject: below --
2009-03-04  8:12 Hans Verkuil
     [not found] <Aclb0Ghhhph2tRyARSuubB27tGfovg==>
2008-12-11 20:38 ` Aguirre Rodriguez, Sergio Alberto
2009-02-23  8:08   ` DongSoo(Nathaniel) Kim
2009-02-23  8:50     ` Tuukka.O Toivonen
2009-03-03  2:48       ` DongSoo(Nathaniel) Kim
2009-03-03  3:53         ` Hiremath, Vaibhav
2009-03-03  5:13           ` DongSoo(Nathaniel) Kim
2009-03-03  5:13             ` DongSoo(Nathaniel) Kim
2009-03-03  7:36             ` Hans Verkuil
2009-03-03  7:36               ` Hans Verkuil
2009-03-04  0:42               ` DongSoo(Nathaniel) Kim
2009-03-04  0:42                 ` DongSoo(Nathaniel) Kim
2009-03-04  7:39                 ` Hans Verkuil
2009-03-04  7:39                   ` Hans Verkuil
2009-03-04  7:49                   ` Tuukka.O Toivonen
2009-03-04 19:22                   ` Sakari Ailus
2009-03-04 21:05                     ` Hans Verkuil
2009-03-04 21:46                       ` Aguirre Rodriguez, Sergio Alberto
2009-03-04 22:44                         ` Hans Verkuil
2009-03-04 23:30                           ` Aguirre Rodriguez, Sergio Alberto
2009-03-05  7:39                             ` Hans Verkuil
2009-03-05 20:11                           ` Sakari Ailus
2009-03-05 21:24                             ` Hans Verkuil
2009-03-10 12:14                               ` Sakari Ailus
2009-03-04 23:42                         ` Trent Piepho
2009-03-05  2:25                           ` hermann pitton
2009-03-03  7:38             ` Sakari Ailus
2009-03-03  7:25         ` Sakari Ailus
2009-03-03  7:40           ` DongSoo(Nathaniel) Kim
2009-02-23  8:26   ` DongSoo(Nathaniel) Kim

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.