summary refs log tree commit diff
path: root/drivers/usb
diff options
context:
space:
mode:
authorLuca Risolia <luca.risolia@studio.unibo.it>2006-01-05 18:14:04 +0000
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-31 17:23:38 -0800
commita966f3e7512084f916049579067f532908ba3a49 (patch)
treeadc4bc3a3b781f4ebc8b169a286f8e60ab3e7e32 /drivers/usb
parentec7dc8d254985dc4a31858c2c7c7029290e223dd (diff)
downloadlinux-a966f3e7512084f916049579067f532908ba3a49.tar.gz
[PATCH] USB: SN9C10x driver updates and bugfixes
SN9C10x driver updates and bugfixes.

Changes: + new, - removed, * cleanup, @ bugfix:

@ fix poll()
@ Remove bad get_ctrl()'s
* Reduce ioctl stack usage
* Remove final ";" from some macro definitions
* Better support for SN9C103
+ Add sn9c102_write_regs()
+ Add 0x0c45/0x602d to the list of SN9C10x based devices
+ Add support for OV7630 image sensors
+ Provide support for the built-in microphone interface of the SN9C103
+ Documentation updates
+ Add 0x0c45/0x602e to the list of SN9C10x based devices

Signed-off-by: Luca Risolia <luca.risolia@studio.unibo.it>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/media/sn9c102.h31
-rw-r--r--drivers/usb/media/sn9c102_core.c1593
-rw-r--r--drivers/usb/media/sn9c102_hv7131d.c2
-rw-r--r--drivers/usb/media/sn9c102_mi0343.c2
-rw-r--r--drivers/usb/media/sn9c102_ov7630.c8
-rw-r--r--drivers/usb/media/sn9c102_pas106b.c2
-rw-r--r--drivers/usb/media/sn9c102_sensor.h69
-rw-r--r--drivers/usb/media/sn9c102_tas5110c1b.c2
-rw-r--r--drivers/usb/media/sn9c102_tas5130d1b.c2
9 files changed, 955 insertions, 756 deletions
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h
index e5cea0e2eb57..967c6b6bc0fa 100644
--- a/drivers/usb/media/sn9c102.h
+++ b/drivers/usb/media/sn9c102.h
@@ -1,7 +1,7 @@
 /***************************************************************************
  * V4L2 driver for SN9C10x PC Camera Controllers                           *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
@@ -53,11 +53,11 @@
 /*****************************************************************************/
 
 #define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
-#define SN9C102_MODULE_AUTHOR   "(C) 2004-2005 Luca Risolia"
+#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.24a"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 24)
+#define SN9C102_MODULE_VERSION  "1:1.25"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 25)
 
 enum sn9c102_bridge {
 	BRIDGE_SN9C101 = 0x01,
@@ -102,12 +102,13 @@ enum sn9c102_stream_state {
 	STREAM_ON,
 };
 
+typedef char sn9c103_sof_header_t[18];
 typedef char sn9c102_sof_header_t[12];
 typedef char sn9c102_eof_header_t[4];
 
 struct sn9c102_sysfs_attr {
 	u8 reg, i2c_reg;
-	sn9c102_sof_header_t frame_header;
+	sn9c103_sof_header_t frame_header;
 };
 
 struct sn9c102_module_param {
@@ -140,8 +141,8 @@ struct sn9c102_device {
 	struct v4l2_jpegcompression compression;
 
 	struct sn9c102_sysfs_attr sysfs;
-	sn9c102_sof_header_t sof_header;
-	u16 reg[32];
+	sn9c103_sof_header_t sof_header;
+	u16 reg[63];
 
 	struct sn9c102_module_param module_param;
 
@@ -170,7 +171,7 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
 #undef KDBG
 #ifdef SN9C102_DEBUG
 #	define DBG(level, fmt, args...)                                       \
-{                                                                             \
+do {                                                                          \
 	if (debug >= (level)) {                                               \
 		if ((level) == 1)                                             \
 			dev_err(&cam->dev, fmt "\n", ## args);                \
@@ -180,9 +181,9 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
 			dev_info(&cam->dev, "[%s:%d] " fmt "\n",              \
 			         __FUNCTION__, __LINE__ , ## args);           \
 	}                                                                     \
-}
+} while (0)
 #	define KDBG(level, fmt, args...)                                      \
-{                                                                             \
+do {                                                                          \
 	if (debug >= (level)) {                                               \
 		if ((level) == 1 || (level) == 2)                             \
 			pr_info("sn9c102: " fmt "\n", ## args);               \
@@ -190,17 +191,17 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
 			pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__,  \
 			         __LINE__ , ## args);                         \
 	}                                                                     \
-}
+} while (0)
 #else
-#	define KDBG(level, fmt, args...) do {;} while(0);
-#	define DBG(level, fmt, args...) do {;} while(0);
+#	define KDBG(level, fmt, args...) do {;} while(0)
+#	define DBG(level, fmt, args...) do {;} while(0)
 #endif
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
+dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
 
 #undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0); /* placeholder */
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
 
 #endif /* _SN9C102_H_ */
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c
index 8d1a1c357d5a..6090439663ee 100644
--- a/drivers/usb/media/sn9c102_core.c
+++ b/drivers/usb/media/sn9c102_core.c
@@ -1,7 +1,7 @@
 /***************************************************************************
  * V4L2 driver for SN9C10x PC Camera Controllers                           *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
@@ -70,10 +70,10 @@ static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
                                SN9C102_FORCE_MUNMAP};
 module_param_array(force_munmap, bool, NULL, 0444);
 MODULE_PARM_DESC(force_munmap,
-                 "\n<0|1[,...]> Force the application to unmap previously "
-                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or "
-                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support "
-                 "\nthis feature. This parameter is specific for each "
+                 "\n<0|1[,...]> Force the application to unmap previously"
+                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                 "\nthis feature. This parameter is specific for each"
                  "\ndetected camera."
                  "\n 0 = do not force memory unmapping"
                  "\n 1 = force memory unmapping (save memory)"
@@ -102,6 +102,9 @@ static sn9c102_sof_header_t sn9c102_sof_header[] = {
 	{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
 };
 
+static sn9c103_sof_header_t sn9c103_sof_header[] = {
+	{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
+};
 
 static sn9c102_eof_header_t sn9c102_eof_header[] = {
 	{0x00, 0x00, 0x00, 0x00},
@@ -202,6 +205,7 @@ static void sn9c102_release_buffers(struct sn9c102_device* cam)
 		       cam->nbuffers * PAGE_ALIGN(cam->frame[0].buf.length));
 		cam->nbuffers = 0;
 	}
+	cam->frame_current = NULL;
 }
 
 
@@ -219,6 +223,19 @@ static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
 }
 
 
+static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
+{
+	struct sn9c102_frame_t *i;
+
+	list_for_each_entry(i, &cam->outqueue, frame) {
+		i->state = F_QUEUED;
+		list_add(&i->frame, &cam->inqueue);
+	}
+
+	INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
 static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
 {
 	unsigned long lock_flags;
@@ -235,19 +252,46 @@ static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
 
 /*****************************************************************************/
 
+int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
+{
+	struct usb_device* udev = cam->usbdev;
+	int i, res;
+
+	if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg))
+		return -1;
+
+	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+	                      index, 0, buff, sizeof(buff),
+	                      SN9C102_CTRL_TIMEOUT*sizeof(buff));
+	if (res < 0) {
+		DBG(3, "Failed to write registers (index 0x%02X, error %d)",
+		    index, res);
+		return -1;
+	}
+
+	for (i = 0; i < sizeof(buff); i++)
+		cam->reg[index+i] = buff[i];
+
+	return 0;
+}
+
+
 int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
 {
 	struct usb_device* udev = cam->usbdev;
 	u8* buff = cam->control_buffer;
 	int res;
 
+	if (index >= ARRAY_SIZE(cam->reg))
+		return -1;
+
 	*buff = value;
 
 	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
 	                      index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
 	if (res < 0) {
 		DBG(3, "Failed to write a register (value 0x%02X, index "
-		       "0x%02X, error %d)", value, index, res)
+		       "0x%02X, error %d)", value, index, res);
 		return -1;
 	}
 
@@ -268,7 +312,7 @@ static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
 	                      index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
 	if (res < 0)
 		DBG(3, "Failed to read a register (index 0x%02X, error %d)",
-		    index, res)
+		    index, res);
 
 	return (res >= 0) ? (int)(*buff) : -1;
 }
@@ -276,8 +320,8 @@ static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
 
 int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
 {
-	if (index > 0x1f)
-		return -EINVAL;
+	if (index >= ARRAY_SIZE(cam->reg))
+		return -1;
 
 	return cam->reg[index];
 }
@@ -367,10 +411,10 @@ sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
 	err += sn9c102_i2c_detect_read_error(cam, sensor);
 
 	PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
-	      data[4])
+	      data[4]);
 
 	if (err) {
-		DBG(3, "I2C read failed for %s image sensor", sensor->name)
+		DBG(3, "I2C read failed for %s image sensor", sensor->name);
 		return -1;
 	}
 
@@ -410,11 +454,11 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
 	err += sn9c102_i2c_detect_write_error(cam, sensor);
 
 	if (err)
-		DBG(3, "I2C write failed for %s image sensor", sensor->name)
+		DBG(3, "I2C write failed for %s image sensor", sensor->name);
 
 	PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
 	      "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
-	      n, data0, data1, data2, data3, data4, data5)
+	      n, data0, data1, data2, data3, data4, data5);
 
 	return err ? -1 : 0;
 }
