diff -r c300798213a9 linux/drivers/media/video/zr364xx.c
--- a/linux/drivers/media/video/zr364xx.c	Sun Jul 05 19:08:55 2009 -0300
+++ b/linux/drivers/media/video/zr364xx.c	Wed Jul 15 20:50:34 2009 -0300
@@ -1,5 +1,5 @@
 /*
- * Zoran 364xx based USB webcam module version 0.72
+ * Zoran 364xx based USB webcam module version 0.73
  *
  * Allows you to use your USB webcam with V4L2 applications
  * This is still in heavy developpement !
@@ -10,6 +10,8 @@
  * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
  * V4L2 version inspired by meye.c driver
  *
+ * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -35,25 +37,34 @@
 #include <linux/highmem.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/videobuf-vmalloc.h>
 #include "compat.h"
 
 
 /* Version Information */
-#define DRIVER_VERSION "v0.72"
+#define DRIVER_VERSION "v0.73"
+#define ZR364_VERSION_CODE KERNEL_VERSION(0, 7, 3)
 #define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
 #define DRIVER_DESC "Zoran 364xx"
 
 
 /* Camera */
-#define FRAMES 2
+#define FRAMES 1
 #define MAX_FRAME_SIZE 100000
 #define BUFFER_SIZE 0x1000
 #define CTRL_TIMEOUT 500
 
+#define ZR364XX_DEF_BUFS	4
+#define ZR364XX_READ_IDLE	0
+#define ZR364XX_READ_FRAME	1
 
 /* Debug macro */
-#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
-
+#define DBG(fmt, args...) \
+	do { \
+		if (debug) { \
+			printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
+		} \
+	} while (0)
 
 /* Init methods, need to find nicer names for these
  * the exact names of the chipsets would be the best if someone finds it */
@@ -102,24 +113,93 @@
 
 MODULE_DEVICE_TABLE(usb, device_table);
 
+struct zr364xx_mode {
+	u32 color;	/* output video color format */
+	u32 brightness;	/* brightness */
+};
+
+/* frame structure */
+struct zr364xx_framei {
+	unsigned long ulState;	/* ulState:ZR364XX_READ_IDLE,
+					   ZR364XX_READ_FRAME */
+	void *lpvbits;		/* image data */
+	unsigned long cur_size;	/* current data copied to it */
+};
+
+/* image buffer structure */
+struct zr364xx_bufferi {
+	unsigned long dwFrames;			/* number of frames in buffer */
+	struct zr364xx_framei frame[FRAMES];	/* array of FRAME structures */
+};
+
+struct zr364xx_dmaqueue {
+	struct list_head	active;
+	struct zr364xx_camera	*cam;
+};
+
+struct zr364xx_pipeinfo {
+	u32 transfer_size;
+	u8 *transfer_buffer;
+	u32 state;
+	void *stream_urb;
+	void *cam;	/* back pointer to zr364xx_camera struct */
+	u32 err_count;
+	u32 idx;
+};
+
+struct zr364xx_fmt {
+	char *name;
+	u32 fourcc;
+	int depth;
+};
+
+/* image formats.  */
+static const struct zr364xx_fmt formats[] = {
+	{
+		.name = "JPG",
+		.fourcc = V4L2_PIX_FMT_JPEG,
+		.depth = 24
+	}
+};
 
 /* Camera stuff */
 struct zr364xx_camera {
 	struct usb_device *udev;	/* save off the usb device pointer */
 	struct usb_interface *interface;/* the interface for this device */
 	struct video_device *vdev;	/* v4l video device */
-	u8 *framebuf;
 	int nb;
-	unsigned char *buffer;
+	struct zr364xx_bufferi		buffer;
 	int skip;
-	int brightness;
 	int width;
 	int height;
 	int method;
 	struct mutex lock;
+	struct mutex open_lock;
 	int users;
+
+	spinlock_t		slock;
+	struct zr364xx_dmaqueue	vidq;
+	int			resources;
+	int			last_frame;
+	int			cur_frame;
+	unsigned long		frame_count;
+	int			b_acquire;
+	struct zr364xx_pipeinfo	pipe[1];
+
+	u8			read_endpoint;
+
+	const struct zr364xx_fmt *fmt;
+	struct videobuf_queue	vb_vidq;
+	enum v4l2_buf_type	type;
+	struct zr364xx_mode	mode;
 };
 
+/* buffer for one video frame */
+struct zr364xx_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+	const struct zr364xx_fmt *fmt;
+};
 
 /* function used to send initialisation commands to the camera */
 static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
@@ -273,139 +353,120 @@
 };
 static unsigned char header3;
 
