summaryrefslogtreecommitdiff
path: root/recipes/linux/linux-omap-2.6.29/isp/omap3camera/0009-omap34xxcam-Add-camera-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-omap-2.6.29/isp/omap3camera/0009-omap34xxcam-Add-camera-driver.patch')
-rw-r--r--recipes/linux/linux-omap-2.6.29/isp/omap3camera/0009-omap34xxcam-Add-camera-driver.patch2249
1 files changed, 2249 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-2.6.29/isp/omap3camera/0009-omap34xxcam-Add-camera-driver.patch b/recipes/linux/linux-omap-2.6.29/isp/omap3camera/0009-omap34xxcam-Add-camera-driver.patch
new file mode 100644
index 0000000000..22074be148
--- /dev/null
+++ b/recipes/linux/linux-omap-2.6.29/isp/omap3camera/0009-omap34xxcam-Add-camera-driver.patch
@@ -0,0 +1,2249 @@
+From 0edf5a50dc0164db5bc71b1a5d1aa8bb1838262c Mon Sep 17 00:00:00 2001
+From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+Date: Tue, 10 Mar 2009 10:49:03 +0200
+Subject: [PATCH] omap34xxcam: Add camera driver
+
+This is the camera driver for the OMAP 3 camera ISP and v4l2-int-device
+sensors, lenses and (led) flashes. There are a few connections to OMAP
+3 left but after those have been broken this is hardware independent.
+Namely, the OMAP 3 ISP must offer a standard interface through
+v4l2_subdev (or v4l2-int-device) first.
+
+This driver has originated from the omap24xxcam camera driver written
+specifically for OMAP 2.
+
+TODO:
+
+- Convert to use v4l2_subdev instead of v4l2-int-device.
+
+Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+---
+ drivers/media/video/Kconfig | 9 +
+ drivers/media/video/Makefile | 2 +
+ drivers/media/video/omap34xxcam.c | 1966 +++++++++++++++++++++++++++++++++++++
+ drivers/media/video/omap34xxcam.h | 207 ++++
+ 4 files changed, 2184 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 19cf3b8..3cdb5a4 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -711,6 +711,15 @@ 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
++ select OMAP_IOMMU
++ 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 e654270..74a684e 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -108,6 +108,8 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+
+ obj-y += isp/
+
++obj-$(CONFIG_VIDEO_OMAP3) += omap34xxcam.o
++
+ obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+
+ obj-$(CONFIG_USB_DABUSB) += dabusb.o
+diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
+new file mode 100644
+index 0000000..00fdbf2
+--- /dev/null
++++ b/drivers/media/video/omap34xxcam.c
+@@ -0,0 +1,1966 @@
++/*
++ * omap34xxcam.c
++ *
++ * Copyright (C) 2006--2009 Nokia Corporation
++ * Copyright (C) 2007--2009 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;
++
++/*
++ *
++ * 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));
++
++#ifdef OMAP34XXCAM_POWEROFF_DELAY
++ vdev->power_state_wish = -1;
++#endif
++
++ 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;
++}
++
++#ifdef OMAP34XXCAM_POWEROFF_DELAY
++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);
++}
++#else /* OMAP34XXCAM_POWEROFF_DELAY */
++#define omap34xxcam_slave_power_suggest(a, b, c) do {} while (0)
++#endif /* 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.
++ */
++void omap34xxcam_vbq_complete(struct videobuf_buffer *vb, void *priv)
++{
++ struct omap34xxcam_fh *fh = priv;
++
++ do_gettimeofday(&vb->ts);
++ vb->field_count = atomic_add_return(2, &fh->field_count);
++
++ wake_up(&vb->done);
++}
++
++/**
++ * 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;
++ struct omap34xxcam_videodev *vdev = fh->vdev;
++
++ if (*cnt <= 0)
++ *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
++
++ if (*cnt > VIDEO_MAX_FRAME)
++ *cnt = VIDEO_MAX_FRAME;
++
++ *size = vdev->pix.sizeimage;
++
++ while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
++ (*cnt)--;
++
++ return isp_vbq_setup(vbq, cnt, size);
++}
++
++/**
++ * 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;
++ struct omap34xxcam_videodev *vdev = fh->vdev;
++ 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 (vdev->pix.sizeimage > vb->bsize)
++ /* The buffer isn't big enough. */
++ return -EINVAL;
++ } else {
++ if (vb->state != VIDEOBUF_NEEDS_INIT
++ && vdev->pix.sizeimage > vb->bsize)
++ /*
++ * We have a kernel bounce buffer that has
++ * already been allocated.
++ */
++ omap34xxcam_vbq_release(vbq, vb);
++ }
++
++ vb->size = vdev->pix.bytesperline * vdev->pix.height;
++ vb->width = vdev->pix.width;
++ vb->height = vdev->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;
++
++ vb->state = VIDEOBUF_ACTIVE;
++
++ isp_buf_queue(vb, omap34xxcam_vbq_complete, (void *)fh);
++}
++
++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;
++ if (vdev->vdev_sensor != v4l2_int_device_dummy())
++ 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 == v4l2_int_device_dummy())
++ return -EINVAL;
++
++ 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;
++
++ if (vdev->vdev_sensor == v4l2_int_device_dummy())
++ return -EINVAL;
++
++ mutex_lock(&vdev->mutex);
++ f->fmt.pix = vdev->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 fmtd_index;
++ int rval;
++ struct v4l2_pix_format best_pix_out;
++
++ if (best_ival->numerator == 0
++ || best_ival->denominator == 0)
++ *best_ival = vdev->vdev_sensor_config.ival_default;
++
++ 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;
++
++ for (fmtd_index = 0; ; fmtd_index++) {
++ int size_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)
++ break;
++ dev_info(&vdev->vfd->dev, "trying fmt %8.8x (%d)\n",
++ fmtd.pixelformat, fmtd_index);
++ /*
++ * 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 = fmtd.pixelformat;
++
++ rval = vidioc_int_enum_framesizes(vdev->vdev_sensor,
++ &frms);
++ if (rval)
++ 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;
++
++ dev_info(&vdev->vfd->dev, "this w %d\th %d\tfmt %8.8x\t"
++ "-> w %d\th %d\t fmt %8.8x"
++ "\twanted w %d\th %d\t fmt %8.8x\n",
++ pix_tmp_in.width, pix_tmp_in.height,
++ pix_tmp_in.pixelformat,
++ pix_tmp_out.width, pix_tmp_out.height,
++ pix_tmp_out.pixelformat,
++ wanted_pix_out->width, wanted_pix_out->height,
++ wanted_pix_out->pixelformat);
++
++#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)) {
++ dev_info(&vdev->vfd->dev, "size diff bigger: "
++ "w %d\th %d\tw %d\th %d\n",
++ pix_tmp_out.width, pix_tmp_out.height,
++ best_pix_out.width,
++ best_pix_out.height);
++ 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;
++ dev_info(&vdev->vfd->dev, "renegotiate: "
++ "w %d\th %d\tw %d\th %d\n",
++ pix_tmp_out.width, pix_tmp_out.height,
++ best_pix_out.width,
++ best_pix_out.height);
++ }
++
++ 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)
++ break;
++
++ dev_info(&vdev->vfd->dev, "fps %d\n",
++ frmi.discrete.denominator
++ / frmi.discrete.numerator);
++
++ 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)) {
++ dev_info(&vdev->vfd->dev, "closer fps: "
++ "fps %d\t fps %d\n",
++ 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 + frmi.height
++ > best_pix_in->width + best_pix_in->height
++ && FPS_ABS_DIFF(fps, frmi.discrete)
++ <= FPS_ABS_DIFF(fps, *best_ival)) {
++ dev_info(&vdev->vfd->dev, "bigger res, "
++ "same fps: "
++ "w %d\th %d\tw %d\th %d\n",
++ frmi.width, frmi.height,
++ best_pix_in->width,
++ best_pix_in->height);
++ goto do_it_now;
++ }
++
++ dev_info(&vdev->vfd->dev, "falling through\n");
++
++ 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;
++
++ dev_info(&vdev->vfd->dev,
++ "best_pix_in: w %d\th %d\tfmt %8.8x"
++ "\tival %d/%d\n",
++ best_pix_in->width,
++ best_pix_in->height,
++ best_pix_in->pixelformat,
++ best_ival->numerator,
++ best_ival->denominator);
++ }
++ }
++ }
++
++ if (best_ival->denominator == 0)
++ return -EINVAL;
++
++ *wanted_pix_out = best_pix_out;
++
++ dev_info(&vdev->vfd->dev, "w %d, h %d, fmt %8.8x -> w %d, h %d\n",
++ best_pix_in->width, best_pix_in->height,
++ best_pix_in->pixelformat,
++ 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;
++
++ rval = try_pix_parm(vdev, best_pix, pix, best_ival);
++ if (rval)
++ return rval;
++
++ 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;
++
++ if (vdev->vdev_sensor == v4l2_int_device_dummy())
++ return -EINVAL;
++
++ 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);
++ if (!rval)
++ vdev->pix = f->fmt.pix;
++
++out:
++ mutex_unlock(&vdev->mutex);
++
++ 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;
++
++ if (vdev->vdev_sensor == v4l2_int_device_dummy())
++ return -EINVAL;
++
++ mutex_lock(&vdev->mutex);
++
++ timeperframe = vdev->want_timeperframe;
++
++ rval = try_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe);
++
++ 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;
++
++ if (vdev->vdev_sensor == v4l2_int_device_dummy())
++ return -EINVAL;
++
++ mutex_lock(&vdev->mutex);
++ if (vdev->streaming) {
++ mutex_unlock(&vdev->mutex);
++ return -EBUSY;
++ }
++
++ rval = videobuf_reqbufs(&ofh->vbq, b);
++
++ mutex_unlock(&vdev->mutex);
++
++ /*
++ * 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;
++ int rval;
++
++videobuf_dqbuf_again:
++ rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
++
++ /*
++ * This is a hack. We don't want to show -EIO to the user
++ * space. Requeue the buffer and try again if we're not doing
++ * this in non-blocking mode.
++ */
++ if (rval == -EIO) {
++ videobuf_qbuf(&ofh->vbq, b);
++ if (!(file->f_flags & O_NONBLOCK))
++ goto videobuf_dqbuf_again;
++ /*
++ * We don't have a videobuf_buffer now --- maybe next
++ * time...
++ */
++ rval = -EAGAIN;
++ }
++
++ return rval;
++}
++
++/**
++ * 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;
++ int rval;
++
++ if (vdev->vdev_sensor == v4l2_int_device_dummy())
++ return -EINVAL;
++
++ mutex_lock(&vdev->mutex);
++ if (vdev->streaming) {
++ rval = -EBUSY;
++ goto out;
++ }
++
++ rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
++ OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
++ if (rval) {
++ dev_dbg(&vdev->vfd->dev,
++ "omap34xxcam_slave_power_set failed\n");
++ goto out;
++ }
++
++ rval = videobuf_streamon(&ofh->vbq);
++ if (rval)
++ omap34xxcam_slave_power_set(
++ vdev, V4L2_POWER_OFF,
++ OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
++ else
++ vdev->streaming = file;
++
++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;
++
++ if (vdev->vdev_sensor == v4l2_int_device_dummy())
++ 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;
++
++ if (vdev->vdev_sensor == v4l2_int_device_dummy())
++ return -EINVAL;
++
++ mutex_lock(&vdev->mutex);
++
++ rval = vidioc_int_cropcap(vdev->vdev_sensor, a);
++
++ if (rval && !vdev->vdev_sensor_config.sensor_isp) {
++ struct v4l2_format f;
++
++ /* 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;
++
++ if (vdev->vdev_sensor == v4l2_int_device_dummy())
++ return -EINVAL;
++
++ 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;
++ int rval = 0;
++
++ if (vdev->vdev_sensor == v4l2_int_device_dummy())
++ return -EINVAL;
++
++ 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, &vdev->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;
++
++ mutex_lock(&vdev->mutex);
++
++ if (vdev->vdev_sensor_config.sensor_isp) {
++ rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
++ } else {
++ pixel_format = frms->pixel_format;
++ frms->pixel_format = -1; /* ISP does format conversion */
++ rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
++ frms->pixel_format = pixel_format;
++ }
++
++ mutex_unlock(&vdev->mutex);
++ 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;
++
++ mutex_lock(&vdev->mutex);
++
++ if (vdev->vdev_sensor_config.sensor_isp) {
++ rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
++ } else {
++ pixel_format = frmi->pixel_format;
++ frmi->pixel_format = -1; /* ISP does format conversion */
++ rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
++ frmi->pixel_format = pixel_format;
++ }
++
++ mutex_unlock(&vdev->mutex);
++ 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 long 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_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) {
++ dev_info(&vdev->vfd->dev, "using "
++ "VIDIOC_PRIVATE_ISP_AEWB_REQ to set "
++ "exposure is deprecated!\n");
++ 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) {
++ dev_info(&vdev->vfd->dev, "using "
++ "VIDIOC_PRIVATE_ISP_AEWB_REQ to set "
++ "gain is deprecated!\n");
++ 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) {
++ dev_info(&vdev->vfd->dev, "using "
++ "VIDIOC_PRIVATE_ISP_AF_REQ to set "
++ "lens position is deprecated!\n");
++ 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;
++ }
++ }
++ break;
++ }
++
++ mutex_lock(&vdev->mutex);
++ rval = isp_handle_private(cmd, arg);
++ mutex_unlock(&vdev->mutex);
++ }
++out:
++ return rval;
++}
++
++/*
++ *
++ * File operations.
++ *
++ */
++
++/**
++ * 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 file *file)
++{
++ int rval = 0;
++ 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(file->f_dentry->d_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);
++ dev_err(&vdev->vfd->dev, "can't try_module_get %s\n",
++ vdev->slave[i]->name);
++ rval = -ENODEV;
++ goto out_try_module_get;
++ }
++ }
++
++ if (atomic_inc_return(&vdev->users) == 1) {
++ rval = isp_get();
++ if (rval < 0) {
++ dev_err(&vdev->vfd->dev, "can't get isp\n");
++ goto out_isp_get;
++ }
++ if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
++ OMAP34XXCAM_SLAVE_POWER_ALL)) {
++ dev_err(&vdev->vfd->dev, "can't power up slaves\n");
++ rval = -EBUSY;
++ 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;
++
++ if (!vdev->pix.width
++ && vdev->vdev_sensor != v4l2_int_device_dummy()) {
++ memset(&format, 0, sizeof(format));
++ if (vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format)) {
++ dev_err(&vdev->vfd->dev,
++ "can't get current pix from sensor!\n");
++ goto out_vidioc_int_g_fmt_cap;
++ }
++ if (!vdev->vdev_sensor_config.sensor_isp) {
++ struct v4l2_pix_format pix = format.fmt.pix;
++ if (isp_s_fmt_cap(&pix, &format.fmt.pix)) {
++ dev_err(&vdev->vfd->dev,
++ "isp doesn't like the sensor!\n");
++ goto out_isp_s_fmt_cap;
++ }
++ }
++ vdev->pix = format.fmt.pix;
++ }
++
++ mutex_unlock(&vdev->mutex);
++
++ 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_isp_s_fmt_cap:
++out_vidioc_int_g_fmt_cap:
++ omap34xxcam_slave_power_set(vdev, V4L2_POWER_OFF,
++ OMAP34XXCAM_SLAVE_POWER_ALL);
++out_slave_power_set_standby:
++ isp_put();
++
++out_isp_get:
++ 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 rval;
++}
++
++/**
++ * 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 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 v4l2_file_operations omap34xxcam_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = video_ioctl2,
++ .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->vfd->dev, "video%d is now %s\n", vfd->num, 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_enum_framesizes = vidioc_enum_framesizes,
++ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
++ .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_hw_config hwc;
++ 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)) {
++ printk(KERN_ERR "%s: we're open (%d), can't register\n",
++ __func__, 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) {
++ rval = isp_get();
++ if (rval < 0) {
++ printk(KERN_ERR "%s: can't get ISP, "
++ "sensor init failed\n", __func__);
++ goto err;
++ }
++ }
++ rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
++ 1 << hwc.dev_type);
++ if (rval)
++ goto err_omap34xxcam_slave_power_set;
++ if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
++ struct v4l2_format format;
++
++ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format);
++ if (rval)
++ rval = -EBUSY;
++
++ vdev->want_pix = format.fmt.pix;
++ }
++ 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();
++ if (!vdev->vfd) {
++ printk(KERN_ERR "%s: could not allocate "
++ "video device struct\n", __func__);
++ rval = -ENOMEM;
++ goto err;
++ }
++ vdev->vfd->release = video_device_release;
++ vdev->vfd->minor = -1;
++ vdev->vfd->fops = &omap34xxcam_fops;
++ vdev->vfd->ioctl_ops = &omap34xxcam_ioctl_ops;
++ video_set_drvdata(vdev->vfd, vdev);
++
++ if (video_register_device(vdev->vfd, VFL_TYPE_GRABBER,
++ hwc.dev_minor) < 0) {
++ printk(KERN_ERR "%s: could not register V4L device\n",
++ __func__);
++ vdev->vfd->minor = -1;
++ rval = -EBUSY;
++ goto err;
++ }
++ }
++
++ omap34xxcam_vfd_name_update(vdev);
++
++ mutex_unlock(&vdev->mutex);
++
++ return 0;
++
++err_omap34xxcam_slave_power_set:
++ if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
++ isp_put();
++
++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,
++};
++
++/*
++ *
++ * Module initialisation and deinitialisation
++ *
++ */
++
++static void omap34xxcam_exit(void)
++{
++ struct omap34xxcam_device *cam = omap34xxcam;
++ int i;
++
++ if (!cam)
++ return;
++
++ 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);
++}
++
++static int __init omap34xxcam_init(void)
++{
++ struct omap34xxcam_device *cam;
++ int i;
++
++ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
++ if (!cam) {
++ printk(KERN_ERR "%s: could not allocate memory\n", __func__);
++ return -ENOMEM;
++ }
++
++ 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();
++#ifdef OMAP34XXCAM_POWEROFF_DELAY
++ setup_timer(&vdev->poweroff_timer,
++ omap34xxcam_slave_power_timer, (unsigned long)vdev);
++ INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
++#endif /* OMAP34XXCAM_POWEROFF_DELAY */
++
++ if (v4l2_int_device_register(m))
++ goto err;
++ }
++
++ return 0;
++
++err:
++ omap34xxcam_exit();
++ return -ENODEV;
++}
++
++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_exit);
+diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
+new file mode 100644
+index 0000000..9859d15
+--- /dev/null
++++ b/drivers/media/video/omap34xxcam.h
+@@ -0,0 +1,207 @@
++/*
++ * omap34xxcam.h
++ *
++ * Copyright (C) 2006--2009 Nokia Corporation
++ * Copyright (C) 2007--2009 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
++
++/* #define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ) */
++
++struct omap34xxcam_device;
++struct omap34xxcam_videodev;
++
++struct omap34xxcam_sensor_config {
++ int xclk;
++ int sensor_isp;
++ u32 capture_mem;
++ struct v4l2_fract ival_default;
++};
++
++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
++ * @want_timeperframe: Desired timeperframe
++ * @want_pix: Desired pix
++ * @pix: Current pix
++ * @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 ***/
++ int index;
++ atomic_t users;
++ enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
++#ifdef OMAP34XXCAM_POWEROFF_DELAY
++ enum v4l2_power power_state_wish;
++ int power_state_mask;
++ struct timer_list poweroff_timer;
++ struct work_struct poweroff_work;
++#endif /* OMAP34XXCAM_POWEROFF_DELAY */
++
++#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 file *streaming;
++ struct v4l2_fract want_timeperframe;
++ struct v4l2_pix_format want_pix;
++ spinlock_t pix_lock;
++ struct v4l2_pix_format pix;
++};
++
++/**
++ * 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
++ * @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 */
++
++ /*** interfaces and device ***/
++ 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
++ * @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;
++ atomic_t field_count;
++ struct omap34xxcam_videodev *vdev;
++};
++
++#endif /* ifndef OMAP34XXCAM_H */
+--
+1.5.6.5
+