@@ -461,13 +505,27 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
 static void*
 sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
 {
-	size_t soflen = sizeof(sn9c102_sof_header_t), i;
-	u8 j, n = sizeof(sn9c102_sof_header) / soflen;
+	size_t soflen = 0, i;
+	u8 j, n = 0;
+
+	switch (cam->bridge) {
+	case BRIDGE_SN9C101:
+	case BRIDGE_SN9C102:
+		soflen = sizeof(sn9c102_sof_header_t);
+		n = sizeof(sn9c102_sof_header) / soflen;
+		break;
+	case BRIDGE_SN9C103:
+		soflen = sizeof(sn9c103_sof_header_t);
+		n = sizeof(sn9c103_sof_header) / soflen;
+	}
 
-	for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
+ 	for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
 		for (j = 0; j < n; j++)
-			/* It's enough to compare 7 bytes */
-			if (!memcmp(mem + i, sn9c102_sof_header[j], 7)) {
+			/* The invariable part of the header is 6 bytes long */
+			if ((cam->bridge != BRIDGE_SN9C103 &&
+			    !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
+			    (cam->bridge == BRIDGE_SN9C103 &&
+			    !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
 				memcpy(cam->sof_header, mem + i, soflen);
 				/* Skip the header */
 				return mem + i + soflen;
@@ -499,8 +557,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
 {
 	struct sn9c102_device* cam = urb->context;
 	struct sn9c102_frame_t** f;
-	size_t imagesize;
-	unsigned long lock_flags;
+	size_t imagesize, soflen;
 	u8 i;
 	int err = 0;
 
@@ -513,7 +570,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
 		cam->stream = STREAM_OFF;
 		if ((*f))
 			(*f)->state = F_QUEUED;
-		DBG(3, "Stream interrupted")
+		DBG(3, "Stream interrupted");
 		wake_up_interruptible(&cam->wait_stream);
 	}
 
@@ -536,6 +593,10 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
 	             cam->sensor->pix_format.height *
 	             cam->sensor->pix_format.priv) / 8;
 
+	soflen = (cam->bridge) == BRIDGE_SN9C103 ?
+	                          sizeof(sn9c103_sof_header_t) :
+	                          sizeof(sn9c102_sof_header_t);
+
 	for (i = 0; i < urb->number_of_packets; i++) {
 		unsigned int img, len, status;
 		void *pos, *sof, *eof;
@@ -545,19 +606,12 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
 		pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
 
 		if (status) {
-			DBG(3, "Error in isochronous frame")
+			DBG(3, "Error in isochronous frame");
 			(*f)->state = F_ERROR;
 			continue;
 		}
 
-		PDBGG("Isochrnous frame: length %u, #%u i", len, i)
-
-		/*
-		   NOTE: It is probably correct to assume that SOF and EOF
-		         headers do not occur between two consecutive packets,
-		         but who knows..Whatever is the truth, this assumption
-		         doesn't introduce bugs.
-		*/
+		PDBGG("Isochrnous frame: length %u, #%u i", len, i);
 
 redo:
 		sof = sn9c102_find_sof_header(cam, pos, len);
@@ -575,10 +629,10 @@ end_of_frame:
 					        imagesize;
 					img = imagesize - (*f)->buf.bytesused;
 					DBG(3, "Expected EOF not found: "
-					       "video frame cut")
+					       "video frame cut");
 					if (eof)
 						DBG(3, "Exceeded limit: +%u "
-						       "bytes", (unsigned)(b))
+						       "bytes", (unsigned)(b));
 				}
 
 				memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
@@ -595,8 +649,7 @@ end_of_frame:
 					u32 b = (*f)->buf.bytesused;
 					(*f)->state = F_DONE;
 					(*f)->buf.sequence= ++cam->frame_count;
-					spin_lock_irqsave(&cam->queue_lock,
-					                  lock_flags);
+					spin_lock(&cam->queue_lock);
 					list_move_tail(&(*f)->frame,
 					               &cam->outqueue);
 					if (!list_empty(&cam->inqueue))
@@ -606,13 +659,11 @@ end_of_frame:
 						        frame );
 					else
 						(*f) = NULL;
-					spin_unlock_irqrestore(&cam->queue_lock
-					                       , lock_flags);
+					spin_unlock(&cam->queue_lock);
 					memcpy(cam->sysfs.frame_header,
-					       cam->sof_header,
-					       sizeof(sn9c102_sof_header_t));
-					DBG(3, "Video frame captured: "
-					       "%lu bytes", (unsigned long)(b))
+					       cam->sof_header, soflen);
+					DBG(3, "Video frame captured: %lu "
+					       "bytes", (unsigned long)(b));
 
 					if (!(*f))
 						goto resubmit_urb;
@@ -621,18 +672,19 @@ end_of_frame:
 					(*f)->state = F_ERROR;
 					DBG(3, "Not expected EOF after %lu "
 					       "bytes of image data", 
-					  (unsigned long)((*f)->buf.bytesused))
+					    (unsigned long)
+					    ((*f)->buf.bytesused));
 				}
 
 				if (sof) /* (1) */
 					goto start_of_frame;
 
 			} else if (eof) {
-				DBG(3, "EOF without SOF")
+				DBG(3, "EOF without SOF");
 				continue;
 
 			} else {
-				PDBGG("Ignoring pointless isochronous frame")
+				PDBGG("Ignoring pointless isochronous frame");
 				continue;
 			}
 
@@ -642,7 +694,7 @@ start_of_frame:
 			(*f)->buf.bytesused = 0;
 			len -= (sof - pos);
 			pos = sof;
-			DBG(3, "SOF detected: new video frame")
+			DBG(3, "SOF detected: new video frame");
 			if (len)
 				goto redo;
 
@@ -653,12 +705,13 @@ start_of_frame:
 			else {
 				if (cam->sensor->pix_format.pixelformat ==
 				    V4L2_PIX_FMT_SN9C10X) {
-					eof = sof-sizeof(sn9c102_sof_header_t);
+					eof = sof - soflen;
 					goto end_of_frame;
 				} else {
 					DBG(3, "SOF before expected EOF after "
 					       "%lu bytes of image data", 
-					  (unsigned long)((*f)->buf.bytesused))
+					    (unsigned long)
+					    ((*f)->buf.bytesused));
 					goto start_of_frame;
 				}
 			}
@@ -670,7 +723,7 @@ resubmit_urb:
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err < 0 && err != -EPERM) {
 		cam->state |= DEV_MISCONFIGURED;
-		DBG(1, "usb_submit_urb() failed")
+		DBG(1, "usb_submit_urb() failed");
 	}
 
 	wake_up_interruptible(&cam->wait_frame);
@@ -681,9 +734,13 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
 {
 	struct usb_device *udev = cam->usbdev;
 	struct urb* urb;
-	const unsigned int wMaxPacketSize[] = {0, 128, 256, 384, 512,
-	                                       680, 800, 900, 1023};
-	const unsigned int psz = wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
+	const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
+	                                               680, 800, 900, 1023};
+	const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
+	                                               680, 800, 900, 1003};
+	const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
+	                    sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
+	                    sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
 	s8 i, j;
 	int err = 0;
 
@@ -692,7 +749,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
 		                                  GFP_KERNEL);
 		if (!cam->transfer_buffer[i]) {
 			err = -ENOMEM;
-			DBG(1, "Not enough memory")
+			DBG(1, "Not enough memory");
 			goto free_buffers;
 		}
 	}
@@ -702,7 +759,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
 		cam->urb[i] = urb;
 		if (!urb) {
 			err = -ENOMEM;
-			DBG(1, "usb_alloc_urb() failed")
+			DBG(1, "usb_alloc_urb() failed");
 			goto free_urbs;
 		}
 		urb->dev = udev;
@@ -725,14 +782,14 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
 		err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
 		if (err) {
 			err = -EIO;
-			DBG(1, "I/O hardware error")
+			DBG(1, "I/O hardware error");
 			goto free_urbs;
 		}
 	}
 
 	err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
 	if (err) {
-		DBG(1, "usb_set_interface() failed")
+		DBG(1, "usb_set_interface() failed");
 		goto free_urbs;
 	}
 
@@ -743,7 +800,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
 		if (err) {
 			for (j = i-1; j >= 0; j--)
 				usb_kill_urb(cam->urb[j]);
-			DBG(1, "usb_submit_urb() failed, error %d", err)
+			DBG(1, "usb_submit_urb() failed, error %d", err);
 			goto free_urbs;
 		}
 	}
@@ -779,7 +836,7 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
 
 	err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
 	if (err)
-		DBG(3, "usb_set_interface() failed")
+		DBG(3, "usb_set_interface() failed");
 
 	return err;
 }
@@ -799,7 +856,7 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
 	else if (err) {
 		cam->state |= DEV_MISCONFIGURED;
 		DBG(1, "The camera is misconfigured. To use it, close and "
-		       "open /dev/video%d again.", cam->v4ldev->minor)
+		       "open /dev/video%d again.", cam->v4ldev->minor);
 		return err;
 	}
 
@@ -885,8 +942,8 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
 
 	cam->sysfs.reg = index;
 
-	DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg)
-	DBG(3, "Written bytes: %zd", count)
+	DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
+	DBG(3, "Written bytes: %zd", count);
 
 	up(&sn9c102_sysfs_lock);
 
@@ -916,7 +973,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
 
 	count = sprintf(buf, "%d\n", val);
 
-	DBG(3, "Read bytes: %zd", count)
+	DBG(3, "Read bytes: %zd", count);
 
 	up(&sn9c102_sysfs_lock);
 
@@ -954,8 +1011,8 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
 	}
 
 	DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
-	    cam->sysfs.reg, value)
-	DBG(3, "Written bytes: %zd", count)
+	    cam->sysfs.reg, value);
+	DBG(3, "Written bytes: %zd", count);
 
 	up(&sn9c102_sysfs_lock);
 
@@ -979,7 +1036,7 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
 
 	count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
 
-	DBG(3, "Read bytes: %zd", count)
+	DBG(3, "Read bytes: %zd", count);
 
 	up(&sn9c102_sysfs_lock);
 
@@ -1011,8 +1068,8 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
 
 	cam->sysfs.i2c_reg = index;
 
-	DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg)
-	DBG(3, "Written bytes: %zd", count)
+	DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
+	DBG(3, "Written bytes: %zd", count);
 
 	up(&sn9c102_sysfs_lock);
 
@@ -1047,7 +1104,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
 
 	count = sprintf(buf, "%d\n", val);
 
-	DBG(3, "Read bytes: %zd", count)
+	DBG(3, "Read bytes: %zd", count);
 
 	up(&sn9c102_sysfs_lock);
 
@@ -1090,8 +1147,8 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
 	}
 
 	DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
-	    cam->sysfs.i2c_reg, value)
-	DBG(3, "Written bytes: %zd", count)
+	    cam->sysfs.i2c_reg, value);
+	DBG(3, "Written bytes: %zd", count);
 
 	up(&sn9c102_sysfs_lock);
 