+/* ------------------------------------------------------------------
+   Videobuf operations
+   ------------------------------------------------------------------*/
 
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+			unsigned int *size)
+{
+	struct zr364xx_camera *cam = vq->priv_data;
+
+	*size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+	if (*count == 0)
+		*count = ZR364XX_DEF_BUFS;
+
+	while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
+		(*count)--;
+
+	return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer 
*buf)
+{
+	DBG("%s\n", __func__);
+
+	/*Lamarque: is this really needed? Sometimes this blocks rmmod forever
+	 * after running Skype on an AMD64 system. */
+	/*videobuf_waiton(&buf->vb, 0, 0);*/
+
+	if (in_interrupt())
+		BUG();
+
+	videobuf_vmalloc_free(&buf->vb);
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer 
*vb,
+			  enum v4l2_field field)
+{
+	struct zr364xx_camera *cam = vq->priv_data;
+	struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+						  vb);
+	int rc;
+
+	DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ?
+	    cam->fmt->name : "");
+	if (cam->fmt == NULL)
+		return -EINVAL;
+
+	buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+	if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
+		DBG("invalid buffer prepare\n");
+		return -EINVAL;
+	}
+
+	buf->fmt = cam->fmt;
+	buf->vb.width = cam->width;
+	buf->vb.height = cam->height;
+	buf->vb.field = field;
+
+	if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc < 0)
+			goto fail;
+	}
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+fail:
+	free_buffer(vq, buf);
+	return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer 
*vb)
+{
+	struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+						  vb);
+	struct zr364xx_camera *cam = vq->priv_data;
+
+	DBG("%s\n", __func__);
+
+	buf->vb.state = VIDEOBUF_QUEUED;
+	list_add_tail(&buf->vb.queue, &cam->vidq.active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+			   struct videobuf_buffer *vb)
+{
+	struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+						  vb);
+
+	DBG("%s\n", __func__);
+	free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops zr364xx_video_qops = {
+	.buf_setup = buffer_setup,
+	.buf_prepare = buffer_prepare,
+	.buf_queue = buffer_queue,
+	.buf_release = buffer_release,
+};
 
 /********************/
 /* V4L2 integration */
 /********************/
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+				   enum v4l2_buf_type type);
 
-/* this function reads a full JPEG picture synchronously
- * TODO: do it asynchronously... */
-static int read_frame(struct zr364xx_camera *cam, int framenum)
-{
-	int i, n, temp, head, size, actual_length;
-	unsigned char *ptr = NULL, *jpeg;
-
-      redo:
-	/* hardware brightness */
-	n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
-	temp = (0x60 << 8) + 127 - cam->brightness;
-	n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-
-	/* during the first loop we are going to insert JPEG header */
-	head = 0;
-	/* this is the place in memory where we are going to build
-	 * the JPEG image */
-	jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
-	/* read data... */
-	do {
-		n = usb_bulk_msg(cam->udev,
-				 usb_rcvbulkpipe(cam->udev, 0x81),
-				 cam->buffer, BUFFER_SIZE, &actual_length,
-				 CTRL_TIMEOUT);
-		DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
-		DBG("bulk : n=%d size=%d", n, actual_length);
-		if (n < 0) {
-			dev_err(&cam->udev->dev, "error reading bulk msg\n");
-			return 0;
-		}
-		if (actual_length < 0 || actual_length > BUFFER_SIZE) {
-			dev_err(&cam->udev->dev, "wrong number of bytes\n");
-			return 0;
-		}
-
-		/* swap bytes if camera needs it */
-		if (cam->method == METHOD0) {
-			u16 *buf = (u16*)cam->buffer;
-			for (i = 0; i < BUFFER_SIZE/2; i++)
-				swab16s(buf + i);
-		}
-
-		/* write the JPEG header */
-		if (!head) {
-			DBG("jpeg header");
-			ptr = jpeg;
-			memcpy(ptr, header1, sizeof(header1));
-			ptr += sizeof(header1);
-			header3 = 0;
-			memcpy(ptr, &header3, 1);
-			ptr++;
-			memcpy(ptr, cam->buffer, 64);
-			ptr += 64;
-			header3 = 1;
-			memcpy(ptr, &header3, 1);
-			ptr++;
-			memcpy(ptr, cam->buffer + 64, 64);
-			ptr += 64;
-			memcpy(ptr, header2, sizeof(header2));
-			ptr += sizeof(header2);
-			memcpy(ptr, cam->buffer + 128,
-			       actual_length - 128);
-			ptr += actual_length - 128;
-			head = 1;
-			DBG("header : %d %d %d %d %d %d %d %d %d",
-			    cam->buffer[0], cam->buffer[1], cam->buffer[2],
-			    cam->buffer[3], cam->buffer[4], cam->buffer[5],
-			    cam->buffer[6], cam->buffer[7], cam->buffer[8]);
-		} else {
-			memcpy(ptr, cam->buffer, actual_length);
-			ptr += actual_length;
-		}
-	}
-	/* ... until there is no more */
-	while (actual_length == BUFFER_SIZE);
-
-	/* we skip the 2 first frames which are usually buggy */
-	if (cam->skip) {
-		cam->skip--;
-		goto redo;
-	}
-
-	/* go back to find the JPEG EOI marker */
-	size = ptr - jpeg;
-	ptr -= 2;
-	while (ptr > jpeg) {
-		if (*ptr == 0xFF && *(ptr + 1) == 0xD9
-		    && *(ptr + 2) == 0xFF)
-			break;
-		ptr--;
-	}
-	if (ptr == jpeg)
-		DBG("No EOI marker");
-
-	/* Sometimes there is junk data in the middle of the picture,
-	 * we want to skip this bogus frames */
-	while (ptr > jpeg) {
-		if (*ptr == 0xFF && *(ptr + 1) == 0xFF
-		    && *(ptr + 2) == 0xFF)
-			break;
-		ptr--;
-	}
-	if (ptr != jpeg) {
-		DBG("Bogus frame ? %d", cam->nb);
-		goto redo;
-	}
-
-	DBG("jpeg : %d %d %d %d %d %d %d %d",
-	    jpeg[0], jpeg[1], jpeg[2], jpeg[3],
-	    jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
-
-	return size;
-}
-
-
-static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t 
count,
 			    loff_t * ppos)
 {
-	unsigned long count = cnt;
-	struct video_device *vdev = video_devdata(file);
-	struct zr364xx_camera *cam;
+	struct zr364xx_camera *cam = video_drvdata(file);
 
-	DBG("zr364xx_read: read %d bytes.", (int) count);
-
-	if (vdev == NULL)
-		return -ENODEV;
