[PATCH 1/1] V4L: stk11xx, add a new webcam driver

!MAILaRCHIVE_VOTE_RePLACE
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
To: Andrew Morton <akpm@...>
Cc: <linux-kernel@...>
Date: Sunday, August 26, 2007 - 10:09 am

Hi,

is it possible to have this driver in the -mm tree for testing purposes until
v4l library will be developped and image resize with bayer->rgb conversion
will be moved there? (Then, I'll push it through v4l people.)

--
stk11xx, add a new webcam driver

Adds support for stk1125, stk1135 and stkdcnew webcam built-in some
notebooks.

Signed-off-by: Jiri Slaby <jirislaby@gmail.com>

---
commit 926af968884e1e153ad2f91892ff71ec33005d22
tree f7d30907d7bd11128cd8f75a0aa2f3873c237980
parent c1b003cd9e5befbc3d915a9e37f46585127f9d1f
author Jiri Slaby <jirislaby@gmail.com> Sun, 26 Aug 2007 16:02:31 +0200
committer Jiri Slaby <jirislaby@gmail.com> Sun, 26 Aug 2007 16:02:31 +0200

 MAINTAINERS                        |    5 
 drivers/media/video/Kconfig        |    9 
 drivers/media/video/Makefile       |    4 
 drivers/media/video/stk1125.c      |  667 +++++++++++++++++++++++++
 drivers/media/video/stk1135.c      |  549 +++++++++++++++++++++
 drivers/media/video/stk11xx-core.c |  962 ++++++++++++++++++++++++++++++++++++
 drivers/media/video/stk11xx-v4l.c  |  790 ++++++++++++++++++++++++++++++
 drivers/media/video/stk11xx.h      |  217 ++++++++
 drivers/media/video/stkdcnew.c     |  669 +++++++++++++++++++++++++
 9 files changed, 3872 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index c986d11..40d7c56 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3525,6 +3525,11 @@ M:	chrisw@sous-sol.org
 L:	stable@kernel.org
 S:	Maintained
 
+STK11XX WEBCAM DRIVER
+P:	Jiri Slaby
+M:	jirislaby@gmail.com
+S:	Maintained
+
 TPM DEVICE DRIVER
 P:	Kylene Hall
 M:	tpmdd-devel@lists.sourceforge.net
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 0e1d2cc..c51dde9 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -809,6 +809,15 @@ config USB_ZR364XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called zr364xx.
 
+config USB_STK11XX
+	tristate "Syntek chip based webcams"
+	depends on VIDEO_V4L2
+	---help---
+	  This will add support for Syntek webcams such as dc1125, stk1135 and
+	  DC NEW. Some notebooks have these cards built-in in their displays.
+
+	  If you choose to build this as module, it will be called stk11xx.
+
 endif # V4L_USB_DRIVERS
 
 endif # VIDEO_CAPTURE_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 113e525..b2268c7 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -6,6 +6,8 @@ zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
 tuner-objs	:=	tuner-core.o tuner-types.o tuner-simple.o \
 			mt20xx.o tda8290.o tea5767.o tda9887.o
+stk11xx-objs	:=	stk11xx-core.o stk11xx-v4l.o stk1125.o stk1135.o \
+			stkdcnew.o
 
 tuner-$(CONFIG_TUNER_TEA5761)	+= tea5761.o
 
@@ -107,6 +109,8 @@ obj-$(CONFIG_USB_STV680)        += stv680.o
 obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
 obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
 
+obj-$(CONFIG_USB_STK11XX)	+= stk11xx.o
+
 obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
 obj-$(CONFIG_USB_PWC)           += pwc/
diff --git a/drivers/media/video/stk1125.c b/drivers/media/video/stk1125.c
new file mode 100644
index 0000000..ed3cc58
--- /dev/null
+++ b/drivers/media/video/stk1125.c
@@ -0,0 +1,667 @@
+/*
+ * STK-1125 part
+ *
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Based on Nicolas VIVIEN's driver
+ *
+ * Licences
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/types.h>
+
+#include "stk11xx.h"
+
+static int stk1125_load_microcode(struct stk11xx *dev)
+{
+	unsigned int i;
+	const u8 *values_204, *values_205;
+	int retok;
+
+	/* From 80x60 to 640x480 */
+	const u8 values_1_204[] = {
+		0x12, 0x11, 0x3b, 0x6a, 0x13, 0x10, 0x00, 0x01, 0x02, 0x13,
+		0x39, 0x38, 0x37, 0x35, 0x0e, 0x12, 0x04, 0x0c, 0x0d, 0x17,
+		0x18, 0x32, 0x19, 0x1a, 0x03, 0x1b, 0x16, 0x33, 0x34, 0x41,
+		0x96, 0x3d, 0x69, 0x3a, 0x8e, 0x3c, 0x8f, 0x8b, 0x8c, 0x94,
+		0x95, 0x40, 0x29, 0x0f, 0xa5, 0x1e, 0xa9, 0xaa, 0xab, 0x90,
+		0x91, 0x9f, 0xa0, 0x24, 0x25, 0x26, 0x14, 0x2a, 0x2b
+	};
+	const u8 values_1_205[] = {
+		0x45, 0x80, 0x01, 0x7d, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
+		0x50, 0x93, 0x00, 0x81, 0x20, 0x45, 0x00, 0x00, 0x00, 0x24,
+		0xc4, 0xb6, 0x00, 0x3c, 0x36, 0x00, 0x07, 0xe2, 0xbf, 0x00,
+		0x04, 0x19, 0x40, 0x0d, 0x00, 0x73, 0xdf, 0x06, 0x20, 0x88,
+		0x88, 0xc1, 0x3f, 0x42, 0x80, 0x04, 0xb8, 0x92, 0x0a, 0x00,
+		0x00, 0x00, 0x00, 0x68, 0x5c, 0xc3, 0x2e, 0x00, 0x00
+	};
+
+	/* From 800x600 to 1280x1024 */
+	const u8 values_2_204[] = {
+		0x12, 0x11, 0x3b, 0x6a, 0x13, 0x10, 0x00, 0x01, 0x02, 0x13,
+		0x39, 0x38, 0x37, 0x35, 0x0e, 0x12, 0x04, 0x0c, 0x0d, 0x17,
+		0x18, 0x32, 0x19, 0x1a, 0x03, 0x1b, 0x16, 0x33, 0x34, 0x41,
+		0x96, 0x3d, 0x69, 0x3a, 0x8e, 0x3c, 0x8f, 0x8b, 0x8c, 0x94,
+		0x95, 0x40, 0x29, 0x0f, 0xa5, 0x1e, 0xa9, 0xaa, 0xab, 0x90,
+		0x91, 0x9f, 0xa0, 0x24, 0x25, 0x26, 0x14, 0x2a, 0x2b
+	};
+	const u8 values_2_205[] = {
+		0x05, 0x80, 0x01, 0x7d, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80,
+		0x50, 0x93, 0x00, 0x81, 0x20, 0x05, 0x00, 0x00, 0x00, 0x1b,
+		0xbb, 0xa4, 0x01, 0x81, 0x12, 0x00, 0x07, 0xe2, 0xbf, 0x00,
+		0x04, 0x19, 0x40, 0x0d, 0x00, 0x73, 0xdf, 0x06, 0x20, 0x88,
+		0x88, 0xc1, 0x3f, 0x42, 0x80, 0x04, 0xb8, 0x92, 0x0a, 0x00,
+		0x00, 0x00, 0x00, 0x68, 0x5c, 0xc3, 0x2e, 0x00, 0x00
+	};
+
+	/* From the resolution */
+	switch (dev->resolution) {
+	case STK11XX_1280x1024:
+	case STK11XX_1024x768:
+	case STK11XX_800x600:
+		values_204 = values_2_204;
+		values_205 = values_2_205;
+		break;
+
+	case STK11XX_640x480:
+	case STK11XX_320x240:
+	case STK11XX_160x120:
+	case STK11XX_80x60:
+	default:
+		values_204 = values_1_204;
+		values_205 = values_1_205;
+		break;
+	}
+
+	for (i = 0; i < 59; i++) {
+		stk11xx_read_dummy(dev, 0x02ff);
+		stk11xx_write_reg(dev, 0x02ff, 0x00);
+
+		stk11xx_write_reg(dev, 0x0204, values_204[i]);
+		stk11xx_write_reg(dev, 0x0205, values_205[i]);
+		stk11xx_write_reg(dev, 0x0200, 0x01);
+
+		retok = stk11xx_check_device(dev, 500);
+		if (retok != 1) {
+			dev_err(&dev->udev->dev, "load microcode fail\n");
+			return -EIO;
+		}
+
+		stk11xx_write_reg(dev, 0x02ff, 0x00);
+	}
+
+	stk11xx_check_device(dev, 500);
+
+	return 0;
+}
+
+/*
+ * The configuration of device is composed of 11 steps.
+ * This function is called by the initialization process.
+ *
+ * We don't know the meaning of these steps! We only replay the USB log.
+ *
+ * The steps 0 to 9 are called during the initialization.
+ * Then, the driver choose the last step :
+ *   10 : for a resolution from 80x60 to 640x480
+ *   11 : for a resolution from 800x600 to 1280x1024
+ */
+static int stk1125_dev_configure(struct stk11xx *dev, unsigned int step)
+{
+	int ret;
+	/*      0,    1,    2,    3,    4,    5,    6,    7,    8,    9,
+		10,   11 */
+
+	const u8 vals_001B[] = {
+		0x0e, 0x03, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+		0x0e, 0x0e
+	};
+	const u8 vals_001C[] = {
+		0x06, 0x02, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
+		0x46, 0x0e
+	};
+	const u8 vals_0202[] = {
+		0x1e, 0x0a, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+		0x1e, 0x1e
+	};
+	const u8 vals_0110[] = {
+		0x07, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x00, 0x00, 0x00,
+		0x00, 0x00
+	};
+	const u8 vals_0112[] = {
+		0x07, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x00, 0x00, 0x00,
+		0x00, 0x00
+	};
+	const u8 vals_0114[] = {
+		0x87, 0x80, 0x80, 0x80, 0x80, 0xbe, 0xbe, 0x80, 0x80, 0x80,
+		0x80, 0x00
+	};
+	const u8 vals_0115[] = {
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x05
+	};
+	const u8 vals_0116[] = {
+		0xe7, 0xe0, 0xe0, 0xe0, 0xe0, 0xe9, 0xe9, 0xe0, 0xe0, 0xe0,
+		0xe0, 0x00
+	};
+	const u8 vals_0117[] = {
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x04
+	};
+	const u8 vals_0100[] = {
+		0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+		0x21, 0x21
+	};
+	struct stk11xx_table table_1[] = {
+		{ 0x0000, 0x24, 2 }, { 0x0002, 0x68, 2 }, { 0x0003, 0x80, 2 },
+		{ 0x0005, 0x00, 2 }, { 0x0007, 0x03, 2 }, { 0x000d, 0x00, 2 },
+		{ 0x000f, 0x02, 2 }, { 0x0300, 0x12, 2 }, { 0x0350, 0x41, 2 },
+		{ 0x0351, 0x00, 2 }, { 0x0352, 0x00, 2 }, { 0x0353, 0x00, 2 },
+		{ 0x0018, 0x10, 2 }, { 0x0019, 0x00, 2 },
+		{ 0x001b, vals_001B[step], 2 }, { 0x001c, vals_001C[step], 2 },
+		{ 0x0300, 0x80, 2 }, { 0x001a, 0x04, 2 },
+		{ 0x0202, vals_0202[step], 2 },
+
+		{ 0x0110, vals_0110[step], 2 }, { 0x0111, 0x00, 2 },
+		{ 0x0112, vals_0112[step], 2 }, { 0x0113, 0x00, 2 },
+		{ 0x0114, vals_0114[step], 2 }, { 0x0115, vals_0115[step], 2 },
+		{ 0x0116, vals_0116[step], 2 }, { 0x0117, vals_0117[step], 2 },
+
+		{ 0x0100, 0x00, 1 },
+		{ 0x0100, vals_0100[step], 2 },
+
+		{ 0x0200, 0x80, 2 }, { 0x0200, 0x00, 2 }, { 0x02ff, 0x00, 2 },
+		{ }
+	};
+
+	dev_dbg(&dev->udev->dev, "%s: %u\n", __FUNCTION__, step);
+
+	ret = stk11xx_process_table(dev, table_1);
+	if (ret)
+		goto err;
+
+
+	switch (step) {
+	case 0: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x40, 2 }, { 0x0204, 0x41, 2 },
+			{ 0x0205, 0x01, 2 }, { 0x0204, 0x1c, 2 },
+			{ 0x0205, 0x02, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 1: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x22, 2 }, { 0x0204, 0x27, 2 },
+			{ 0x0205, 0xa5, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 2: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x60, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xbf, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 3: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x42, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x24, 2 },
+			{ 0x0205, 0xa5, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 4: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x42, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xe0, 2 }, { 0x0204, 0x24, 2 },
+			{ 0x0205, 0xa5, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 5: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x60, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xff, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 6: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x60, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xff, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 7: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x60, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xb7, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 8:
+		stk11xx_write_reg(dev, 0x0203, 0x60);
+
+		ret = stk1125_load_microcode(dev);
+
+		stk11xx_write_reg(dev, 0x0200, 0x80);
+		stk11xx_write_reg(dev, 0x0200, 0x00);
+		stk11xx_write_reg(dev, 0x02ff, 0x01);
+		stk11xx_write_reg(dev, 0x0203, 0xa0);
+
+		break;
+
+	case 9:
+		stk11xx_write_reg(dev, 0x0203, 0x60);
+
+		ret = stk1125_load_microcode(dev);
+
+		stk11xx_write_reg(dev, 0x0104, 0x00);
+		stk11xx_write_reg(dev, 0x0105, 0x00);
+		stk11xx_write_reg(dev, 0x0106, 0x00);
+
+		break;
+
+	case 10:
+	case 11: {
+		const struct stk11xx_table table[] = {
+			{ 0x0106, 0x00, 2 }, { 0x02ff, 0x00, 1 },
+			{ 0x02ff, 0x00, 2 }, { 0x0204, 0x2a, 2 },
+			{ 0x0205, 0x00, 2 }, { 0x0200, 0x01, 2 },
+			{    500, 0x00, 3 }, { 0x02ff, 0x00, 2 },
+			{ 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+			{ 0x0204, 0x2b, 2 }, { 0x0205, 0x00, 2 },
+			{ 0x0200, 0x01, 2 }, {    500, 0x00, 3 },
+			{ 0x02ff, 0x00, 2 }, { }
+		};
+
+		stk11xx_write_reg(dev, 0x0203, 0x60);
+
+		ret = stk1125_load_microcode(dev);
+		if (ret)
+			goto err;
+
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	}
+err:
+	return ret;
+}
+
+static int stk1125_cam_asleep(struct stk11xx *dev)
+{
+	const struct stk11xx_table table[] = {
+		{ 0x0104, 0x00, 1 }, { 0x0105, 0x00, 1 }, { 0x0106, 0x00, 1 },
+		{ 0x0100, 0x21, 2 }, { 0x0116, 0x00, 2 }, { 0x0117, 0x00, 2 },
+		{ 0x0018, 0x00, 2 }, { 0x0000, 0x00, 1 }, { 0x0000, 0x4c, 2 },
+		{ }
+	};
+
+	return stk11xx_process_table(dev, table);
+}
+
+static u16 stk1125_get_fps_code(unsigned int fps)
+{
+	switch (fps) {
+	case 10:
+		return 0x0004;
+	case 15:
+		return 0x0002;
+	case 20:
+		return 0x0001;
+	default:
+	case 25:
+		return 0x6400;
+	case 30:
+		return 0x0000;
+	}
+}
+
+/*
+ * This functions permits to modify the settings :
+ *   - brightness
+ *   - contrast
+ *   - white balance
+ *   - ...
+ *
+ * 0x204 = 0xa1 : unknown (by default 0x00)
+ * 0x204 = 0x10 : contrast (by default 0x7c)
+ * 0x204 = 0x04 : Mode (unknown) (by default 0x00) (=> already looked 0x01 and
+ * 		  0x02)
+ * 0x204 = 0x00 : brightness / white balance (by default 0x00)
+ * 0x204 = 0x2e : Fps MSB (by default 0x01)
+ * 0x204 = 0x2d : Fps LSB (by default 0x00)
+ *
+ * 0x2e | 0x2d | Nbr fps
+ * -----+------+--------
+ * 0x00 | 0x00 |  30
+ * 0x00 | 0x64 |  25
+ * 0x01 | 0x00 |  20
+ * 0x02 | 0x00 |  15
+ * 0x03 | 0x00 |  12
+ * 0x04 | 0x00 |  10
+ */
+static int stk1125_cam_setting(struct stk11xx *dev)
+{
+	int ret;
+	u16 fps = stk1125_get_fps_code(dev->vsettings.fps);
+
+	struct stk11xx_table table_1[] = {
+		{ 0x0200, 0x00, 2 },
+		/* Unknown register */
+		{ 0x0204, 0xa1, 2 }, { 0x0205, 0x00, 2 },
+		/* Contrast register */
+		{ 0x0204, 0x10, 2 }, { 0x0205, dev->vsettings.contrast, 2 },
+		/* Unknown register */
+		{ 0x0204, 0x04, 2 }, { 0x0205, 0x00, 2 },
+		/* Whiteness register */
+		{ 0x0204, 0x00, 2 }, { 0x0205, dev->vsettings.whiteness, 2 },
+		{ 0x0204, 0x2e, 2 }, { 0x0205, fps & 0xff, 2 },
+		{ 0x0204, 0x2d, 2 }, { 0x0205, fps >> 8, 2 },
+		{ 0x0200, 0x06, 2 }, { }
+	};
+
+	ret = stk11xx_process_table(dev, table_1);
+	if (ret)
+		goto end;
+
+	dev_dbg(&dev->udev->dev, "set contrast: %d, whiteness: %d, ",
+			dev->vsettings.contrast, dev->vsettings.whiteness);
+
+	ret = stk11xx_check_device(dev, 500);
+	if (!ret)
+		dev_dbg(&dev->udev->dev, "find not 0x4 ... seems OK\n");
+	ret = 0;
+end:
+	return ret;
+}
+
+static int stk1125_cam_init(struct stk11xx *dev)
+{
+	int ret;
+
+	const struct stk11xx_table table[] = {
+		{ 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 }, { 0x0204, 0x2a, 2 },
+		{ 0x0205, 0x00, 2 }, { 0x0200, 0x01, 2 }, {    500, 0x00, 3 },
+		{ 0x02ff, 0x00, 2 }, { 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+		{ 0x0204, 0x2b, 2 }, { 0x0205, 0x00, 2 }, { 0x0200, 0x01, 2 },
+		{    500, 0x00, 3 }, { 0x02ff, 0x00, 2 },
+		{ }
+	};
+
+	stk1125_cam_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+	stk11xx_write_reg(dev, 0x0000, 0xe0);
+	stk11xx_write_reg(dev, 0x0002, 0xe8);
+	stk11xx_write_reg(dev, 0x0002, 0x68);
+	stk11xx_write_reg(dev, 0x0000, 0x20);
+
+	stk1125_dev_configure(dev, 9);
+
+	stk11xx_cam_off(dev);
+
+	ret = stk11xx_process_table(dev, table);
+	if (ret)
+		return ret;
+
+	return stk1125_cam_setting(dev);
+}
+
+static int stk1125_stream_start(struct stk11xx *dev)
+{
+	u8 value_116, value_117;
+
+	stk11xx_read_reg(dev, 0x0116, &value_116);
+	stk11xx_read_reg(dev, 0x0117, &value_117);
+
+	stk11xx_write_reg(dev, 0x0116, 0x00);
+	stk11xx_write_reg(dev, 0x0117, 0x00);
+
+	stk11xx_read_dummy(dev, 0x0100);	/* read 0x21 */
+	stk11xx_write_reg(dev, 0x0100, 0xa1);
+
+	stk11xx_write_reg(dev, 0x0116, value_116);
+	stk11xx_write_reg(dev, 0x0117, value_117);
+
+	return 0;
+}
+
+static int stk1125_stream_stop(struct stk11xx *dev)
+{
+	stk11xx_read_dummy(dev, 0x0100);
+	stk11xx_write_reg(dev, 0x0100, 0x21);
+
+	return 0;
+}
+
+static int stk1125_cam_reconf(struct stk11xx *dev)
+{
+	int step;
+
+	switch (dev->resolution) {
+	case STK11XX_1280x1024:
+	case STK11XX_1024x768:
+	case STK11XX_800x600:
+		step = 11;
+		break;
+
+	case STK11XX_640x480:
+	case STK11XX_320x240:
+	case STK11XX_160x120:
+	case STK11XX_80x60:
+	default:
+		step = 10;
+		break;
+	}
+
+	stk1125_dev_configure(dev, step);
+
+	return 0;
+}
+
+/* this function is written from the USB log */
+static int stk1125_dev_init(struct stk11xx *dev)
+{
+	unsigned int i;
+	int ret;
+	u8 value;
+
+	const struct stk11xx_table table_1[] = {
+		{ 0x0000, 0x24, 2 }, { 0x0002, 0x68, 2 }, { 0x0003, 0x80, 2 },
+		{ 0x0002, 0x6f, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0002, 0x6d, 2 },
+		{ 0x0000, 0x24, 2 },
+		{ }
+	};
+	const struct stk11xx_table table_2[] = {
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x20, 2 }, { 0x0002, 0x6f, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0002, 0x6d, 2 }, { 0x0000, 0x24, 2 },
+		{ }
+	};
+	const struct stk11xx_table table_3[] = {
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x20, 2 }, { 0x0002, 0x6f, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0002, 0x6d, 2 }, { 0x0000, 0x24, 2 },
+		{ }
+	};
+	const struct stk11xx_table table_4[] = {
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x20, 2 }, { 0x0002, 0x6f, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x20, 2 }, { 0x0117, 0x00, 2 },
+		{ 0x0103, 0x00, 1 }, { 0x0103, 0x01, 2 }, { 0x0103, 0x00, 1 },
+		{ 0x0103, 0x00, 2 }, { 0x0000, 0xe0, 2 }, { 0x0002, 0xe8, 2 },
+		{ 0x0002, 0x68, 2 }, { 0x0000, 0x20, 2 },
+
+		{      0, 0x00, 4 }, {    65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      1, 0x00, 4 }, {    65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+
+		{      2, 0x00, 4 }, {    500, 0x00, 3 }, { 0x02ff, 0x00, 1 },
+		{ 0x02ff, 0x00, 2 }, { 0x0208, 0x13, 2 }, { 0x0200, 0x20, 2 },
+		{    500, 0x00, 3 }, { 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+		{ 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 }, { 0x0208, 0x0a, 2 },
+		{ 0x0200, 0x20, 2 }, {    500, 0x00, 3 }, { 0x0209, 0x00, 1 },
+		{ 0x02ff, 0x00, 2 }, { 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+		{ 0x0208, 0x0b, 2 }, { 0x0200, 0x20, 2 }, {    500, 0x00, 3 },
+		{ 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+
+		{      3, 0x00, 4 }, {    65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      4, 0x00, 4 }, {    65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+
+		{      5, 0x00, 4 }, {    500, 0x00, 3 }, { 0x02ff, 0x00, 1 },
+		{ 0x02ff, 0x00, 2 }, { 0x0208, 0x13, 2 }, { 0x0200, 0x20, 2 },
+		{    500, 0x00, 3 }, { 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+		{ 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 }, { 0x0208, 0x0a, 2 },
+		{ 0x0200, 0x20, 2 }, {    500, 0x00, 3 }, { 0x0209, 0x00, 1 },
+		{ 0x02ff, 0x00, 2 }, { 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+		{ 0x0208, 0x0b, 2 }, { 0x0200, 0x20, 2 }, {    500, 0x00, 3 },
+		{ 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+
+		{      6, 0x00, 4 }, {    500, 0x00, 3 }, { 0x02ff, 0x00, 1 },
+		{ 0x02ff, 0x00, 2 }, { 0x0208, 0x13, 2 }, { 0x0200, 0x20, 2 },
+		{    500, 0x00, 3 }, { 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+		{ 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 }, { 0x0208, 0x0a, 2 },
+		{ 0x0200, 0x20, 2 }, {    500, 0x00, 3 }, { 0x0209, 0x00, 1 },
+		{ 0x02ff, 0x00, 2 }, { 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+		{ 0x0208, 0x0b, 2 }, { 0x0200, 0x20, 2 }, {    500, 0x00, 3 },
+		{ 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+
+		{      7, 0x00, 4 }, {    500, 0x00, 3 }, { 0x02ff, 0x00, 1 },
+		{ 0x02ff, 0x00, 2 }, { 0x0208, 0x13, 2 }, { 0x0200, 0x20, 2 },
+		{    500, 0x00, 3 }, { 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+		{ 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 }, { 0x0208, 0x0a, 2 },
+		{ 0x0200, 0x20, 2 }, {    500, 0x00, 3 }, { 0x0209, 0x00, 1 },
+		{ 0x02ff, 0x00, 2 }, { 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+		{ 0x0208, 0x0b, 2 }, { 0x0200, 0x20, 2 }, {    500, 0x00, 3 },
+		{ 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+
+		{ 0x0002, 0x6f, 2 }, { 0x0000, 0x24, 2 }, { 0x0002, 0x6d, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0000, 0x20, 2 },
+
+		{      8, 0x00, 4 },
+		{ }
+	};
+
+	ret = stk11xx_process_table(dev, table_1);
+	if (ret)
+		goto end;
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_reg(dev, 0x0000, 0x25);
+		stk11xx_write_reg(dev, 0x0000, 0x24);
+		stk11xx_read_reg(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 1: Read 0x0000 = %02x\n", value);
+	}
+
+	ret = stk11xx_process_table(dev, table_2);
+	if (ret)
+		goto end;
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_reg(dev, 0x0000, 0x25);
+		stk11xx_write_reg(dev, 0x0000, 0x24);
+		stk11xx_read_reg(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 2: Read 0x0000 = %02x\n", value);
+	}
+
+	ret = stk11xx_process_table(dev, table_3);
+	if (ret)
+		goto end;
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_reg(dev, 0x0000, 0x25);
+		stk11xx_write_reg(dev, 0x0000, 0x24);
+		stk11xx_read_reg(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 3: Read 0x0000 = %02x\n", value);
+	}
+
+	ret = stk11xx_process_table(dev, table_4);
+	if (ret)
+		goto end;
+
+	stk1125_cam_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+end:
+	return ret;
+}
+
+struct stk_model stk_model_1125 = {
+	.model = SYNTEK_STK1125,
+	.name = "1125",
+	.dev_init = stk1125_dev_init,
+	.dev_configure = stk1125_dev_configure,
+	.cam_init = stk1125_cam_init,
+	.cam_setting = stk1125_cam_setting,
+	.cam_asleep = stk1125_cam_asleep,
+	.cam_reconf = stk1125_cam_reconf,
+	.stream_start = stk1125_stream_start,
+	.stream_stop = stk1125_stream_stop,
+};
diff --git a/drivers/media/video/stk1135.c b/drivers/media/video/stk1135.c
new file mode 100644
index 0000000..c6e0361
--- /dev/null
+++ b/drivers/media/video/stk1135.c
@@ -0,0 +1,549 @@
+/*
+ * STK-1135 part
+ *
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Based on Nicolas VIVIEN's driver
+ *
+ * Licences
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/types.h>
+
+#include "stk11xx.h"
+
+static int stk1135_load_microcode(struct stk11xx *dev)
+{
+	unsigned int i;
+	int retok;
+
+	const u8 values_204[] = {
+		0x17, 0x19, 0xb4, 0xa6, 0x12, 0x13, 0x1e, 0x21, 0x24, 0x32,
+		0x36, 0x39, 0x4d, 0x53, 0x5d, 0x5f, 0x60, 0x61, 0x62, 0x63,
+		0x64, 0x65, 0x66, 0x82, 0x83, 0x85, 0x86, 0x89, 0x97, 0x98,
+		0xad, 0xae, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbf, 0x48, 0xd8,
+		0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+		0x80, 0x81, 0xd8, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,
+		0x7d, 0x7e, 0x7f, 0x80, 0x81, 0xd8, 0x76, 0x77, 0x78, 0x79,
+		0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x5c, 0xc0,
+		0x59, 0x5a, 0x5b, 0xd4, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
+		0x94, 0x95, 0x96, 0xb3, 0x73, 0x06, 0x07, 0x0b, 0x15, 0x20,
+		0x4e, 0x4f, 0x49, 0x4a, 0x4b, 0x4c, 0x46, 0x06, 0x07, 0xb9,
+		0xba, 0xbb, 0xbc, 0x61, 0x62, 0x65, 0x66
+	};
+	const u8 values_205[] = {
+		0x41, 0x41, 0x03, 0x06, 0x06, 0x08, 0x06, 0x00, 0x02, 0x69,
+		0x35, 0x60, 0xfe, 0x1c, 0x04, 0x08, 0x08, 0x08, 0x08, 0x00,
+		0x00, 0x10, 0x14, 0x01, 0x80, 0x0c, 0xb6, 0x00, 0x25, 0x25,
+		0x3f, 0x24, 0x10, 0x07, 0xcc, 0x1f, 0x30, 0x02, 0x9c, 0x80,
+		0x00, 0x0d, 0x18, 0x22, 0x2c, 0x3e, 0x4f, 0x6f, 0x8e, 0xac,
+		0xc8, 0xe5, 0xa0, 0x00, 0x0d, 0x18, 0x22, 0x2c, 0x3e, 0x4f,
+		0x6f, 0x8e, 0xac, 0xc8, 0xe5, 0xc0, 0x00, 0x0d, 0x18, 0x22,
+		0x2c, 0x3e, 0x4f, 0x6f, 0x8e, 0xac, 0xc8, 0xe5, 0x70, 0x18,
+		0x09, 0x07, 0x07, 0x3c, 0x3d, 0x95, 0x88, 0x89, 0x47, 0x9c,
+		0x81, 0x9c, 0x3d, 0x76, 0x76, 0x01, 0xf3, 0x05, 0x00, 0x44,
+		0x06, 0x0a, 0x96, 0x00, 0x7d, 0x00, 0x20, 0x01, 0xf3, 0x04,
+		0xe4, 0x09, 0xc8, 0x08, 0x08, 0x10, 0x14
+	};
+
+	for (i = 0; i < 117; i++) {
+		stk11xx_read_dummy(dev, 0x02ff);
+		stk11xx_write_reg(dev, 0x02ff, 0x00);
+
+		stk11xx_write_reg(dev, 0x0204, values_204[i]);
+		stk11xx_write_reg(dev, 0x0205, values_205[i]);
+		stk11xx_write_reg(dev, 0x0200, 0x01);
+
+		retok = stk11xx_check_device(dev, 500);
+		if (retok != 1) {
+			dev_err(&dev->udev->dev, "load microcode failed\n");
+			return -EIO;
+		}
+
+		stk11xx_write_reg(dev, 0x02ff, 0x00);
+	}
+
+	stk11xx_check_device(dev, 500);
+
+	return 0;
+}
+
+/*
+ * The configuration of device is composed of 12 steps.
+ * This function is called by the initialization process.
+ *
+ * We don't know the meaning of these steps! We only replay the USB log.
+ */
+static int stk1135_dev_configure(struct stk11xx *dev, unsigned int step)
+{
+	int ret;
+	/*      0,    1,    2,    3,    4,    5,    6,    7,    8,    9,
+		10,   11,   12,   13 */
+
+	const u8 vals_001B[] = {
+		0x0e, 0x03, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x07,
+		0x07, 0x07, 0x07, 0x07
+	};
+	const u8 vals_001C[] = {
+		0x06, 0x02, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x06, 0x06,
+		0x06, 0x06, 0x06, 0x06
+	};
+	const u8 vals_0202[] = {
+		0x1e, 0x0a, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+		0x1e, 0x1e, 0x1e, 0x1e
+	};
+	const u8 vals_0110[] = {
+		0x07, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x00, 0x04, 0x00,
+		0x00, 0x00, 0x00, 0x00
+	};
+	const u8 vals_0112[] = {
+		0x07, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x00, 0x04, 0x00,
+		0x00, 0x00, 0x00, 0x00
+	};
+	const u8 vals_0114[] = {
+		0x87, 0x80, 0x80, 0x80, 0x80, 0xbe, 0xbe, 0x80, 0x84, 0x80,
+		0x80, 0x80, 0x80, 0x80
+	};
+	const u8 vals_0116[] = {
+		0xe7, 0xe0, 0xe0, 0xe0, 0xe0, 0xe9, 0xe9, 0xe0, 0xe4, 0xe0,
+		0xe0, 0xe0, 0xe0, 0xe0
+	};
+	const u8 vals_0100[] = {
+		0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x20,
+		0x20, 0x20, 0x20, 0x20
+	};
+	struct stk11xx_table table_1[] = {
+		{ 0x0000, 0x24, 2 }, { 0x0002, 0x68, 2 }, { 0x0003, 0x80, 2 },
+		{ 0x0005, 0x00, 2 }, { 0x0007, 0x03, 2 }, { 0x000d, 0x00, 2 },
+		{ 0x000f, 0x02, 2 }, { 0x0300, 0x12, 2 }, { 0x0350, 0x41, 2 },
+		{ 0x0351, 0x00, 2 }, { 0x0352, 0x00, 2 }, { 0x0353, 0x00, 2 },
+		{ 0x0018, 0x10, 2 }, { 0x0019, 0x00, 2 },
+
+		{ 0x001b, vals_001B[step], 2 }, { 0x001c, vals_001C[step], 2 },
+		{ 0x0300, 0x80, 2 }, { 0x001a, 0x04, 2 },
+		{ 0x0202, vals_0202[step], 2 },
+
+		{ 0x0110, vals_0110[step], 2 }, { 0x0111, 0x00, 2 },
+		{ 0x0112, vals_0112[step], 2 }, { 0x0113, 0x00, 2 },
+		{ 0x0114, vals_0114[step], 2 }, { 0x0115, 0x02, 2 },
+		{ 0x0116, vals_0116[step], 2 }, { 0x0117, 0x01, 2 },
+
+		{ 0x0100, 0x00, 1 }, { 0x0100, vals_0100[step], 2 },
+
+		{ 0x0200, 0x80, 2 }, { 0x0200, 0x00, 2 }, { 0x02ff, 0x00, 2 },
+		{ }
+	};
+
+	dev_dbg(&dev->udev->dev, "stk1135_dev_configure: %d\n", step);
+
+	ret = stk11xx_process_table(dev, table_1);
+	if (ret)
+		goto err;
+
+	switch (step) {
+	case 0: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x40, 2 }, { 0x0204, 0x41, 2 },
+			{ 0x0205, 0x01, 2 }, { 0x0204, 0x1c, 2 },
+			{ 0x0205, 0x02, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 1: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x22, 2 }, { 0x0204, 0x27, 2 },
+			{ 0x0205, 0xa5, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 2: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x60, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xbf, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 3: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x42, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x24, 2 },
+			{ 0x0205, 0xa5, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 4: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x42, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xe0, 2 }, { 0x0204, 0x24, 2 },
+			{ 0x0205, 0xa5, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 5: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x60, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xff, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 6: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x60, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xff, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 7: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x60, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x13, 2 },
+			{ 0x0205, 0xb7, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 8: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0x80, 2 }, { 0x0204, 0x12, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0204, 0x0a, 2 },
+			{ 0x0205, 0xff, 2 }, { 0x0200, 0x05, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 9: {
+		const struct stk11xx_table table[] = {
+			{ 0x0203, 0xdc, 2 }, { 0x0204, 0x15, 2 },
+			{ 0x0205, 0x80, 2 }, { 0x0200, 0x05, 2 },
+			{    500, 0x00, 3 }, { 0x02ff, 0x00, 1 },
+			{ 0x02ff, 0x00, 2 }, { 0x0208, 0x00, 2 },
+			{ 0x0200, 0x20, 2 }, {    500, 0x00, 3 },
+			{ 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+			{ 0x02ff, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+			{ 0x0208, 0x01, 2 }, { 0x0200, 0x20, 2 },
+			{    500, 0x00, 3 }, { 0x0209, 0x00, 1 },
+			{ 0x02ff, 0x00, 2 }, { 0x02ff, 0x00, 1 },
+			{ 0x02ff, 0x00, 2 }, { 0x0208, 0x02, 2 },
+			{ 0x0200, 0x20, 2 }, {    500, 0x00, 3 },
+			{ 0x0209, 0x00, 1 }, { 0x02ff, 0x00, 2 },
+			{ 0x0002, 0x6f, 2 }, { }
+		};
+		ret = stk11xx_process_table(dev, table);
+
+		break;
+	}
+	case 10:
+		stk11xx_write_reg(dev, 0x0203, 0xdc);
+
+		ret = stk1135_load_microcode(dev);
+
+		break;
+
+	case 11:
+		stk11xx_write_reg(dev, 0x0203, 0xdc);
+
+		ret = stk1135_load_microcode(dev);
+
+		stk11xx_write_reg(dev, 0x0104, 0x00);
+		stk11xx_write_reg(dev, 0x0105, 0x00);
+		stk11xx_write_reg(dev, 0x0106, 0x00);
+
+		break;
+
+	case 12:
+		stk11xx_write_reg(dev, 0x0203, 0xdc);
+
+		ret = stk1135_load_microcode(dev);
+
+		stk11xx_write_reg(dev, 0x0104, 0x00);
+		stk11xx_write_reg(dev, 0x0105, 0x00);
+		stk11xx_write_reg(dev, 0x0106, 0x00);
+
+		break;
+
+	case 13:
+		stk11xx_write_reg(dev, 0x0203, 0xdc);
+
+		ret = stk1135_load_microcode(dev);
+
+		stk11xx_write_reg(dev, 0x0106, 0x00);
+
+		break;
+	}
+
+err:
+	return ret;
+}
+
+static int stk1135_cam_asleep(struct stk11xx *dev)
+{
+	const struct stk11xx_table table[] = {
+		{ 0x0104, 0x00, 1 }, { 0x0105, 0x00, 1 }, { 0x0106, 0x00, 1 },
+		{ 0x0100, 0x21, 2 }, { 0x0116, 0x00, 2 }, { 0x0117, 0x00, 2 },
+		{ 0x0018, 0x00, 2 }, { 0x0000, 0x00, 1 }, { 0x0000, 0x49, 2 },
+		{ }
+	};
+
+	return stk11xx_process_table(dev, table);
+}
+
+static int stk1135_cam_setting(struct stk11xx *dev)
+{
+	unsigned int i;
+
+	const u8 values_204[] = {
+		0xb3, 0x73, 0x46, 0x06, 0x07, 0xb9, 0xba, 0xbb, 0xbc, 0x61,
+		0x62, 0x65, 0x66
+	};
+	const u8 values_205[] = {
+		0x76, 0x76, 0x20, 0x01, 0xf3, 0x04, 0xe4, 0x09, 0xc8, 0x08,
+		0x08, 0x10, 0x14
+	};
+
+	for (i = 0; i < ARRAY_SIZE(values_204); i++) {
+		stk11xx_read_dummy(dev, 0x02ff);
+		stk11xx_write_reg(dev, 0x02ff, 0x00);
+
+		stk11xx_write_reg(dev, 0x0204, values_204[i]);
+		stk11xx_write_reg(dev, 0x0205, values_205[i]);
+
+		stk11xx_write_reg(dev, 0x0200, 0x01);
+		stk11xx_check_device(dev, 500);
+		stk11xx_write_reg(dev, 0x02ff, 0x00);
+	}
+
+	return 0;
+}
+
+static int stk1135_cam_init(struct stk11xx *dev)
+{
+	stk1135_cam_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+	stk11xx_write_reg(dev, 0x0000, 0xe0);
+	stk11xx_write_reg(dev, 0x0002, 0xe8);
+	stk11xx_write_reg(dev, 0x0002, 0x68);
+	stk11xx_write_reg(dev, 0x0000, 0x20);
+
+	stk1135_dev_configure(dev, 11);
+
+	stk11xx_cam_off(dev);
+	stk1135_cam_setting(dev);
+	stk1135_cam_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+	stk11xx_write_reg(dev, 0x0000, 0xe0);
+	stk11xx_write_reg(dev, 0x0002, 0xe8);
+	stk11xx_write_reg(dev, 0x0002, 0x68);
+	stk11xx_write_reg(dev, 0x0000, 0x20);
+
+	stk1135_dev_configure(dev, 12);
+
+	stk11xx_cam_off(dev);
+	stk1135_cam_setting(dev);
+
+	return 0;
+}
+
+static int stk1135_cam_reconf(struct stk11xx *dev)
+{
+	stk1135_dev_configure(dev, 13);
+
+	return 0;
+}
+
+static int stk1135_stream_start(struct stk11xx *dev)
+{
+	u8 value_116, value_117;
+
+	stk11xx_read_reg(dev, 0x0116, &value_116);
+	stk11xx_read_reg(dev, 0x0117, &value_117);
+
+	stk11xx_write_reg(dev, 0x0116, 0x00);
+	stk11xx_write_reg(dev, 0x0117, 0x00);
+
+	stk11xx_read_dummy(dev, 0x0100);	/* read 0x21 */
+	stk11xx_write_reg(dev, 0x0100, 0xa0);
+
+	stk11xx_write_reg(dev, 0x0116, value_116);
+	stk11xx_write_reg(dev, 0x0117, value_117);
+
+	return 0;
+}
+
+static int stk1135_stream_stop(struct stk11xx *dev)
+{
+	stk11xx_read_dummy(dev, 0x0100);
+	stk11xx_write_reg(dev, 0x0100, 0x20);
+
+	return 0;
+}
+
+/* this function is written from the USB log */
+static int stk1135_dev_init(struct stk11xx *dev)
+{
+	unsigned int i;
+	int ret;
+	u8 value;
+
+	const struct stk11xx_table table_1[] = {
+		{ 0x0000, 0x24, 2 }, { 0x0002, 0x68, 2 }, { 0x0003, 0x80, 2 },
+		{ 0x0002, 0x6f, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x26, 2 }, { 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0002, 0x6d, 2 },
+		{ 0x0000, 0x24, 2 },
+		{ }
+	};
+	const struct stk11xx_table table_2[] = {
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x20, 2 }, { 0x0002, 0x6f, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0002, 0x6d, 2 }, { 0x0000, 0x24, 2 },
+		{ }
+	};
+	const struct stk11xx_table table_3[] = {
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x20, 2 }, { 0x0002, 0x6f, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x24, 2 }, { 0x0000, 0x26, 2 },
+		{ 0x0000, 0x27, 2 }, { 0x0000, 0x26, 2 }, { 0x0000, 0x24, 2 },
+		{ 0x0000, 0x25, 2 }, { 0x0002, 0x6d, 2 }, { 0x0000, 0x24, 2 },
+		{ }
+	};
+	const struct stk11xx_table table_4[] = {
+		{ 0x0000, 0x25, 2 }, { 0x0000, 0x20, 2 }, { 0x0002, 0x6f, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x20, 2 }, { 0x0117, 0x00, 2 },
+		{ 0x0103, 0x00, 1 }, { 0x0103, 0x01, 2 }, { 0x0103, 0x00, 1 },
+		{ 0x0103, 0x00, 2 }, { 0x0000, 0xe0, 2 }, { 0x0002, 0xe8, 2 },
+		{ 0x0002, 0x68, 2 }, { 0x0000, 0x20, 2 },
+
+		{      0, 0x00, 4 }, {     65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      1, 0x00, 4 }, {     65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      2, 0x00, 4 }, {     65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      3, 0x00, 4 }, {     65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      4, 0x00, 4 }, {     65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      5, 0x00, 4 }, {     65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      6, 0x00, 4 }, {     65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      7, 0x00, 4 }, {     65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      8, 0x00, 4 }, {     65, 0x00, 3 }, { 0x0200, 0x08, 2 },
+		{      9, 0x00, 4 }, { 0x0000, 0x24, 2 }, { 0x0002, 0x6d, 2 },
+		{ 0x0000, 0x24, 2 }, { 0x0000, 0x25, 2 }, { 0x0000, 0x20, 2 },
+		{     10, 0x00, 4 }, { 0x0200, 0x80, 2 }, { 0x0200, 0x00, 2 },
+		{ 0x02ff, 0x01, 2 }, { 0x0203, 0xa0, 2 },
+		{ }
+	};
+
+	ret = stk11xx_process_table(dev, table_1);
+	if (ret)
+		goto end;
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_reg(dev, 0x0000, 0x25);
+		stk11xx_write_reg(dev, 0x0000, 0x24);
+		stk11xx_read_reg(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 1: Read 0x0000 = %02x\n", value);
+	}
+
+	ret = stk11xx_process_table(dev, table_2);
+	if (ret)
+		goto end;
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_reg(dev, 0x0000, 0x25);
+		stk11xx_write_reg(dev, 0x0000, 0x24);
+		stk11xx_read_reg(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 2: Read 0x0000 = %02x\n", value);
+	}
+
+	ret = stk11xx_process_table(dev, table_3);
+	if (ret)
+		goto end;
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_reg(dev, 0x0000, 0x25);
+		stk11xx_write_reg(dev, 0x0000, 0x24);
+		stk11xx_read_reg(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 3: Read 0x0000 = %02x\n", value);
+	}
+
+	ret = stk11xx_process_table(dev, table_4);
+	if (ret)
+		goto end;
+
+	stk1135_cam_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+end:
+	return ret;
+}
+
+struct stk_model stk_model_1135 = {
+	.model = SYNTEK_STK1135,
+	.name = "1135",
+	.dev_init = stk1135_dev_init,
+	.dev_configure = stk1135_dev_configure,
+	.cam_init = stk1135_cam_init,
+	.cam_setting = stk1135_cam_setting,
+	.cam_asleep = stk1135_cam_asleep,
+	.cam_reconf = stk1135_cam_reconf,
+	.stream_start = stk1135_stream_start,
+	.stream_stop = stk1135_stream_stop,
+};
diff --git a/drivers/media/video/stk11xx-core.c b/drivers/media/video/stk11xx-core.c
new file mode 100644
index 0000000..13549db
--- /dev/null
+++ b/drivers/media/video/stk11xx-core.c
@@ -0,0 +1,962 @@
+/*
+ * Driver for Syntek USB video camera
+ *
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Based on Nicolas VIVIEN's driver
+ *
+ * Licences
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/usb.h>
+#include <media/v4l2-common.h>
+
+#include "stk11xx.h"
+
+#define USB_SYNTEK1_VENDOR_ID		0x174f
+#define USB_SYNTEK2_VENDOR_ID		0x05e1
+
+#define USB_STK1125_PRODUCT_ID		0xa311
+#define USB_STK1135_PRODUCT_ID		0xa821
+#define USB_STKDCNEW_PRODUCT_ID		0x6a31
+#define USB_DC1125_PRODUCT_ID		0x0501
+
+static const struct stk11xx_coord stk11xx_image_sizes[STK11XX_NBR_SIZES] = {
+	{   80,   60 },
+	{  160,  120 },
+	{  320,  240 },
+	{  640,  480 },
+	{  800,  600 },
+	{ 1024,  768 },
+	{ 1280, 1024 }
+};
+
+static unsigned int fps = 10;
+module_param(fps, uint, 0444);
+MODULE_PARM_DESC(fps, "Frames per second [10-30]");
+
+int stk11xx_read_reg(struct stk11xx *dev, u16 index, u8 *value)
+{
+	struct usb_device *udev = dev->udev;
+	int result;
+
+	*value = 0;
+
+	result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x00,
+			index, value, sizeof(u8), 500);
+
+	if (result < 0)
+		dev_err(&udev->dev, "Read registry fails %02X\n", index);
+	else
+		result = 0;
+
+	return result;
+}
+
+int stk11xx_write_reg(struct stk11xx *dev, u16 index, u16 value)
+{
+	struct usb_device *udev = dev->udev;
+	int result;
+
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value,
+			index, NULL, 0, 500);
+
+	if (result < 0)
+		dev_err(&udev->dev, "Write registry fails %02X = %02X\n", index,
+				value);
+	else
+		result = 0;
+
+	return result;
+}
+
+int stk11xx_set_feature(struct stk11xx *dev, int index)
+{
+	struct usb_device *udev = dev->udev;
+	int result;
+
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				 USB_REQ_SET_FEATURE,
+				 USB_TYPE_STANDARD | USB_DIR_OUT |
+				 USB_RECIP_DEVICE, USB_DEVICE_REMOTE_WAKEUP,
+				 index, NULL, 0, 500);
+
+	if (result < 0)
+		dev_err(&udev->dev, "SET FEATURE fail !\n");
+
+	return result;
+}
+
+int stk11xx_process_table(struct stk11xx *dev,
+		const struct stk11xx_table *table)
+{
+	int ret = 0;
+
+	for (; table->type; table++)
+		switch (table->type) {
+		case 1:
+			ret = stk11xx_read_dummy(dev, table->addr);
+			break;
+		case 2:
+			ret = stk11xx_write_reg(dev, table->addr, table->val);
+			break;
+		case 3:
+			ret = stk11xx_check_device(dev, table->addr);
+			if (ret > 0)
+				ret = 0;
+			break;
+		case 4:
+			dev->model->dev_configure(dev, table->addr);
+			break;
+		}
+
+	return ret;
+}
+
+/*
+ * Bayer conversion
+ */
+
+#define STK11XX_AVG2(x, y) (u8)(((int)x + (int)y) / 2)
+#define STK11XX_AVG4(a, b, c, d) (u8)(((int)a + (int)b + (int)c + (int)d) / 4)
+
+static void stk11xx_bayer_to_rgb(u8 *rgb, const u8 *bayer,
+		  unsigned int width, unsigned int height, unsigned int factor)
+{
+	const u8 *src;
+	u8 *dst;
+	unsigned int x, y, pos, above, below;
+
+	/*
+	 * Picture from cam is vertically flipped and is of this form:
+	 * .   .      .
+	 * .   .    .
+	 * .   .  .
+	 * GRGRGR . . .
+	 * BGBGBG
+	 * GRGRGR . . .
+	 */
+	/* blit out initial data */
+	for (y = 0; y < height; y += factor) {
+		src = &bayer[(height - y - 1) * width];
+		dst = &rgb[y * width * 3 / (factor * factor)];
+		for (x = 0; x < width; x += factor, src += factor, dst += 3)
+			dst[!(y & 1) + (x & 1)] = *src;
+	}
+
+	/* blit in everything but the borders */
+	for (y = factor; y < height - factor; y += factor) {
+		pos = (height - y - 1) * width + factor;
+		dst = &rgb[y * width * 3 / (factor * factor) + 3];
+		for (x = factor; x < width - factor; x += factor, pos += factor,
+				dst += 3) {
+			above = pos - width;
+			below = pos + width;
+
+			if (y & 1) {
+				/* XGBGBG line */
+				if (x & 1) {	/* G is known */
+					dst[2] = STK11XX_AVG2( /* R */
+						bayer[above],	bayer[below]);
+					dst[0] = STK11XX_AVG2( /* B */
+						bayer[pos - 1],	bayer[pos + 1]);
+				} else {	/* B is known */
+					dst[2] = STK11XX_AVG4( /* R */
+						bayer[above-1],	bayer[above+1],
+						bayer[below-1],	bayer[below+1]);
+					dst[1] = STK11XX_AVG4( /* G */
+						bayer[above],	bayer[below],
+						bayer[pos - 1],	bayer[pos + 1]);
+				}
+			} else {
+				/* XRGRGR line */
+				if (x & 1) {	/* R is known */
+					dst[0] = STK11XX_AVG4( /* B */
+						bayer[above-1],	bayer[above+1],
+						bayer[below-1],	bayer[below+1]);
+					dst[1] = STK11XX_AVG4( /* G */
+						bayer[above],	bayer[below],
+						bayer[pos - 1],	bayer[pos + 1]);
+				} else {	/* G is known */
+					dst[0] = STK11XX_AVG2( /* B */
+						bayer[above], bayer[below]);
+					dst[2] = STK11XX_AVG2( /* R */
+						bayer[pos - 1],	bayer[pos + 1]);
+				}
+			}
+		}
+	}
+}
+
+int stk11xx_decompress(struct stk11xx *dev)
+{
+	struct stk11xx_frame_buf *framebuf = dev->read_frame;
+	void *data, *image = dev->image_data;
+	unsigned int width, height, factor;
+
+	if (framebuf == NULL)
+		return -EFAULT;
+
+	image += dev->images[dev->fill_image].offset;
+
+	data = framebuf->data;
+
+	switch (dev->resolution) {
+	case STK11XX_80x60:
+		factor = 8;
+		width = stk11xx_image_sizes[STK11XX_640x480].x;
+		height = stk11xx_image_sizes[STK11XX_640x480].y;
+		break;
+
+	case STK11XX_160x120:
+		factor = 4;
+		width = stk11xx_image_sizes[STK11XX_640x480].x;
+		height = stk11xx_image_sizes[STK11XX_640x480].y;
+		break;
+
+	case STK11XX_320x240:
+		factor = 2;
+		width = stk11xx_image_sizes[STK11XX_640x480].x;
+		height = stk11xx_image_sizes[STK11XX_640x480].y;
+		break;
+
+	case STK11XX_640x480:
+		factor = 1;
+		width = stk11xx_image_sizes[STK11XX_640x480].x;
+		height = stk11xx_image_sizes[STK11XX_640x480].y;
+		break;
+
+	case STK11XX_800x600:
+		factor = 1;
+		width = stk11xx_image_sizes[STK11XX_1280x1024].x;
+		height = stk11xx_image_sizes[STK11XX_1280x1024].y;
+		break;
+
+	case STK11XX_1024x768:
+		factor = 1;
+		width = stk11xx_image_sizes[STK11XX_1280x1024].x;
+		height = stk11xx_image_sizes[STK11XX_1280x1024].y;
+		break;
+
+	case STK11XX_1280x1024:
+		factor = 1;
+		width = stk11xx_image_sizes[STK11XX_1280x1024].x;
+		height = stk11xx_image_sizes[STK11XX_1280x1024].y;
+		break;
+
+	default:
+		return -EFAULT;
+	}
+
+	stk11xx_bayer_to_rgb(image, data, width, height, factor);
+
+	return 0;
+}
+
+/*
+ * Device
+ */
+
+/*
+ * called when a frame is ready to prepare the next frame
+ */
+static int stk11xx_next_frame(struct stk11xx *dev)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	STK_STREAM("Select next frame\n");
+
+	spin_lock_irqsave(&dev->spinlock, flags);
+
+	if (dev->fill_frame != NULL) {
+		if (dev->full_frames == NULL) {
+			dev->full_frames = dev->fill_frame;
+			dev->full_frames_tail = dev->full_frames;
+		} else {
+			dev->full_frames_tail->next = dev->fill_frame;
+			dev->full_frames_tail = dev->fill_frame;
+		}
+	}
+
+	if (dev->empty_frames != NULL) {
+		dev->fill_frame = dev->empty_frames;
+		dev->empty_frames = dev->empty_frames->next;
+	} else {
+		if (dev->full_frames == NULL) {
+			dev_err(&dev->udev->dev, "neither empty or full frames "
+					"available!\n");
+			spin_unlock_irqrestore(&dev->spinlock, flags);
+			return -EINVAL;
+		}
+
+		dev->fill_frame = dev->full_frames;
+		dev->full_frames = dev->full_frames->next;
+
+		ret = 1;
+	}
+
+	dev->fill_frame->next = NULL;
+
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+
+	return ret;
+}
+
+/*
+ * This function is called as an URB transfert is complete (Isochronous pipe).
+ * So, the traitement is done in interrupt time, so it has be fast, not crash,
+ * ans not stall. Neat.
+ */
+static void stk11xx_isoc_handler(struct urb *urb)
+{
+	struct stk11xx *dev = urb->context;
+	struct stk11xx_frame_buf *framebuf;
+	unsigned char *fill = NULL, *iso_buf = NULL;
+	unsigned int i;
+	int ret, skip, awake = 0, framestatus, framelen;
+
+	STK_STREAM("Isoc handler\n");
+
+	if (dev == NULL) {
+		dev_err(&dev->udev->dev, "isoc_handler called with NULL "
+				"device\n");
+		return;
+	}
+
+	switch (urb->status) {
+	case 0:
+	case -ETIMEDOUT:
+		break;
+	case -ENOENT:
+	case -ECONNRESET:
+	case -ESHUTDOWN:
+		return;
+	default:
+		dev_warn(&dev->udev->dev, "unknown urb status %d\n",
+				urb->status);
+
+	}
+
+	framebuf = dev->fill_frame;
+	if (framebuf == NULL) {
+		dev_err(&dev->udev->dev, "isoc_handler without valid fill "
+				"frame\n");
+
+		wake_up_interruptible(&dev->wait_frame);
+
+		urb->dev = dev->udev;
+		ret = usb_submit_urb(urb, GFP_ATOMIC);
+
+		if (ret != 0)
+			dev_err(&dev->udev->dev, "error (%d) re-submitting urb "
+					"in isoc_handler\n", ret);
+
+		return;
+	}
+
+	fill = framebuf->data + framebuf->filled;
+
+	/* Compact data */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		framestatus = urb->iso_frame_desc[i].status;
+		framelen = urb->iso_frame_desc[i].actual_length;
+		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		if (framestatus == 0) {
+			skip = 4;
+
+			if (framelen > 4) {
+	/* we found something informational from there */
+	/* the isoc frames have two type of headers */
+	/* type1: 00 xx 00 00 or 20 xx 00 00 */
+	/* type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00 */
+	/* xx is a sequencer which has never been seen over 0x3f */
+
+	/* imho data written down looks like bayer, i see similarities after */
+	/* every 640 bytes */
+				if (*iso_buf & 0x80)
+					skip = 8;
+
+				if (framelen - skip + framebuf->filled >
+						dev->frame_size) {
+					dev_err(&dev->udev->dev, "frame buffer "
+							"overflow\n");
+				} else {
+					memcpy(fill, iso_buf + skip,
+					       framelen - skip);
+					fill += framelen - skip;
+				}
+
+				framebuf->filled += framelen - skip;
+			}
+
+			STK_STREAM("URB : Length = %d - Skip = %d - Buffer "
+					"size = %d\n", framelen, skip,
+					framebuf->filled);
+
+			if (framelen == 4) {
+				if (framebuf->filled > 0) {
+					stk11xx_next_frame(dev);
+
+					awake = 1;
+					framebuf = dev->fill_frame;
+					framebuf->filled = 0;
+					fill = framebuf->data;
+				}
+			}
+		} else
+			dev_err(&dev->udev->dev, "iso frame %d has error %d\n",
+					i, framestatus);
+	}
+
+	if (awake == 1)
+		wake_up_interruptible(&dev->wait_frame);
+
+	urb->dev = dev->udev;
+
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret != 0)
+		dev_err(&dev->udev->dev, "error (%d) re-submitting urb in "
+				"isoc_handler.\n", ret);
+}
+
+void stk11xx_isoc_cleanup(struct stk11xx *dev)
+{
+	unsigned int i;
+
+	dev_dbg(&dev->udev->dev, "isoc cleanup\n");
+
+	if (!test_bit(STK11XX_STAT_ISOC, dev->status))
+		return;
+
+	/* Unlinking ISOC buffers */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		struct urb *urb;
+
+		urb = dev->isobuf[i].urb;
+
+		if (urb != 0) {
+			if (test_bit(STK11XX_STAT_ISOC, dev->status))
+				usb_kill_urb(urb);
+
+			usb_free_urb(urb);
+			dev->isobuf[i].urb = NULL;
+		}
+	}
+
+	/* All is done */
+	clear_bit(STK11XX_STAT_ISOC, dev->status);;
+}
+
+int stk11xx_isoc_init(struct stk11xx *dev)
+{
+	struct usb_device *udev = dev->udev;
+	struct urb *urb;
+	unsigned int i, j;
+	int ret = 0;
+
+	if (test_bit(STK11XX_STAT_ISOC, dev->status))
+		return 0;
+
+	/* Allocate URB structure */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
+
+		if (urb == NULL) {
+			dev_err(&udev->dev, "failed to allocate URB %d\n", i);
+			ret = -ENOMEM;
+			goto err_free;
+		}
+
+		dev->isobuf[i].urb = urb;
+	}
+
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		urb = dev->isobuf[i].urb;
+
+		urb->interval = 1;
+		urb->dev = udev;
+		urb->pipe = usb_rcvisocpipe(udev, dev->isoc_in_endpointAddr);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = dev->isobuf[i].data;
+		urb->transfer_buffer_length = ISO_BUFFER_SIZE;
+		urb->complete = stk11xx_isoc_handler;
+		urb->context = dev;
+		urb->start_frame = 0;
+		urb->number_of_packets = ISO_FRAMES_PER_DESC;
+
+		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
+			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
+			urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
+		}
+
+		ret = usb_submit_urb(urb, GFP_KERNEL);
+		if (ret)
+			dev_err(&udev->dev, "isoc_init submit_urb %d "
+					"failed with error %d\n", i, ret);
+		else
+			dev_dbg(&udev->dev, "URB 0x%p submitted\n", urb);
+	}
+
+	dev_dbg(&udev->dev, "isoc_in_endpointAddr = %x\n",
+			dev->isoc_in_endpointAddr);
+
+	/* All is done */
+	set_bit(STK11XX_STAT_ISOC, dev->status);
+
+	return 0;
+err_free:
+	for (; i > 0; i--) { /* i is unsigned */
+		usb_free_urb(dev->isobuf[i - 1].urb);
+		dev->isobuf[i - 1].urb = NULL;
+	}
+
+	return ret;
+}
+
+/*
+ * When we configure the stk11xx, this function is used to check the device
+ * status.
+ *   - If the read value is 0x00, then the device isn't ready.
+ *   - If the read value is 0x04, then the device is ready.
+ *   - If the read value is other, then the device is misconfigured.
+ */
+int stk11xx_check_device(struct stk11xx *dev, unsigned int nbr)
+{
+	unsigned int i;
+	int ret = 0;
+	u8 value;
+
+	for (i = 0; i < nbr; i++) {
+		ret = stk11xx_read_reg(dev, 0x201, &value);
+		if (ret)
+			goto end;
+
+		switch (value) {
+		case 0x00:
+			break;
+		case 0x01:
+		case 0x04:
+			return 1;
+		default:
+			dev_err(&dev->udev->dev, "check device return error "
+					"(0x201 = %02X)\n", value);
+			return -EIO;
+		}
+	}
+end:
+	return ret;
+}
+
+int stk11xx_cam_on(struct stk11xx *dev)
+{
+	struct usb_device *udev = dev->udev;
+	int ret;
+
+	ret = usb_set_interface(udev, 0, 5);
+
+	if (ret < 0)
+		dev_err(&udev->dev, "usb_set_interface failed\n");
+
+	return ret;
+}
+
+int stk11xx_cam_off(struct stk11xx *dev)
+{
+	struct usb_device *udev = dev->udev;
+	int ret;
+
+	ret = usb_set_interface(udev, 0, 0);
+
+	if (ret < 0)
+		dev_err(&udev->dev, "usb_set_interface failed\n");
+
+	return 0;
+}
+
+/*
+ * This function reads periodically the value of register 0x0001.
+ * We don't know the purpose. I assume that it seems to a software watchdog.
+ */
+int stk11xx_cam_watchdog(struct stk11xx *dev)
+{
+	u8 value;
+
+	stk11xx_read_reg(dev, 0x0001, &value);
+
+	if (value != 0x03)
+		dev_err(&dev->udev->dev, "Error: Register 0x0001 = %02X\n",
+				value);
+
+	return value;
+}
+
+int stk11xx_check_image_size(struct stk11xx *dev, unsigned int *width,
+		unsigned int *height)
+{
+	unsigned int a;
+
+	for (a = 0; a < ARRAY_SIZE(stk11xx_image_sizes); a++)
+		if (*width == stk11xx_image_sizes[a].x &&
+				*height == stk11xx_image_sizes[a].y)
+			break;
+
+	if (*width < stk11xx_image_sizes[0].x)
+		*width = stk11xx_image_sizes[0].x;
+	else if (*width > stk11xx_image_sizes[STK11XX_NBR_SIZES - 1].x)
+		*width = stk11xx_image_sizes[STK11XX_NBR_SIZES - 1].x;
+
+	if (*height < stk11xx_image_sizes[0].y)
+		*height = stk11xx_image_sizes[0].y;
+	else if (*height > stk11xx_image_sizes[STK11XX_NBR_SIZES - 1].y)
+		*height = stk11xx_image_sizes[STK11XX_NBR_SIZES - 1].y;
+
+	if (a >= ARRAY_SIZE(stk11xx_image_sizes))
+		return -EINVAL;
+
+	return 0;
+}
+
+int stk11xx_select_video_mode(struct stk11xx *dev, int width, int height)
+{
+	unsigned int i, find;
+
+	/* Check width and height */
+	/* Driver can't build an image more little than the minimal
+	 * resolution ! */
+	if ((width < stk11xx_image_sizes[0].x) ||
+			(height < stk11xx_image_sizes[0].y))
+		return -EINVAL;
+
+	/* Seek the best resolution */
+	switch (dev->model->model) {
+	case SYNTEK_STK1125:
+	case SYNTEK_STKDCNEW:
+		for (i = 0, find = 0; i < STK11XX_NBR_SIZES; i++) {
+			if (stk11xx_image_sizes[i].x <= width &&
+					stk11xx_image_sizes[i].y <= height)
+				find = i;
+		}
+		break;
+
+	case SYNTEK_STK1135:
+		for (i = 0, find = 0; i < STK11XX_NBR_SIZES - 3; i++) {
+			if (stk11xx_image_sizes[i].x <= width &&
+					stk11xx_image_sizes[i].y <= height)
+				find = i;
+		}
+		break;
+
+	default:
+		return -ENODEV;
+	}
+
+	/* Save the new resolution */
+	dev->resolution = find;
+
+	dev_dbg(&dev->udev->dev, "set mode %d [%dx%d]\n", dev->resolution,
+			stk11xx_image_sizes[dev->resolution].x,
+			stk11xx_image_sizes[dev->resolution].y);
+
+	/* Save the new size */
+	dev->view.x = stk11xx_image_sizes[dev->resolution].x;
+	dev->view.y = stk11xx_image_sizes[dev->resolution].y;
+
+	/* Calculate the frame size */
+	switch (dev->resolution) {
+	case STK11XX_80x60:
+	case STK11XX_160x120:
+	case STK11XX_320x240:
+	case STK11XX_640x480:
+		dev->frame_size = stk11xx_image_sizes[STK11XX_640x480].x *
+				stk11xx_image_sizes[STK11XX_640x480].y;
+		dev->image_size = 3 * dev->frame_size;
+		break;
+
+	case STK11XX_800x600:
+	case STK11XX_1024x768:
+	case STK11XX_1280x1024:
+		dev->frame_size = stk11xx_image_sizes[STK11XX_1280x1024].x *
+				stk11xx_image_sizes[STK11XX_1280x1024].y;
+		dev->image_size = 3 * dev->frame_size;
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * sysfs stuff
+ */
+
+static ssize_t show_contrast(struct class_device *class, char *buf)
+{
+	struct stk11xx *dev = video_get_drvdata(to_video_device(class));
+
+	return sprintf(buf, "%X\n", dev->vsettings.contrast);
+}
+
+static ssize_t show_whitebalance(struct class_device *class, char *buf)
+{
+	struct stk11xx *dev = video_get_drvdata(to_video_device(class));
+
+	return sprintf(buf, "%X\n", dev->vsettings.whiteness);
+}
+
+static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+static CLASS_DEVICE_ATTR(whitebalance, S_IRUGO, show_whitebalance, NULL);
+
+static inline int stk11xx_create_sysfs_file(const struct stk11xx *dev,
+		const struct class_device_attribute *cda)
+{
+	int ret;
+
+	ret = class_device_create_file(&dev->vdev->class_dev, cda);
+	if (ret)
+		dev_err(&dev->udev->dev, "can't create sysfs file %s: %d\n",
+				attr_name(*cda), ret);
+
+	return ret;
+}
+
+/*
+ * USB
+ */
+
+static int stk11xx_usb_probe(struct usb_interface *interface,
+			     const struct usb_device_id *id)
+{
+	struct stk11xx *dev = NULL;
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	unsigned int i;
+	int retval;
+
+	/* The interface are probed one by one. */
+	/* We are interested in the video interface (always the interface '0')*/
+	/* The interfaces '1' or '2' (if presents) are the audio control. */
+	if (interface->cur_altsetting->desc.bInterfaceNumber > 0) {
+		retval = -ENODEV;
+		goto err;
+	}
+
+	dev = kzalloc(sizeof(struct stk11xx), GFP_KERNEL);
+	if (dev == NULL) {
+		dev_err(&udev->dev, "can't alloc device info!\n");
+		retval = -ENOMEM;
+		goto err;
+	}
+
+	mutex_init(&dev->open_lock);
+	spin_lock_init(&dev->spinlock);
+	init_waitqueue_head(&dev->wait_frame);
+
+	set_bit(STK11XX_STAT_PRESENT, dev->status);
+	dev->model = (void *)id->driver_info;
+	dev->udev = udev;
+
+	dev->vsettings.fps = fps;
+
+/* TODO: check why is no driver that we can see claiming the interfaces ? */
+/* the apis say it should be done, none of the video usb drivers are doing it */
+/* NICKLAS: Claiming the interface is usefull when the driver want manage
+ * severals interfaces. */
+/*          For us, we have only one interface (the video) */
+
+	stk11xx_cam_on(dev);
+
+	/* Set up the endpoint information use only the first isoc-in */
+	/* endpoint for the current alternate setting */
+	iface_desc = interface->cur_altsetting;
+
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+
+		if (!dev->isoc_in_endpointAddr && ((endpoint->bEndpointAddress &
+					USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
+				((endpoint->bmAttributes &
+					USB_ENDPOINT_XFERTYPE_MASK) ==
+				USB_ENDPOINT_XFER_ISOC)) {
+			/* we've found an isoc in endpoint */
+			dev->isoc_in_endpointAddr =
+					(endpoint->bEndpointAddress & 0xf);
+		}
+	}
+
+	if (!dev->isoc_in_endpointAddr) {
+		dev_err(&udev->dev, "can't find both isoc-in endpoint\n");
+		retval = -ENODEV;
+		goto err_free;
+	}
+
+	stk11xx_cam_off(dev);
+
+	dev->vdev = video_device_alloc();
+	if (dev->vdev == NULL) {
+		dev_err(&udev->dev, "can't allocate videodevice\n");
+		retval = -ENOMEM;
+		goto err_free;
+	}
+
+	retval = dev->model->dev_init(dev);
+	if (retval)
+		goto err_vfree;
+
+	memcpy(dev->vdev, &stk11xx_vdev_template, sizeof(*dev->vdev));
+
+	video_set_drvdata(dev->vdev, dev);
+
+	retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
+	if (retval) {
+		dev_err(&udev->dev, "can't register video device\n");
+		goto err_vfree;
+	}
+
+	stk11xx_create_sysfs_file(dev, &class_device_attr_contrast);
+	stk11xx_create_sysfs_file(dev, &class_device_attr_whitebalance);
+	usb_set_intfdata(interface, dev);
+
+	dev_info(&udev->dev, "Syntek USB2.0 - STK-%s based webcam found and "
+		"ready\n", dev->model->name);
+
+	return 0;
+err_vfree:
+	video_device_release(dev->vdev);
+err_free:
+	kfree(dev);
+err:
+	return retval;
+}
+
+static void stk11xx_usb_disconnect(struct usb_interface *interface)
+{
+	struct stk11xx *dev = usb_get_intfdata(interface);
+	unsigned int free = 0;
+
+	class_device_remove_file(&dev->vdev->class_dev,
+					&class_device_attr_contrast);
+	class_device_remove_file(&dev->vdev->class_dev,
+					&class_device_attr_whitebalance);
+	mutex_lock(&dev->open_lock);
+	clear_bit(STK11XX_STAT_PRESENT, dev->status);
+	if (dev->vopen == 0) {
+		free++;
+		video_unregister_device(dev->vdev);
+	} else {
+		dev->model->stream_stop(dev);
+		stk11xx_isoc_cleanup(dev);
+		stk11xx_cam_off(dev);
+		dev->model->cam_asleep(dev);
+	}
+	mutex_unlock(&dev->open_lock);
+	if (free)
+		kfree(dev);
+}
+
+#ifdef CONFIG_PM
+static int stk11xx_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct stk11xx *dev = usb_get_intfdata(intf);
+
+	mutex_lock(&dev->open_lock);
+	if (dev->vopen) {
+		dev->model->stream_stop(dev);
+		stk11xx_isoc_cleanup(dev);
+		stk11xx_cam_off(dev);
+		dev->model->cam_asleep(dev);
+	}
+	mutex_unlock(&dev->open_lock);
+	return 0;
+}
+
+static int stk11xx_usb_resume(struct usb_interface *intf)
+{
+	struct stk11xx *dev = usb_get_intfdata(intf);
+
+	mutex_lock(&dev->open_lock);
+	if (dev->vopen && test_bit(STK11XX_STAT_PRESENT, dev->status)) {
+		if (stk11xx_select_video_mode(dev, dev->view.x, dev->view.y)) {
+			dev_err(&dev->udev->dev, "Select video mode failed\n");
+			return -EINVAL;
+		}
+
+		dev->model->cam_ini
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[PATCH 1/1] V4L: stk11xx, add a new webcam driver, Jiri Slaby, (Sun Aug 26, 10:09 am)
Re: [PATCH 1/1] V4L: stk11xx, add a new webcam driver, Andrew Morton, (Tue Nov 6, 3:40 am)
Re: [PATCH 1/1] V4L: stk11xx, add a new webcam driver, Mauro Carvalho Chehab, (Wed Nov 7, 1:57 pm)
Re: [PATCH 1/1] V4L: stk11xx, add a new webcam driver, Alexander E. Patrakov, (Tue Aug 28, 2:35 am)
Re: [PATCH 1/1] V4L: stk11xx, add a new webcam driver, Andrew Morton, (Mon Aug 27, 6:40 pm)
Re: [PATCH 1/1] V4L: stk11xx, add a new webcam driver, Andrew Morton, (Tue Aug 28, 1:36 am)