@@ -1193,7 +1250,7 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
 	count = sizeof(cam->sysfs.frame_header);
 	memcpy(buf, cam->sysfs.frame_header, count);
 
-	DBG(3, "Frame header, read bytes: %zd", count)
+	DBG(3, "Frame header, read bytes: %zd", count);
 
 	return count;
 } 
@@ -1227,7 +1284,7 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
 		video_device_create_file(v4ldev, &class_device_attr_blue);
 		video_device_create_file(v4ldev, &class_device_attr_red);
 	}
-	if (cam->sensor->sysfs_ops) {
+	if (cam->sensor && cam->sensor->sysfs_ops) {
 		video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
 		video_device_create_file(v4ldev, &class_device_attr_i2c_val);
 	}
@@ -1281,7 +1338,7 @@ static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
 	if (err)
 		return -EIO;
 
-	PDBGG("Scaling factor: %u", scale)
+	PDBGG("Scaling factor: %u", scale);
 
 	return 0;
 }
@@ -1304,7 +1361,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
 		return -EIO;
 
 	PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
-	      "%u %u %u %u", h_start, v_start, h_size, v_size)
+	      "%u %u %u %u", h_start, v_start, h_size, v_size);
 
 	return 0;
 }
@@ -1336,7 +1393,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
 	if (s->init) {
 		err = s->init(cam);
 		if (err) {
-			DBG(3, "Sensor initialization failed")
+			DBG(3, "Sensor initialization failed");
 			return err;
 		}
 	}
@@ -1353,13 +1410,13 @@ static int sn9c102_init(struct sn9c102_device* cam)
 
 	if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
 		DBG(3, "Compressed video format is active, quality %d",
-		    cam->compression.quality)
+		    cam->compression.quality);
 	else
-		DBG(3, "Uncompressed video format is active")
+		DBG(3, "Uncompressed video format is active");
 
 	if (s->set_crop)
 		if ((err = s->set_crop(cam, rect))) {
-			DBG(3, "set_crop() failed")
+			DBG(3, "set_crop() failed");
 			return err;
 		}
 
@@ -1372,11 +1429,11 @@ static int sn9c102_init(struct sn9c102_device* cam)
 				err = s->set_ctrl(cam, &ctrl);
 				if (err) {
 					DBG(3, "Set %s control failed",
-					    s->qctrl[i].name)
+					    s->qctrl[i].name);
 					return err;
 				}
 				DBG(3, "Image sensor supports '%s' control",
-				    s->qctrl[i].name)
+				    s->qctrl[i].name);
 			}
 	}
 
@@ -1392,7 +1449,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
 		cam->state |= DEV_INITIALIZED;
 	}
 
-	DBG(2, "Initialization succeeded")
+	DBG(2, "Initialization succeeded");
 	return 0;
 }
 
@@ -1401,7 +1458,7 @@ static void sn9c102_release_resources(struct sn9c102_device* cam)
 {
 	down(&sn9c102_sysfs_lock);
 
-	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor)
+	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
 	video_set_drvdata(cam->v4ldev, NULL);
 	video_unregister_device(cam->v4ldev);
 
@@ -1432,7 +1489,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
 	}
 
 	if (cam->users) {
-		DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor)
+		DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
 		if ((filp->f_flags & O_NONBLOCK) ||
 		    (filp->f_flags & O_NDELAY)) {
 			err = -EWOULDBLOCK;
@@ -1458,7 +1515,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
 		err = sn9c102_init(cam);
 		if (err) {
 			DBG(1, "Initialization failed again. "
-			       "I will retry on next open().")
+			       "I will retry on next open().");
 			goto out;
 		}
 		cam->state &= ~DEV_MISCONFIGURED;
@@ -1475,7 +1532,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
 	cam->frame_count = 0;
 	sn9c102_empty_framequeues(cam);
 
-	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor)
+	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
 	up(&cam->dev_sem);
@@ -1504,7 +1561,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp)
 	cam->users--;
 	wake_up_interruptible_nr(&cam->open, 1);
 
-	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor)
+	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
 	up(&cam->dev_sem);
 
@@ -1524,32 +1581,38 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 		return -ERESTARTSYS;
 
 	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present")
+		DBG(1, "Device not present");
 		up(&cam->fileop_sem);
 		return -ENODEV;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it again.")
+		DBG(1, "The camera is misconfigured. Close and open it "
+		       "again.");
 		up(&cam->fileop_sem);
 		return -EIO;
 	}
 
 	if (cam->io == IO_MMAP) {
 		DBG(3, "Close and open the device again to choose "
-		       "the read method")
+		       "the read method");
 		up(&cam->fileop_sem);
 		return -EINVAL;
 	}
 
 	if (cam->io == IO_NONE) {
 		if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
-			DBG(1, "read() failed, not enough memory")
+			DBG(1, "read() failed, not enough memory");
 			up(&cam->fileop_sem);
 			return -ENOMEM;
 		}
 		cam->io = IO_READ;
 		cam->stream = STREAM_ON;
+	}
+
+	if (list_empty(&cam->inqueue)) {
+		if (!list_empty(&cam->outqueue))
+			sn9c102_empty_framequeues(cam);
 		sn9c102_queue_unusedframes(cam);
 	}
 
@@ -1584,6 +1647,16 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 
 	f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
 
+	if (count > f->buf.bytesused)
+		count = f->buf.bytesused;
+
+	if (copy_to_user(buf, f->bufmem, count)) {
+		err = -EFAULT;
+		goto exit;
+	}
+	*f_pos += count;
+
+exit:
 	spin_lock_irqsave(&cam->queue_lock, lock_flags);
 	list_for_each_entry(i, &cam->outqueue, frame)
 		i->state = F_UNUSED;
@@ -1592,16 +1665,8 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 
 	sn9c102_queue_unusedframes(cam);
 
-	if (count > f->buf.bytesused)
-		count = f->buf.bytesused;
-
-	if (copy_to_user(buf, f->bufmem, count)) {
-		up(&cam->fileop_sem);
-		return -EFAULT;
-	}
-	*f_pos += count;
-
-	PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index,count)
+	PDBGG("Frame #%lu, bytes read: %zu",
+	      (unsigned long)f->buf.index, count);
 
 	up(&cam->fileop_sem);
 
@@ -1612,33 +1677,42 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
 static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
 {
 	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+	struct sn9c102_frame_t* f;
+	unsigned long lock_flags;
 	unsigned int mask = 0;
 
 	if (down_interruptible(&cam->fileop_sem))
 		return POLLERR;
 
 	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present")
+		DBG(1, "Device not present");
 		goto error;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it again.")
+		DBG(1, "The camera is misconfigured. Close and open it "
+		       "again.");
 		goto error;
 	}
 
 	if (cam->io == IO_NONE) {
 		if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
 		                             IO_READ)) {
-			DBG(1, "poll() failed, not enough memory")
+			DBG(1, "poll() failed, not enough memory");
 			goto error;
 		}
 		cam->io = IO_READ;
 		cam->stream = STREAM_ON;
 	}
 
-	if (cam->io == IO_READ)
+	if (cam->io == IO_READ) {
+		spin_lock_irqsave(&cam->queue_lock, lock_flags);
+		list_for_each_entry(f, &cam->outqueue, frame)
+			f->state = F_UNUSED;
+		INIT_LIST_HEAD(&cam->outqueue);
+		spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
 		sn9c102_queue_unusedframes(cam);
+	}
 
 	poll_wait(filp, &cam->wait_frame, wait);
 
@@ -1689,13 +1763,14 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 		return -ERESTARTSYS;
 
 	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present")
+		DBG(1, "Device not present");
 		up(&cam->fileop_sem);
 		return -ENODEV;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it again.")
+		DBG(1, "The camera is misconfigured. Close and open it "
+		       "again.");
 		up(&cam->fileop_sem);
 		return -EIO;
 	}
@@ -1742,738 +1817,860 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
 	return 0;
 }
 
+/*****************************************************************************/
 
-static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
-                              unsigned int cmd, void __user * arg)
+static int
+sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
 {
-	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+	struct v4l2_capability cap = {
+		.driver = "sn9c102",
+		.version = SN9C102_MODULE_VERSION_CODE,
+		.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+		                V4L2_CAP_STREAMING,
+	};
+
+	strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+	if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+		strlcpy(cap.bus_info, cam->dev.bus_id, sizeof(cap.bus_info));
+
+	if (copy_to_user(arg, &cap, sizeof(cap)))
+		return -EFAULT;
 
-	switch (cmd) {
+	return 0;
+}
 
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability cap = {
-			.driver = "sn9c102",
-			.version = SN9C102_MODULE_VERSION_CODE,
-			.capabilities = V4L2_CAP_VIDEO_CAPTURE | 
-			                V4L2_CAP_READWRITE |
-			                V4L2_CAP_STREAMING,
-		};
-
-		strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-		if (usb_make_path(cam->usbdev, cap.bus_info,
-		    sizeof(cap.bus_info)) < 0)
-			strlcpy(cap.bus_info, cam->dev.bus_id,
-			        sizeof(cap.bus_info));
-
-		if (copy_to_user(arg, &cap, sizeof(cap)))
-			return -EFAULT;
 
-		return 0;
-	}
+static int
+sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_input i;
 
-	case VIDIOC_ENUMINPUT:
-	{
-		struct v4l2_input i;
+	if (copy_from_user(&i, arg, sizeof(i)))
+		return -EFAULT;
 
-		if (copy_from_user(&i, arg, sizeof(i)))
-			return -EFAULT;
+	if (i.index)
+		return -EINVAL;
 
-		if (i.index)
-			return -EINVAL;
+	memset(&i, 0, sizeof(i));
+	strcpy(i.name, "USB");
 
-		memset(&i, 0, sizeof(i));
-		strcpy(i.name, "USB");
+	if (copy_to_user(arg, &i, sizeof(i)))
+		return -EFAULT;
 
-		if (copy_to_user(arg, &i, sizeof(i)))
-			return -EFAULT;
+	return 0;
+}
 
-		return 0;
-	}
 
