Rename cafe_ccic.c -> cafe-ccic.c

Andres Salomon dilinger at debian.org
Mon Nov 6 17:52:52 EST 2006


Commit:     6a94be8adce907b459ed6232f03e7db1543873e2
Parent:     f1d0f51e7ec12427c71ca678cacf22063e5cc918
commit 6a94be8adce907b459ed6232f03e7db1543873e2
Author:     Andres Salomon <dilinger at debian.org>
AuthorDate: Mon Nov 6 17:56:30 2006 -0500
Commit:     Andres Salomon <dilinger at debian.org>
CommitDate: Mon Nov 6 17:56:30 2006 -0500

    Rename cafe_ccic.c -> cafe-ccic.c
    
    Signed-off-by: Andres Salomon <dilinger at debian.org>
---
 drivers/media/video/cafe-ccic.c | 2254 +++++++++++++++++++++++++++++++++++++++
 drivers/media/video/cafe_ccic.c | 2254 ---------------------------------------
 2 files changed, 2254 insertions(+), 2254 deletions(-)

diff --git a/drivers/media/video/cafe-ccic.c b/drivers/media/video/cafe-ccic.c
new file mode 100644
index 0000000..d5cc93c
--- /dev/null
+++ b/drivers/media/video/cafe-ccic.c
@@ -0,0 +1,2254 @@
+/*
+ * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
+ * multifunction chip.  Currently works with the Omnivision OV7670
+ * sensor.
+ *
+ * Copyright 2006 One Laptop Per Child Association, Inc.
+ *
+ * Written by Jonathan Corbet, corbet at lwn.net.
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/jiffies.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "cafe_ccic-regs.h"
+
+#define CAFE_VERSION 0x000001
+
+
+/*
+ * Parameters.
+ */
+MODULE_AUTHOR("Jonathan Corbet <corbet at lwn.net>");
+MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("Video");
+
+/*
+ * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
+ * we must have physically contiguous buffers to bring frames into.
+ * These parameters control how many buffers we use, whether we
+ * allocate them at load time (better chance of success, but nails down
+ * memory) or when somebody tries to use the camera (riskier), and,
+ * for load-time allocation, how big they should be.
+ *
+ * The controller can cycle through three buffers.  We could use
+ * more by flipping pointers around, but it probably makes little
+ * sense.
+ */
+
+#define MAX_DMA_BUFS 3
+static int alloc_bufs_at_load = 0;
+module_param(alloc_bufs_at_load, bool, 0444);
+MODULE_PARM_DESC(alloc_bufs_at_load,
+		"Non-zero value causes DMA buffers to be allocated at module "
+		"load time.  This increases the chances of successfully getting "
+		"those buffers, but at the cost of nailing down the memory from "
+		"the outset.");
+
+static int n_dma_bufs = 3; 
+module_param(n_dma_bufs, uint, 0644);
+MODULE_PARM_DESC(n_dma_bufs,
+		"The number of DMA buffers to allocate.  Can be either two "
+		"(saves memory, makes timing tighter) or three.");
+
+static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2;  /* Worst case */
+module_param(dma_buf_size, uint, 0444);
+MODULE_PARM_DESC(dma_buf_size,
+		"The size of the allocated DMA buffers.  If actual operating "
+		"parameters require larger buffers, an attempt to reallocate "
+		"will be made.");
+		
+static int min_buffers = 1;
+module_param(min_buffers, uint, 0644);
+MODULE_PARM_DESC(min_buffers,
+		"The minimum number of streaming I/O buffers we are willing "
+		"to work with.");
+
+static int max_buffers = 10;
+module_param(max_buffers, uint, 0644);
+MODULE_PARM_DESC(max_buffers,
+		"The maximum number of streaming I/O buffers an application "
+		"will be allowed to allocate.  These buffers are big and live "
+		"in vmalloc space.");
+
+static int flip = 0;
+module_param(flip, bool, 0444);
+MODULE_PARM_DESC(flip,
+		"If set, the sensor will be instructed to flip the image "
+		"vertically.");
+
+
+enum cafe_state {
+	S_NOTREADY,	/* Not yet initialized */
+	S_IDLE,		/* Just hanging around */
+	S_FLAKED,	/* Some sort of problem */
+	S_SINGLEREAD,	/* In read() */
+	S_SPECREAD,   	/* Speculative read (for future read()) */
+	S_STREAMING	/* Streaming data */
+};
+
+/*
+ * Tracking of streaming I/O buffers.
+ */
+struct cafe_sio_buffer {
+	struct list_head list;
+	struct v4l2_buffer v4lbuf;
+	char *buffer;   /* Where it lives in kernel space */
+	int mapcount;
+	struct cafe_camera *cam;
+};
+
+/*
+ * A description of one of our devices.
+ * Locking: controlled by s_mutex.  Certain fields, however, require
+ * 	    the dev_lock spinlock; they are marked as such by comments.
+ *	    dev_lock is also required for access to device registers.
+ */
+struct cafe_camera
+{
+	enum cafe_state state;  
+	unsigned long flags;   		/* Buffer status, mainly (dev_lock) */
+	int users;			/* How many open FDs */
+	struct file *owner;	 	/* Who has data access (v4l2) */
+
+	/*
+	 * Subsystem structures.
+	 */
+	struct pci_dev *pdev;
+	struct video_device v4ldev;
+	struct i2c_adapter i2c_adapter;
+	struct i2c_client *sensor;
+
+	unsigned char __iomem *regs;
+	struct list_head dev_list;	/* link to other devices */
+
+	/* DMA buffers */
+	unsigned int nbufs;		/* How many are alloc'd */
+	int next_buf;			/* Next to consume (dev_lock) */
+	unsigned int dma_buf_size;  	/* allocated size */
+	void *dma_bufs[MAX_DMA_BUFS];	/* Internal buffer addresses */
+	dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
+	unsigned int specframes;	/* Unconsumed spec frames (dev_lock) */
+	unsigned int sequence;		/* Frame sequence number */
+	unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */
+
+	/* Streaming buffers */
+	unsigned int n_sbufs;		/* How many we have */
+	struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */
+	struct list_head sb_avail;	/* Available for data (we own) (dev_lock) */
+	struct list_head sb_full;	/* With data (user space owns) (dev_lock) */
+	struct tasklet_struct s_tasklet; 
+
+	/* Current operating parameters */
+	enum v4l2_chip_ident sensor_type;		/* Currently ov7670 only */
+	struct v4l2_pix_format pix_format;
+	
+	/* Locks */
+	struct mutex s_mutex; /* Access to this structure */
+	spinlock_t dev_lock;  /* Access to device */
+
+	/* Misc */
+	wait_queue_head_t smbus_wait;	/* Waiting on i2c events */
+	wait_queue_head_t iowait;	/* Waiting on frame data */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	struct dentry *dfs_regs;
+	struct dentry *dfs_cam_regs;
+#endif
+};
+
+/*
+ * Status flags.  Always manipulated with bit operations.
+ */
+#define CF_BUF0_VALID	 0	/* Buffers valid - first three */
+#define CF_BUF1_VALID	 1
+#define CF_BUF2_VALID	 2
+#define CF_DMA_ACTIVE	 3	/* A frame is incoming */
+#define CF_CONFIG_NEEDED 4	/* Must configure hardware */
+
+
+
+/*
+ * Start over with DMA buffers - dev_lock needed.
+ */
+static void cafe_reset_buffers(struct cafe_camera *cam)
+{
+	int i;
+	
+	cam->next_buf = -1;
+	for (i = 0; i < cam->nbufs; i++) 
+		clear_bit(i, &cam->flags);
+	cam->specframes = 0;
+}
+
+static inline int cafe_needs_config(struct cafe_camera *cam)
+{
+	return test_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+static void cafe_set_config_needed(struct cafe_camera *cam, int needed)
+{
+	if (needed)
+		set_bit(CF_CONFIG_NEEDED, &cam->flags);
+	else
+		clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+
+
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+	dev_err(&(cam)->pdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+	dev_warn(&(cam)->pdev->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+	dev_dbg(&(cam)->pdev->dev, fmt, ##arg);
+
+
+/* ---------------------------------------------------------------------*/
+/*
+ * We keep a simple list of known devices to search at open time.
+ */
+static LIST_HEAD(cafe_dev_list);
+static DEFINE_MUTEX(cafe_dev_list_lock);
+
+static void cafe_add_dev(struct cafe_camera *cam)
+{
+	mutex_lock(&cafe_dev_list_lock);
+	list_add_tail(&cam->dev_list, &cafe_dev_list);
+	mutex_unlock(&cafe_dev_list_lock);
+}
+
+static void cafe_remove_dev(struct cafe_camera *cam)
+{
+	mutex_lock(&cafe_dev_list_lock);
+	list_del(&cam->dev_list);
+	mutex_unlock(&cafe_dev_list_lock);
+}
+
+static struct cafe_camera *cafe_find_dev(int minor)
+{
+	struct cafe_camera *cam;
+	
+	mutex_lock(&cafe_dev_list_lock);
+	list_for_each_entry(cam, &cafe_dev_list, dev_list) {
+		if (cam->v4ldev.minor == minor)
+			goto done;
+	}
+	cam = NULL;
+  done:
+	mutex_unlock(&cafe_dev_list_lock);
+	return cam;
+}
+	
+
+static struct cafe_camera *cafe_find_by_pdev(struct pci_dev *pdev)
+{
+	struct cafe_camera *cam;
+	
+	mutex_lock(&cafe_dev_list_lock);
+	list_for_each_entry(cam, &cafe_dev_list, dev_list) {
+		if (cam->pdev == pdev)
+			goto done;
+	}
+	cam = NULL;
+  done:
+	mutex_unlock(&cafe_dev_list_lock);
+	return cam;
+}
+	
+
+/* ------------------------------------------------------------------------ */
+/*
+ * Device register I/O
+ */
+static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg,
+		unsigned int val)
+{
+	iowrite32(val, cam->regs + reg);
+}
+
+static inline unsigned int cafe_reg_read(struct cafe_camera *cam,
+		unsigned int reg)
+{
+	return ioread32(cam->regs + reg);
+}
+
+
+static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg,
+		unsigned int val, unsigned int mask)
+{
+	unsigned int v = cafe_reg_read(cam, reg);
+
+	v = (v & ~mask) | (val & mask);
+	cafe_reg_write(cam, reg, v);
+}
+
+static inline void cafe_reg_clear_bit(struct cafe_camera *cam,
+		unsigned int reg, unsigned int val)
+{
+	cafe_reg_write_mask(cam, reg, 0, val);
+}
+
+static inline void cafe_reg_set_bit(struct cafe_camera *cam,
+		unsigned int reg, unsigned int val)
+{
+	cafe_reg_write_mask(cam, reg, val, val);
+}
+
+
+
+/* -------------------------------------------------------------------- */
+/*
+ * The I2C/SMBUS interface to the camera itself starts here.  The
+ * controller handles SMBUS itself, presenting a relatively simple register
+ * interface; all we have to do is to tell it where to route the data.
+ */
+#define CAFE_SMBUS_TIMEOUT (HZ)  /* generous */
+
+static int cafe_smbus_write_done(struct cafe_camera *cam)
+{
+	unsigned long flags;
+	int c1;
+
+	/*
+	 * We must delay after the interrupt, or the controller gets confused
+	 * and never does give us good status.  Fortunately, we don't do this
+	 * often.
+	 */
+	udelay(20);
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	c1 = cafe_reg_read(cam, REG_TWSIC1);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
+}
+
+static int cafe_smbus_write_data(struct cafe_camera *cam,
+		u16 addr, u8 command, u8 value)
+{
+	unsigned int rval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+	rval |= TWSIC0_OVMAGIC;  /* Make OV sensors work */
+	/*
+	 * Marvell sez set clkdiv to all 1's for now.
+	 */
+	rval |= TWSIC0_CLKDIV;
+	cafe_reg_write(cam, REG_TWSIC0, rval);
+	(void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
+	rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+	cafe_reg_write(cam, REG_TWSIC1, rval);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	msleep(2); /* Required or things flake */
+
+	wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
+			CAFE_SMBUS_TIMEOUT);
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	rval = cafe_reg_read(cam, REG_TWSIC1);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	
+	if (rval & TWSIC1_WSTAT) {
+		cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
+				command, value);
+		return -EIO;
+	}
+	if (rval & TWSIC1_ERROR) {
+		cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
+				command, value);
+		return -EIO;
+	}
+	return 0;
+}
+
+
+
+static int cafe_smbus_read_done(struct cafe_camera *cam)
+{
+	unsigned long flags;
+	int c1;
+
+	/*
+	 * We must delay after the interrupt, or the controller gets confused
+	 * and never does give us good status.  Fortunately, we don't do this
+	 * often.
+	 */
+	udelay(20);
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	c1 = cafe_reg_read(cam, REG_TWSIC1);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
+}
+
+
+
+static int cafe_smbus_read_data(struct cafe_camera *cam,
+		u16 addr, u8 command, u8 *value)
+{
+	unsigned int rval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+	rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
+	/*
+	 * Marvel sez set clkdiv to all 1's for now.
+	 */
+	rval |= TWSIC0_CLKDIV;
+	cafe_reg_write(cam, REG_TWSIC0, rval);
+	(void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
+	rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+	cafe_reg_write(cam, REG_TWSIC1, rval);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+	wait_event_timeout(cam->smbus_wait,
+			cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT);
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	rval = cafe_reg_read(cam, REG_TWSIC1);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	
+	if (rval & TWSIC1_ERROR) {
+		cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
+		return -EIO;
+	}
+	if (! (rval & TWSIC1_RVALID)) {
+		cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
+				command);
+		return -EIO;
+	}
+	*value = rval & 0xff;
+	return 0;
+}
+
+/*
+ * Perform a transfer over SMBUS.  This thing is called under
+ * the i2c bus lock, so we shouldn't race with ourselves...
+ */
+static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+		unsigned short flags, char rw, u8 command,
+		int size, union i2c_smbus_data *data)
+{
+	struct cafe_camera *cam = i2c_get_adapdata(adapter);
+	int ret = -EINVAL;
+	
+	/*
+	 * Refuse to talk to anything but OV cam chips.  We should
+	 * never even see an attempt to do so, but one never knows.
+	 */
+#if 0  /* client needs to talk during attach process */
+	if (! cam->sensor) {
+		cam_err(cam, "SMBUS xfer with no client\n");
+		return -EINVAL;
+	}
+#endif
+	if (cam->sensor && addr != cam->sensor->addr) {
+		cam_err(cam, "funky smbus addr %d\n", addr);
+		return -EINVAL;
+	}
+	/*
+	 * This interface would appear to only do byte data ops.  OK
+	 * it can do word too, but the cam chip has no use for that.
+	 */
+	if (size != I2C_SMBUS_BYTE_DATA) {
+		cam_err(cam, "funky xfer size %d\n", size);
+		return -EINVAL;
+	}
+
+	if (rw == I2C_SMBUS_WRITE)
+		ret = cafe_smbus_write_data(cam, addr, command, data->byte);
+	else if (rw == I2C_SMBUS_READ)
+		ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
+	return ret;
+}
+
+
+static void cafe_smbus_enable_irq(struct cafe_camera *cam)
+{
+	unsigned long flags;
+	
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+static u32 cafe_smbus_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_READ_BYTE_DATA  |
+	       I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+static struct i2c_algorithm cafe_smbus_algo = {
+	.smbus_xfer = cafe_smbus_xfer,
+	.functionality = cafe_smbus_func
+};
+
+/* Somebody is on the bus */
+static int cafe_cam_init(struct cafe_camera *cam);
+
+static int cafe_smbus_attach(struct i2c_client *client)
+{
+	struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
+
+	/*
+	 * Don't talk to chips we don't recognize.
+	 */
+	cam_err(cam, "smbus_attach id = %d\n", client->driver->id);
+	if (client->driver->id == I2C_DRIVERID_OV7670) {
+		cam->sensor = client;
+		return cafe_cam_init(cam);
+	}
+	return -EINVAL;
+}
+
+static int cafe_smbus_detach(struct i2c_client *client)
+{
+	struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
+
+	if (cam->sensor == client)
+		cam->sensor = NULL;  /* Bummer, no camera */
+	return 0;
+}
+
+static int cafe_smbus_setup(struct cafe_camera *cam)
+{
+	struct i2c_adapter *adap = &cam->i2c_adapter;
+	int ret;
+
+	cafe_smbus_enable_irq(cam);
+	adap->id = I2C_HW_SMBUS_CAFE;
+	adap->class = I2C_CLASS_CAM_DIGITAL;
+	adap->owner = THIS_MODULE;
+	adap->client_register = cafe_smbus_attach;
+	adap->client_unregister = cafe_smbus_detach;
+	adap->algo = &cafe_smbus_algo;
+	strcpy(adap->name, "cafe_ccic");
+	i2c_set_adapdata(adap, cam);
+	ret = i2c_add_adapter(adap);
+	if (ret)
+		printk(KERN_ERR "Unable to register cafe i2c adapter\n");
+	return ret;
+}
+
+static void cafe_smbus_shutdown(struct cafe_camera *cam)
+{
+	i2c_del_adapter(&cam->i2c_adapter);
+}
+
+
+/* ------------------------------------------------------------------- */
+/*
+ * Deal with the controller.
+ */
+
+/*
+ * Do everything we think we need to have the interface operating
+ * according to the desired format.
+ */
+static void cafe_ctlr_dma(struct cafe_camera *cam)
+{
+	/*
+	 * Store the first two Y buffers (we aren't supporting
+	 * planar formats for now, so no UV bufs).  Then either
+	 * set the third if it exists, or tell the controller
+	 * to just use two.
+	 */
+	cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]);
+	cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]);
+	if (cam->nbufs > 2) {
+		cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]);
+		cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
+	}
+	else
+		cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
+	cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */
+}
+			
+static void cafe_ctlr_image(struct cafe_camera *cam)
+{
+	int imgsz;
+	struct v4l2_pix_format *fmt = &cam->pix_format;
+
+	imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
+		(fmt->bytesperline & IMGSZ_H_MASK);
+	cafe_reg_write(cam, REG_IMGSIZE, imgsz);
+	cafe_reg_write(cam, REG_IMGOFFSET, 0);
+	/* YPITCH just drops the last two bits */
+	cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
+			IMGP_YP_MASK);
+	/*
+	 * Tell the controller about the image format we are using.
+	 */
+	switch (cam->pix_format.pixelformat) {
+    	case V4L2_PIX_FMT_YUYV:
+	    cafe_reg_write_mask(cam, REG_CTRL0,
+			    C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
+			    C0_DF_MASK);
+	    break;
+
+    	/*
+	 * For "fake rgb32" get the image pitch right.
+	 */
+	case V4L2_PIX_FMT_RGB32:
+	    cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline/2,
+			    IMGP_YP_MASK);
+	    imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
+		    ((fmt->bytesperline/2) & IMGSZ_H_MASK);
+	    cafe_reg_write(cam, REG_IMGSIZE, imgsz);
+    	    /* fall into ... */
+	case V4L2_PIX_FMT_RGB444:
+	    cafe_reg_write_mask(cam, REG_CTRL0,
+			    C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
+			    C0_DF_MASK);
+    		/* Alpha value? */
+	    break;
+
+	case V4L2_PIX_FMT_RGB565:
+	    cafe_reg_write_mask(cam, REG_CTRL0,
+			    C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
+			    C0_DF_MASK);
+	    break;
+
+	default:
+	    cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
+	    break;
+	}
+	/*
+	 * Make sure it knows we want to use hsync/vsync.
+	 */
+	cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
+			C0_SIFM_MASK);
+}
+
+
+/*
+ * Configure the controller for operation; caller holds the
+ * device mutex.
+ */
+static int cafe_ctlr_configure(struct cafe_camera *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	cafe_ctlr_dma(cam);
+	cafe_ctlr_image(cam);
+	cafe_set_config_needed(cam, 0);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	return 0;
+}
+
+static void cafe_ctlr_irq_enable(struct cafe_camera *cam)
+{
+	/*
+	 * Clear any pending interrupts, since we do not
+	 * expect to have I/O active prior to enabling.
+	 */
+	cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS);
+	cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+static void cafe_ctlr_irq_disable(struct cafe_camera *cam)
+{
+	cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+/*
+ * Make the controller start grabbing images.  Everything must
+ * be set up before doing this.
+ */
+static void cafe_ctlr_start(struct cafe_camera *cam)
+{
+	/* set_bit performs a read, so no other barrier should be
+	   needed here */
+	cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+static void cafe_ctlr_stop(struct cafe_camera *cam)
+{
+	cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+static void cafe_ctlr_init(struct cafe_camera *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	/*
+	 * Added magic to bring up the hardware on the B-Test board
+	 */
+	cafe_reg_write(cam, 0x3038, 0x8);
+	cafe_reg_write(cam, 0x315c, 0x80008);
+	/*
+	 * Go through the dance needed to wake the device up.
+	 * Note that these registers are global and shared
+	 * with the NAND and SD devices.  Interaction between the
+	 * three still needs to be examined.
+	 */
+	cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
+	cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
+	cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
+	mdelay(5);	/* FIXME revisit this */
+	cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
+	cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN);
+	/*
+	 * Make sure it's not powered down. 
+	 */
+	cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+	/*
+	 * Turn off the enable bit.  It sure should be off anyway,
+	 * but it's good to be sure.
+	 */
+	cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+	/*
+	 * Mask all interrupts.
+	 */
+	cafe_reg_write(cam, REG_IRQMASK, 0);
+	/*
+	 * Clock the sensor appropriately.  Controller clock should
+	 * be 48MHz, sensor "typical" value is half that.
+	 */
+	cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+/*
+ * Stop the controller, and don't return until we're really sure that no
+ * further DMA is going on.
+ */
+static void cafe_ctlr_stop_dma(struct cafe_camera *cam)
+{
+	unsigned long flags;
+
+	/*
+	 * Theory: stop the camera controller (whether it is operating
+	 * or not).  Delay briefly just in case we race with the SOF
+	 * interrupt, then wait until no DMA is active.
+	 */
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	cafe_ctlr_stop(cam);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	mdelay(1);
+	wait_event_timeout(cam->iowait,
+			!test_bit(CF_DMA_ACTIVE, &cam->flags), HZ);
+	if (test_bit(CF_DMA_ACTIVE, &cam->flags)) 
+		cam_err(cam, "Timeout waiting for DMA to end\n");
+		/* This would be bad news - what now? */
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	cam->state = S_IDLE;
+	cafe_ctlr_irq_disable(cam);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/*
+ * Power up and down.
+ */
+static void cafe_ctlr_power_up(struct cafe_camera *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+	/*
+	 * Put the sensor into operational mode (assumes OLPC-style
+	 * wiring).  Control 0 is reset - set to 1 to operate.
+	 * Control 1 is power down, set to 0 to operate.
+	 */
+	cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
+	mdelay(1); /* Marvell says 1ms will do it */
+	cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
+	mdelay(1); /* Enough? */
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+static void cafe_ctlr_power_down(struct cafe_camera *cam)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
+	cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}	
+
+/* -------------------------------------------------------------------- */
+/*
+ * Communications with the sensor.
+ */
+
+static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg)
+{
+	struct i2c_client *sc = cam->sensor;
+	int ret;
+
+	if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL)
+		return -EINVAL;
+	ret = sc->driver->command(sc, cmd, arg);
+	if (ret == -EPERM) /* Unsupported command */
+		return 0;
+	return ret;
+}
+
+static int __cafe_cam_reset(struct cafe_camera *cam)
+{
+	int zero = 0;
+	return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero);
+}
+
+/*
+ * We have found the sensor on the i2c.  Let's try to have a
+ * conversation.
+ */
+static int cafe_cam_init(struct cafe_camera *cam)
+{
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	if (cam->state != S_NOTREADY)
+		cam_warn(cam, "Cam init with device in funky state %d",
+				cam->state);
+	ret = __cafe_cam_reset(cam);
+	if (ret)
+		goto out;
+	ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type);
+	if (ret)
+		goto out;
+//	if (cam->sensor->addr != OV7xx0_SID) {
+	if (cam->sensor_type != V4L2_IDENT_OV7670) {
+		cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
+		ret = -EINVAL;
+		goto out;
+	}
+/* Get/set parameters? */
+	ret = 0;
+	cam->state = S_IDLE;
+  out:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+/*
+ * Configure the sensor to match the parameters we have.  Caller should
+ * hold s_mutex
+ */
+static int cafe_cam_set_flip(struct cafe_camera *cam)
+{
+	struct v4l2_control ctrl;
+
+	memset(&ctrl, 0, sizeof(ctrl));
+	ctrl.id = V4L2_CID_VFLIP;
+	ctrl.value = flip;
+	return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl);
+}
+
+
+static int cafe_cam_configure(struct cafe_camera *cam)
+{
+	struct v4l2_format fmt;
+	int ret, zero = 0;
+	
+	if (cam->state != S_IDLE)
+		return -EINVAL;
+	fmt.fmt.pix = cam->pix_format;
+	ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
+	if (ret == 0) 
+		ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt);
+	/*
+	 * OV7670 does weird things if flip is set *before* format...
+	 */
+	ret += cafe_cam_set_flip(cam);
+	return ret;
+}
+
+/* -------------------------------------------------------------------- */
+/*
+ * DMA buffer management.  These functions need s_mutex held.
+ */
+
+/* FIXME: this is inefficient as hell, since dma_alloc_coherent just
+ * does a get_free_pages() call, and we waste a good chunk of an orderN
+ * allocation.  Should try to allocate the whole set in one chunk.
+ */
+static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime)
+{
+	int i;
+
+	cafe_set_config_needed(cam, 1);
+	if (loadtime) 
+		cam->dma_buf_size = dma_buf_size;
+	else {
+		cam->dma_buf_size = cam->pix_format.sizeimage;
+		if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32)
+			cam->dma_buf_size /= 2;
+	}
+	if (n_dma_bufs > 3)
+		n_dma_bufs = 3;
+
+	cam->nbufs = 0;
+	for (i = 0; i < n_dma_bufs; i++) {
+		cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev,
+				cam->dma_buf_size, cam->dma_handles + i,
+				GFP_KERNEL);
+		if (cam->dma_bufs[i] == NULL) {
+			cam_warn(cam, "Failed to allocate DMA buffer\n");
+			break;
+		}
+		/* For debug, remove eventually */
+		memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size);
+		(cam->nbufs)++;
+	}
+
+	switch (cam->nbufs) {
+	case 1:
+	    dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
+			    cam->dma_bufs[0], cam->dma_handles[0]);
+	    cam->nbufs = 0;
+	case 0:
+	    cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
+	    return -ENOMEM;
+
+	case 2:
+	    if (n_dma_bufs > 2)
+		    cam_warn(cam, "Will limp along with only 2 buffers\n");
+	    break;
+	}
+	return 0;
+}
+		
+static void cafe_free_dma_bufs(struct cafe_camera *cam)
+{
+	int i;
+
+	for (i = 0; i < cam->nbufs; i++) {
+		dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
+				cam->dma_bufs[i], cam->dma_handles[i]);
+		cam->dma_bufs[i] = NULL;
+	}
+	cam->nbufs = 0;
+}
+
+
+
+
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Here starts the V4L2 interface code.
+ */
+
+/*
+ * Read an image from the device. 
+ */
+static ssize_t cafe_deliver_buffer(struct cafe_camera *cam,
+		char __user *buffer, size_t len, loff_t *pos)
+{
+	int bufno;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	if (cam->next_buf < 0) {
+		cam_err(cam, "deliver_buffer: No next buffer\n");
+		spin_unlock_irqrestore(&cam->dev_lock, flags);
+		return -EIO;
+	}
+	bufno = cam->next_buf;
+	clear_bit(bufno, &cam->flags);
+	if (++(cam->next_buf) >= cam->nbufs)
+		cam->next_buf = 0;
+	if (! test_bit(cam->next_buf, &cam->flags))
+		cam->next_buf = -1;
+	cam->specframes = 0;
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+
+	if (len > cam->pix_format.sizeimage)
+		len = cam->pix_format.sizeimage;
+	if (copy_to_user(buffer, cam->dma_bufs[bufno], len)) 
+		return -EFAULT;
+	(*pos) += len;
+	return len;
+}	
+
+/*
+ * Get everything ready, and start grabbing frames.
+ */
+static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state)
+{
+	int ret;
+	unsigned long flags;
+	
+	/*
+	 * Configuration.  If we still don't have DMA buffers,
+	 * make one last, desperate attempt.
+	 */
+	if (cam->nbufs == 0) 
+		if (cafe_alloc_dma_bufs(cam, 0))
+			return -ENOMEM;
+
+	if (cafe_needs_config(cam)) {
+		cafe_cam_configure(cam);
+		ret = cafe_ctlr_configure(cam);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * Turn it loose.
+	 */
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	cafe_reset_buffers(cam);
+	cafe_ctlr_irq_enable(cam);
+	cam->state = state;
+	cafe_ctlr_start(cam);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	return 0;
+}
+
+
+static ssize_t cafe_v4l_read(struct file *filp,
+		char __user *buffer, size_t len, loff_t *pos)
+{
+	struct cafe_camera *cam = filp->private_data;
+	int ret;
+	
+	/*
+	 * Perhaps we're in speculative read mode and already
+	 * have data?
+	 */
+	mutex_lock(&cam->s_mutex);
+	if (cam->state == S_SPECREAD) {
+		if (cam->next_buf >= 0) {
+			ret = cafe_deliver_buffer(cam, buffer, len, pos);
+			if (ret != 0)
+				goto out_unlock;
+		}
+	} else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) {
+		ret = -EIO;
+		goto out_unlock;
+	} else if (cam->state != S_IDLE) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+
+	/*
+	 * v4l2: multiple processes can open the device, but only
+	 * one gets to grab data from it.
+	 */
+	if (cam->owner && cam->owner != filp) {
+		ret = -EBUSY;
+		goto out_unlock;
+	}
+	cam->owner = filp;
+
+	/*
+	 * Do setup if need be.
+	 */
+	if (cam->state != S_SPECREAD) {
+		ret = cafe_read_setup(cam, S_SINGLEREAD);
+		if (ret)
+			goto out_unlock;
+	}
+	/*
+	 * Wait for something to happen.  This should probably
+	 * be interruptible (FIXME).
+	 */
+	wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ);
+	if (cam->next_buf < 0) {
+		cam_err(cam, "read() operation timed out\n");
+		cafe_ctlr_stop_dma(cam);
+		ret = -EIO;
+		goto out_unlock;
+	}
+	/*
+	 * Give them their data and we should be done.
+	 */
+	ret = cafe_deliver_buffer(cam, buffer, len, pos);
+
+  out_unlock:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+
+
+
+
+
+
+/*
+ * Streaming I/O support.
+ */
+
+
+
+static int cafe_vidioc_streamon(struct file *filp, void *priv,
+		enum v4l2_buf_type type)
+{
+	struct cafe_camera *cam = filp->private_data;
+	int ret = -EINVAL;
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		goto out;
+	mutex_lock(&cam->s_mutex);
+	if (cam->state != S_IDLE || cam->n_sbufs == 0)
+		goto out_unlock;
+
+	cam->sequence = 0;
+	ret = cafe_read_setup(cam, S_STREAMING);
+
+  out_unlock:
+	mutex_unlock(&cam->s_mutex);
+  out:
+	return ret;
+}
+
+
+static int cafe_vidioc_streamoff(struct file *filp, void *priv,
+		enum v4l2_buf_type type)
+{
+	struct cafe_camera *cam = filp->private_data;
+	int ret = -EINVAL;
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		goto out;
+	mutex_lock(&cam->s_mutex);
+	if (cam->state != S_STREAMING)
+		goto out_unlock;
+
+	cafe_ctlr_stop_dma(cam);
+	ret = 0;
+
+  out_unlock:
+	mutex_unlock(&cam->s_mutex);
+  out:
+	return ret;
+}
+
+
+
+static int cafe_setup_siobuf(struct cafe_camera *cam, int index)
+{
+	struct cafe_sio_buffer *buf = cam->sb_bufs + index;
+	
+	INIT_LIST_HEAD(&buf->list);
+	buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage);
+	buf->buffer = vmalloc_user(buf->v4lbuf.length);
+	if (buf->buffer == NULL)
+		return -ENOMEM;
+	buf->mapcount = 0;
+	buf->cam = cam;
+
+	buf->v4lbuf.index = index;
+	buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	buf->v4lbuf.field = V4L2_FIELD_NONE;
+	buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
+	/*
+	 * Offset: must be 32-bit even on a 64-bit system.  video-buf
+	 * just uses the length times the index, but the spec warns
+	 * against doing just that - vma merging problems.  So we
+	 * leave a gap between each pair of buffers.
+	 */
+	buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
+	return 0;
+}
+
+static int cafe_free_sio_buffers(struct cafe_camera *cam)
+{
+	int i;
+
+	/*
+	 * If any buffers are mapped, we cannot free them at all.
+	 */
+	for (i = 0; i < cam->n_sbufs; i++)
+		if (cam->sb_bufs[i].mapcount > 0)
+			return -EBUSY;
+	/*
+	 * OK, let's do it.
+	 */
+	for (i = 0; i < cam->n_sbufs; i++)
+		vfree(cam->sb_bufs[i].buffer);
+	cam->n_sbufs = 0;
+	kfree(cam->sb_bufs);
+	cam->sb_bufs = NULL;
+	INIT_LIST_HEAD(&cam->sb_avail);
+	INIT_LIST_HEAD(&cam->sb_full);
+	return 0;
+}
+
+
+
+static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
+		struct v4l2_requestbuffers *req)
+{
+	struct cafe_camera *cam = filp->private_data;
+	int ret;
+
+	/*
+	 * Make sure it's something we can do.  User pointers could be
+	 * implemented without great pain, but that's not been done yet.
+	 */
+	if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (req->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+	/*
+	 * If they ask for zero buffers, they really want us to stop streaming
+	 * (if it's happening) and free everything.  Should we check owner?
+	 */
+	mutex_lock(&cam->s_mutex);
+	if (req->count == 0) {
+		if (cam->state == S_STREAMING)
+			cafe_ctlr_stop_dma(cam);
+		ret = cafe_free_sio_buffers (cam);
+		goto out;
+	}
+	/*
+	 * Device needs to be idle and working.  We *could* try to do the
+	 * right thing in S_SPECREAD by shutting things down, but it
+	 * probably doesn't matter.
+	 */
+	if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) {
+		ret = -EBUSY;
+		goto out;
+	}
+	cam->owner = filp;
+
+	if (req->count < min_buffers)
+		req->count = min_buffers;
+	else if (req->count > max_buffers)
+		req->count = max_buffers;
+	if (cam->n_sbufs > 0) {
+		ret = cafe_free_sio_buffers(cam);
+		if (ret)
+			goto out;
+	}
+
+	cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer),
+			GFP_KERNEL);
+	if (cam->sb_bufs == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) {
+		ret = cafe_setup_siobuf(cam, cam->n_sbufs);
+		if (ret)
+			break;
+	}
+
+	if (cam->n_sbufs == 0)  /* no luck at all - ret already set */
+		kfree(cam->sb_bufs);
+	else
+		ret = 0;
+	req->count = cam->n_sbufs;  /* In case of partial success */
+
+  out:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int cafe_vidioc_querybuf(struct file *filp, void *priv,
+		struct v4l2_buffer *buf)
+{
+	struct cafe_camera *cam = filp->private_data;
+	int ret = -EINVAL;
+
+	mutex_lock(&cam->s_mutex);
+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		goto out;
+	if (buf->index < 0 || buf->index >= cam->n_sbufs)
+		goto out;
+	*buf = cam->sb_bufs[buf->index].v4lbuf;
+	ret = 0;
+  out:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+static int cafe_vidioc_qbuf(struct file *filp, void *priv,
+		struct v4l2_buffer *buf)
+{
+	struct cafe_camera *cam = filp->private_data;
+	struct cafe_sio_buffer *sbuf;
+	int ret = -EINVAL;
+	unsigned long flags;
+
+	mutex_lock(&cam->s_mutex);
+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		goto out;
+	if (buf->index < 0 || buf->index >= cam->n_sbufs)
+		goto out;
+	sbuf = cam->sb_bufs + buf->index;
+	if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {
+		ret = 0; /* Already queued?? */
+		goto out;
+	}
+	if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) {
+		/* Spec doesn't say anything, seems appropriate tho */
+		ret = -EBUSY;
+		goto out;
+	}
+	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	list_add(&sbuf->list, &cam->sb_avail);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+	ret = 0;
+  out:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+static int cafe_vidioc_dqbuf(struct file *filp, void *priv,
+		struct v4l2_buffer *buf)
+{
+	struct cafe_camera *cam = filp->private_data;
+	struct cafe_sio_buffer *sbuf;
+	int ret = -EINVAL;
+	unsigned long flags;
+
+	mutex_lock(&cam->s_mutex);
+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		goto out_unlock;
+	if (cam->state != S_STREAMING)
+		goto out_unlock;
+	if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) {
+		ret = -EAGAIN;
+		goto out_unlock;
+	}
+
+	while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) {
+		mutex_unlock(&cam->s_mutex);
+		if (wait_event_interruptible(cam->iowait,
+						!list_empty(&cam->sb_full))) {
+			ret = -ERESTARTSYS;
+			goto out;
+		}
+		mutex_lock(&cam->s_mutex);
+	}
+
+	if (cam->state != S_STREAMING)
+		ret = -EINTR;
+	else {
+		spin_lock_irqsave(&cam->dev_lock, flags);
+		/* Should probably recheck !list_empty() here */
+		sbuf = list_entry(cam->sb_full.next,
+				struct cafe_sio_buffer, list);
+		list_del_init(&sbuf->list);
+		spin_unlock_irqrestore(&cam->dev_lock, flags);
+		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
+		*buf = sbuf->v4lbuf;
+		ret = 0;
+	}
+
+  out_unlock:
+	mutex_unlock(&cam->s_mutex);
+  out:
+	return ret;
+}
+
+
+
+static void cafe_v4l_vm_open(struct vm_area_struct *vma)
+{
+	struct cafe_sio_buffer *sbuf = vma->vm_private_data;
+	/*
+	 * Locking: done under mmap_sem, so we don't need to
+	 * go back to the camera lock here.
+	 */
+	sbuf->mapcount++;
+}
+
+
+static void cafe_v4l_vm_close(struct vm_area_struct *vma)
+{
+	struct cafe_sio_buffer *sbuf = vma->vm_private_data;
+
+	mutex_lock(&sbuf->cam->s_mutex);
+	sbuf->mapcount--;
+	/* Docs say we should stop I/O too... */
+	if (sbuf->mapcount == 0)
+		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
+	mutex_unlock(&sbuf->cam->s_mutex);
+}
+
+static struct vm_operations_struct cafe_v4l_vm_ops = {
+	.open = cafe_v4l_vm_open,
+	.close = cafe_v4l_vm_close
+};
+
+
+static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct cafe_camera *cam = filp->private_data;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	int ret = -EINVAL;
+	int i;
+	struct cafe_sio_buffer *sbuf = NULL;
+
+	if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+	/*
+	 * Find the buffer they are looking for.
+	 */
+	mutex_lock(&cam->s_mutex);
+	for (i = 0; i < cam->n_sbufs; i++)
+		if (cam->sb_bufs[i].v4lbuf.m.offset == offset) {
+			sbuf = cam->sb_bufs + i;
+			break;
+		}
+	if (sbuf == NULL)
+		goto out;
+
+	ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
+	if (ret)
+		goto out;
+	vma->vm_flags |= VM_DONTEXPAND;
+	vma->vm_private_data = sbuf;
+	vma->vm_ops = &cafe_v4l_vm_ops;
+	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
+	cafe_v4l_vm_open(vma);
+	ret = 0;
+  out:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+	
+
+
+static int cafe_v4l_open(struct inode *inode, struct file *filp)
+{
+	struct cafe_camera *cam;
+
+	cam = cafe_find_dev(iminor(inode));
+	if (cam == NULL)
+		return -ENODEV;
+	filp->private_data = cam;
+
+	mutex_lock(&cam->s_mutex);
+	if (cam->users == 0) {
+		cafe_ctlr_power_up(cam);
+		__cafe_cam_reset(cam);
+		cafe_set_config_needed(cam, 1);
+	/* FIXME make sure this is complete */
+	}
+	(cam->users)++;
+	mutex_unlock(&cam->s_mutex);
+	return 0;
+}
+
+
+static int cafe_v4l_release(struct inode *inode, struct file *filp)
+{
+	struct cafe_camera *cam = filp->private_data;
+	
+	mutex_lock(&cam->s_mutex);
+	(cam->users)--;
+	if (filp == cam->owner) {
+		cafe_ctlr_stop_dma(cam);
+		cafe_free_sio_buffers(cam);
+		cam->owner = NULL;
+	}
+	if (cam->users == 0)
+		cafe_ctlr_power_down(cam);
+	mutex_unlock(&cam->s_mutex);
+	return 0;
+}
+
+
+
+static unsigned int cafe_v4l_poll(struct file *filp,
+		struct poll_table_struct *pt)
+{
+	struct cafe_camera *cam = filp->private_data;
+
+	poll_wait(filp, &cam->iowait, pt);
+	if (cam->next_buf >= 0)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+
+
+static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
+		struct v4l2_queryctrl *qc)
+{
+	struct cafe_camera *cam = filp->private_data;
+	int ret;
+	
+	mutex_lock(&cam->s_mutex);
+	ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct cafe_camera *cam = filp->private_data;
+	int ret;
+	
+	mutex_lock(&cam->s_mutex);
+	ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct cafe_camera *cam = filp->private_data;
+	int ret;
+	
+	mutex_lock(&cam->s_mutex);
+	ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+
+
+
+static int cafe_vidioc_querycap(struct file *file, void *priv,
+		struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "cafe_ccic");
+	strcpy(cap->card, "cafe_ccic");
+	cap->version = CAFE_VERSION;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+
+/*
+ * The default format we use until somebody says otherwise.
+ */
+static struct v4l2_pix_format cafe_def_pix_format = {
+	.width		= VGA_WIDTH,
+	.height		= VGA_HEIGHT,
+	.pixelformat	= V4L2_PIX_FMT_YUYV,
+	.field		= V4L2_FIELD_NONE,
+	.bytesperline	= VGA_WIDTH*2,
+	.sizeimage	= VGA_WIDTH*VGA_HEIGHT*2,
+};
+
+static int cafe_vidioc_enum_fmt_cap(struct file *filp,
+		void *priv, struct v4l2_fmtdesc *fmt)
+{
+	struct cafe_camera *cam = priv;
+	int ret;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	mutex_lock(&cam->s_mutex);
+	ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+
+static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
+		struct v4l2_format *fmt)
+{
+	struct cafe_camera *cam = priv;
+	int ret;
+
+	mutex_lock(&cam->s_mutex);
+	ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt);
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
+		struct v4l2_format *fmt)
+{
+	struct cafe_camera *cam = priv;
+	int ret;
+
+	/*
+	 * Can't do anything if the device is not idle
+	 * Also can't if there are streaming buffers in place.
+	 */
+	if (cam->state != S_IDLE || cam->n_sbufs > 0)
+		return -EBUSY;
+	/*
+	 * See if the formatting works in principle.
+	 */
+	ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt);
+	if (ret)
+		return ret;
+	/*
+	 * Now we start to change things for real, so let's do it
+	 * under lock.
+	 */
+	mutex_lock(&cam->s_mutex);
+	cam->pix_format = fmt->fmt.pix;
+	/*
+	 * Make sure we have appropriate DMA buffers.
+	 */
+	ret = -ENOMEM;
+	if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
+		cafe_free_dma_bufs(cam);
+	if (cam->nbufs == 0) {
+		if (cafe_alloc_dma_bufs(cam, 0))
+			goto out;
+	}
+	/*
+	 * It looks like this might work, so let's program the sensor.
+	 */
+	ret = cafe_cam_configure(cam);
+	if (! ret)
+		ret = cafe_ctlr_configure(cam);
+  out:
+	mutex_unlock(&cam->s_mutex);
+	return ret;
+}
+
+/*
+ * Return our stored notion of how the camera is/should be configured.
+ * The V4l2 spec wants us to be smarter, and actually get this from
+ * the camera (and not mess with it at open time).  Someday.
+ */
+static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv,
+		struct v4l2_format *f)
+{
+	struct cafe_camera *cam = priv;
+	
+	f->fmt.pix = cam->pix_format;
+	return 0;
+}
+
+/*
+ * We only have one input - the sensor - so minimize the nonsense here.
+ */
+static int cafe_vidioc_enum_input(struct file *filp, void *priv,
+		struct v4l2_input *input)
+{
+	if (input->index != 0)
+		return -EINVAL;
+
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+	input->std = V4L2_STD_ALL; /* Not sure what should go here */
+	strcpy(input->name, "Camera");
+	return 0;
+}
+
+static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	return 0;
+}
+
+/* from vivi.c */
+static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a)
+{
+	return 0;
+}
+
+
+/*
+ * The TV Norm stuff is weird - we're a camera with little to do with TV,
+ * really.  The following is what vivi does.
+ */
+static struct v4l2_tvnorm cafe_tvnorm[] = {
+	{
+		.name      = "NTSC-M",
+		.id        = V4L2_STD_NTSC_M,
+	}
+};
+
+
+void cafe_v4l_dev_release(struct video_device *vd)
+{
+	struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
+
+	kfree(cam);
+}
+
+
+/*
+ * This template device holds all of those v4l2 methods; we
+ * clone it for specific real devices.
+ */
+
+static struct file_operations cafe_v4l_fops = {
+	.owner = THIS_MODULE,
+	.open = cafe_v4l_open,
+	.release = cafe_v4l_release,
+	.read = cafe_v4l_read,
+	.poll = cafe_v4l_poll,
+	.mmap = cafe_v4l_mmap,
+	.ioctl = video_ioctl2,
+	.llseek = no_llseek,
+};
+
+static struct video_device cafe_v4l_template = {
+	.name = "cafe",
+	.type = VFL_TYPE_GRABBER,
+	.type2 = VID_TYPE_CAPTURE,
+	.minor = -1, /* Get one dynamically */
+	.tvnorms = cafe_tvnorm,
+	.tvnormsize = 1,
+	.current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
+
+	.fops = &cafe_v4l_fops,
+	.release = cafe_v4l_dev_release,
+
+	.vidioc_querycap 	= cafe_vidioc_querycap,
+	.vidioc_enum_fmt_cap	= cafe_vidioc_enum_fmt_cap,
+	.vidioc_try_fmt_cap	= cafe_vidioc_try_fmt_cap,
+	.vidioc_s_fmt_cap	= cafe_vidioc_s_fmt_cap,
+	.vidioc_g_fmt_cap	= cafe_vidioc_g_fmt_cap,
+	.vidioc_enum_input	= cafe_vidioc_enum_input,
+	.vidioc_g_input		= cafe_vidioc_g_input,
+	.vidioc_s_input		= cafe_vidioc_s_input,
+	.vidioc_s_std		= cafe_vidioc_s_std,
+	.vidioc_reqbufs		= cafe_vidioc_reqbufs,
+	.vidioc_querybuf	= cafe_vidioc_querybuf,
+	.vidioc_qbuf		= cafe_vidioc_qbuf,
+	.vidioc_dqbuf		= cafe_vidioc_dqbuf,
+	.vidioc_streamon	= cafe_vidioc_streamon,
+	.vidioc_streamoff	= cafe_vidioc_streamoff,
+	.vidioc_queryctrl	= cafe_vidioc_queryctrl,
+	.vidioc_g_ctrl		= cafe_vidioc_g_ctrl,
+	.vidioc_s_ctrl		= cafe_vidioc_s_ctrl,
+	/* Do cropping someday */
+};
+
+
+
+
+
+
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Interrupt handler stuff
+ */
+
+/*
+ * Create RGB32 from RGB444 so it can be displayed before the applications
+ * know about the latter format.
+ */
+static void cafe_fake_rgb32(struct cafe_camera *cam, char *dest, char *src)
+{
+	int i;
+	u16 *ssrc = (u16 *) src;
+
+	/* RGB444 version */
+	for (i = 0; i < cam->pix_format.sizeimage; i += 4) {
+	//		dest[0] = (*ssrc & 0xf000) >> 8;
+		dest[0] = (*ssrc & 0x000f) << 4;
+		dest[1] = (*ssrc & 0x00f0);
+		dest[2] = (*ssrc & 0x0f00) >> 4;
+		dest[3] = (*ssrc & 0xf000);   /* Alpha */
+		dest += 4;
+		ssrc++;
+	}
+#if 0
+	/* RGB565 version */
+	for (i = 0; i < cam->pix_format.sizeimage; i += 4) {
+		dest[0] = (*ssrc & 0xf800) >> 8;
+		dest[1] = (*ssrc & 0x07e0) >> 3;
+		dest[2] = (*ssrc & 0x001f) << 3;
+		dest[3] = 0;
+		dest += 4;
+		ssrc++;
+	}
+#endif
+}
+
+
+static void cafe_frame_tasklet(unsigned long data)
+{
+	struct cafe_camera *cam = (struct cafe_camera *) data;
+	int i;
+	unsigned long flags;
+	struct cafe_sio_buffer *sbuf;
+
+	spin_lock_irqsave(&cam->dev_lock, flags);
+	for (i = 0; i < cam->nbufs; i++) {
+		int bufno = cam->next_buf;
+		if (bufno < 0) {  /* "will never happen" */
+			cam_err(cam, "No valid bufs in tasklet!\n");
+			break;
+		}
+		if (++(cam->next_buf) >= cam->nbufs)
+			cam->next_buf = 0;
+		if (! test_bit(bufno, &cam->flags))
+			continue;
+		if (list_empty(&cam->sb_avail))
+			break;  /* Leave it valid, hope for better later */
+		clear_bit(bufno, &cam->flags);
+		/*
+		 * We could perhaps drop the spinlock during this
+		 * big copy.  Something to consider.
+		 */
+		sbuf = list_entry(cam->sb_avail.next,
+				struct cafe_sio_buffer, list);
+		if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32)
+			cafe_fake_rgb32(cam, sbuf->buffer, cam->dma_bufs[bufno]);
+		else
+			memcpy(sbuf->buffer, cam->dma_bufs[bufno],
+					cam->pix_format.sizeimage);
+		sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
+		sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
+		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
+		sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
+		list_move_tail(&sbuf->list, &cam->sb_full);
+	}
+	if (! list_empty(&cam->sb_full))
+		wake_up(&cam->iowait);
+	spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+
+static void cafe_frame_complete(struct cafe_camera *cam, int frame)
+{
+	/*
+	 * Basic frame housekeeping.
+	 */
+	if (test_bit(frame, &cam->flags) && printk_ratelimit())
+		cam_err(cam, "Frame overrun on %d, frames lost\n", frame);		
+	set_bit(frame, &cam->flags);
+	clear_bit(CF_DMA_ACTIVE, &cam->flags);
+	if (cam->next_buf < 0)
+		cam->next_buf = frame;
+	cam->buf_seq[frame] = ++(cam->sequence);
+
+	switch (cam->state) {
+	/*
+	 * If in single read mode, try going speculative.
+	 */
+	    case S_SINGLEREAD:
+		cam->state = S_SPECREAD;
+		cam->specframes = 0;
+		wake_up(&cam->iowait);
+		break;
+		
+	/*
+	 * If we are already doing speculative reads, and nobody is
+	 * reading them, just stop.
+	 */
+	    case S_SPECREAD:
+		if (++(cam->specframes) >= cam->nbufs) {
+			cafe_ctlr_stop(cam);
+			cafe_ctlr_irq_disable(cam);
+			cam->state = S_IDLE;
+		}
+		wake_up(&cam->iowait);
+		break;
+	/*
+	 * For the streaming case, we defer the real work to the
+	 * camera tasklet.
+	 *
+	 * FIXME: if the application is not consuming the buffers,
+	 * we should eventually put things on hold and restart in
+	 * vidioc_dqbuf().
+	 */
+	    case S_STREAMING:
+		tasklet_schedule(&cam->s_tasklet);
+		break;
+
+	    default:
+		cam_err(cam, "Frame interrupt in non-operational state\n");
+		break;
+	}
+}
+
+
+
+
+static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs)
+{
+	unsigned int frame;
+
+	cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */
+	/*
+	 * Handle any frame completions.  There really should
+	 * not be more than one of these, or we have fallen
+	 * far behind.
+	 */
+	for (frame = 0; frame < cam->nbufs; frame++)
+		if (irqs & (IRQ_EOF0 << frame))
+			cafe_frame_complete(cam, frame);
+	/*
+	 * If a frame starts, note that we have DMA active.  This
+	 * code assumes that we won't get multiple frame interrupts
+	 * at once; may want to rethink that.
+	 */
+	if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2))
+		set_bit(CF_DMA_ACTIVE, &cam->flags);
+}
+
+
+
+static irqreturn_t cafe_irq(int irq, void *data)
+{
+	struct cafe_camera *cam = data;
+	unsigned int irqs;
+
+	spin_lock(&cam->dev_lock);
+	irqs = cafe_reg_read(cam, REG_IRQSTAT);
+	if ((irqs & ALLIRQS) == 0) {
+		spin_unlock(&cam->dev_lock);
+		return IRQ_NONE;
+	}
+	if (irqs & FRAMEIRQS)
+		cafe_frame_irq(cam, irqs);
+	if (irqs & TWSIIRQS) {
+		cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS);
+		wake_up(&cam->smbus_wait);
+	}
+	spin_unlock(&cam->dev_lock);
+	return IRQ_HANDLED;
+}
+
+
+/* -------------------------------------------------------------------------- */
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * Debugfs stuff.
+ */
+
+static char cafe_debug_buf[1024];
+static struct dentry *cafe_dfs_root;
+
+static void cafe_dfs_setup(void)
+{
+	cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL);
+	if (IS_ERR(cafe_dfs_root)) {
+		cafe_dfs_root = NULL;  /* Never mind */
+		printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n");
+	}
+}
+
+static void cafe_dfs_shutdown(void)
+{
+	if (cafe_dfs_root)
+		debugfs_remove(cafe_dfs_root);
+}
+
+static int cafe_dfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t cafe_dfs_read_regs(struct file *file,
+		char __user *buf, size_t count, loff_t *ppos)
+{
+	struct cafe_camera *cam = file->private_data;
+	char *s = cafe_debug_buf;
+	int offset;
+
+	for (offset = 0; offset < 0x44; offset += 4)
+		s += sprintf(s, "%02x: %08x\n", offset,
+				cafe_reg_read(cam, offset));
+	for (offset = 0x88; offset <= 0x90; offset += 4)
+		s += sprintf(s, "%02x: %08x\n", offset,
+				cafe_reg_read(cam, offset));
+	for (offset = 0xb4; offset <= 0xbc; offset += 4)
+		s += sprintf(s, "%02x: %08x\n", offset,
+				cafe_reg_read(cam, offset));
+	for (offset = 0x3000; offset <= 0x300c; offset += 4)
+		s += sprintf(s, "%04x: %08x\n", offset,
+				cafe_reg_read(cam, offset));
+	return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
+			s - cafe_debug_buf);
+}
+		
+static struct file_operations cafe_dfs_reg_ops = {
+	.owner = THIS_MODULE,
+	.read = cafe_dfs_read_regs,
+	.open = cafe_dfs_open
+};
+
+static ssize_t cafe_dfs_read_cam(struct file *file,
+		char __user *buf, size_t count, loff_t *ppos)
+{
+	struct cafe_camera *cam = file->private_data;
+	char *s = cafe_debug_buf;
+	int offset;
+
+	if (! cam->sensor)
+		return -EINVAL;
+	for (offset = 0x0; offset < 0x8a; offset++)
+	{
+		u8 v;
+
+		cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v);
+		s += sprintf(s, "%02x: %02x\n", offset, v);
+	}
+	return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
+			s - cafe_debug_buf);
+}
+
+static struct file_operations cafe_dfs_cam_ops = {
+	.owner = THIS_MODULE,
+	.read = cafe_dfs_read_cam,
+	.open = cafe_dfs_open
+};
+
+
+
+static void cafe_dfs_cam_setup(struct cafe_camera *cam)
+{
+	char fname[40];
+
+	if (!cafe_dfs_root)
+		return;
+	sprintf(fname, "regs-%d", cam->v4ldev.minor);
+	cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
+			cam, &cafe_dfs_reg_ops);
+	sprintf(fname, "cam-%d", cam->v4ldev.minor);
+	cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
+			cam, &cafe_dfs_cam_ops);
+}
+
+
+static void cafe_dfs_cam_shutdown(struct cafe_camera *cam)
+{
+	if (! IS_ERR(cam->dfs_regs))
+		debugfs_remove(cam->dfs_regs);
+	if (! IS_ERR(cam->dfs_cam_regs))
+		debugfs_remove(cam->dfs_cam_regs);
+}
+
+#else
+
+#define cafe_dfs_setup()
+#define cafe_dfs_shutdown()
+#define cafe_dfs_cam_setup(cam)
+#define cafe_dfs_cam_shutdown(cam)
+#endif    /* CONFIG_VIDEO_ADV_DEBUG */
+
+
+
+
+/* ------------------------------------------------------------------------*/
+/*
+ * PCI interface stuff.
+ */
+
+static int cafe_pci_probe(struct pci_dev *pdev,
+		const struct pci_device_id *id)
+{
+	int ret;
+	u16 classword;
+	struct cafe_camera *cam;
+	/*
+	 * Make sure we have a camera here - we'll get calls for
+	 * the other cafe devices as well.
+	 */
+	pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword);
+	if (classword != PCI_CLASS_MULTIMEDIA_VIDEO)
+		return -ENODEV;
+	/*
+	 * Start putting together one of our big camera structures.
+	 */
+	ret = -ENOMEM;
+	cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
+	if (cam == NULL)
+		goto out;
+	mutex_init(&cam->s_mutex);
+	mutex_lock(&cam->s_mutex);
+	spin_lock_init(&cam->dev_lock);
+	cam->state = S_NOTREADY;
+	cafe_set_config_needed(cam, 1);
+	init_waitqueue_head(&cam->smbus_wait);
+	init_waitqueue_head(&cam->iowait);
+	cam->pdev = pdev;
+	cam->pix_format = cafe_def_pix_format;
+	INIT_LIST_HEAD(&cam->dev_list);
+	INIT_LIST_HEAD(&cam->sb_avail);
+	INIT_LIST_HEAD(&cam->sb_full);
+	tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam);
+	/*
+	 * Get set up on the PCI bus.
+	 */
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto out_free;
+	pci_set_master(pdev);
+
+	ret = -EIO;
+	cam->regs = pci_iomap(pdev, 0, 0);
+	if (! cam->regs) {
+		printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
+		goto out_free;
+	}
+	ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
+	if (ret)
+		goto out_iounmap;
+	cafe_ctlr_init(cam);
+	cafe_ctlr_power_up(cam);
+	/*
+	 * Set up I2C/SMBUS communications
+	 */
+	mutex_unlock(&cam->s_mutex);  /* attach can deadlock */
+	ret = cafe_smbus_setup(cam);
+	if (ret)
+		goto out_freeirq;
+	/*
+	 * Get the v4l2 setup done.
+	 */
+	mutex_lock(&cam->s_mutex);
+	cam->v4ldev = cafe_v4l_template;
+	cam->v4ldev.debug = 0;
+//	cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;
+	ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
+	if (ret)
+		goto out_smbus;
+	/*
+	 * If so requested, try to get our DMA buffers now.
+	 */
+	if (alloc_bufs_at_load) {
+		if (cafe_alloc_dma_bufs(cam, 1))
+			cam_warn(cam, "Unable to alloc DMA buffers at load"
+					" will try again later.");
+	}
+
+	cafe_dfs_cam_setup(cam);
+	mutex_unlock(&cam->s_mutex);
+	cafe_add_dev(cam);
+	return 0;
+
+  out_smbus:
+	cafe_smbus_shutdown(cam);
+  out_freeirq:
+	cafe_ctlr_power_down(cam);
+	free_irq(pdev->irq, cam);
+  out_iounmap:
+	pci_iounmap(pdev, cam->regs);
+  out_free:
+	kfree(cam);
+  out:
+	return ret;
+}
+
+
+/*
+ * Shut down an initialized device
+ */
+static void cafe_shutdown(struct cafe_camera *cam)
+{
+/* FIXME: Make sure we take care of everything here */
+	cafe_dfs_cam_shutdown(cam);
+	if (cam->n_sbufs > 0)
+		/* What if they are still mapped?  Shouldn't be, but... */
+		cafe_free_sio_buffers(cam);
+	cafe_remove_dev(cam);
+	cafe_ctlr_stop_dma(cam);
+	cafe_ctlr_power_down(cam);
+	cafe_smbus_shutdown(cam);
+	cafe_free_dma_bufs(cam);
+	free_irq(cam->pdev->irq, cam);
+	pci_iounmap(cam->pdev, cam->regs);
+	video_unregister_device(&cam->v4ldev);
+	/* kfree(cam); done in v4l_release () */
+}
+		
+
+static void cafe_pci_remove(struct pci_dev *pdev)
+{
+	struct cafe_camera *cam = cafe_find_by_pdev(pdev);
+
+	if (cam == NULL) {
+		cam_warn(cam, "pci_remove on unknown pdev %p\n", pdev);
+		return;
+	}
+	mutex_lock(&cam->s_mutex);
+	if (cam->users > 0)
+		cam_warn(cam, "Removing a device with users!\n");
+	cafe_shutdown(cam);
+/* No unlock - it no longer exists */
+}
+
+
+
+
+static struct pci_device_id cafe_ids[] = {
+	{ PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */
+	{ PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
+	{ PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, cafe_ids);
+
+static struct pci_driver cafe_pci_driver = {
+	.name = "cafe1000-ccic",
+	.id_table = cafe_ids,
+	.probe = cafe_pci_probe,
+	.remove = cafe_pci_remove,
+};
+
+
+
+
+static int __init cafe_init(void)
+{
+	int ret;
+
+	printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
+			CAFE_VERSION);
+	cafe_dfs_setup();
+	ret = pci_register_driver(&cafe_pci_driver);
+	if (ret) {
+		printk(KERN_ERR "Unable to register cafe_ccic driver\n");
+		goto out;
+	}
+	request_module("ov7670");  /* FIXME want something more general */
+	ret = 0;
+
+  out:
+	return ret;
+}
+
+
+static void __exit cafe_exit(void)
+{
+	pci_unregister_driver(&cafe_pci_driver);
+	cafe_dfs_shutdown();
+}
+
+module_init(cafe_init);
+module_exit(cafe_exit);
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
deleted file mode 100644
index d5cc93c..0000000
--- a/drivers/media/video/cafe_ccic.c
+++ /dev/null
@@ -1,2254 +0,0 @@
-/*
- * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
- * multifunction chip.  Currently works with the Omnivision OV7670
- * sensor.
- *
- * Copyright 2006 One Laptop Per Child Association, Inc.
- *
- * Written by Jonathan Corbet, corbet at lwn.net.
- *
- * This file may be distributed under the terms of the GNU General
- * Public License, version 2.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/debugfs.h>
-#include <linux/jiffies.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include "cafe_ccic-regs.h"
-
-#define CAFE_VERSION 0x000001
-
-
-/*
- * Parameters.
- */
-MODULE_AUTHOR("Jonathan Corbet <corbet at lwn.net>");
-MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("Video");
-
-/*
- * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
- * we must have physically contiguous buffers to bring frames into.
- * These parameters control how many buffers we use, whether we
- * allocate them at load time (better chance of success, but nails down
- * memory) or when somebody tries to use the camera (riskier), and,
- * for load-time allocation, how big they should be.
- *
- * The controller can cycle through three buffers.  We could use
- * more by flipping pointers around, but it probably makes little
- * sense.
- */
-
-#define MAX_DMA_BUFS 3
-static int alloc_bufs_at_load = 0;
-module_param(alloc_bufs_at_load, bool, 0444);
-MODULE_PARM_DESC(alloc_bufs_at_load,
-		"Non-zero value causes DMA buffers to be allocated at module "
-		"load time.  This increases the chances of successfully getting "
-		"those buffers, but at the cost of nailing down the memory from "
-		"the outset.");
-
-static int n_dma_bufs = 3; 
-module_param(n_dma_bufs, uint, 0644);
-MODULE_PARM_DESC(n_dma_bufs,
-		"The number of DMA buffers to allocate.  Can be either two "
-		"(saves memory, makes timing tighter) or three.");
-
-static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2;  /* Worst case */
-module_param(dma_buf_size, uint, 0444);
-MODULE_PARM_DESC(dma_buf_size,
-		"The size of the allocated DMA buffers.  If actual operating "
-		"parameters require larger buffers, an attempt to reallocate "
-		"will be made.");
-		
-static int min_buffers = 1;
-module_param(min_buffers, uint, 0644);
-MODULE_PARM_DESC(min_buffers,
-		"The minimum number of streaming I/O buffers we are willing "
-		"to work with.");
-
-static int max_buffers = 10;
-module_param(max_buffers, uint, 0644);
-MODULE_PARM_DESC(max_buffers,
-		"The maximum number of streaming I/O buffers an application "
-		"will be allowed to allocate.  These buffers are big and live "
-		"in vmalloc space.");
-
-static int flip = 0;
-module_param(flip, bool, 0444);
-MODULE_PARM_DESC(flip,
-		"If set, the sensor will be instructed to flip the image "
-		"vertically.");
-
-
-enum cafe_state {
-	S_NOTREADY,	/* Not yet initialized */
-	S_IDLE,		/* Just hanging around */
-	S_FLAKED,	/* Some sort of problem */
-	S_SINGLEREAD,	/* In read() */
-	S_SPECREAD,   	/* Speculative read (for future read()) */
-	S_STREAMING	/* Streaming data */
-};
-
-/*
- * Tracking of streaming I/O buffers.
- */
-struct cafe_sio_buffer {
-	struct list_head list;
-	struct v4l2_buffer v4lbuf;
-	char *buffer;   /* Where it lives in kernel space */
-	int mapcount;
-	struct cafe_camera *cam;
-};
-
-/*
- * A description of one of our devices.
- * Locking: controlled by s_mutex.  Certain fields, however, require
- * 	    the dev_lock spinlock; they are marked as such by comments.
- *	    dev_lock is also required for access to device registers.
- */
-struct cafe_camera
-{
-	enum cafe_state state;  
-	unsigned long flags;   		/* Buffer status, mainly (dev_lock) */
-	int users;			/* How many open FDs */
-	struct file *owner;	 	/* Who has data access (v4l2) */
-
-	/*
-	 * Subsystem structures.
-	 */
-	struct pci_dev *pdev;
-	struct video_device v4ldev;
-	struct i2c_adapter i2c_adapter;
-	struct i2c_client *sensor;
-
-	unsigned char __iomem *regs;
-	struct list_head dev_list;	/* link to other devices */
-
-	/* DMA buffers */
-	unsigned int nbufs;		/* How many are alloc'd */
-	int next_buf;			/* Next to consume (dev_lock) */
-	unsigned int dma_buf_size;  	/* allocated size */
-	void *dma_bufs[MAX_DMA_BUFS];	/* Internal buffer addresses */
-	dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
-	unsigned int specframes;	/* Unconsumed spec frames (dev_lock) */
-	unsigned int sequence;		/* Frame sequence number */
-	unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */
-
-	/* Streaming buffers */
-	unsigned int n_sbufs;		/* How many we have */
-	struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */
-	struct list_head sb_avail;	/* Available for data (we own) (dev_lock) */
-	struct list_head sb_full;	/* With data (user space owns) (dev_lock) */
-	struct tasklet_struct s_tasklet; 
-
-	/* Current operating parameters */
-	enum v4l2_chip_ident sensor_type;		/* Currently ov7670 only */
-	struct v4l2_pix_format pix_format;
-	
-	/* Locks */
-	struct mutex s_mutex; /* Access to this structure */
-	spinlock_t dev_lock;  /* Access to device */
-
-	/* Misc */
-	wait_queue_head_t smbus_wait;	/* Waiting on i2c events */
-	wait_queue_head_t iowait;	/* Waiting on frame data */
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-	struct dentry *dfs_regs;
-	struct dentry *dfs_cam_regs;
-#endif
-};
-
-/*
- * Status flags.  Always manipulated with bit operations.
- */
-#define CF_BUF0_VALID	 0	/* Buffers valid - first three */
-#define CF_BUF1_VALID	 1
-#define CF_BUF2_VALID	 2
-#define CF_DMA_ACTIVE	 3	/* A frame is incoming */
-#define CF_CONFIG_NEEDED 4	/* Must configure hardware */
-
-
-
-/*
- * Start over with DMA buffers - dev_lock needed.
- */
-static void cafe_reset_buffers(struct cafe_camera *cam)
-{
-	int i;
-	
-	cam->next_buf = -1;
-	for (i = 0; i < cam->nbufs; i++) 
-		clear_bit(i, &cam->flags);
-	cam->specframes = 0;
-}
-
-static inline int cafe_needs_config(struct cafe_camera *cam)
-{
-	return test_bit(CF_CONFIG_NEEDED, &cam->flags);
-}
-
-static void cafe_set_config_needed(struct cafe_camera *cam, int needed)
-{
-	if (needed)
-		set_bit(CF_CONFIG_NEEDED, &cam->flags);
-	else
-		clear_bit(CF_CONFIG_NEEDED, &cam->flags);
-}
-
-
-
-
-/*
- * Debugging and related.
- */
-#define cam_err(cam, fmt, arg...) \
-	dev_err(&(cam)->pdev->dev, fmt, ##arg);
-#define cam_warn(cam, fmt, arg...) \
-	dev_warn(&(cam)->pdev->dev, fmt, ##arg);
-#define cam_dbg(cam, fmt, arg...) \
-	dev_dbg(&(cam)->pdev->dev, fmt, ##arg);
-
-
-/* ---------------------------------------------------------------------*/
-/*
- * We keep a simple list of known devices to search at open time.
- */
-static LIST_HEAD(cafe_dev_list);
-static DEFINE_MUTEX(cafe_dev_list_lock);
-
-static void cafe_add_dev(struct cafe_camera *cam)
-{
-	mutex_lock(&cafe_dev_list_lock);
-	list_add_tail(&cam->dev_list, &cafe_dev_list);
-	mutex_unlock(&cafe_dev_list_lock);
-}
-
-static void cafe_remove_dev(struct cafe_camera *cam)
-{
-	mutex_lock(&cafe_dev_list_lock);
-	list_del(&cam->dev_list);
-	mutex_unlock(&cafe_dev_list_lock);
-}
-
-static struct cafe_camera *cafe_find_dev(int minor)
-{
-	struct cafe_camera *cam;
-	
-	mutex_lock(&cafe_dev_list_lock);
-	list_for_each_entry(cam, &cafe_dev_list, dev_list) {
-		if (cam->v4ldev.minor == minor)
-			goto done;
-	}
-	cam = NULL;
-  done:
-	mutex_unlock(&cafe_dev_list_lock);
-	return cam;
-}
-	
-
-static struct cafe_camera *cafe_find_by_pdev(struct pci_dev *pdev)
-{
-	struct cafe_camera *cam;
-	
-	mutex_lock(&cafe_dev_list_lock);
-	list_for_each_entry(cam, &cafe_dev_list, dev_list) {
-		if (cam->pdev == pdev)
-			goto done;
-	}
-	cam = NULL;
-  done:
-	mutex_unlock(&cafe_dev_list_lock);
-	return cam;
-}
-	
-
-/* ------------------------------------------------------------------------ */
-/*
- * Device register I/O
- */
-static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg,
-		unsigned int val)
-{
-	iowrite32(val, cam->regs + reg);
-}
-
-static inline unsigned int cafe_reg_read(struct cafe_camera *cam,
-		unsigned int reg)
-{
-	return ioread32(cam->regs + reg);
-}
-
-
-static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg,
-		unsigned int val, unsigned int mask)
-{
-	unsigned int v = cafe_reg_read(cam, reg);
-
-	v = (v & ~mask) | (val & mask);
-	cafe_reg_write(cam, reg, v);
-}
-
-static inline void cafe_reg_clear_bit(struct cafe_camera *cam,
-		unsigned int reg, unsigned int val)
-{
-	cafe_reg_write_mask(cam, reg, 0, val);
-}
-
-static inline void cafe_reg_set_bit(struct cafe_camera *cam,
-		unsigned int reg, unsigned int val)
-{
-	cafe_reg_write_mask(cam, reg, val, val);
-}
-
-
-
-/* -------------------------------------------------------------------- */
-/*
- * The I2C/SMBUS interface to the camera itself starts here.  The
- * controller handles SMBUS itself, presenting a relatively simple register
- * interface; all we have to do is to tell it where to route the data.
- */
-#define CAFE_SMBUS_TIMEOUT (HZ)  /* generous */
-
-static int cafe_smbus_write_done(struct cafe_camera *cam)
-{
-	unsigned long flags;
-	int c1;
-
-	/*
-	 * We must delay after the interrupt, or the controller gets confused
-	 * and never does give us good status.  Fortunately, we don't do this
-	 * often.
-	 */
-	udelay(20);
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	c1 = cafe_reg_read(cam, REG_TWSIC1);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
-}
-
-static int cafe_smbus_write_data(struct cafe_camera *cam,
-		u16 addr, u8 command, u8 value)
-{
-	unsigned int rval;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
-	rval |= TWSIC0_OVMAGIC;  /* Make OV sensors work */
-	/*
-	 * Marvell sez set clkdiv to all 1's for now.
-	 */
-	rval |= TWSIC0_CLKDIV;
-	cafe_reg_write(cam, REG_TWSIC0, rval);
-	(void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
-	rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
-	cafe_reg_write(cam, REG_TWSIC1, rval);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	msleep(2); /* Required or things flake */
-
-	wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
-			CAFE_SMBUS_TIMEOUT);
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	rval = cafe_reg_read(cam, REG_TWSIC1);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	
-	if (rval & TWSIC1_WSTAT) {
-		cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
-				command, value);
-		return -EIO;
-	}
-	if (rval & TWSIC1_ERROR) {
-		cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
-				command, value);
-		return -EIO;
-	}
-	return 0;
-}
-
-
-
-static int cafe_smbus_read_done(struct cafe_camera *cam)
-{
-	unsigned long flags;
-	int c1;
-
-	/*
-	 * We must delay after the interrupt, or the controller gets confused
-	 * and never does give us good status.  Fortunately, we don't do this
-	 * often.
-	 */
-	udelay(20);
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	c1 = cafe_reg_read(cam, REG_TWSIC1);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
-}
-
-
-
-static int cafe_smbus_read_data(struct cafe_camera *cam,
-		u16 addr, u8 command, u8 *value)
-{
-	unsigned int rval;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
-	rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
-	/*
-	 * Marvel sez set clkdiv to all 1's for now.
-	 */
-	rval |= TWSIC0_CLKDIV;
-	cafe_reg_write(cam, REG_TWSIC0, rval);
-	(void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
-	rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
-	cafe_reg_write(cam, REG_TWSIC1, rval);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-	wait_event_timeout(cam->smbus_wait,
-			cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT);
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	rval = cafe_reg_read(cam, REG_TWSIC1);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	
-	if (rval & TWSIC1_ERROR) {
-		cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
-		return -EIO;
-	}
-	if (! (rval & TWSIC1_RVALID)) {
-		cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
-				command);
-		return -EIO;
-	}
-	*value = rval & 0xff;
-	return 0;
-}
-
-/*
- * Perform a transfer over SMBUS.  This thing is called under
- * the i2c bus lock, so we shouldn't race with ourselves...
- */
-static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
-		unsigned short flags, char rw, u8 command,
-		int size, union i2c_smbus_data *data)
-{
-	struct cafe_camera *cam = i2c_get_adapdata(adapter);
-	int ret = -EINVAL;
-	
-	/*
-	 * Refuse to talk to anything but OV cam chips.  We should
-	 * never even see an attempt to do so, but one never knows.
-	 */
-#if 0  /* client needs to talk during attach process */
-	if (! cam->sensor) {
-		cam_err(cam, "SMBUS xfer with no client\n");
-		return -EINVAL;
-	}
-#endif
-	if (cam->sensor && addr != cam->sensor->addr) {
-		cam_err(cam, "funky smbus addr %d\n", addr);
-		return -EINVAL;
-	}
-	/*
-	 * This interface would appear to only do byte data ops.  OK
-	 * it can do word too, but the cam chip has no use for that.
-	 */
-	if (size != I2C_SMBUS_BYTE_DATA) {
-		cam_err(cam, "funky xfer size %d\n", size);
-		return -EINVAL;
-	}
-
-	if (rw == I2C_SMBUS_WRITE)
-		ret = cafe_smbus_write_data(cam, addr, command, data->byte);
-	else if (rw == I2C_SMBUS_READ)
-		ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
-	return ret;
-}
-
-
-static void cafe_smbus_enable_irq(struct cafe_camera *cam)
-{
-	unsigned long flags;
-	
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-static u32 cafe_smbus_func(struct i2c_adapter *adapter)
-{
-	return I2C_FUNC_SMBUS_READ_BYTE_DATA  |
-	       I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-static struct i2c_algorithm cafe_smbus_algo = {
-	.smbus_xfer = cafe_smbus_xfer,
-	.functionality = cafe_smbus_func
-};
-
-/* Somebody is on the bus */
-static int cafe_cam_init(struct cafe_camera *cam);
-
-static int cafe_smbus_attach(struct i2c_client *client)
-{
-	struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
-
-	/*
-	 * Don't talk to chips we don't recognize.
-	 */
-	cam_err(cam, "smbus_attach id = %d\n", client->driver->id);
-	if (client->driver->id == I2C_DRIVERID_OV7670) {
-		cam->sensor = client;
-		return cafe_cam_init(cam);
-	}
-	return -EINVAL;
-}
-
-static int cafe_smbus_detach(struct i2c_client *client)
-{
-	struct cafe_camera *cam = i2c_get_adapdata(client->adapter);
-
-	if (cam->sensor == client)
-		cam->sensor = NULL;  /* Bummer, no camera */
-	return 0;
-}
-
-static int cafe_smbus_setup(struct cafe_camera *cam)
-{
-	struct i2c_adapter *adap = &cam->i2c_adapter;
-	int ret;
-
-	cafe_smbus_enable_irq(cam);
-	adap->id = I2C_HW_SMBUS_CAFE;
-	adap->class = I2C_CLASS_CAM_DIGITAL;
-	adap->owner = THIS_MODULE;
-	adap->client_register = cafe_smbus_attach;
-	adap->client_unregister = cafe_smbus_detach;
-	adap->algo = &cafe_smbus_algo;
-	strcpy(adap->name, "cafe_ccic");
-	i2c_set_adapdata(adap, cam);
-	ret = i2c_add_adapter(adap);
-	if (ret)
-		printk(KERN_ERR "Unable to register cafe i2c adapter\n");
-	return ret;
-}
-
-static void cafe_smbus_shutdown(struct cafe_camera *cam)
-{
-	i2c_del_adapter(&cam->i2c_adapter);
-}
-
-
-/* ------------------------------------------------------------------- */
-/*
- * Deal with the controller.
- */
-
-/*
- * Do everything we think we need to have the interface operating
- * according to the desired format.
- */
-static void cafe_ctlr_dma(struct cafe_camera *cam)
-{
-	/*
-	 * Store the first two Y buffers (we aren't supporting
-	 * planar formats for now, so no UV bufs).  Then either
-	 * set the third if it exists, or tell the controller
-	 * to just use two.
-	 */
-	cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]);
-	cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]);
-	if (cam->nbufs > 2) {
-		cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]);
-		cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
-	}
-	else
-		cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
-	cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */
-}
-			
-static void cafe_ctlr_image(struct cafe_camera *cam)
-{
-	int imgsz;
-	struct v4l2_pix_format *fmt = &cam->pix_format;
-
-	imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
-		(fmt->bytesperline & IMGSZ_H_MASK);
-	cafe_reg_write(cam, REG_IMGSIZE, imgsz);
-	cafe_reg_write(cam, REG_IMGOFFSET, 0);
-	/* YPITCH just drops the last two bits */
-	cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
-			IMGP_YP_MASK);
-	/*
-	 * Tell the controller about the image format we are using.
-	 */
-	switch (cam->pix_format.pixelformat) {
-    	case V4L2_PIX_FMT_YUYV:
-	    cafe_reg_write_mask(cam, REG_CTRL0,
-			    C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
-			    C0_DF_MASK);
-	    break;
-
-    	/*
-	 * For "fake rgb32" get the image pitch right.
-	 */
-	case V4L2_PIX_FMT_RGB32:
-	    cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline/2,
-			    IMGP_YP_MASK);
-	    imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
-		    ((fmt->bytesperline/2) & IMGSZ_H_MASK);
-	    cafe_reg_write(cam, REG_IMGSIZE, imgsz);
-    	    /* fall into ... */
-	case V4L2_PIX_FMT_RGB444:
-	    cafe_reg_write_mask(cam, REG_CTRL0,
-			    C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
-			    C0_DF_MASK);
-    		/* Alpha value? */
-	    break;
-
-	case V4L2_PIX_FMT_RGB565:
-	    cafe_reg_write_mask(cam, REG_CTRL0,
-			    C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
-			    C0_DF_MASK);
-	    break;
-
-	default:
-	    cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
-	    break;
-	}
-	/*
-	 * Make sure it knows we want to use hsync/vsync.
-	 */
-	cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
-			C0_SIFM_MASK);
-}
-
-
-/*
- * Configure the controller for operation; caller holds the
- * device mutex.
- */
-static int cafe_ctlr_configure(struct cafe_camera *cam)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	cafe_ctlr_dma(cam);
-	cafe_ctlr_image(cam);
-	cafe_set_config_needed(cam, 0);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	return 0;
-}
-
-static void cafe_ctlr_irq_enable(struct cafe_camera *cam)
-{
-	/*
-	 * Clear any pending interrupts, since we do not
-	 * expect to have I/O active prior to enabling.
-	 */
-	cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS);
-	cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);
-}
-
-static void cafe_ctlr_irq_disable(struct cafe_camera *cam)
-{
-	cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
-}
-
-/*
- * Make the controller start grabbing images.  Everything must
- * be set up before doing this.
- */
-static void cafe_ctlr_start(struct cafe_camera *cam)
-{
-	/* set_bit performs a read, so no other barrier should be
-	   needed here */
-	cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
-}
-
-static void cafe_ctlr_stop(struct cafe_camera *cam)
-{
-	cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
-}
-
-static void cafe_ctlr_init(struct cafe_camera *cam)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	/*
-	 * Added magic to bring up the hardware on the B-Test board
-	 */
-	cafe_reg_write(cam, 0x3038, 0x8);
-	cafe_reg_write(cam, 0x315c, 0x80008);
-	/*
-	 * Go through the dance needed to wake the device up.
-	 * Note that these registers are global and shared
-	 * with the NAND and SD devices.  Interaction between the
-	 * three still needs to be examined.
-	 */
-	cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
-	cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
-	cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
-	mdelay(5);	/* FIXME revisit this */
-	cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
-	cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN);
-	/*
-	 * Make sure it's not powered down. 
-	 */
-	cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
-	/*
-	 * Turn off the enable bit.  It sure should be off anyway,
-	 * but it's good to be sure.
-	 */
-	cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
-	/*
-	 * Mask all interrupts.
-	 */
-	cafe_reg_write(cam, REG_IRQMASK, 0);
-	/*
-	 * Clock the sensor appropriately.  Controller clock should
-	 * be 48MHz, sensor "typical" value is half that.
-	 */
-	cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-
-/*
- * Stop the controller, and don't return until we're really sure that no
- * further DMA is going on.
- */
-static void cafe_ctlr_stop_dma(struct cafe_camera *cam)
-{
-	unsigned long flags;
-
-	/*
-	 * Theory: stop the camera controller (whether it is operating
-	 * or not).  Delay briefly just in case we race with the SOF
-	 * interrupt, then wait until no DMA is active.
-	 */
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	cafe_ctlr_stop(cam);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	mdelay(1);
-	wait_event_timeout(cam->iowait,
-			!test_bit(CF_DMA_ACTIVE, &cam->flags), HZ);
-	if (test_bit(CF_DMA_ACTIVE, &cam->flags)) 
-		cam_err(cam, "Timeout waiting for DMA to end\n");
-		/* This would be bad news - what now? */
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	cam->state = S_IDLE;
-	cafe_ctlr_irq_disable(cam);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-/*
- * Power up and down.
- */
-static void cafe_ctlr_power_up(struct cafe_camera *cam)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
-	/*
-	 * Put the sensor into operational mode (assumes OLPC-style
-	 * wiring).  Control 0 is reset - set to 1 to operate.
-	 * Control 1 is power down, set to 0 to operate.
-	 */
-	cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
-	mdelay(1); /* Marvell says 1ms will do it */
-	cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
-	mdelay(1); /* Enough? */
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-static void cafe_ctlr_power_down(struct cafe_camera *cam)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
-	cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-}	
-
-/* -------------------------------------------------------------------- */
-/*
- * Communications with the sensor.
- */
-
-static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg)
-{
-	struct i2c_client *sc = cam->sensor;
-	int ret;
-
-	if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL)
-		return -EINVAL;
-	ret = sc->driver->command(sc, cmd, arg);
-	if (ret == -EPERM) /* Unsupported command */
-		return 0;
-	return ret;
-}
-
-static int __cafe_cam_reset(struct cafe_camera *cam)
-{
-	int zero = 0;
-	return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero);
-}
-
-/*
- * We have found the sensor on the i2c.  Let's try to have a
- * conversation.
- */
-static int cafe_cam_init(struct cafe_camera *cam)
-{
-	int ret;
-
-	mutex_lock(&cam->s_mutex);
-	if (cam->state != S_NOTREADY)
-		cam_warn(cam, "Cam init with device in funky state %d",
-				cam->state);
-	ret = __cafe_cam_reset(cam);
-	if (ret)
-		goto out;
-	ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type);
-	if (ret)
-		goto out;
-//	if (cam->sensor->addr != OV7xx0_SID) {
-	if (cam->sensor_type != V4L2_IDENT_OV7670) {
-		cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr);
-		ret = -EINVAL;
-		goto out;
-	}
-/* Get/set parameters? */
-	ret = 0;
-	cam->state = S_IDLE;
-  out:
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-/*
- * Configure the sensor to match the parameters we have.  Caller should
- * hold s_mutex
- */
-static int cafe_cam_set_flip(struct cafe_camera *cam)
-{
-	struct v4l2_control ctrl;
-
-	memset(&ctrl, 0, sizeof(ctrl));
-	ctrl.id = V4L2_CID_VFLIP;
-	ctrl.value = flip;
-	return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl);
-}
-
-
-static int cafe_cam_configure(struct cafe_camera *cam)
-{
-	struct v4l2_format fmt;
-	int ret, zero = 0;
-	
-	if (cam->state != S_IDLE)
-		return -EINVAL;
-	fmt.fmt.pix = cam->pix_format;
-	ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero);
-	if (ret == 0) 
-		ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt);
-	/*
-	 * OV7670 does weird things if flip is set *before* format...
-	 */
-	ret += cafe_cam_set_flip(cam);
-	return ret;
-}
-
-/* -------------------------------------------------------------------- */
-/*
- * DMA buffer management.  These functions need s_mutex held.
- */
-
-/* FIXME: this is inefficient as hell, since dma_alloc_coherent just
- * does a get_free_pages() call, and we waste a good chunk of an orderN
- * allocation.  Should try to allocate the whole set in one chunk.
- */
-static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime)
-{
-	int i;
-
-	cafe_set_config_needed(cam, 1);
-	if (loadtime) 
-		cam->dma_buf_size = dma_buf_size;
-	else {
-		cam->dma_buf_size = cam->pix_format.sizeimage;
-		if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32)
-			cam->dma_buf_size /= 2;
-	}
-	if (n_dma_bufs > 3)
-		n_dma_bufs = 3;
-
-	cam->nbufs = 0;
-	for (i = 0; i < n_dma_bufs; i++) {
-		cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev,
-				cam->dma_buf_size, cam->dma_handles + i,
-				GFP_KERNEL);
-		if (cam->dma_bufs[i] == NULL) {
-			cam_warn(cam, "Failed to allocate DMA buffer\n");
-			break;
-		}
-		/* For debug, remove eventually */
-		memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size);
-		(cam->nbufs)++;
-	}
-
-	switch (cam->nbufs) {
-	case 1:
-	    dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
-			    cam->dma_bufs[0], cam->dma_handles[0]);
-	    cam->nbufs = 0;
-	case 0:
-	    cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
-	    return -ENOMEM;
-
-	case 2:
-	    if (n_dma_bufs > 2)
-		    cam_warn(cam, "Will limp along with only 2 buffers\n");
-	    break;
-	}
-	return 0;
-}
-		
-static void cafe_free_dma_bufs(struct cafe_camera *cam)
-{
-	int i;
-
-	for (i = 0; i < cam->nbufs; i++) {
-		dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
-				cam->dma_bufs[i], cam->dma_handles[i]);
-		cam->dma_bufs[i] = NULL;
-	}
-	cam->nbufs = 0;
-}
-
-
-
-
-
-/* ----------------------------------------------------------------------- */
-/*
- * Here starts the V4L2 interface code.
- */
-
-/*
- * Read an image from the device. 
- */
-static ssize_t cafe_deliver_buffer(struct cafe_camera *cam,
-		char __user *buffer, size_t len, loff_t *pos)
-{
-	int bufno;
-	unsigned long flags;
-
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	if (cam->next_buf < 0) {
-		cam_err(cam, "deliver_buffer: No next buffer\n");
-		spin_unlock_irqrestore(&cam->dev_lock, flags);
-		return -EIO;
-	}
-	bufno = cam->next_buf;
-	clear_bit(bufno, &cam->flags);
-	if (++(cam->next_buf) >= cam->nbufs)
-		cam->next_buf = 0;
-	if (! test_bit(cam->next_buf, &cam->flags))
-		cam->next_buf = -1;
-	cam->specframes = 0;
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-	if (len > cam->pix_format.sizeimage)
-		len = cam->pix_format.sizeimage;
-	if (copy_to_user(buffer, cam->dma_bufs[bufno], len)) 
-		return -EFAULT;
-	(*pos) += len;
-	return len;
-}	
-
-/*
- * Get everything ready, and start grabbing frames.
- */
-static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state)
-{
-	int ret;
-	unsigned long flags;
-	
-	/*
-	 * Configuration.  If we still don't have DMA buffers,
-	 * make one last, desperate attempt.
-	 */
-	if (cam->nbufs == 0) 
-		if (cafe_alloc_dma_bufs(cam, 0))
-			return -ENOMEM;
-
-	if (cafe_needs_config(cam)) {
-		cafe_cam_configure(cam);
-		ret = cafe_ctlr_configure(cam);
-		if (ret)
-			return ret;
-	}
-
-	/*
-	 * Turn it loose.
-	 */
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	cafe_reset_buffers(cam);
-	cafe_ctlr_irq_enable(cam);
-	cam->state = state;
-	cafe_ctlr_start(cam);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	return 0;
-}
-
-
-static ssize_t cafe_v4l_read(struct file *filp,
-		char __user *buffer, size_t len, loff_t *pos)
-{
-	struct cafe_camera *cam = filp->private_data;
-	int ret;
-	
-	/*
-	 * Perhaps we're in speculative read mode and already
-	 * have data?
-	 */
-	mutex_lock(&cam->s_mutex);
-	if (cam->state == S_SPECREAD) {
-		if (cam->next_buf >= 0) {
-			ret = cafe_deliver_buffer(cam, buffer, len, pos);
-			if (ret != 0)
-				goto out_unlock;
-		}
-	} else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) {
-		ret = -EIO;
-		goto out_unlock;
-	} else if (cam->state != S_IDLE) {
-		ret = -EBUSY;
-		goto out_unlock;
-	}
-
-	/*
-	 * v4l2: multiple processes can open the device, but only
-	 * one gets to grab data from it.
-	 */
-	if (cam->owner && cam->owner != filp) {
-		ret = -EBUSY;
-		goto out_unlock;
-	}
-	cam->owner = filp;
-
-	/*
-	 * Do setup if need be.
-	 */
-	if (cam->state != S_SPECREAD) {
-		ret = cafe_read_setup(cam, S_SINGLEREAD);
-		if (ret)
-			goto out_unlock;
-	}
-	/*
-	 * Wait for something to happen.  This should probably
-	 * be interruptible (FIXME).
-	 */
-	wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ);
-	if (cam->next_buf < 0) {
-		cam_err(cam, "read() operation timed out\n");
-		cafe_ctlr_stop_dma(cam);
-		ret = -EIO;
-		goto out_unlock;
-	}
-	/*
-	 * Give them their data and we should be done.
-	 */
-	ret = cafe_deliver_buffer(cam, buffer, len, pos);
-
-  out_unlock:
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-
-
-
-
-
-
-
-/*
- * Streaming I/O support.
- */
-
-
-
-static int cafe_vidioc_streamon(struct file *filp, void *priv,
-		enum v4l2_buf_type type)
-{
-	struct cafe_camera *cam = filp->private_data;
-	int ret = -EINVAL;
-
-	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		goto out;
-	mutex_lock(&cam->s_mutex);
-	if (cam->state != S_IDLE || cam->n_sbufs == 0)
-		goto out_unlock;
-
-	cam->sequence = 0;
-	ret = cafe_read_setup(cam, S_STREAMING);
-
-  out_unlock:
-	mutex_unlock(&cam->s_mutex);
-  out:
-	return ret;
-}
-
-
-static int cafe_vidioc_streamoff(struct file *filp, void *priv,
-		enum v4l2_buf_type type)
-{
-	struct cafe_camera *cam = filp->private_data;
-	int ret = -EINVAL;
-
-	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		goto out;
-	mutex_lock(&cam->s_mutex);
-	if (cam->state != S_STREAMING)
-		goto out_unlock;
-
-	cafe_ctlr_stop_dma(cam);
-	ret = 0;
-
-  out_unlock:
-	mutex_unlock(&cam->s_mutex);
-  out:
-	return ret;
-}
-
-
-
-static int cafe_setup_siobuf(struct cafe_camera *cam, int index)
-{
-	struct cafe_sio_buffer *buf = cam->sb_bufs + index;
-	
-	INIT_LIST_HEAD(&buf->list);
-	buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage);
-	buf->buffer = vmalloc_user(buf->v4lbuf.length);
-	if (buf->buffer == NULL)
-		return -ENOMEM;
-	buf->mapcount = 0;
-	buf->cam = cam;
-
-	buf->v4lbuf.index = index;
-	buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	buf->v4lbuf.field = V4L2_FIELD_NONE;
-	buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
-	/*
-	 * Offset: must be 32-bit even on a 64-bit system.  video-buf
-	 * just uses the length times the index, but the spec warns
-	 * against doing just that - vma merging problems.  So we
-	 * leave a gap between each pair of buffers.
-	 */
-	buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
-	return 0;
-}
-
-static int cafe_free_sio_buffers(struct cafe_camera *cam)
-{
-	int i;
-
-	/*
-	 * If any buffers are mapped, we cannot free them at all.
-	 */
-	for (i = 0; i < cam->n_sbufs; i++)
-		if (cam->sb_bufs[i].mapcount > 0)
-			return -EBUSY;
-	/*
-	 * OK, let's do it.
-	 */
-	for (i = 0; i < cam->n_sbufs; i++)
-		vfree(cam->sb_bufs[i].buffer);
-	cam->n_sbufs = 0;
-	kfree(cam->sb_bufs);
-	cam->sb_bufs = NULL;
-	INIT_LIST_HEAD(&cam->sb_avail);
-	INIT_LIST_HEAD(&cam->sb_full);
-	return 0;
-}
-
-
-
-static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
-		struct v4l2_requestbuffers *req)
-{
-	struct cafe_camera *cam = filp->private_data;
-	int ret;
-
-	/*
-	 * Make sure it's something we can do.  User pointers could be
-	 * implemented without great pain, but that's not been done yet.
-	 */
-	if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	if (req->memory != V4L2_MEMORY_MMAP)
-		return -EINVAL;
-	/*
-	 * If they ask for zero buffers, they really want us to stop streaming
-	 * (if it's happening) and free everything.  Should we check owner?
-	 */
-	mutex_lock(&cam->s_mutex);
-	if (req->count == 0) {
-		if (cam->state == S_STREAMING)
-			cafe_ctlr_stop_dma(cam);
-		ret = cafe_free_sio_buffers (cam);
-		goto out;
-	}
-	/*
-	 * Device needs to be idle and working.  We *could* try to do the
-	 * right thing in S_SPECREAD by shutting things down, but it
-	 * probably doesn't matter.
-	 */
-	if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) {
-		ret = -EBUSY;
-		goto out;
-	}
-	cam->owner = filp;
-
-	if (req->count < min_buffers)
-		req->count = min_buffers;
-	else if (req->count > max_buffers)
-		req->count = max_buffers;
-	if (cam->n_sbufs > 0) {
-		ret = cafe_free_sio_buffers(cam);
-		if (ret)
-			goto out;
-	}
-
-	cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer),
-			GFP_KERNEL);
-	if (cam->sb_bufs == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) {
-		ret = cafe_setup_siobuf(cam, cam->n_sbufs);
-		if (ret)
-			break;
-	}
-
-	if (cam->n_sbufs == 0)  /* no luck at all - ret already set */
-		kfree(cam->sb_bufs);
-	else
-		ret = 0;
-	req->count = cam->n_sbufs;  /* In case of partial success */
-
-  out:
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-
-static int cafe_vidioc_querybuf(struct file *filp, void *priv,
-		struct v4l2_buffer *buf)
-{
-	struct cafe_camera *cam = filp->private_data;
-	int ret = -EINVAL;
-
-	mutex_lock(&cam->s_mutex);
-	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		goto out;
-	if (buf->index < 0 || buf->index >= cam->n_sbufs)
-		goto out;
-	*buf = cam->sb_bufs[buf->index].v4lbuf;
-	ret = 0;
-  out:
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-static int cafe_vidioc_qbuf(struct file *filp, void *priv,
-		struct v4l2_buffer *buf)
-{
-	struct cafe_camera *cam = filp->private_data;
-	struct cafe_sio_buffer *sbuf;
-	int ret = -EINVAL;
-	unsigned long flags;
-
-	mutex_lock(&cam->s_mutex);
-	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		goto out;
-	if (buf->index < 0 || buf->index >= cam->n_sbufs)
-		goto out;
-	sbuf = cam->sb_bufs + buf->index;
-	if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {
-		ret = 0; /* Already queued?? */
-		goto out;
-	}
-	if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) {
-		/* Spec doesn't say anything, seems appropriate tho */
-		ret = -EBUSY;
-		goto out;
-	}
-	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	list_add(&sbuf->list, &cam->sb_avail);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	ret = 0;
-  out:
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-static int cafe_vidioc_dqbuf(struct file *filp, void *priv,
-		struct v4l2_buffer *buf)
-{
-	struct cafe_camera *cam = filp->private_data;
-	struct cafe_sio_buffer *sbuf;
-	int ret = -EINVAL;
-	unsigned long flags;
-
-	mutex_lock(&cam->s_mutex);
-	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		goto out_unlock;
-	if (cam->state != S_STREAMING)
-		goto out_unlock;
-	if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) {
-		ret = -EAGAIN;
-		goto out_unlock;
-	}
-
-	while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) {
-		mutex_unlock(&cam->s_mutex);
-		if (wait_event_interruptible(cam->iowait,
-						!list_empty(&cam->sb_full))) {
-			ret = -ERESTARTSYS;
-			goto out;
-		}
-		mutex_lock(&cam->s_mutex);
-	}
-
-	if (cam->state != S_STREAMING)
-		ret = -EINTR;
-	else {
-		spin_lock_irqsave(&cam->dev_lock, flags);
-		/* Should probably recheck !list_empty() here */
-		sbuf = list_entry(cam->sb_full.next,
-				struct cafe_sio_buffer, list);
-		list_del_init(&sbuf->list);
-		spin_unlock_irqrestore(&cam->dev_lock, flags);
-		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
-		*buf = sbuf->v4lbuf;
-		ret = 0;
-	}
-
-  out_unlock:
-	mutex_unlock(&cam->s_mutex);
-  out:
-	return ret;
-}
-
-
-
-static void cafe_v4l_vm_open(struct vm_area_struct *vma)
-{
-	struct cafe_sio_buffer *sbuf = vma->vm_private_data;
-	/*
-	 * Locking: done under mmap_sem, so we don't need to
-	 * go back to the camera lock here.
-	 */
-	sbuf->mapcount++;
-}
-
-
-static void cafe_v4l_vm_close(struct vm_area_struct *vma)
-{
-	struct cafe_sio_buffer *sbuf = vma->vm_private_data;
-
-	mutex_lock(&sbuf->cam->s_mutex);
-	sbuf->mapcount--;
-	/* Docs say we should stop I/O too... */
-	if (sbuf->mapcount == 0)
-		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
-	mutex_unlock(&sbuf->cam->s_mutex);
-}
-
-static struct vm_operations_struct cafe_v4l_vm_ops = {
-	.open = cafe_v4l_vm_open,
-	.close = cafe_v4l_vm_close
-};
-
-
-static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
-{
-	struct cafe_camera *cam = filp->private_data;
-	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	int ret = -EINVAL;
-	int i;
-	struct cafe_sio_buffer *sbuf = NULL;
-
-	if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
-		return -EINVAL;
-	/*
-	 * Find the buffer they are looking for.
-	 */
-	mutex_lock(&cam->s_mutex);
-	for (i = 0; i < cam->n_sbufs; i++)
-		if (cam->sb_bufs[i].v4lbuf.m.offset == offset) {
-			sbuf = cam->sb_bufs + i;
-			break;
-		}
-	if (sbuf == NULL)
-		goto out;
-
-	ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
-	if (ret)
-		goto out;
-	vma->vm_flags |= VM_DONTEXPAND;
-	vma->vm_private_data = sbuf;
-	vma->vm_ops = &cafe_v4l_vm_ops;
-	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
-	cafe_v4l_vm_open(vma);
-	ret = 0;
-  out:
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-	
-
-
-static int cafe_v4l_open(struct inode *inode, struct file *filp)
-{
-	struct cafe_camera *cam;
-
-	cam = cafe_find_dev(iminor(inode));
-	if (cam == NULL)
-		return -ENODEV;
-	filp->private_data = cam;
-
-	mutex_lock(&cam->s_mutex);
-	if (cam->users == 0) {
-		cafe_ctlr_power_up(cam);
-		__cafe_cam_reset(cam);
-		cafe_set_config_needed(cam, 1);
-	/* FIXME make sure this is complete */
-	}
-	(cam->users)++;
-	mutex_unlock(&cam->s_mutex);
-	return 0;
-}
-
-
-static int cafe_v4l_release(struct inode *inode, struct file *filp)
-{
-	struct cafe_camera *cam = filp->private_data;
-	
-	mutex_lock(&cam->s_mutex);
-	(cam->users)--;
-	if (filp == cam->owner) {
-		cafe_ctlr_stop_dma(cam);
-		cafe_free_sio_buffers(cam);
-		cam->owner = NULL;
-	}
-	if (cam->users == 0)
-		cafe_ctlr_power_down(cam);
-	mutex_unlock(&cam->s_mutex);
-	return 0;
-}
-
-
-
-static unsigned int cafe_v4l_poll(struct file *filp,
-		struct poll_table_struct *pt)
-{
-	struct cafe_camera *cam = filp->private_data;
-
-	poll_wait(filp, &cam->iowait, pt);
-	if (cam->next_buf >= 0)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-
-
-static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
-		struct v4l2_queryctrl *qc)
-{
-	struct cafe_camera *cam = filp->private_data;
-	int ret;
-	
-	mutex_lock(&cam->s_mutex);
-	ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc);
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-
-static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
-		struct v4l2_control *ctrl)
-{
-	struct cafe_camera *cam = filp->private_data;
-	int ret;
-	
-	mutex_lock(&cam->s_mutex);
-	ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl);
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-
-static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,
-		struct v4l2_control *ctrl)
-{
-	struct cafe_camera *cam = filp->private_data;
-	int ret;
-	
-	mutex_lock(&cam->s_mutex);
-	ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl);
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-
-
-
-
-static int cafe_vidioc_querycap(struct file *file, void *priv,
-		struct v4l2_capability *cap)
-{
-	strcpy(cap->driver, "cafe_ccic");
-	strcpy(cap->card, "cafe_ccic");
-	cap->version = CAFE_VERSION;
-	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-		V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-	return 0;
-}
-
-
-/*
- * The default format we use until somebody says otherwise.
- */
-static struct v4l2_pix_format cafe_def_pix_format = {
-	.width		= VGA_WIDTH,
-	.height		= VGA_HEIGHT,
-	.pixelformat	= V4L2_PIX_FMT_YUYV,
-	.field		= V4L2_FIELD_NONE,
-	.bytesperline	= VGA_WIDTH*2,
-	.sizeimage	= VGA_WIDTH*VGA_HEIGHT*2,
-};
-
-static int cafe_vidioc_enum_fmt_cap(struct file *filp,
-		void *priv, struct v4l2_fmtdesc *fmt)
-{
-	struct cafe_camera *cam = priv;
-	int ret;
-
-	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		return -EINVAL;
-	mutex_lock(&cam->s_mutex);
-	ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt);
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-
-static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv,
-		struct v4l2_format *fmt)
-{
-	struct cafe_camera *cam = priv;
-	int ret;
-
-	mutex_lock(&cam->s_mutex);
-	ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt);
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv,
-		struct v4l2_format *fmt)
-{
-	struct cafe_camera *cam = priv;
-	int ret;
-
-	/*
-	 * Can't do anything if the device is not idle
-	 * Also can't if there are streaming buffers in place.
-	 */
-	if (cam->state != S_IDLE || cam->n_sbufs > 0)
-		return -EBUSY;
-	/*
-	 * See if the formatting works in principle.
-	 */
-	ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt);
-	if (ret)
-		return ret;
-	/*
-	 * Now we start to change things for real, so let's do it
-	 * under lock.
-	 */
-	mutex_lock(&cam->s_mutex);
-	cam->pix_format = fmt->fmt.pix;
-	/*
-	 * Make sure we have appropriate DMA buffers.
-	 */
-	ret = -ENOMEM;
-	if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
-		cafe_free_dma_bufs(cam);
-	if (cam->nbufs == 0) {
-		if (cafe_alloc_dma_bufs(cam, 0))
-			goto out;
-	}
-	/*
-	 * It looks like this might work, so let's program the sensor.
-	 */
-	ret = cafe_cam_configure(cam);
-	if (! ret)
-		ret = cafe_ctlr_configure(cam);
-  out:
-	mutex_unlock(&cam->s_mutex);
-	return ret;
-}
-
-/*
- * Return our stored notion of how the camera is/should be configured.
- * The V4l2 spec wants us to be smarter, and actually get this from
- * the camera (and not mess with it at open time).  Someday.
- */
-static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv,
-		struct v4l2_format *f)
-{
-	struct cafe_camera *cam = priv;
-	
-	f->fmt.pix = cam->pix_format;
-	return 0;
-}
-
-/*
- * We only have one input - the sensor - so minimize the nonsense here.
- */
-static int cafe_vidioc_enum_input(struct file *filp, void *priv,
-		struct v4l2_input *input)
-{
-	if (input->index != 0)
-		return -EINVAL;
-
-	input->type = V4L2_INPUT_TYPE_CAMERA;
-	input->std = V4L2_STD_ALL; /* Not sure what should go here */
-	strcpy(input->name, "Camera");
-	return 0;
-}
-
-static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-	*i = 0;
-	return 0;
-}
-
-static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-	if (i != 0)
-		return -EINVAL;
-	return 0;
-}
-
-/* from vivi.c */
-static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a)
-{
-	return 0;
-}
-
-
-/*
- * The TV Norm stuff is weird - we're a camera with little to do with TV,
- * really.  The following is what vivi does.
- */
-static struct v4l2_tvnorm cafe_tvnorm[] = {
-	{
-		.name      = "NTSC-M",
-		.id        = V4L2_STD_NTSC_M,
-	}
-};
-
-
-void cafe_v4l_dev_release(struct video_device *vd)
-{
-	struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
-
-	kfree(cam);
-}
-
-
-/*
- * This template device holds all of those v4l2 methods; we
- * clone it for specific real devices.
- */
-
-static struct file_operations cafe_v4l_fops = {
-	.owner = THIS_MODULE,
-	.open = cafe_v4l_open,
-	.release = cafe_v4l_release,
-	.read = cafe_v4l_read,
-	.poll = cafe_v4l_poll,
-	.mmap = cafe_v4l_mmap,
-	.ioctl = video_ioctl2,
-	.llseek = no_llseek,
-};
-
-static struct video_device cafe_v4l_template = {
-	.name = "cafe",
-	.type = VFL_TYPE_GRABBER,
-	.type2 = VID_TYPE_CAPTURE,
-	.minor = -1, /* Get one dynamically */
-	.tvnorms = cafe_tvnorm,
-	.tvnormsize = 1,
-	.current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
-
-	.fops = &cafe_v4l_fops,
-	.release = cafe_v4l_dev_release,
-
-	.vidioc_querycap 	= cafe_vidioc_querycap,
-	.vidioc_enum_fmt_cap	= cafe_vidioc_enum_fmt_cap,
-	.vidioc_try_fmt_cap	= cafe_vidioc_try_fmt_cap,
-	.vidioc_s_fmt_cap	= cafe_vidioc_s_fmt_cap,
-	.vidioc_g_fmt_cap	= cafe_vidioc_g_fmt_cap,
-	.vidioc_enum_input	= cafe_vidioc_enum_input,
-	.vidioc_g_input		= cafe_vidioc_g_input,
-	.vidioc_s_input		= cafe_vidioc_s_input,
-	.vidioc_s_std		= cafe_vidioc_s_std,
-	.vidioc_reqbufs		= cafe_vidioc_reqbufs,
-	.vidioc_querybuf	= cafe_vidioc_querybuf,
-	.vidioc_qbuf		= cafe_vidioc_qbuf,
-	.vidioc_dqbuf		= cafe_vidioc_dqbuf,
-	.vidioc_streamon	= cafe_vidioc_streamon,
-	.vidioc_streamoff	= cafe_vidioc_streamoff,
-	.vidioc_queryctrl	= cafe_vidioc_queryctrl,
-	.vidioc_g_ctrl		= cafe_vidioc_g_ctrl,
-	.vidioc_s_ctrl		= cafe_vidioc_s_ctrl,
-	/* Do cropping someday */
-};
-
-
-
-
-
-
-
-/* ---------------------------------------------------------------------- */
-/*
- * Interrupt handler stuff
- */
-
-/*
- * Create RGB32 from RGB444 so it can be displayed before the applications
- * know about the latter format.
- */
-static void cafe_fake_rgb32(struct cafe_camera *cam, char *dest, char *src)
-{
-	int i;
-	u16 *ssrc = (u16 *) src;
-
-	/* RGB444 version */
-	for (i = 0; i < cam->pix_format.sizeimage; i += 4) {
-	//		dest[0] = (*ssrc & 0xf000) >> 8;
-		dest[0] = (*ssrc & 0x000f) << 4;
-		dest[1] = (*ssrc & 0x00f0);
-		dest[2] = (*ssrc & 0x0f00) >> 4;
-		dest[3] = (*ssrc & 0xf000);   /* Alpha */
-		dest += 4;
-		ssrc++;
-	}
-#if 0
-	/* RGB565 version */
-	for (i = 0; i < cam->pix_format.sizeimage; i += 4) {
-		dest[0] = (*ssrc & 0xf800) >> 8;
-		dest[1] = (*ssrc & 0x07e0) >> 3;
-		dest[2] = (*ssrc & 0x001f) << 3;
-		dest[3] = 0;
-		dest += 4;
-		ssrc++;
-	}
-#endif
-}
-
-
-static void cafe_frame_tasklet(unsigned long data)
-{
-	struct cafe_camera *cam = (struct cafe_camera *) data;
-	int i;
-	unsigned long flags;
-	struct cafe_sio_buffer *sbuf;
-
-	spin_lock_irqsave(&cam->dev_lock, flags);
-	for (i = 0; i < cam->nbufs; i++) {
-		int bufno = cam->next_buf;
-		if (bufno < 0) {  /* "will never happen" */
-			cam_err(cam, "No valid bufs in tasklet!\n");
-			break;
-		}
-		if (++(cam->next_buf) >= cam->nbufs)
-			cam->next_buf = 0;
-		if (! test_bit(bufno, &cam->flags))
-			continue;
-		if (list_empty(&cam->sb_avail))
-			break;  /* Leave it valid, hope for better later */
-		clear_bit(bufno, &cam->flags);
-		/*
-		 * We could perhaps drop the spinlock during this
-		 * big copy.  Something to consider.
-		 */
-		sbuf = list_entry(cam->sb_avail.next,
-				struct cafe_sio_buffer, list);
-		if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32)
-			cafe_fake_rgb32(cam, sbuf->buffer, cam->dma_bufs[bufno]);
-		else
-			memcpy(sbuf->buffer, cam->dma_bufs[bufno],
-					cam->pix_format.sizeimage);
-		sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
-		sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
-		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
-		sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
-		list_move_tail(&sbuf->list, &cam->sb_full);
-	}
-	if (! list_empty(&cam->sb_full))
-		wake_up(&cam->iowait);
-	spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-
-
-static void cafe_frame_complete(struct cafe_camera *cam, int frame)
-{
-	/*
-	 * Basic frame housekeeping.
-	 */
-	if (test_bit(frame, &cam->flags) && printk_ratelimit())
-		cam_err(cam, "Frame overrun on %d, frames lost\n", frame);		
-	set_bit(frame, &cam->flags);
-	clear_bit(CF_DMA_ACTIVE, &cam->flags);
-	if (cam->next_buf < 0)
-		cam->next_buf = frame;
-	cam->buf_seq[frame] = ++(cam->sequence);
-
-	switch (cam->state) {
-	/*
-	 * If in single read mode, try going speculative.
-	 */
-	    case S_SINGLEREAD:
-		cam->state = S_SPECREAD;
-		cam->specframes = 0;
-		wake_up(&cam->iowait);
-		break;
-		
-	/*
-	 * If we are already doing speculative reads, and nobody is
-	 * reading them, just stop.
-	 */
-	    case S_SPECREAD:
-		if (++(cam->specframes) >= cam->nbufs) {
-			cafe_ctlr_stop(cam);
-			cafe_ctlr_irq_disable(cam);
-			cam->state = S_IDLE;
-		}
-		wake_up(&cam->iowait);
-		break;
-	/*
-	 * For the streaming case, we defer the real work to the
-	 * camera tasklet.
-	 *
-	 * FIXME: if the application is not consuming the buffers,
-	 * we should eventually put things on hold and restart in
-	 * vidioc_dqbuf().
-	 */
-	    case S_STREAMING:
-		tasklet_schedule(&cam->s_tasklet);
-		break;
-
-	    default:
-		cam_err(cam, "Frame interrupt in non-operational state\n");
-		break;
-	}
-}
-
-
-
-
-static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs)
-{
-	unsigned int frame;
-
-	cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */
-	/*
-	 * Handle any frame completions.  There really should
-	 * not be more than one of these, or we have fallen
-	 * far behind.
-	 */
-	for (frame = 0; frame < cam->nbufs; frame++)
-		if (irqs & (IRQ_EOF0 << frame))
-			cafe_frame_complete(cam, frame);
-	/*
-	 * If a frame starts, note that we have DMA active.  This
-	 * code assumes that we won't get multiple frame interrupts
-	 * at once; may want to rethink that.
-	 */
-	if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2))
-		set_bit(CF_DMA_ACTIVE, &cam->flags);
-}
-
-
-
-static irqreturn_t cafe_irq(int irq, void *data)
-{
-	struct cafe_camera *cam = data;
-	unsigned int irqs;
-
-	spin_lock(&cam->dev_lock);
-	irqs = cafe_reg_read(cam, REG_IRQSTAT);
-	if ((irqs & ALLIRQS) == 0) {
-		spin_unlock(&cam->dev_lock);
-		return IRQ_NONE;
-	}
-	if (irqs & FRAMEIRQS)
-		cafe_frame_irq(cam, irqs);
-	if (irqs & TWSIIRQS) {
-		cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS);
-		wake_up(&cam->smbus_wait);
-	}
-	spin_unlock(&cam->dev_lock);
-	return IRQ_HANDLED;
-}
-
-
-/* -------------------------------------------------------------------------- */
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-/*
- * Debugfs stuff.
- */
-
-static char cafe_debug_buf[1024];
-static struct dentry *cafe_dfs_root;
-
-static void cafe_dfs_setup(void)
-{
-	cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL);
-	if (IS_ERR(cafe_dfs_root)) {
-		cafe_dfs_root = NULL;  /* Never mind */
-		printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n");
-	}
-}
-
-static void cafe_dfs_shutdown(void)
-{
-	if (cafe_dfs_root)
-		debugfs_remove(cafe_dfs_root);
-}
-
-static int cafe_dfs_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static ssize_t cafe_dfs_read_regs(struct file *file,
-		char __user *buf, size_t count, loff_t *ppos)
-{
-	struct cafe_camera *cam = file->private_data;
-	char *s = cafe_debug_buf;
-	int offset;
-
-	for (offset = 0; offset < 0x44; offset += 4)
-		s += sprintf(s, "%02x: %08x\n", offset,
-				cafe_reg_read(cam, offset));
-	for (offset = 0x88; offset <= 0x90; offset += 4)
-		s += sprintf(s, "%02x: %08x\n", offset,
-				cafe_reg_read(cam, offset));
-	for (offset = 0xb4; offset <= 0xbc; offset += 4)
-		s += sprintf(s, "%02x: %08x\n", offset,
-				cafe_reg_read(cam, offset));
-	for (offset = 0x3000; offset <= 0x300c; offset += 4)
-		s += sprintf(s, "%04x: %08x\n", offset,
-				cafe_reg_read(cam, offset));
-	return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
-			s - cafe_debug_buf);
-}
-		
-static struct file_operations cafe_dfs_reg_ops = {
-	.owner = THIS_MODULE,
-	.read = cafe_dfs_read_regs,
-	.open = cafe_dfs_open
-};
-
-static ssize_t cafe_dfs_read_cam(struct file *file,
-		char __user *buf, size_t count, loff_t *ppos)
-{
-	struct cafe_camera *cam = file->private_data;
-	char *s = cafe_debug_buf;
-	int offset;
-
-	if (! cam->sensor)
-		return -EINVAL;
-	for (offset = 0x0; offset < 0x8a; offset++)
-	{
-		u8 v;
-
-		cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v);
-		s += sprintf(s, "%02x: %02x\n", offset, v);
-	}
-	return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf,
-			s - cafe_debug_buf);
-}
-
-static struct file_operations cafe_dfs_cam_ops = {
-	.owner = THIS_MODULE,
-	.read = cafe_dfs_read_cam,
-	.open = cafe_dfs_open
-};
-
-
-
-static void cafe_dfs_cam_setup(struct cafe_camera *cam)
-{
-	char fname[40];
-
-	if (!cafe_dfs_root)
-		return;
-	sprintf(fname, "regs-%d", cam->v4ldev.minor);
-	cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
-			cam, &cafe_dfs_reg_ops);
-	sprintf(fname, "cam-%d", cam->v4ldev.minor);
-	cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root,
-			cam, &cafe_dfs_cam_ops);
-}
-
-
-static void cafe_dfs_cam_shutdown(struct cafe_camera *cam)
-{
-	if (! IS_ERR(cam->dfs_regs))
-		debugfs_remove(cam->dfs_regs);
-	if (! IS_ERR(cam->dfs_cam_regs))
-		debugfs_remove(cam->dfs_cam_regs);
-}
-
-#else
-
-#define cafe_dfs_setup()
-#define cafe_dfs_shutdown()
-#define cafe_dfs_cam_setup(cam)
-#define cafe_dfs_cam_shutdown(cam)
-#endif    /* CONFIG_VIDEO_ADV_DEBUG */
-
-
-
-
-/* ------------------------------------------------------------------------*/
-/*
- * PCI interface stuff.
- */
-
-static int cafe_pci_probe(struct pci_dev *pdev,
-		const struct pci_device_id *id)
-{
-	int ret;
-	u16 classword;
-	struct cafe_camera *cam;
-	/*
-	 * Make sure we have a camera here - we'll get calls for
-	 * the other cafe devices as well.
-	 */
-	pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword);
-	if (classword != PCI_CLASS_MULTIMEDIA_VIDEO)
-		return -ENODEV;
-	/*
-	 * Start putting together one of our big camera structures.
-	 */
-	ret = -ENOMEM;
-	cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
-	if (cam == NULL)
-		goto out;
-	mutex_init(&cam->s_mutex);
-	mutex_lock(&cam->s_mutex);
-	spin_lock_init(&cam->dev_lock);
-	cam->state = S_NOTREADY;
-	cafe_set_config_needed(cam, 1);
-	init_waitqueue_head(&cam->smbus_wait);
-	init_waitqueue_head(&cam->iowait);
-	cam->pdev = pdev;
-	cam->pix_format = cafe_def_pix_format;
-	INIT_LIST_HEAD(&cam->dev_list);
-	INIT_LIST_HEAD(&cam->sb_avail);
-	INIT_LIST_HEAD(&cam->sb_full);
-	tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam);
-	/*
-	 * Get set up on the PCI bus.
-	 */
-	ret = pci_enable_device(pdev);
-	if (ret)
-		goto out_free;
-	pci_set_master(pdev);
-
-	ret = -EIO;
-	cam->regs = pci_iomap(pdev, 0, 0);
-	if (! cam->regs) {
-		printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
-		goto out_free;
-	}
-	ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
-	if (ret)
-		goto out_iounmap;
-	cafe_ctlr_init(cam);
-	cafe_ctlr_power_up(cam);
-	/*
-	 * Set up I2C/SMBUS communications
-	 */
-	mutex_unlock(&cam->s_mutex);  /* attach can deadlock */
-	ret = cafe_smbus_setup(cam);
-	if (ret)
-		goto out_freeirq;
-	/*
-	 * Get the v4l2 setup done.
-	 */
-	mutex_lock(&cam->s_mutex);
-	cam->v4ldev = cafe_v4l_template;
-	cam->v4ldev.debug = 0;
-//	cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG;
-	ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1);
-	if (ret)
-		goto out_smbus;
-	/*
-	 * If so requested, try to get our DMA buffers now.
-	 */
-	if (alloc_bufs_at_load) {
-		if (cafe_alloc_dma_bufs(cam, 1))
-			cam_warn(cam, "Unable to alloc DMA buffers at load"
-					" will try again later.");
-	}
-
-	cafe_dfs_cam_setup(cam);
-	mutex_unlock(&cam->s_mutex);
-	cafe_add_dev(cam);
-	return 0;
-
-  out_smbus:
-	cafe_smbus_shutdown(cam);
-  out_freeirq:
-	cafe_ctlr_power_down(cam);
-	free_irq(pdev->irq, cam);
-  out_iounmap:
-	pci_iounmap(pdev, cam->regs);
-  out_free:
-	kfree(cam);
-  out:
-	return ret;
-}
-
-
-/*
- * Shut down an initialized device
- */
-static void cafe_shutdown(struct cafe_camera *cam)
-{
-/* FIXME: Make sure we take care of everything here */
-	cafe_dfs_cam_shutdown(cam);
-	if (cam->n_sbufs > 0)
-		/* What if they are still mapped?  Shouldn't be, but... */
-		cafe_free_sio_buffers(cam);
-	cafe_remove_dev(cam);
-	cafe_ctlr_stop_dma(cam);
-	cafe_ctlr_power_down(cam);
-	cafe_smbus_shutdown(cam);
-	cafe_free_dma_bufs(cam);
-	free_irq(cam->pdev->irq, cam);
-	pci_iounmap(cam->pdev, cam->regs);
-	video_unregister_device(&cam->v4ldev);
-	/* kfree(cam); done in v4l_release () */
-}
-		
-
-static void cafe_pci_remove(struct pci_dev *pdev)
-{
-	struct cafe_camera *cam = cafe_find_by_pdev(pdev);
-
-	if (cam == NULL) {
-		cam_warn(cam, "pci_remove on unknown pdev %p\n", pdev);
-		return;
-	}
-	mutex_lock(&cam->s_mutex);
-	if (cam->users > 0)
-		cam_warn(cam, "Removing a device with users!\n");
-	cafe_shutdown(cam);
-/* No unlock - it no longer exists */
-}
-
-
-
-
-static struct pci_device_id cafe_ids[] = {
-	{ PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */
-	{ PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */
-	{ PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, cafe_ids);
-
-static struct pci_driver cafe_pci_driver = {
-	.name = "cafe1000-ccic",
-	.id_table = cafe_ids,
-	.probe = cafe_pci_probe,
-	.remove = cafe_pci_remove,
-};
-
-
-
-
-static int __init cafe_init(void)
-{
-	int ret;
-
-	printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
-			CAFE_VERSION);
-	cafe_dfs_setup();
-	ret = pci_register_driver(&cafe_pci_driver);
-	if (ret) {
-		printk(KERN_ERR "Unable to register cafe_ccic driver\n");
-		goto out;
-	}
-	request_module("ov7670");  /* FIXME want something more general */
-	ret = 0;
-
-  out:
-	return ret;
-}
-
-
-static void __exit cafe_exit(void)
-{
-	pci_unregister_driver(&cafe_pci_driver);
-	cafe_dfs_shutdown();
-}
-
-module_init(cafe_init);
-module_exit(cafe_exit);


More information about the Commits-kernel mailing list