-	case VIDIOC_G_INPUT:
-	case VIDIOC_S_INPUT:
-	{
-		int index;
+static int
+sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
+{
+	int index;
 
-		if (copy_from_user(&index, arg, sizeof(index)))
-			return -EFAULT;
+	if (copy_from_user(&index, arg, sizeof(index)))
+		return -EFAULT;
 
-		if (index != 0)
-			return -EINVAL;
+	if (index != 0)
+		return -EINVAL;
 
-		return 0;
-	}
+	return 0;
+}
 
-	case VIDIOC_QUERYCTRL:
-	{
-		struct sn9c102_sensor* s = cam->sensor;
-		struct v4l2_queryctrl qc;
-		u8 i;
 
-		if (copy_from_user(&qc, arg, sizeof(qc)))
-			return -EFAULT;
+static int
+sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+	struct sn9c102_sensor* s = cam->sensor;
+	struct v4l2_queryctrl qc;
+	u8 i;
+
+	if (copy_from_user(&qc, arg, sizeof(qc)))
+		return -EFAULT;
+
+	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+		if (qc.id && qc.id == s->qctrl[i].id) {
+			memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+			if (copy_to_user(arg, &qc, sizeof(qc)))
+				return -EFAULT;
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+
+static int
+sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+	struct sn9c102_sensor* s = cam->sensor;
+	struct v4l2_control ctrl;
+	int err = 0;
+	u8 i;
+
+	if (!s->get_ctrl && !s->set_ctrl)
+		return -EINVAL;
 
+	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+		return -EFAULT;
+
+	if (!s->get_ctrl) {
 		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-			if (qc.id && qc.id == s->qctrl[i].id) {
-				memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-				if (copy_to_user(arg, &qc, sizeof(qc)))
-					return -EFAULT;
-				return 0;
+			if (ctrl.id && ctrl.id == s->qctrl[i].id) {
+				ctrl.value = s->_qctrl[i].default_value;
+				goto exit;
 			}
-
 		return -EINVAL;
-	}
+	} else
+		err = s->get_ctrl(cam, &ctrl);
 
-	case VIDIOC_G_CTRL:
-	{
-		struct sn9c102_sensor* s = cam->sensor;
-		struct v4l2_control ctrl;
-		int err = 0;
+exit:
+	if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+		return -EFAULT;
 
-		if (!s->get_ctrl)
-			return -EINVAL;
+	return err;
+}
 
-		if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-			return -EFAULT;
 
-		err = s->get_ctrl(cam, &ctrl);
+static int
+sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+	struct sn9c102_sensor* s = cam->sensor;
+	struct v4l2_control ctrl;
+	u8 i;
+	int err = 0;
 
-		if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-			return -EFAULT;
+	if (!s->set_ctrl)
+		return -EINVAL;
 
+	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+		return -EFAULT;
+
+	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+		if (ctrl.id == s->qctrl[i].id) {
+			if (ctrl.value < s->qctrl[i].minimum ||
+			    ctrl.value > s->qctrl[i].maximum)
+				return -ERANGE;
+			ctrl.value -= ctrl.value % s->qctrl[i].step;
+			break;
+		}
+
+	if ((err = s->set_ctrl(cam, &ctrl)))
 		return err;
-	}
 
-	case VIDIOC_S_CTRL_OLD:
-	case VIDIOC_S_CTRL:
-	{
-		struct sn9c102_sensor* s = cam->sensor;
-		struct v4l2_control ctrl;
-		u8 i;
-		int err = 0;
+	s->_qctrl[i].default_value = ctrl.value;
 
-		if (!s->set_ctrl)
-			return -EINVAL;
+	PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
+	      (unsigned long)ctrl.id, (unsigned long)ctrl.value);
 
-		if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-			return -EFAULT;
+	return 0;
+}
 
-		for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-			if (ctrl.id == s->qctrl[i].id) {
-				if (ctrl.value < s->qctrl[i].minimum ||
-				    ctrl.value > s->qctrl[i].maximum)
-					return -ERANGE;
-				ctrl.value -= ctrl.value % s->qctrl[i].step;
-				break;
+
+static int
+sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+
+	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	cc->pixelaspect.numerator = 1;
+	cc->pixelaspect.denominator = 1;
+
+	if (copy_to_user(arg, cc, sizeof(*cc)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
+{
+	struct sn9c102_sensor* s = cam->sensor;
+	struct v4l2_crop crop = {
+		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+	};
+
+	memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+	if (copy_to_user(arg, &crop, sizeof(crop)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
+{
+	struct sn9c102_sensor* s = cam->sensor;
+	struct v4l2_crop crop;
+	struct v4l2_rect* rect;
+	struct v4l2_rect* bounds = &(s->cropcap.bounds);
+	struct v4l2_pix_format* pix_format = &(s->pix_format);
+	u8 scale;
+	const enum sn9c102_stream_state stream = cam->stream;
+	const u32 nbuffers = cam->nbuffers;
+	u32 i;
+	int err = 0;
+
+	if (copy_from_user(&crop, arg, sizeof(crop)))
+		return -EFAULT;
+
+	rect = &(crop.c);
+
+	if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (cam->module_param.force_munmap)
+		for (i = 0; i < cam->nbuffers; i++)
+			if (cam->frame[i].vma_use_count) {
+				DBG(3, "VIDIOC_S_CROP failed. "
+				       "Unmap the buffers first.");
+				return -EINVAL;
 			}
 
-		if ((err = s->set_ctrl(cam, &ctrl)))
+	/* Preserve R,G or B origin */
+	rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
+	rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
+
+	if (rect->width < 16)
+		rect->width = 16;
+	if (rect->height < 16)
+		rect->height = 16;
+	if (rect->width > bounds->width)
+		rect->width = bounds->width;
+	if (rect->height > bounds->height)
+		rect->height = bounds->height;
+	if (rect->left < bounds->left)
+		rect->left = bounds->left;
+	if (rect->top < bounds->top)
+		rect->top = bounds->top;
+	if (rect->left + rect->width > bounds->left + bounds->width)
+		rect->left = bounds->left+bounds->width - rect->width;
+	if (rect->top + rect->height > bounds->top + bounds->height)
+		rect->top = bounds->top+bounds->height - rect->height;
+
+	rect->width &= ~15L;
+	rect->height &= ~15L;
+
+	if (SN9C102_PRESERVE_IMGSCALE) {
+		/* Calculate the actual scaling factor */
+		u32 a, b;
+		a = rect->width * rect->height;
+		b = pix_format->width * pix_format->height;
+		scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+	} else
+		scale = 1;
+
+	if (cam->stream == STREAM_ON)
+		if ((err = sn9c102_stream_interrupt(cam)))
 			return err;
 
-		s->_qctrl[i].default_value = ctrl.value;
+	if (copy_to_user(arg, &crop, sizeof(crop))) {
+		cam->stream = stream;
+		return -EFAULT;
+	}
 
-		PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
-		      (unsigned long)ctrl.id, (unsigned long)ctrl.value)
+	if (cam->module_param.force_munmap || cam->io == IO_READ)
+		sn9c102_release_buffers(cam);
 
-		return 0;
+	err = sn9c102_set_crop(cam, rect);
+	if (s->set_crop)
+		err += s->set_crop(cam, rect);
+	err += sn9c102_set_scale(cam, scale);
+
+	if (err) { /* atomic, no rollback in ioctl() */
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+		       "use the camera, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -EIO;
 	}
 
-	case VIDIOC_CROPCAP:
-	{
-		struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+	s->pix_format.width = rect->width/scale;
+	s->pix_format.height = rect->height/scale;
+	memcpy(&(s->_rect), rect, sizeof(*rect));
 
-		cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		cc->pixelaspect.numerator = 1;
-		cc->pixelaspect.denominator = 1;
+	if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
+	    nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+		       "use the camera, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -ENOMEM;
+	}
 
-		if (copy_to_user(arg, cc, sizeof(*cc)))
-			return -EFAULT;
+	if (cam->io == IO_READ)
+		sn9c102_empty_framequeues(cam);
+	else if (cam->module_param.force_munmap)
+		sn9c102_requeue_outqueue(cam);
 
-		return 0;
-	}
+	cam->stream = stream;
 
-	case VIDIOC_G_CROP:
-	{
-		struct sn9c102_sensor* s = cam->sensor;
-		struct v4l2_crop crop = {
-			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-		};
+	return 0;
+}
 
-		memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
 
-		if (copy_to_user(arg, &crop, sizeof(crop)))
-			return -EFAULT;
+static int
+sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_fmtdesc fmtd;
 
-		return 0;
-	}
+	if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+		return -EFAULT;
 
-	case VIDIOC_S_CROP:
-	{
-		struct sn9c102_sensor* s = cam->sensor;
-		struct v4l2_crop crop;
-		struct v4l2_rect* rect;
-		struct v4l2_rect* bounds = &(s->cropcap.bounds);
-		struct v4l2_pix_format* pix_format = &(s->pix_format);
-		u8 scale;
-		const enum sn9c102_stream_state stream = cam->stream;
-		const u32 nbuffers = cam->nbuffers;
-		u32 i;
-		int err = 0;
-
-		if (copy_from_user(&crop, arg, sizeof(crop)))
-			return -EFAULT;
+	if (fmtd.index == 0) {
+		strcpy(fmtd.description, "bayer rgb");
+		fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+	} else if (fmtd.index == 1) {
+		strcpy(fmtd.description, "compressed");
+		fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+		fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+	} else
+		return -EINVAL;
 
-		rect = &(crop.c);
+	fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
 
-		if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
+	if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+		return -EFAULT;
 
-		if (cam->module_param.force_munmap)
-			for (i = 0; i < cam->nbuffers; i++)
-				if (cam->frame[i].vma_use_count) {
-					DBG(3, "VIDIOC_S_CROP failed. "
-					       "Unmap the buffers first.")
-					return -EINVAL;
-				}
+	return 0;
+}
 
-		/* Preserve R,G or B origin */
-		rect->left = (s->_rect.left & 1L) ?
-		             rect->left | 1L : rect->left & ~1L;
-		rect->top = (s->_rect.top & 1L) ?
-		            rect->top | 1L : rect->top & ~1L;
-
-		if (rect->width < 16)
-			rect->width = 16;
-		if (rect->height < 16)
-			rect->height = 16;
-		if (rect->width > bounds->width)
-			rect->width = bounds->width;
-		if (rect->height > bounds->height)
-			rect->height = bounds->height;
-		if (rect->left < bounds->left)
-			rect->left = bounds->left;
-		if (rect->top < bounds->top)
-			rect->top = bounds->top;
-		if (rect->left + rect->width > bounds->left + bounds->width)
-			rect->left = bounds->left+bounds->width - rect->width;
-		if (rect->top + rect->height > bounds->top + bounds->height)
-			rect->top = bounds->top+bounds->height - rect->height;
-
-		rect->width &= ~15L;
-		rect->height &= ~15L;
-
-		if (SN9C102_PRESERVE_IMGSCALE) {
-			/* Calculate the actual scaling factor */
-			u32 a, b;
-			a = rect->width * rect->height;
-			b = pix_format->width * pix_format->height;
-			scale = b ? (u8)((a / b) < 4 ? 1 :
-		                        ((a / b) < 16 ? 2 : 4)) : 1;
-		} else
-			scale = 1;
-
-		if (cam->stream == STREAM_ON)
-			if ((err = sn9c102_stream_interrupt(cam)))
-				return err;
-
-		if (copy_to_user(arg, &crop, sizeof(crop))) {
-			cam->stream = stream;
-			return -EFAULT;
-		}
 
-		if (cam->module_param.force_munmap || cam->io == IO_READ)
-			sn9c102_release_buffers(cam);
+static int
+sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_format format;
+	struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
 
-		err = sn9c102_set_crop(cam, rect);
-		if (s->set_crop)
-			err += s->set_crop(cam, rect);
-		err += sn9c102_set_scale(cam, scale);
+	if (copy_from_user(&format, arg, sizeof(format)))
+		return -EFAULT;
 
-		if (err) { /* atomic, no rollback in ioctl() */
-			cam->state |= DEV_MISCONFIGURED;
-			DBG(1, "VIDIOC_S_CROP failed because of hardware "
-			       "problems. To use the camera, close and open "
-			       "/dev/video%d again.", cam->v4ldev->minor)
-			return -EIO;
-		}
+	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
 
-		s->pix_format.width = rect->width/scale;
-		s->pix_format.height = rect->height/scale;
-		memcpy(&(s->_rect), rect, sizeof(*rect));
-
-		if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
-		    nbuffers != sn9c102_request_buffers(cam, nbuffers,
-		                                        cam->io)) {
-			cam->state |= DEV_MISCONFIGURED;
-			DBG(1, "VIDIOC_S_CROP failed because of not enough "
-			       "memory. To use the camera, close and open "
-			       "/dev/video%d again.", cam->v4ldev->minor)
-			return -ENOMEM;
-		}
+	pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+	                     ? 0 : (pfmt->width * pfmt->priv) / 8;
+	pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+	pfmt->field = V4L2_FIELD_NONE;
+	memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
 
-		cam->stream = stream;
+	if (copy_to_user(arg, &format, sizeof(format)))
+		return -EFAULT;
 
-		return 0;
-	}
+	return 0;
+}
 
-	case VIDIOC_ENUM_FMT:
-	{
-		struct v4l2_fmtdesc fmtd;
 
-		if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-			return -EFAULT;
+static int
+sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
+                         void __user * arg)
+{
+	struct sn9c102_sensor* s = cam->sensor;
+	struct v4l2_format format;
+	struct v4l2_pix_format* pix;
+	struct v4l2_pix_format* pfmt = &(s->pix_format);
+	struct v4l2_rect* bounds = &(s->cropcap.bounds);
+	struct v4l2_rect rect;
+	u8 scale;
+	const enum sn9c102_stream_state stream = cam->stream;
+	const u32 nbuffers = cam->nbuffers;
+	u32 i;
+	int err = 0;
 
-		if (fmtd.index == 0) {
-			strcpy(fmtd.description, "bayer rgb");
-			fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
-		} else if (fmtd.index == 1) {
-			strcpy(fmtd.description, "compressed");
-			fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
-			fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-		} else
-			return -EINVAL;
+	if (copy_from_user(&format, arg, sizeof(format)))
+		return -EFAULT;
 
-		fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+	pix = &(format.fmt.pix);
 
-		if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-			return -EFAULT;
+	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
 
-		return 0;
+	memcpy(&rect, &(s->_rect), sizeof(rect));
+
+	{ /* calculate the actual scaling factor */
+		u32 a, b;
+		a = rect.width * rect.height;
+		b = pix->width * pix->height;
+		scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
 	}
 
-	case VIDIOC_G_FMT:
-	{
-		struct v4l2_format format;
-		struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
+	rect.width = scale * pix->width;
+	rect.height = scale * pix->height;
 
-		if (copy_from_user(&format, arg, sizeof(format)))
-			return -EFAULT;
+	if (rect.width < 16)
+		rect.width = 16;
+	if (rect.height < 16)
+		rect.height = 16;
+	if (rect.width > bounds->left + bounds->width - rect.left)
+		rect.width = bounds->left + bounds->width - rect.left;
+	if (rect.height > bounds->top + bounds->height - rect.top)
+		rect.height = bounds->top + bounds->height - rect.top;
 
-		if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
+	rect.width &= ~15L;
+	rect.height &= ~15L;
+
+	{ /* adjust the scaling factor */
+		u32 a, b;
+		a = rect.width * rect.height;
+		b = pix->width * pix->height;
+		scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+	}
+
+	pix->width = rect.width / scale;
+	pix->height = rect.height / scale;
 
-		pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
-		                     ? 0 : (pfmt->width * pfmt->priv) / 8;
-		pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-		pfmt->field = V4L2_FIELD_NONE;
-		memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+	if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
+	    pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+		pix->pixelformat = pfmt->pixelformat;
+	pix->priv = pfmt->priv; /* bpp */
+	pix->colorspace = pfmt->colorspace;
+	pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+	                    ? 0 : (pix->width * pix->priv) / 8;
+	pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+	pix->field = V4L2_FIELD_NONE;
 
+	if (cmd == VIDIOC_TRY_FMT) {
 		if (copy_to_user(arg, &format, sizeof(format)))
 			return -EFAULT;
-
 		return 0;
 	}
 
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_S_FMT:
-	{
-		struct sn9c102_sensor* s = cam->sensor;
-		struct v4l2_format format;
-		struct v4l2_pix_format* pix;
-		struct v4l2_pix_format* pfmt = &(s->pix_format);
-		struct v4l2_rect* bounds = &(s->cropcap.bounds);
-		struct v4l2_rect rect;
-		u8 scale;
-		const enum sn9c102_stream_state stream = cam->stream;
-		const u32 nbuffers = cam->nbuffers;
-		u32 i;
-		int err = 0;
-
-		if (copy_from_user(&format, arg, sizeof(format)))
-			return -EFAULT;
+	if (cam->module_param.force_munmap)
+		for (i = 0; i < cam->nbuffers; i++)
+			if (cam->frame[i].vma_use_count) {
+				DBG(3, "VIDIOC_S_FMT failed. Unmap the "
+				       "buffers first.");
+				return -EINVAL;
+			}
 
-		pix = &(format.fmt.pix);
+	if (cam->stream == STREAM_ON)
+		if ((err = sn9c102_stream_interrupt(cam)))
+			return err;
 
-		if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
+	if (copy_to_user(arg, &format, sizeof(format))) {
+		cam->stream = stream;
+		return -EFAULT;
+	}
 
-		memcpy(&rect, &(s->_rect), sizeof(rect));
+	if (cam->module_param.force_munmap  || cam->io == IO_READ)
+		sn9c102_release_buffers(cam);
 
-		{ /* calculate the actual scaling factor */
-			u32 a, b;
-			a = rect.width * rect.height;
-			b = pix->width * pix->height;
-			scale = b ? (u8)((a / b) < 4 ? 1 :
-		                        ((a / b) < 16 ? 2 : 4)) : 1;
-		}
+	err += sn9c102_set_pix_format(cam, pix);
+	err += sn9c102_set_crop(cam, &rect);
+	if (s->set_pix_format)
+		err += s->set_pix_format(cam, pix);
+	if (s->set_crop)
+		err += s->set_crop(cam, &rect);
+	err += sn9c102_set_scale(cam, scale);
 
-		rect.width = scale * pix->width;
-		rect.height = scale * pix->height;
-
-		if (rect.width < 16)
-			rect.width = 16;
-		if (rect.height < 16)
-			rect.height = 16;
-		if (rect.width > bounds->left + bounds->width - rect.left)
-			rect.width = bounds->left + bounds->width - rect.left;
-		if (rect.height > bounds->top + bounds->height - rect.top)
-			rect.height = bounds->top + bounds->height - rect.top;
-
-		rect.width &= ~15L;
-		rect.height &= ~15L;
-
-		{ /* adjust the scaling factor */
-			u32 a, b;
-			a = rect.width * rect.height;
-			b = pix->width * pix->height;
-			scale = b ? (u8)((a / b) < 4 ? 1 :
-		                        ((a / b) < 16 ? 2 : 4)) : 1;
-		}
+	if (err) { /* atomic, no rollback in ioctl() */
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+		       "use the camera, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -EIO;
+	}
 
-		pix->width = rect.width / scale;
-		pix->height = rect.height / scale;
-
-		if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
-		    pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
-			pix->pixelformat = pfmt->pixelformat;
-		pix->priv = pfmt->priv; /* bpp */
-		pix->colorspace = pfmt->colorspace;
-		pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-		                    ? 0 : (pix->width * pix->priv) / 8;
-		pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-		pix->field = V4L2_FIELD_NONE;
-
-		if (cmd == VIDIOC_TRY_FMT) {
-			if (copy_to_user(arg, &format, sizeof(format)))
-				return -EFAULT;
-			return 0;
-		}
+	memcpy(pfmt, pix, sizeof(*pix));
+	memcpy(&(s->_rect), &rect, sizeof(rect));
 
-		if (cam->module_param.force_munmap)
-			for (i = 0; i < cam->nbuffers; i++)
-				if (cam->frame[i].vma_use_count) {
-					DBG(3, "VIDIOC_S_FMT failed. "
-					       "Unmap the buffers first.")
-					return -EINVAL;
-				}
+	if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+	    nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+		       "use the camera, close and open /dev/video%d again.",
+		    cam->v4ldev->minor);
+		return -ENOMEM;
+	}
 
-		if (cam->stream == STREAM_ON)
-			if ((err = sn9c102_stream_interrupt(cam)))
-				return err;
+	if (cam->io == IO_READ)
+		sn9c102_empty_framequeues(cam);
+	else if (cam->module_param.force_munmap)
+		sn9c102_requeue_outqueue(cam);
 
-		if (copy_to_user(arg, &format, sizeof(format))) {
-			cam->stream = stream;
-			return -EFAULT;
-		}
+	cam->stream = stream;
 
-		if (cam->module_param.force_munmap  || cam->io == IO_READ)
-			sn9c102_release_buffers(cam);
-
-		err += sn9c102_set_pix_format(cam, pix);
-		err += sn9c102_set_crop(cam, &rect);
-		if (s->set_pix_format)
-			err += s->set_pix_format(cam, pix);
-		if (s->set_crop)
-			err += s->set_crop(cam, &rect);
-		err += sn9c102_set_scale(cam, scale);
-
-		if (err) { /* atomic, no rollback in ioctl() */
-			cam->state |= DEV_MISCONFIGURED;
-			DBG(1, "VIDIOC_S_FMT failed because of hardware "
-			       "problems. To use the camera, close and open "
-			       "/dev/video%d again.", cam->v4ldev->minor)
-			return -EIO;
-		}
+	return 0;
+}
 
-		memcpy(pfmt, pix, sizeof(*pix));
-		memcpy(&(s->_rect), &rect, sizeof(rect));
 
-		if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-		    nbuffers != sn9c102_request_buffers(cam, nbuffers,
-		                                        cam->io)) {
-			cam->state |= DEV_MISCONFIGURED;
-			DBG(1, "VIDIOC_S_FMT failed because of not enough "
-			       "memory. To use the camera, close and open "
-			       "/dev/video%d again.", cam->v4ldev->minor)
-			return -ENOMEM;
-		}
+static int
+sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+{
+	if (copy_to_user(arg, &cam->compression,
+	                 sizeof(cam->compression)))
+		return -EFAULT;
 
-		cam->stream = stream;
+	return 0;
+}
 
-		return 0;
-	}
 
-	case VIDIOC_G_JPEGCOMP:
-	{
-		if (copy_to_user(arg, &cam->compression,
-		                 sizeof(cam->compression)))
-			return -EFAULT;
+static int
+sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_jpegcompression jc;
+	const enum sn9c102_stream_state stream = cam->stream;
+	int err = 0;
 
-		return 0;
-	}
+	if (copy_from_user(&jc, arg, sizeof(jc)))
+		return -EFAULT;
 
-	case VIDIOC_S_JPEGCOMP:
-	{
-		struct v4l2_jpegcompression jc;
-		const enum sn9c102_stream_state stream = cam->stream;
-		int err = 0;
+	if (jc.quality != 0 && jc.quality != 1)
+		return -EINVAL;
 
-		if (copy_from_user(&jc, arg, sizeof(jc)))
-			return -EFAULT;
+	if (cam->stream == STREAM_ON)
+		if ((err = sn9c102_stream_interrupt(cam)))
+			return err;
 
-		if (jc.quality != 0 && jc.quality != 1)
-			return -EINVAL;
+	err += sn9c102_set_compression(cam, &jc);
+	if (err) { /* atomic, no rollback in ioctl() */
+		cam->state |= DEV_MISCONFIGURED;
+		DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+		       "problems. To use the camera, close and open "
+		       "/dev/video%d again.", cam->v4ldev->minor);
+		return -EIO;
+	}
 
-		if (cam->stream == STREAM_ON)
-			if ((err = sn9c102_stream_interrupt(cam)))
-				return err;
+	cam->compression.quality = jc.quality;
 
-		err += sn9c102_set_compression(cam, &jc);
-		if (err) { /* atomic, no rollback in ioctl() */
-			cam->state |= DEV_MISCONFIGURED;
-			DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-			       "problems. To use the camera, close and open "
-			       "/dev/video%d again.", cam->v4ldev->minor)
-			return -EIO;
-		}
+	cam->stream = stream;
 
-		cam->compression.quality = jc.quality;
+	return 0;
+}
 
-		cam->stream = stream;
 
-		return 0;
-	}
+static int
+sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_requestbuffers rb;
+	u32 i;
+	int err;
 
-	case VIDIOC_REQBUFS:
-	{
-		struct v4l2_requestbuffers rb;
-		u32 i;
-		int err;
+	if (copy_from_user(&rb, arg, sizeof(rb)))
+		return -EFAULT;
 
-		if (copy_from_user(&rb, arg, sizeof(rb)))
-			return -EFAULT;
+	if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    rb.memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
 
-		if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-		    rb.memory != V4L2_MEMORY_MMAP)
-			return -EINVAL;
+	if (cam->io == IO_READ) {
+		DBG(3, "Close and open the device again to choose the mmap "
+		       "I/O method");
+		return -EINVAL;
+	}
 
-		if (cam->io == IO_READ) {
-			DBG(3, "Close and open the device again to choose "
-			       "the mmap I/O method")
+	for (i = 0; i < cam->nbuffers; i++)
+		if (cam->frame[i].vma_use_count) {
+			DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
+			       "still mapped.");
 			return -EINVAL;
 		}
 
-		for (i = 0; i < cam->nbuffers; i++)
-			if (cam->frame[i].vma_use_count) {
-				DBG(3, "VIDIOC_REQBUFS failed. "
-				       "Previous buffers are still mapped.")
-				return -EINVAL;
-			}
+	if (cam->stream == STREAM_ON)
+		if ((err = sn9c102_stream_interrupt(cam)))
+			return err;
 
-		if (cam->stream == STREAM_ON)
-			if ((err = sn9c102_stream_interrupt(cam)))
-				return err;
+	sn9c102_empty_framequeues(cam);
 
-		sn9c102_empty_framequeues(cam);
+	sn9c102_release_buffers(cam);
+	if (rb.count)
+		rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
 
+	if (copy_to_user(arg, &rb, sizeof(rb))) {
 		sn9c102_release_buffers(cam);
-		if (rb.count)
-			rb.count = sn9c102_request_buffers(cam, rb.count,
-			                                   IO_MMAP);
+		cam->io = IO_NONE;
+		return -EFAULT;
+	}
 
-		if (copy_to_user(arg, &rb, sizeof(rb))) {
-			sn9c102_release_buffers(cam);
-			cam->io = IO_NONE;
-			return -EFAULT;
-		}
+	cam->io = rb.count ? IO_MMAP : IO_NONE;
 
-		cam->io = rb.count ? IO_MMAP : IO_NONE;
+	return 0;
+}
 
-		return 0;
-	}
 
-	case VIDIOC_QUERYBUF:
-	{
-		struct v4l2_buffer b;
+static int
+sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_buffer b;
 
-		if (copy_from_user(&b, arg, sizeof(b)))
-			return -EFAULT;
+	if (copy_from_user(&b, arg, sizeof(b)))
+		return -EFAULT;
 
-		if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-		    b.index >= cam->nbuffers || cam->io != IO_MMAP)
-			return -EINVAL;
+	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
+		return -EINVAL;
 
-		memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+	memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
 
-		if (cam->frame[b.index].vma_use_count)
-			b.flags |= V4L2_BUF_FLAG_MAPPED;
+	if (cam->frame[b.index].vma_use_count)
+		b.flags |= V4L2_BUF_FLAG_MAPPED;
 
-		if (cam->frame[b.index].state == F_DONE)
-			b.flags |= V4L2_BUF_FLAG_DONE;
-		else if (cam->frame[b.index].state != F_UNUSED)
-			b.flags |= V4L2_BUF_FLAG_QUEUED;
+	if (cam->frame[b.index].state == F_DONE)
+		b.flags |= V4L2_BUF_FLAG_DONE;
+	else if (cam->frame[b.index].state != F_UNUSED)
+		b.flags |= V4L2_BUF_FLAG_QUEUED;
 
-		if (copy_to_user(arg, &b, sizeof(b)))
-			return -EFAULT;
+	if (copy_to_user(arg, &b, sizeof(b)))
+		return -EFAULT;
 
-		return 0;
-	}
+	return 0;
+}
 
-	case VIDIOC_QBUF:
-	{
-		struct v4l2_buffer b;
-		unsigned long lock_flags;
 
-		if (copy_from_user(&b, arg, sizeof(b)))
-			return -EFAULT;
+static int
+sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_buffer b;
+	unsigned long lock_flags;
 
-		if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-		    b.index >= cam->nbuffers || cam->io != IO_MMAP)
-			return -EINVAL;
+	if (copy_from_user(&b, arg, sizeof(b)))
+		return -EFAULT;
 
-		if (cam->frame[b.index].state != F_UNUSED)
-			return -EINVAL;
+	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    b.index >= cam->nbuffers || cam->io != IO_MMAP)
+		return -EINVAL;
 
-		cam->frame[b.index].state = F_QUEUED;
+	if (cam->frame[b.index].state != F_UNUSED)
+		return -EINVAL;
 
-		spin_lock_irqsave(&cam->queue_lock, lock_flags);
-		list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-		spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+	cam->frame[b.index].state = F_QUEUED;
 
-		PDBGG("Frame #%lu queued", (unsigned long)b.index)
+	spin_lock_irqsave(&cam->queue_lock, lock_flags);
+	list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
 
-		return 0;
-	}
+	PDBGG("Frame #%lu queued", (unsigned long)b.index);
 
-	case VIDIOC_DQBUF:
-	{
-		struct v4l2_buffer b;
-		struct sn9c102_frame_t *f;
-		unsigned long lock_flags;
-		int err = 0;
+	return 0;
+}
 
-		if (copy_from_user(&b, arg, sizeof(b)))
-			return -EFAULT;
 
-		if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
+static int
+sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
+                     void __user * arg)
+{
+	struct v4l2_buffer b;
+	struct sn9c102_frame_t *f;
+	unsigned long lock_flags;
+	int err = 0;
+
+	if (copy_from_user(&b, arg, sizeof(b)))
+		return -EFAULT;
+
+	if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+		return -EINVAL;
+
+	if (list_empty(&cam->outqueue)) {
+		if (cam->stream == STREAM_OFF)
 			return -EINVAL;
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		err = wait_event_interruptible
+		      ( cam->wait_frame,
+		        (!list_empty(&cam->outqueue)) ||
+		        (cam->state & DEV_DISCONNECTED) ||
+		        (cam->state & DEV_MISCONFIGURED) );
+		if (err)
+			return err;
+		if (cam->state & DEV_DISCONNECTED)
+			return -ENODEV;
+		if (cam->state & DEV_MISCONFIGURED)
+			return -EIO;
+	}
 
-		if (list_empty(&cam->outqueue)) {
-			if (cam->stream == STREAM_OFF)
-				return -EINVAL;
-			if (filp->f_flags & O_NONBLOCK)
-				return -EAGAIN;
-			err = wait_event_interruptible
-			      ( cam->wait_frame, 
-			        (!list_empty(&cam->outqueue)) ||
-			        (cam->state & DEV_DISCONNECTED) ||
-			        (cam->state & DEV_MISCONFIGURED) );
-			if (err)
-				return err;
-			if (cam->state & DEV_DISCONNECTED)
-				return -ENODEV;
-			if (cam->state & DEV_MISCONFIGURED)
-				return -EIO;
-		}
+	spin_lock_irqsave(&cam->queue_lock, lock_flags);
+	f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
+	list_del(cam->outqueue.next);
+	spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
 
-		spin_lock_irqsave(&cam->queue_lock, lock_flags);
-		f = list_entry(cam->outqueue.next, struct sn9c102_frame_t,
-		               frame);
-		list_del(cam->outqueue.next);
-		spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+	f->state = F_UNUSED;
 
-		f->state = F_UNUSED;
+	memcpy(&b, &f->buf, sizeof(b));
+	if (f->vma_use_count)
+		b.flags |= V4L2_BUF_FLAG_MAPPED;
 
-		memcpy(&b, &f->buf, sizeof(b));
-		if (f->vma_use_count)
-			b.flags |= V4L2_BUF_FLAG_MAPPED;
+	if (copy_to_user(arg, &b, sizeof(b)))
+		return -EFAULT;
 
-		if (copy_to_user(arg, &b, sizeof(b)))
-			return -EFAULT;
+	PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
 
-		PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index)
+	return 0;
+}
 
-		return 0;
-	}
 
-	case VIDIOC_STREAMON:
-	{
-		int type;
+static int
+sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
+{
+	int type;
 
-		if (copy_from_user(&type, arg, sizeof(type)))
-			return -EFAULT;
+	if (copy_from_user(&type, arg, sizeof(type)))
+		return -EFAULT;
 
-		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-			return -EINVAL;
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+		return -EINVAL;
 
-		if (list_empty(&cam->inqueue))
-			return -EINVAL;
+	if (list_empty(&cam->inqueue))
+		return -EINVAL;
 
-		cam->stream = STREAM_ON;
+	cam->stream = STREAM_ON;
 
-		DBG(3, "Stream on")
+	DBG(3, "Stream on");
 
-		return 0;
-	}
+	return 0;
+}
 
-	case VIDIOC_STREAMOFF:
-	{
-		int type, err;
 
-		if (copy_from_user(&type, arg, sizeof(type)))
-			return -EFAULT;
+static int
+sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
+{
+	int type, err;
 
-		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-			return -EINVAL;
+	if (copy_from_user(&type, arg, sizeof(type)))
+		return -EFAULT;
 
-		if (cam->stream == STREAM_ON)
-			if ((err = sn9c102_stream_interrupt(cam)))
-				return err;
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+		return -EINVAL;
 
-		sn9c102_empty_framequeues(cam);
+	if (cam->stream == STREAM_ON)
+		if ((err = sn9c102_stream_interrupt(cam)))
+			return err;
 
-		DBG(3, "Stream off")
+	sn9c102_empty_framequeues(cam);
 
-		return 0;
-	}
+	DBG(3, "Stream off");
 
-	case VIDIOC_G_PARM:
-	{
-		struct v4l2_streamparm sp;
+	return 0;
+}
 
-		if (copy_from_user(&sp, arg, sizeof(sp)))
-			return -EFAULT;
 
-		if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
+static int
+sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_streamparm sp;
+
+	if (copy_from_user(&sp, arg, sizeof(sp)))
+		return -EFAULT;
+
+	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	sp.parm.capture.extendedmode = 0;
+	sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+	if (copy_to_user(arg, &sp, sizeof(sp)))
+		return -EFAULT;
+
+	return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
+{
+	struct v4l2_streamparm sp;
+
+	if (copy_from_user(&sp, arg, sizeof(sp)))
+		return -EFAULT;
+
+	if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	sp.parm.capture.extendedmode = 0;
 
-		sp.parm.capture.extendedmode = 0;
+	if (sp.parm.capture.readbuffers == 0)
 		sp.parm.capture.readbuffers = cam->nreadbuffers;
 
-		if (copy_to_user(arg, &sp, sizeof(sp)))
-			return -EFAULT;
+	if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
+		sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
 
-		return 0;
-	}
+	if (copy_to_user(arg, &sp, sizeof(sp)))
+		return -EFAULT;
 
-	case VIDIOC_S_PARM_OLD:
-	case VIDIOC_S_PARM:
-	{
-		struct v4l2_streamparm sp;
+	cam->nreadbuffers = sp.parm.capture.readbuffers;
 
-		if (copy_from_user(&sp, arg, sizeof(sp)))
-			return -EFAULT;
+	return 0;
+}
 
-		if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
 
-		sp.parm.capture.extendedmode = 0;
+static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
+                              unsigned int cmd, void __user * arg)
+{
+	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
 
-		if (sp.parm.capture.readbuffers == 0)
-			sp.parm.capture.readbuffers = cam->nreadbuffers;
+	switch (cmd) {
 
-		if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
-			sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
+	case VIDIOC_QUERYCAP:
+		return sn9c102_vidioc_querycap(cam, arg);
 
-		if (copy_to_user(arg, &sp, sizeof(sp)))
-			return -EFAULT;
+	case VIDIOC_ENUMINPUT:
+		return sn9c102_vidioc_enuminput(cam, arg);
 
-		cam->nreadbuffers = sp.parm.capture.readbuffers;
+	case VIDIOC_G_INPUT:
+	case VIDIOC_S_INPUT:
+		return sn9c102_vidioc_gs_input(cam, arg);
 
-		return 0;
-	}
+	case VIDIOC_QUERYCTRL:
+		return sn9c102_vidioc_query_ctrl(cam, arg);
+
+	case VIDIOC_G_CTRL:
+		return sn9c102_vidioc_g_ctrl(cam, arg);
+
+	case VIDIOC_S_CTRL_OLD:
+	case VIDIOC_S_CTRL:
+		return sn9c102_vidioc_s_ctrl(cam, arg);
+
+	case VIDIOC_CROPCAP_OLD:
+	case VIDIOC_CROPCAP:
+		return sn9c102_vidioc_cropcap(cam, arg);
+
+	case VIDIOC_G_CROP:
+		return sn9c102_vidioc_g_crop(cam, arg);
+
+	case VIDIOC_S_CROP:
+		return sn9c102_vidioc_s_crop(cam, arg);
+
+	case VIDIOC_ENUM_FMT:
+		return sn9c102_vidioc_enum_fmt(cam, arg);
+
+	case VIDIOC_G_FMT:
+		return sn9c102_vidioc_g_fmt(cam, arg);
+
+	case VIDIOC_TRY_FMT:
+	case VIDIOC_S_FMT:
+		return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);
+
+	case VIDIOC_G_JPEGCOMP:
+		return sn9c102_vidioc_g_jpegcomp(cam, arg);
+
+	case VIDIOC_S_JPEGCOMP:
+		return sn9c102_vidioc_s_jpegcomp(cam, arg);
+
+	case VIDIOC_REQBUFS:
+		return sn9c102_vidioc_reqbufs(cam, arg);
+
+	case VIDIOC_QUERYBUF:
+		return sn9c102_vidioc_querybuf(cam, arg);
+
+	case VIDIOC_QBUF:
+		return sn9c102_vidioc_qbuf(cam, arg);
+
+	case VIDIOC_DQBUF:
+		return sn9c102_vidioc_dqbuf(cam, filp, arg);
+
+	case VIDIOC_STREAMON:
+		return sn9c102_vidioc_streamon(cam, arg);
+
+	case VIDIOC_STREAMOFF:
+		return sn9c102_vidioc_streamoff(cam, arg);
+
+	case VIDIOC_G_PARM:
+		return sn9c102_vidioc_g_parm(cam, arg);
+
+	case VIDIOC_S_PARM_OLD:
+	case VIDIOC_S_PARM:
+		return sn9c102_vidioc_s_parm(cam, arg);
 
 	case VIDIOC_G_STD:
 	case VIDIOC_S_STD:
@@ -2499,13 +2696,14 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
 		return -ERESTARTSYS;
 
 	if (cam->state & DEV_DISCONNECTED) {
-		DBG(1, "Device not present")
+		DBG(1, "Device not present");
 		up(&cam->fileop_sem);
 		return -ENODEV;
 	}
 
 	if (cam->state & DEV_MISCONFIGURED) {
-		DBG(1, "The camera is misconfigured. Close and open it again.")
+		DBG(1, "The camera is misconfigured. Close and open it "
+		       "again.");
 		up(&cam->fileop_sem);
 		return -EIO;
 	}
@@ -2517,9 +2715,10 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
 	return err;
 }
 
+/*****************************************************************************/
 
 static struct file_operations sn9c102_fops = {
-	.owner =   THIS_MODULE,
+	.owner = THIS_MODULE,
 	.open =    sn9c102_open,
 	.release = sn9c102_release,
 	.ioctl =   sn9c102_ioctl,
@@ -2538,36 +2737,23 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct sn9c102_device* cam;
 	static unsigned int dev_nr = 0;
-	unsigned int i, n;
+	unsigned int i;
 	int err = 0, r;
 
-	n = ARRAY_SIZE(sn9c102_id_table);
-	for (i = 0; i < n-1; i++)
-		if (le16_to_cpu(udev->descriptor.idVendor) == 
-		    sn9c102_id_table[i].idVendor &&
-		    le16_to_cpu(udev->descriptor.idProduct) ==
-		    sn9c102_id_table[i].idProduct)
-			break;
-	if (i == n-1)
-		return -ENODEV;
-
 	if (!(cam = kmalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
 		return -ENOMEM;
-	memset(cam, 0, sizeof(*cam));
 
 	cam->usbdev = udev;
-
 	memcpy(&cam->dev, &udev->dev, sizeof(struct device));
 
 	if (!(cam->control_buffer = kmalloc(8, GFP_KERNEL))) {
-		DBG(1, "kmalloc() failed")
+		DBG(1, "kmalloc() failed");
 		err = -ENOMEM;
 		goto fail;
 	}
-	memset(cam->control_buffer, 0, 8);
 
 	if (!(cam->v4ldev = video_device_alloc())) {
-		DBG(1, "video_device_alloc() failed")
+		DBG(1, "video_device_alloc() failed");
 		err = -ENOMEM;
 		goto fail;
 	}
@@ -2577,25 +2763,22 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 	r = sn9c102_read_reg(cam, 0x00);
 	if (r < 0 || r != 0x10) {
 		DBG(1, "Sorry, this is not a SN9C10x based camera "
-		       "(vid/pid 0x%04X/0x%04X)",
-		    sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct)
+		       "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
 		err = -ENODEV;
 		goto fail;
 	}
 
-	cam->bridge = (sn9c102_id_table[i].idProduct & 0xffc0) == 0x6080 ?
+	cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
 	              BRIDGE_SN9C103 : BRIDGE_SN9C102;
 	switch (cam->bridge) {
 	case BRIDGE_SN9C101:
 	case BRIDGE_SN9C102:
 		DBG(2, "SN9C10[12] PC Camera Controller detected "
-		       "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
-		    sn9c102_id_table[i].idProduct)
+		       "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
 		break;
 	case BRIDGE_SN9C103:
 		DBG(2, "SN9C103 PC Camera Controller detected "
-		       "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
-		    sn9c102_id_table[i].idProduct)
+		       "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
 		break;
 	}
 
@@ -2606,17 +2789,17 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 	}
 
 	if (!err && cam->sensor) {
-		DBG(2, "%s image sensor detected", cam->sensor->name)
+		DBG(2, "%s image sensor detected", cam->sensor->name);
 		DBG(3, "Support for %s maintained by %s",
-		    cam->sensor->name, cam->sensor->maintainer)
+		    cam->sensor->name, cam->sensor->maintainer);
 	} else {
-		DBG(1, "No supported image sensor detected")
+		DBG(1, "No supported image sensor detected");
 		err = -ENODEV;
 		goto fail;
 	}
 
 	if (sn9c102_init(cam)) {
-		DBG(1, "Initialization failed. I will retry on open().")
+		DBG(1, "Initialization failed. I will retry on open().");
 		cam->state |= DEV_MISCONFIGURED;
 	}
 
@@ -2634,23 +2817,23 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
 	                            video_nr[dev_nr]);
 	if (err) {
-		DBG(1, "V4L2 device registration failed")
+		DBG(1, "V4L2 device registration failed");
 		if (err == -ENFILE && video_nr[dev_nr] == -1)
-			DBG(1, "Free /dev/videoX node not found")
+			DBG(1, "Free /dev/videoX node not found");
 		video_nr[dev_nr] = -1;
 		dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
 		up(&cam->dev_sem);
 		goto fail;
 	}
 
-	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor)
+	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
 
 	cam->module_param.force_munmap = force_munmap[dev_nr];
 
 	dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
 	sn9c102_create_sysfs(cam);
-	DBG(2, "Optional device control through 'sysfs' interface ready")
+	DBG(2, "Optional device control through 'sysfs' interface ready");
 
 	usb_set_intfdata(intf, cam);
 
@@ -2680,14 +2863,14 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
 
 	down(&cam->dev_sem); 
 
-	DBG(2, "Disconnecting %s...", cam->v4ldev->name)
+	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
 	wake_up_interruptible_all(&cam->open);
 
 	if (cam->users) {
 		DBG(2, "Device /dev/video%d is open! Deregistration and "
 		       "memory deallocation are deferred on close.",
-		    cam->v4ldev->minor)
+		    cam->v4ldev->minor);
 		cam->state |= DEV_MISCONFIGURED;
 		sn9c102_stop_transfer(cam);
 		cam->state |= DEV_DISCONNECTED;
@@ -2720,11 +2903,11 @@ static int __init sn9c102_module_init(void)
 {
 	int err = 0;
 
-	KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION)
-	KDBG(3, SN9C102_MODULE_AUTHOR)
+	KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);
+	KDBG(3, SN9C102_MODULE_AUTHOR);
 
 	if ((err = usb_register(&sn9c102_usb_driver)))
-		KDBG(1, "usb_register() failed")
+		KDBG(1, "usb_register() failed");
 
 	return err;
 }
diff --git a/drivers/usb/media/sn9c102_hv7131d.c b/drivers/usb/media/sn9c102_hv7131d.c
index 18070d5333cf..46c12ec3ca62 100644
--- a/drivers/usb/media/sn9c102_hv7131d.c
+++ b/drivers/usb/media/sn9c102_hv7131d.c
@@ -2,7 +2,7 @@
  * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera     *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
diff --git a/drivers/usb/media/sn9c102_mi0343.c b/drivers/usb/media/sn9c102_mi0343.c
index 86676abf3547..d9aa7a61095d 100644
--- a/drivers/usb/media/sn9c102_mi0343.c
+++ b/drivers/usb/media/sn9c102_mi0343.c
@@ -2,7 +2,7 @@
  * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera     *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c
index d27c5aedeaf8..4a36519b5af4 100644
--- a/drivers/usb/media/sn9c102_ov7630.c
+++ b/drivers/usb/media/sn9c102_ov7630.c
@@ -2,7 +2,7 @@
  * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera      *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2005 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
@@ -375,8 +375,10 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam)
 
 	sn9c102_attach_sensor(cam, &ov7630);
 
-	if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
-	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c)
+	if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c &&
+	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d &&
+	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
+	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0)
 		return -ENODEV;
 
 	err += sn9c102_write_reg(cam, 0x01, 0x01);
diff --git a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c
index 48e3ec39d4e2..b1dee78abe04 100644
--- a/drivers/usb/media/sn9c102_pas106b.c
+++ b/drivers/usb/media/sn9c102_pas106b.c
@@ -2,7 +2,7 @@
  * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera     *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h
index a45166c3488c..a0e561b2c852 100644
--- a/drivers/usb/media/sn9c102_sensor.h
+++ b/drivers/usb/media/sn9c102_sensor.h
@@ -1,7 +1,7 @@
 /***************************************************************************
  * API for image sensors connected to the SN9C10x PC Camera Controllers    *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
@@ -92,7 +92,18 @@ extern void
 sn9c102_attach_sensor(struct sn9c102_device* cam,
                       struct sn9c102_sensor* sensor);
 
-/* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/
+/*
+   Each SN9C10x camera has proper PID/VID identifiers.
+   SN9C103 supports multiple interfaces, but we only handle the video class
+   interface.
+*/
+#define SN9C102_USB_DEVICE(vend, prod, intclass)                              \
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
+	               USB_DEVICE_ID_MATCH_INT_CLASS,                         \
+	.idVendor = (vend),                                                   \
+	.idProduct = (prod),                                                  \
+	.bInterfaceClass = (intclass)
+
 #define SN9C102_ID_TABLE                                                      \
 static const struct usb_device_id sn9c102_id_table[] = {                      \
 	{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
@@ -107,33 +118,34 @@ static const struct usb_device_id sn9c102_id_table[] = {                      \
 	{ USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */                        \
 	{ USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */                         \
 	{ USB_DEVICE(0x0c45, 0x602d), },                                      \
+	{ USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */                         \
 	{ USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */                          \
-	{ USB_DEVICE(0x0c45, 0x6080), },                                      \
-	{ USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */              \
-	{ USB_DEVICE(0x0c45, 0x6083), }, /* HV7131[D|E1] */                   \
-	{ USB_DEVICE(0x0c45, 0x6088), },                                      \
-	{ USB_DEVICE(0x0c45, 0x608a), },                                      \
-	{ USB_DEVICE(0x0c45, 0x608b), },                                      \
-	{ USB_DEVICE(0x0c45, 0x608c), }, /* HV7131x */                        \
-	{ USB_DEVICE(0x0c45, 0x608e), }, /* CIS-VF10 */                       \
-	{ USB_DEVICE(0x0c45, 0x608f), }, /* OV7630 */                         \
-	{ USB_DEVICE(0x0c45, 0x60a0), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60a2), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60a3), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60a8), }, /* PAS106B */                        \
-	{ USB_DEVICE(0x0c45, 0x60aa), }, /* TAS5130D1B */                     \
-	{ USB_DEVICE(0x0c45, 0x60ab), }, /* TAS5110C1B */                     \
-	{ USB_DEVICE(0x0c45, 0x60ac), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60ae), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60af), }, /* PAS202BCB */                      \
-	{ USB_DEVICE(0x0c45, 0x60b0), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60b2), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60b3), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60b8), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60ba), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60bb), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60bc), },                                      \
-	{ USB_DEVICE(0x0c45, 0x60be), },                                      \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */  \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */     \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131x */          \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */          \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */       \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */       \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */       \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), },                        \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), },                        \
 	{ }                                                                   \
 };
 
@@ -177,6 +189,7 @@ extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value);
 extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
 
 /* I/O on registers in the bridge. Could be used by the sensor methods too */
+extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
 extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
 extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
 
diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c
index 8775999b5aff..32ddf236cafe 100644
--- a/drivers/usb/media/sn9c102_tas5110c1b.c
+++ b/drivers/usb/media/sn9c102_tas5110c1b.c
@@ -2,7 +2,7 @@
  * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera  *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *
diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c
index 927eafdd8c73..a0728f0ae00c 100644
--- a/drivers/usb/media/sn9c102_tas5130d1b.c
+++ b/drivers/usb/media/sn9c102_tas5130d1b.c
@@ -2,7 +2,7 @@
  * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera  *
  * Controllers                                                             *
  *                                                                         *
- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
  *                                                                         *
  * 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    *