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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Well, no objections on v4l list, try to merge it. Any further comments will be
appreciated.

--

stk11xx, add a new webcam driver

Cc: Mauro Carvalho Chehab <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>

---
commit 1f023432798b6e6fd52ad81af0eab250e1a71449
tree 4045ace3523a78ae2b5bff194ed9c10945b27171
parent 119ce83eb190c70d50ed7558c7b67b400ea00ec7
author Jiri Slaby <[email protected]> Thu, 24 May 2007 15:56:41 +0200
committer Jiri Slaby <[email protected]> Thu, 24 May 2007 15:56:41 +0200

 drivers/media/video/Kconfig   |    8 
 drivers/media/video/Makefile  |    2 
 drivers/media/video/stk11xx.c | 3608 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 3618 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 070f4b1..cbab1ed 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -792,6 +792,14 @@ config USB_ZR364XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called zr364xx.
 
+config USB_STK11XX
+	tristate "STK11XX based webcams"
+	depends on VIDEO_V4L2
+	---help---
+	  This will add support for Syntek webcams such as dc1125 and stk1135.
+
+	  If you choose to build it 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 3202e87..409125d 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -106,6 +106,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/stk11xx.c b/drivers/media/video/stk11xx.c
new file mode 100644
index 0000000..53c36cb
--- /dev/null
+++ b/drivers/media/video/stk11xx.c
@@ -0,0 +1,3608 @@
+/* 
+ * Driver for Syntek USB video camera
+ *
+ * Copyright (C) Nicolas VIVIEN
+ * Copyright (c) 2007 Jiri Slaby <[email protected]>
+ *
+ * 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/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
+#include <media/v4l2-common.h>
+
+#define DRIVER_DESC			"Syntek USB Video Camera"
+#define DRIVER_VERSION			"v0.0.1"
+#define DRIVER_VERSION_NUM		0x000001
+
+#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_DC1125_PRODUCT_ID		0x0501
+
+typedef enum {
+	SYNTEK_DC1125 = 1,
+	SYNTEK_STK1135 = 2
+} T_SYNTEK_DEVICE;
+
+/**
+ * @def MAX_ISO_BUFS
+ *   Number maximal of ISOC buffers
+ *
+ * @def ISO_FRAMES_PER_DESC
+ *   Number frames per ISOC descriptor
+ *
+ * @def ISO_MAX_FRAME_SIZE
+ *   Maximale size of frame
+ *
+ * @def ISO_BUFFER_SIZE
+ *   Maximal size of buffer
+ */
+#define MAX_ISO_BUFS			16 /* 2 */
+#define ISO_FRAMES_PER_DESC		10
+#define ISO_MAX_FRAME_SIZE		3 * 1024
+#define ISO_BUFFER_SIZE			(ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
+
+/**
+ * @def STK11XX_MAX_IMAGES
+ *   Absolute maximum number of buffers available for mmap()
+ *
+ * @def STK11XX_FRAME_SIZE
+ *   Maximum size after decompression
+ */
+#define STK11XX_MAX_IMAGES		10
+#define STK11XX_FRAME_SIZE		(1280 * 1024 * 3)
+
+#ifndef CONFIG_STK11XX_DEBUG_STREAM
+#define CONFIG_STK11XX_DEBUG_STREAM	0
+#endif
+
+#if CONFIG_STK11XX_DEBUG_STREAM
+#define STK_STREAM(str, args...)	printk(KERN_DEBUG "stk11xx: " str, \
+									##args)
+#else
+#define STK_STREAM(str, args...)	do { } while(0)
+#endif
+
+enum {
+	STK11XX_80x60,
+	STK11XX_160x120,
+	STK11XX_320x240,
+	STK11XX_640x480,
+	STK11XX_800x600,
+	STK11XX_1024x758,
+	STK11XX_1280x1024,
+	STK11XX_NBR_SIZES
+};
+
+struct stk11xx_iso_buf {
+	void *data;
+	int length;
+	int read;
+	struct urb *urb;
+};
+
+struct stk11xx_frame_buf {
+	void *data;
+	volatile int filled;
+	struct stk11xx_frame_buf *next;
+};
+
+struct stk11xx_image_buf {
+	unsigned long offset;
+	int vma_use_count;
+};
+
+struct stk11xx_coord {
+	int x;
+	int y;
+};
+
+struct stk11xx_video {
+	int fps;
+	int brightness;
+	int contrast;
+	int whiteness;
+	u32 pixformat;
+};
+
+struct stk11xx {
+	struct video_device *vdev;
+	struct usb_device *udev;
+
+	int webcam_model;
+
+	unsigned char *int_in_buffer;	/**< Interrupt IN buffer */
+	size_t int_in_size;		/**< Interrupt IN buffer size */
+	u8 int_in_endpointAddr;		/**< Interrupt IN endpoint address */
+
+	size_t isoc_in_size;		/**< Isochrone IN size */
+	u8 isoc_in_endpointAddr;	/**< Isochrone IN endpoint address */
+
+	int watchdog;		/**< Counter for the software watchdog */
+
+	struct stk11xx_video vsettings;		/**< Video settings (brightness, whiteness...) */
+
+	int error_status;
+
+	struct mutex open_lock;
+	unsigned int vopen;
+	int visoc_errors;
+	int vframes_error;
+	int vlast_packet_size;
+	char vsync;
+
+	spinlock_t spinlock;
+	wait_queue_head_t wait_frame;
+
+	/* 1: isoc */
+	char isoc_init_ok;
+	struct stk11xx_iso_buf isobuf[MAX_ISO_BUFS];
+
+	/* 2: frame */
+	int frame_size;
+	struct stk11xx_frame_buf *framebuf;
+	struct stk11xx_frame_buf *empty_frames, *empty_frames_tail;
+	struct stk11xx_frame_buf *full_frames, *full_frames_tail;
+	struct stk11xx_frame_buf *fill_frame;
+	struct stk11xx_frame_buf *read_frame;
+
+	/* 3: decompression */
+	void *decompress_data;
+	
+	/* 4: image */
+	int image_size;
+	void *image_data;
+	struct stk11xx_image_buf images[STK11XX_MAX_IMAGES];
+	u32 image_f[STK11XX_MAX_IMAGES];
+	unsigned int nbuffers;
+	unsigned int len_per_image;
+	int image_read_pos;
+	int fill_image;
+	int resolution;
+	struct stk11xx_coord view;
+	struct stk11xx_coord image;
+};
+
+static const struct stk11xx_coord stk11xx_image_sizes[STK11XX_NBR_SIZES] = {
+	{   80,   60 },
+	{  160,  120 },
+	{  320,  240 },
+	{  640,  480 },
+	{  800,  600 },
+	{ 1024,  758 },
+	{ 1280, 1024 }
+};
+
+static int default_nbrframebuf = 3;	/* Number of frame buffer by default */
+static int default_fps = 10;
+
+static int fps;
+module_param(fps, int, 0444);
+MODULE_PARM_DESC(fps, "Frames per second [5-30]");
+
+static int stk11xx_read_registry(struct stk11xx *dev, u16 index, int *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, (u8 *)value, sizeof(u8), 500);
+
+	if (result < 0)
+		dev_err(&udev->dev, "Read registry fails %02X\n", index);
+
+	return result;
+}
+
+static int stk11xx_write_registry(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);
+
+	return result;
+}
+
+static 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;
+}
+
+/*
+ * 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,
+			  const int width, const int height)
+{
+	unsigned int i, j, x, y;
+	int rpos, wpos, ltpos, lbpos;
+	int runlength = width > height ? width : height;
+	int lastrow = ((height - 1) * width) * 3;
+	int lastcolumn = (width - 1) * 3;
+
+	/* blit out initial data */
+	for (j = 0, y = 0; y < height; y++) {
+		for (i = 0, x = 0; x < width; x++) {
+			if (y & 1) {
+				/* GBGBGB line */
+				if (x & 1) {	/* blue */
+					rgb[j * width * 3 + i * 3 + 2] =
+					    bayer[(height - y) * width + x];
+				} else {	/* green */
+					rgb[j * width * 3 + i * 3 + 1] =
+					    bayer[(height - y) * width + x];
+				}
+			} else {
+				/* RGRGRG line */
+				if (x & 1) {	/* green */
+					rgb[j * width * 3 + i * 3 + 1] =
+					    bayer[(height - y) * width + x];
+				} else {	/* red */
+					rgb[j * width * 3 + i * 3 + 0] =
+					    bayer[(height - y) * width + x];
+				}
+			}
+
+			i++;
+		}
+
+		j++;
+	}
+
+	/* blit in everything but the borders */
+	for (y = 1; y < (height - 1); y++) {
+		if (y & 1) {
+			/* GBGBGB line */
+			for (x = 1; x < (width - 1); x++) {
+				rpos = (height - y) * width + x;
+				wpos = y * width + x;
+				ltpos = rpos - width;
+				lbpos = rpos + width;
+
+				if (x & 1) {	/* blue is known */
+					/* calculate red */
+					rgb[(wpos) * 3 + 0] = STK11XX_AVG4(
+						/*Rtl */ bayer[ltpos - 1],
+						/*Rtr */ bayer[ltpos + 1],
+						/*Rbl */ bayer[lbpos - 1],
+						/*Rbr */ bayer[lbpos + 1]);
+					/* calculate green */
+					rgb[(wpos) * 3 + 1] = STK11XX_AVG4(
+						/*Gt */ bayer[ltpos],
+						/*Gl */ bayer[rpos - 1],
+						/*Gb */ bayer[lbpos],
+						/*Gr */ bayer[rpos + 1]);
+				} else {	/* green is known */
+					/* calculate red */
+					rgb[(wpos) * 3 + 0] = STK11XX_AVG2(
+						/*Rt */ bayer[ltpos],
+						/*Rb */ bayer[lbpos]);
+					/* calculate blue */
+					rgb[(wpos) * 3 + 2] = STK11XX_AVG2(
+						/*Bl */ bayer[rpos - 1],
+						/*Br */ bayer[rpos + 1]);
+				}
+			}
+		} else {
+			/* RGRG line */
+			for (x = 1; x < (width - 1); x++) {
+				rpos = (height - y) * width + x;
+				wpos = y * width + x;
+				ltpos = rpos - width;
+				lbpos = rpos + width;
+
+				if (x & 1) {	/* green is known */
+					/* calculate red */
+					rgb[(wpos) * 3 + 0] = STK11XX_AVG2(
+						/*Rl */ bayer[rpos - 1],
+						/*Rr */ bayer[rpos + 1]);
+					/* calculate blue */
+					rgb[(wpos) * 3 + 2] = STK11XX_AVG2(
+						/*Bt */ bayer[ltpos],
+						/*Bb */ bayer[lbpos]);
+
+				} else {	/* red is known */
+					/* calculate blue */
+					rgb[(wpos) * 3 + 2] = STK11XX_AVG4(
+						/*Btl */ bayer[ltpos - 1],
+						/*Btr */ bayer[ltpos + 1],
+						/*Bbl */ bayer[lbpos - 1],
+						/*Bbr */ bayer[lbpos + 1]);
+					/* calculate green */
+					rgb[(wpos) * 3 + 1] = STK11XX_AVG4(
+						/*Gt */ bayer[ltpos],
+						/*Gl */ bayer[rpos - 1],
+						/*Gb */ bayer[lbpos],
+						/*Gr */ bayer[rpos + 1]);
+				}
+			}
+		}
+	}
+
+	for (i = 0; i < runlength; i++) {
+		if (i < width) {
+			/* top border: we have certain red and green pixels */
+			if ((i & 1) == 1) {
+				/* red, we use avg4(bot, bot, l-bot, l) */
+				rgb[i * 3] = STK11XX_AVG4(
+					rgb[(i + width) * 3],
+					rgb[(i + width) * 3],
+					rgb[(i + width - 1) * 3],
+					rgb[(i - 1) * 3]);
+			} else {
+				/* green, we use avg4(bot, bot, r-bot, r) */
+				rgb[i * 3 + 1] = STK11XX_AVG4(
+					rgb[(i + width) * 3 + 1],
+					rgb[(i + width) * 3 + 1],
+					rgb[(i + width + 1) * 3 + 1],
+					rgb[(i + 1) * 3 + 1]);
+			}
+			/* blue has to be calculated for every pixel, we'll
+			   use bottom and one more bottom */
+			rgb[i * 3 + 2] = STK11XX_AVG2(rgb[(i + width) * 3 + 2],
+					rgb[(i + width * 2) * 3 + 2]);
+
+			/* bottom border: we have green and blue pixels for
+			   sure */
+			if ((i & 1) == 1) {
+				/* green, we use avg4(top, top, l-top, l) */
+				rgb[lastrow + i * 3 + 1] = STK11XX_AVG4(
+					rgb[lastrow + (i - width) * 3 + 1],
+					rgb[lastrow + (i - width) * 3 + 1],
+					rgb[lastrow + (i - width - 1) * 3 + 1],
+					rgb[lastrow + (i - 1) * 3 + 1]);
+			} else {
+				/* blue, we use avg4(top, top, r-top, r) */
+				rgb[lastrow + i * 3 + 2] = STK11XX_AVG4(
+					rgb[lastrow + (i - width) * 3 + 2],
+					rgb[lastrow + (i - width) * 3 + 2],
+					rgb[lastrow + (i - width + 1) * 3 + 2],
+					rgb[lastrow + (i + 1) * 3 + 2]);
+			}
+			/* red has to be calculated for every pixel, we'll use
+			   top and another top */
+			rgb[lastrow + i * 3] = STK11XX_AVG2(
+					rgb[lastrow + (i - width) * 3],
+					rgb[lastrow + (i - width * 2) * 3]);
+
+		}
+		if (i < height) {	/* the left and right borders */
+			/* left border */
+			if ((i & 1) == 0) {
+				/* calc green, just avg right and bottom */
+				rgb[(i * width) * 3 + 1] = STK11XX_AVG2(
+					rgb[(i * width + 1) * 3 + 1],
+					rgb[((i + 1) * width) * 3 + 1]);
+				/* calc blue, avg right and right bottom */
+				rgb[(i * width) * 3 + 2] = STK11XX_AVG2(
+					rgb[(i * width + 1) * 3 + 2],
+					rgb[((i + 1) * width + 1) * 3 + 2]);
+			} else {
+				/* calc red, 2x top , 1xtopright, 1xright */
+				rgb[(i * width) * 3] = STK11XX_AVG4(
+					rgb[((i - 1) * width) * 3],
+					rgb[((i - 1) * width) * 3],
+					rgb[((i - 1) * width + 1) * 3],
+					rgb[(i * width + 1) * 3]);
+				/* calc blue, avg top and right */
+				rgb[(i * width) * 3 + 2] = STK11XX_AVG2(
+					rgb[((i - 1) * width) * 3 + 2],
+					rgb[(i * width + 1) * 3 + 2]);
+			}
+			/* right border */
+			if ((i & 1) == 0) {
+				/* calc red, take left and bottom left */
+				rgb[lastcolumn + (i * width) * 3] =STK11XX_AVG2(
+					rgb[lastcolumn + (i * width - 1) * 3],
+					rgb[lastcolumn + ((i+1)*width-1) * 3]);
+				/* calc blue, left and bottom */
+				rgb[lastcolumn + (i * width) * 3 + 2] =
+				    STK11XX_AVG2(
+					rgb[lastcolumn + (i*width - 1) * 3 + 2],
+					rgb[lastcolumn + ((i+1)*width)*3 + 2]);
+			} else {	/* i&1 == 1 */
+				/* calc red, top and left */
+				rgb[lastcolumn + (i * width) * 3] =STK11XX_AVG2(
+					rgb[lastcolumn +((i-1)*width - 1) * 3],
+					rgb[lastcolumn + (i * width - 1) * 3]);
+				/* calc green, 2xtop, topleft, left */
+				rgb[lastcolumn + (i * width) * 3 + 1] =
+				    STK11XX_AVG4(
+					rgb[lastcolumn + ((i-1)*width) * 3 + 1],
+					rgb[lastcolumn + ((i-1)*width) * 3 + 1],
+					rgb[lastcolumn + ((i-1)*width-1)*3 + 1],
+					rgb[lastcolumn + (i*width-1) * 3 + 1]);
+			}
+
+		}
+
+	}
+
+}
+
+static void stk11xx_resize_image(u8 *out, const u8 *in,
+		unsigned int width, unsigned int height, unsigned int factor)
+{
+	unsigned int x, y, nwidth, nheight;
+
+	nheight = height / factor;
+	nwidth = width / factor;
+
+	for (y = 0; y < nheight; y++) {
+		for (x = 0; x < nwidth; x++) {
+			/* R */
+			out[y * nwidth * 3 + x * 3 + 0] =
+			    in[y * factor * width * 3 + x * factor * 3 + 0];
+			/* G */
+			out[y * nwidth * 3 + x * 3 + 1] =
+			    in[y * factor * width * 3 + x * factor * 3 + 1];
+			/* B */
+			out[y * nwidth * 3 + x * 3 + 2] =
+			    in[y * factor * width * 3 + x * factor * 3 + 2];
+		}
+	}
+}
+
+static void stk11xx_correct_brightness(u8 *rgb, unsigned int width,
+				unsigned int height, int brightness)
+{
+	unsigned int i;
+
+	for (i = 0; i < width * height; i++) {
+		brightness = min_t(int, brightness, min(255 - rgb[i],
+			min(255 - rgb[i + 1], 255 - rgb[i + 2])));
+		brightness = max(brightness, -min_t(int, rgb[i],
+			min(rgb[i + 1], rgb[i + 2])));
+
+		rgb[i] = rgb[i] + brightness;
+		rgb[i + 1] = rgb[i + 1] + brightness;
+		rgb[i + 2] = rgb[i + 2] + brightness;
+	}
+}
+
+static int stk11xx_decompress(struct stk11xx *dev)
+{
+	struct stk11xx_frame_buf *framebuf = dev->read_frame;
+	void *data, *image = dev->image_data;
+	void *decompress = dev->decompress_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_1024x758:
+		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(decompress, data, width, height);
+
+	stk11xx_resize_image(image, decompress, width, height, factor);
+
+	stk11xx_correct_brightness(image, width / factor, height / factor,
+				   dev->vsettings.brightness - 200);
+
+	return 0;
+}
+
+/*
+ * Device
+ */
+
+static int stk11xx_setting_camera(struct stk11xx *dev);
+
+/* 
+ * 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;
+	}
+
+	if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+		dev_dbg(&dev->udev->dev, "URB unlinked synchronuously\n");
+		return;
+	}
+
+	if (urb->status != -EINPROGRESS && urb->status != 0) {
+		dev_err(&dev->udev->dev, "isoc_handler called with status %d\n",
+				urb->status);
+
+		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;
+	}
+
+	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;
+	} else
+		fill = framebuf->data + framebuf->filled;
+
+	/* Reset ISOC error counter */
+	dev->visoc_errors = 0;
+
+	/* 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);
+}
+
+static void stk11xx_isoc_cleanup(struct stk11xx *dev)
+{
+	unsigned int i;
+
+	dev_dbg(&dev->udev->dev, "isoc cleanup\n");
+
+	if (dev->isoc_init_ok == 0)
+		return;
+
+	/* Unlinking ISOC buffers */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		struct urb *urb;
+
+		urb = dev->isobuf[i].urb;
+
+		if (urb != 0) {
+			if (dev->isoc_init_ok)
+				usb_kill_urb(urb);
+
+			usb_free_urb(urb);
+			dev->isobuf[i].urb = NULL;
+		}
+	}
+
+	/* All is done */
+	dev->isoc_init_ok = 0;
+}
+
+static int stk11xx_isoc_init(struct stk11xx *dev)
+{
+	struct usb_device *udev;
+	struct urb *urb;
+	unsigned int i, j;
+	int ret = 0;
+
+	if (dev->isoc_init_ok)
+		return 0;
+
+	udev = dev->udev;
+
+	dev_dbg(&udev->dev, "%s\n", __FUNCTION__);
+
+	/* 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;
+			break;
+		}
+
+		dev->isobuf[i].urb = urb;
+	}
+
+	if (ret) {
+		while (i >= 0) {
+			if (dev->isobuf[i].urb != NULL)
+				usb_free_urb(dev->isobuf[i].urb);
+
+			dev->isobuf[i].urb = NULL;
+			i--;
+		}
+
+		return ret;
+	}
+	/* Init URB structure */
+	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;
+		}
+	}
+
+	dev_dbg(&dev->udev->dev, "isoc_in_size = %zx, "
+			"isoc_in_endpointAddr = %x\n",
+			dev->isoc_in_size, dev->isoc_in_endpointAddr);
+
+	/* Link */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		ret = usb_submit_urb(dev->isobuf[i].urb, GFP_KERNEL);
+
+		if (ret)
+			dev_err(&dev->udev->dev, "isoc_init submit_urb %d "
+					"failed with error %d\n", i, ret);
+		else
+			dev_dbg(&dev->udev->dev, "URB 0x%p submitted\n",
+					dev->isobuf[i].urb);
+	}
+
+	/* All is done */
+	dev->isoc_init_ok = 1;
+
+	return 0;
+}
+
+/* 
+ * 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.
+ */
+static int stk11xx_check_device(struct stk11xx *dev, int nbr)
+{
+	unsigned int i;
+	int value;
+
+	for (i = 0; i < nbr; i++) {
+		stk11xx_read_registry(dev, 0x201, &value);
+
+		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 -1;
+		}
+	}
+
+	return 0;
+}
+
+static int stk11xx_camera_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;
+}
+
+/*
+ * STK-1125 API
+ */
+
+static int stk1125_load_microcode(struct stk11xx *dev)
+{
+	unsigned int i;
+	const u8 *values_204, *values_205;
+	int retok, value;
+
+	/* 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_1024x758:
+	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_registry(dev, 0x02FF, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+		stk11xx_write_registry(dev, 0x0204, values_204[i]);
+		stk11xx_write_registry(dev, 0x0205, values_205[i]);
+		stk11xx_write_registry(dev, 0x0200, 0x0001);
+
+		retok = stk11xx_check_device(dev, 500);
+		if (retok != 1) {
+			dev_err(&dev->udev->dev, "load microcode fail\n");
+			return -1;
+		}
+
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	}
+
+	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_configure_device(struct stk11xx *dev, int step)
+{
+	int value;
+
+	/*      0,    1,    2,    3,    4,    5,    6,    7,    8,    9, 
+		    10,   11 */
+
+	const u8 values_001B[] = {
+		0x0E, 0x03, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E,
+		    0x0E, 0x0E
+	};
+	const u8 values_001C[] = {
+		0x06, 0x02, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
+		    0x46, 0x0E
+	};
+	const u8 values_0202[] = {
+		0x1E, 0x0A, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
+		    0x1E, 0x1E
+	};
+	const u8 values_0110[] = {
+		0x07, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0x00,
+		    0x00, 0x00
+	};
+	const u8 values_0112[] = {
+		0x07, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x00, 0x00, 0x00,
+		    0x00, 0x00
+	};
+	const u8 values_0114[] = {
+		0x87, 0x80, 0x80, 0x80, 0x80, 0xBE, 0xBE, 0x80, 0x80, 0x80,
+		    0x80, 0x00
+	};
+	const u8 values_0115[] = {
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		    0x02, 0x05
+	};
+	const u8 values_0116[] = {
+		0xE7, 0xE0, 0xE0, 0xE0, 0xE0, 0xE9, 0xE9, 0xE0, 0xE0, 0xE0,
+		    0xE0, 0x00
+	};
+	const u8 values_0117[] = {
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		    0x01, 0x04
+	};
+	const u8 values_0100[] = {
+		0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+		    0x21, 0x21
+	};
+
+	dev_dbg(&dev->udev->dev, "stk1125_configure_device: %d\n", step);
+
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0002, 0x0068);
+	stk11xx_write_registry(dev, 0x0003, 0x0080);
+	stk11xx_write_registry(dev, 0x0005, 0x0000);
+
+	stk11xx_write_registry(dev, 0x0007, 0x0003);
+	stk11xx_write_registry(dev, 0x000d, 0x0000);
+	stk11xx_write_registry(dev, 0x000f, 0x0002);
+	stk11xx_write_registry(dev, 0x0300, 0x0012);
+	stk11xx_write_registry(dev, 0x0350, 0x0041);
+
+	stk11xx_write_registry(dev, 0x0351, 0x0000);
+	stk11xx_write_registry(dev, 0x0352, 0x0000);
+	stk11xx_write_registry(dev, 0x0353, 0x0000);
+	stk11xx_write_registry(dev, 0x0018, 0x0010);
+	stk11xx_write_registry(dev, 0x0019, 0x0000);
+
+	stk11xx_write_registry(dev, 0x001b, values_001B[step]);
+	stk11xx_write_registry(dev, 0x001c, values_001C[step]);
+	stk11xx_write_registry(dev, 0x0300, 0x0080);
+	stk11xx_write_registry(dev, 0x001a, 0x0004);
+	stk11xx_write_registry(dev, 0x0202, values_0202[step]);
+
+	stk11xx_write_registry(dev, 0x0110, values_0110[step]);
+	stk11xx_write_registry(dev, 0x0111, 0x0000);
+	stk11xx_write_registry(dev, 0x0112, values_0112[step]);
+	stk11xx_write_registry(dev, 0x0113, 0x0000);
+	stk11xx_write_registry(dev, 0x0114, values_0114[step]);
+
+	stk11xx_write_registry(dev, 0x0115, values_0115[step]);
+	stk11xx_write_registry(dev, 0x0116, values_0116[step]);
+	stk11xx_write_registry(dev, 0x0117, values_0117[step]);
+
+	stk11xx_read_registry(dev, 0x0100, &value);
+	stk11xx_write_registry(dev, 0x0100, values_0100[step]);
+
+	stk11xx_write_registry(dev, 0x0200, 0x0080);
+	stk11xx_write_registry(dev, 0x0200, 0x0000);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+	switch (step) {
+	case 0:
+		stk11xx_write_registry(dev, 0x0203, 0x0040);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0041);
+		stk11xx_write_registry(dev, 0x0205, 0x0001);
+		stk11xx_write_registry(dev, 0x0204, 0x001C);
+		stk11xx_write_registry(dev, 0x0205, 0x0002);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 1:
+		stk11xx_write_registry(dev, 0x0203, 0x0022);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0027);
+		stk11xx_write_registry(dev, 0x0205, 0x00A5);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 2:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00BF);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 3:
+		stk11xx_write_registry(dev, 0x0203, 0x0042);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0024);
+		stk11xx_write_registry(dev, 0x0205, 0x00A5);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 4:
+		stk11xx_write_registry(dev, 0x0203, 0x0042);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00E0);
+		stk11xx_write_registry(dev, 0x0204, 0x0024);
+		stk11xx_write_registry(dev, 0x0205, 0x00A5);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 5:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00FF);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 6:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00FF);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 7:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00B7);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 8:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk1125_load_microcode(dev);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0080);
+		stk11xx_write_registry(dev, 0x0200, 0x0000);
+		stk11xx_write_registry(dev, 0x02FF, 0x0001);
+		stk11xx_write_registry(dev, 0x0203, 0x00A0);
+
+		break;
+
+	case 9:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk1125_load_microcode(dev);
+
+		stk11xx_write_registry(dev, 0x0104, 0x0000);
+		stk11xx_write_registry(dev, 0x0105, 0x0000);
+		stk11xx_write_registry(dev, 0x0106, 0x0000);
+
+		break;
+
+	case 10:
+	case 11:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk1125_load_microcode(dev);
+
+		stk11xx_write_registry(dev, 0x0106, 0x0000);
+		stk11xx_read_registry(dev, 0x02FF, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+		stk11xx_write_registry(dev, 0x0204, 0x002A);
+		stk11xx_write_registry(dev, 0x0205, 0x0000);
+		stk11xx_write_registry(dev, 0x0200, 0x0001);
+		stk11xx_check_device(dev, 500);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+		stk11xx_read_registry(dev, 0x02FF, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+		stk11xx_write_registry(dev, 0x0204, 0x002B);
+		stk11xx_write_registry(dev, 0x0205, 0x0000);
+		stk11xx_write_registry(dev, 0x0200, 0x0001);
+		stk11xx_check_device(dev, 500);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+		break;
+	}
+
+	return 0;
+}
+
+static int stk1125_camera_asleep(struct stk11xx *dev)
+{
+	int value;
+
+	stk11xx_read_registry(dev, 0x0104, &value);
+	stk11xx_read_registry(dev, 0x0105, &value);
+	stk11xx_read_registry(dev, 0x0106, &value);
+
+	stk11xx_write_registry(dev, 0x0100, 0x0021);
+	stk11xx_write_registry(dev, 0x0116, 0x0000);
+	stk11xx_write_registry(dev, 0x0117, 0x0000);
+	stk11xx_write_registry(dev, 0x0018, 0x0000);
+
+	stk11xx_read_registry(dev, 0x0000, &value);
+	stk11xx_write_registry(dev, 0x0000, 0x004C);
+
+	return 0;
+}
+
+/*
+ * 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
+ * 0x01 | 0x00 |  20
+ * 0x02 | 0x00 |  15
+ * 0x03 | 0x00 |  12
+ * 0x04 | 0x00 |  10
+ */
+static int stk1125_setting_camera(struct stk11xx *dev)
+{
+	int ret;
+
+	stk11xx_write_registry(dev, 0x0200, 0x0000);
+
+	/* Unknown register */
+	stk11xx_write_registry(dev, 0x0204, 0x00A1);
+	stk11xx_write_registry(dev, 0x0205, 0x0000);
+
+	/* Contrast register */
+	stk11xx_write_registry(dev, 0x0204, 0x0010);
+	stk11xx_write_registry(dev, 0x0205, dev->vsettings.contrast);
+
+	/* Unknown register */
+	stk11xx_write_registry(dev, 0x0204, 0x0004);
+	stk11xx_write_registry(dev, 0x0205, 0x0000);
+
+	/* Whiteness register */
+	stk11xx_write_registry(dev, 0x0204, 0x0000);
+	stk11xx_write_registry(dev, 0x0205, dev->vsettings.whiteness);
+
+	/* FPS register */
+	switch (dev->vsettings.fps) {
+	case 10:
+		stk11xx_write_registry(dev, 0x0204, 0x002E);
+		stk11xx_write_registry(dev, 0x0205, 0x0004);
+		stk11xx_write_registry(dev, 0x0204, 0x002D);
+		stk11xx_write_registry(dev, 0x0205, 0x0000);
+		break;
+
+	case 15:
+		stk11xx_write_registry(dev, 0x0204, 0x002E);
+		stk11xx_write_registry(dev, 0x0205, 0x0002);
+		stk11xx_write_registry(dev, 0x0204, 0x002D);
+		stk11xx_write_registry(dev, 0x0205, 0x0000);
+		break;
+
+	case 20:
+		stk11xx_write_registry(dev, 0x0204, 0x002E);
+		stk11xx_write_registry(dev, 0x0205, 0x0001);
+		stk11xx_write_registry(dev, 0x0204, 0x002D);
+		stk11xx_write_registry(dev, 0x0205, 0x0000);
+		break;
+
+	case 30:
+		stk11xx_write_registry(dev, 0x0204, 0x002E);
+		stk11xx_write_registry(dev, 0x0205, 0x0000);
+		stk11xx_write_registry(dev, 0x0204, 0x002D);
+		stk11xx_write_registry(dev, 0x0205, 0x0000);
+		break;
+
+	default:
+		stk11xx_write_registry(dev, 0x0204, 0x002E);
+		stk11xx_write_registry(dev, 0x0205, 0x0001);
+		stk11xx_write_registry(dev, 0x0204, 0x002D);
+		stk11xx_write_registry(dev, 0x0205, 0x0000);
+	}
+
+	stk11xx_write_registry(dev, 0x0200, 0x0006);
+
+	dev_dbg(&dev->udev->dev, "set contrast: %d, whiteness: %d, "
+			"brightness: %d\n", dev->vsettings.contrast,
+			dev->vsettings.whiteness, dev->vsettings.brightness);
+
+	ret = stk11xx_check_device(dev, 500);
+	if (!ret)
+		dev_dbg(&dev->udev->dev, "find not 0x4 ... seems OK\n");
+
+	return 0;
+}
+
+static int stk1125_init_camera(struct stk11xx *dev)
+{
+	int value;
+
+	stk1125_camera_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+	stk11xx_write_registry(dev, 0x0000, 0x00E0);
+	stk11xx_write_registry(dev, 0x0002, 0x00E8);
+	stk11xx_write_registry(dev, 0x0002, 0x0068);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk1125_configure_device(dev, 9);
+
+	stk11xx_camera_off(dev);
+
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0204, 0x002a);
+	stk11xx_write_registry(dev, 0x0205, 0x0000);
+	stk11xx_write_registry(dev, 0x0200, 0x0001);
+	stk11xx_check_device(dev, 500);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0204, 0x002B);
+	stk11xx_write_registry(dev, 0x0205, 0x0000);
+	stk11xx_write_registry(dev, 0x0200, 0x0001);
+	stk11xx_check_device(dev, 500);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+	stk1125_setting_camera(dev);
+
+	return 0;
+}
+
+static int stk1125_start_stream(struct stk11xx *dev)
+{
+	int value, value_116, value_117;
+
+	stk11xx_read_registry(dev, 0x0116, &value_116);
+	stk11xx_read_registry(dev, 0x0117, &value_117);
+
+	stk11xx_write_registry(dev, 0x0116, 0x0000);
+	stk11xx_write_registry(dev, 0x0117, 0x0000);
+
+	stk11xx_read_registry(dev, 0x0100, &value);	/* read 0x21 */
+	stk11xx_write_registry(dev, 0x0100, 0x00A1);
+
+	stk11xx_write_registry(dev, 0x0116, value_116);
+	stk11xx_write_registry(dev, 0x0117, value_117);
+
+	return 0;
+}
+
+static int stk1125_reconf_camera(struct stk11xx *dev)
+{
+	int step;
+
+	switch (dev->resolution) {
+	case STK11XX_1280x1024:
+	case STK11XX_1024x758:
+	case STK11XX_800x600:
+		step = 11;
+		break;
+
+	case STK11XX_640x480:
+	case STK11XX_320x240:
+	case STK11XX_160x120:
+	case STK11XX_80x60:
+	default:
+		step = 10;
+		break;
+	}
+
+	stk1125_configure_device(dev, step);
+
+	stk11xx_setting_camera(dev);
+
+	return 0;
+}
+
+static int stk1125_stop_stream(struct stk11xx *dev)
+{
+	int value;
+
+	stk11xx_read_registry(dev, 0x0100, &value);
+	stk11xx_write_registry(dev, 0x0100, 0x0021);
+
+	return 0;
+}
+
+/*
+ * STK-1135 API
+ */
+
+static int stk1135_load_microcode(struct stk11xx *dev)
+{
+	unsigned int i;
+	int retok, value;
+
+	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 < 59; i++) {
+		stk11xx_read_registry(dev, 0x02FF, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+		stk11xx_write_registry(dev, 0x0204, values_204[i]);
+		stk11xx_write_registry(dev, 0x0205, values_205[i]);
+		stk11xx_write_registry(dev, 0x0200, 0x0001);
+
+		retok = stk11xx_check_device(dev, 500);
+		if (retok != 1) {
+			dev_err(&dev->udev->dev, "load microcode failed\n");
+			return -1;
+		}
+
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	}
+
+	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_configure_device(struct stk11xx *dev, int step)
+{
+	int value;
+
+	/*      0,    1,    2,    3,    4,    5,    6,    7,    8,    9,
+		    10,   11,   12,   13 */
+
+	const u8 values_001B[] = {
+		0x0E, 0x03, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x07,
+		    0x07, 0x07, 0x07, 0x07
+	};
+	const u8 values_001C[] = {
+		0x06, 0x02, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x06, 0x06,
+		    0x06, 0x06, 0x06, 0x07
+	};
+	const u8 values_0202[] = {
+		0x1E, 0x0A, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
+		    0x1E, 0x1E, 0x1E, 0x1E
+	};
+	const u8 values_0110[] = {
+		0x07, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x04, 0x00,
+		    0x00, 0x00, 0x00, 0x00
+	};
+	const u8 values_0112[] = {
+		0x07, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x00, 0x04, 0x00,
+		    0x00, 0x00, 0x00, 0x00
+	};
+	const u8 values_0114[] = {
+		0x87, 0x80, 0x80, 0x80, 0x80, 0xBE, 0xBE, 0x80, 0x84, 0x80,
+		    0x80, 0x80, 0x80, 0x80
+	};
+	const u8 values_0116[] = {
+		0xE7, 0xE0, 0xE0, 0xE0, 0xE0, 0xE9, 0xE9, 0xE0, 0xE4, 0xE0,
+		    0xE0, 0xE0, 0xE0, 0xE0
+	};
+	const u8 values_0100[] = {
+		0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x20,
+		    0x20, 0x20, 0x20, 0x20
+	};
+
+	dev_dbg(&dev->udev->dev, "stk1135_configure_device: %d\n", step);
+
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0002, 0x0068);
+	stk11xx_write_registry(dev, 0x0003, 0x0080);
+	stk11xx_write_registry(dev, 0x0005, 0x0000);
+
+	stk11xx_write_registry(dev, 0x0007, 0x0003);
+	stk11xx_write_registry(dev, 0x000d, 0x0000);
+	stk11xx_write_registry(dev, 0x000f, 0x0002);
+	stk11xx_write_registry(dev, 0x0300, 0x0012);
+	stk11xx_write_registry(dev, 0x0350, 0x0041);
+
+	stk11xx_write_registry(dev, 0x0351, 0x0000);
+	stk11xx_write_registry(dev, 0x0352, 0x0000);
+	stk11xx_write_registry(dev, 0x0353, 0x0000);
+	stk11xx_write_registry(dev, 0x0018, 0x0010);
+	stk11xx_write_registry(dev, 0x0019, 0x0000);
+
+	stk11xx_write_registry(dev, 0x001b, values_001B[step]);
+	stk11xx_write_registry(dev, 0x001c, values_001C[step]);
+	stk11xx_write_registry(dev, 0x0300, 0x0080);
+	stk11xx_write_registry(dev, 0x001a, 0x0004);
+	stk11xx_write_registry(dev, 0x0202, values_0202[step]);
+
+	stk11xx_write_registry(dev, 0x0110, values_0110[step]);
+	stk11xx_write_registry(dev, 0x0111, 0x0000);
+	stk11xx_write_registry(dev, 0x0112, values_0112[step]);
+	stk11xx_write_registry(dev, 0x0113, 0x0000);
+	stk11xx_write_registry(dev, 0x0114, values_0114[step]);
+
+	stk11xx_write_registry(dev, 0x0115, 0x0002);
+	stk11xx_write_registry(dev, 0x0116, values_0116[step]);
+	stk11xx_write_registry(dev, 0x0117, 0x0001);
+
+	stk11xx_read_registry(dev, 0x0100, &value);
+	stk11xx_write_registry(dev, 0x0100, values_0100[step]);
+
+	stk11xx_write_registry(dev, 0x0200, 0x0080);
+	stk11xx_write_registry(dev, 0x0200, 0x0000);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+	switch (step) {
+	case 0:
+		stk11xx_write_registry(dev, 0x0203, 0x0040);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0041);
+		stk11xx_write_registry(dev, 0x0205, 0x0001);
+		stk11xx_write_registry(dev, 0x0204, 0x001C);
+		stk11xx_write_registry(dev, 0x0205, 0x0002);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 1:
+		stk11xx_write_registry(dev, 0x0203, 0x0022);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0027);
+		stk11xx_write_registry(dev, 0x0205, 0x00A5);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 2:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00BF);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 3:
+		stk11xx_write_registry(dev, 0x0203, 0x0042);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0024);
+		stk11xx_write_registry(dev, 0x0205, 0x00A5);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 4:
+		stk11xx_write_registry(dev, 0x0203, 0x0042);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00E0);
+		stk11xx_write_registry(dev, 0x0204, 0x0024);
+		stk11xx_write_registry(dev, 0x0205, 0x00A5);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 5:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00FF);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 6:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00FF);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 7:
+		stk11xx_write_registry(dev, 0x0203, 0x0060);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x0013);
+		stk11xx_write_registry(dev, 0x0205, 0x00B7);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 8:
+		stk11xx_write_registry(dev, 0x0203, 0x0080);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0012);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+		stk11xx_write_registry(dev, 0x0204, 0x000A);
+		stk11xx_write_registry(dev, 0x0205, 0x00FF);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		break;
+
+	case 9:
+		stk11xx_write_registry(dev, 0x0203, 0x00DC);
+
+		stk11xx_write_registry(dev, 0x0204, 0x0015);
+		stk11xx_write_registry(dev, 0x0205, 0x0080);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0005);
+
+		stk11xx_check_device(dev, 500);
+		stk11xx_read_registry(dev, 0x02FF, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+		stk11xx_write_registry(dev, 0x0208, 0x0000);
+		stk11xx_write_registry(dev, 0x0200, 0x0020);
+		stk11xx_check_device(dev, 500);
+		stk11xx_read_registry(dev, 0x0209, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+		stk11xx_read_registry(dev, 0x02FF, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+		stk11xx_write_registry(dev, 0x0208, 0x0001);
+		stk11xx_write_registry(dev, 0x0200, 0x0020);
+		stk11xx_check_device(dev, 500);
+		stk11xx_read_registry(dev, 0x0209, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+		stk11xx_read_registry(dev, 0x02FF, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+		stk11xx_write_registry(dev, 0x0208, 0x0002);
+		stk11xx_write_registry(dev, 0x0200, 0x0020);
+		stk11xx_check_device(dev, 500);
+		stk11xx_read_registry(dev, 0x0209, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+		stk11xx_write_registry(dev, 0x0002, 0x006F);
+
+		break;
+
+	case 10:
+		stk11xx_write_registry(dev, 0x0203, 0x00DC);
+
+		stk1135_load_microcode(dev);
+
+		break;
+
+	case 11:
+		stk11xx_write_registry(dev, 0x0203, 0x00DC);
+
+		stk1135_load_microcode(dev);
+
+		stk11xx_write_registry(dev, 0x0104, 0x0000);
+		stk11xx_write_registry(dev, 0x0105, 0x0000);
+		stk11xx_write_registry(dev, 0x0106, 0x0000);
+
+		break;
+
+	case 12:
+		stk11xx_write_registry(dev, 0x0203, 0x00DC);
+
+		stk1135_load_microcode(dev);
+
+		stk11xx_write_registry(dev, 0x0104, 0x0000);
+		stk11xx_write_registry(dev, 0x0105, 0x0000);
+		stk11xx_write_registry(dev, 0x0106, 0x0000);
+
+		break;
+
+	case 13:
+		stk11xx_write_registry(dev, 0x0203, 0x00DC);
+
+		stk1135_load_microcode(dev);
+	}
+
+	return 0;
+}
+
+static int stk1135_camera_asleep(struct stk11xx *dev)
+{
+	int value;
+
+	stk11xx_read_registry(dev, 0x0104, &value);
+	stk11xx_read_registry(dev, 0x0105, &value);
+	stk11xx_read_registry(dev, 0x0106, &value);
+
+	stk11xx_write_registry(dev, 0x0100, 0x0021);
+	stk11xx_write_registry(dev, 0x0116, 0x0000);
+	stk11xx_write_registry(dev, 0x0117, 0x0000);
+	stk11xx_write_registry(dev, 0x0018, 0x0000);
+
+	stk11xx_read_registry(dev, 0x0000, &value);
+	stk11xx_write_registry(dev, 0x0000, 0x0049);
+
+	return 0;
+}
+
+static int stk1135_setting_camera(struct stk11xx *dev)
+{
+	unsigned int i;
+	int ret, value;
+
+	const u8 values_204[] = {
+		0x46, 0x06, 0x07, 0xb9, 0xba, 0xbb, 0xbc, 0x61, 0x62, 0x65, 0x66
+	};
+	const u8 values_205[] = {
+		0x20, 0x01, 0xf3, 0x04, 0xe4, 0x09, 0xc8, 0x08, 0x08, 0x10, 0x14
+	};
+
+	for (i = 0; i < 11; i++) {
+		stk11xx_read_registry(dev, 0x02FF, &value);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+		stk11xx_write_registry(dev, 0x0204, values_204[i]);
+		stk11xx_write_registry(dev, 0x0205, values_205[i]);
+
+		stk11xx_write_registry(dev, 0x0200, 0x0001);
+		ret = stk11xx_check_device(dev, 500);
+		stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	}
+
+	return 0;
+}
+
+static int stk1135_init_camera(struct stk11xx *dev)
+{
+	stk1135_camera_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+	stk11xx_write_registry(dev, 0x0000, 0x00E0);
+	stk11xx_write_registry(dev, 0x0002, 0x00E8);
+	stk11xx_write_registry(dev, 0x0002, 0x0068);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk1135_configure_device(dev, 11);
+
+	stk11xx_camera_off(dev);
+
+	stk1135_setting_camera(dev);
+
+	stk1135_camera_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+	stk11xx_write_registry(dev, 0x0000, 0x00E0);
+	stk11xx_write_registry(dev, 0x0002, 0x00E8);
+	stk11xx_write_registry(dev, 0x0002, 0x0068);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk1135_configure_device(dev, 12);
+
+	stk11xx_camera_off(dev);
+
+	stk1135_setting_camera(dev);
+
+	return 0;
+}
+
+static int stk1135_start_stream(struct stk11xx *dev)
+{
+	int value, value_116, value_117;
+
+	stk11xx_read_registry(dev, 0x0116, &value_116);
+	stk11xx_read_registry(dev, 0x0117, &value_117);
+
+	stk11xx_write_registry(dev, 0x0116, 0x0000);
+	stk11xx_write_registry(dev, 0x0117, 0x0000);
+
+	stk11xx_read_registry(dev, 0x0100, &value);	/* read 0x21 */
+	stk11xx_write_registry(dev, 0x0100, 0x00A0);
+
+	stk11xx_write_registry(dev, 0x0116, value_116);
+	stk11xx_write_registry(dev, 0x0117, value_117);
+
+	return 0;
+}
+
+static int stk1135_reconf_camera(struct stk11xx *dev)
+{
+	stk1135_configure_device(dev, 13);
+
+	return 0;
+}
+
+static int stk1135_stop_stream(struct stk11xx *dev)
+{
+	int value;
+
+	stk11xx_read_registry(dev, 0x0100, &value);
+	stk11xx_write_registry(dev, 0x0100, 0x0020);
+
+	return 0;
+}
+
+static int stk11xx_setting_camera(struct stk11xx *dev)
+{
+	int ret = -1;
+
+	switch (dev->webcam_model) {
+	case SYNTEK_DC1125:
+		ret = stk1125_setting_camera(dev);
+		break;
+	case SYNTEK_STK1135:
+		ret = stk1135_setting_camera(dev);
+		break;
+	}
+
+	return ret;
+}
+
+/* 
+ * It's the start. This function has to be called at first, before
+ * enabling the video stream.
+ */
+static int stk11xx_init_camera(struct stk11xx *dev)
+{
+	int ret = -1;
+
+	switch (dev->webcam_model) {
+	case SYNTEK_DC1125:
+		ret = stk1125_init_camera(dev);
+		break;
+	case SYNTEK_STK1135:
+		ret = stk1135_init_camera(dev);
+		break;
+	}
+
+	return ret;
+}
+
+static int stk11xx_camera_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;
+}
+
+/* Wake-up the camera */
+static int stk11xx_camera_asleep(struct stk11xx *dev)
+{
+	int ret = -1;
+
+	switch (dev->webcam_model) {
+	case SYNTEK_DC1125:
+		ret = stk1125_camera_asleep(dev);
+		break;
+	case SYNTEK_STK1135:
+		ret = stk1135_camera_asleep(dev);
+		break;
+	}
+
+	return ret;
+}
+
+/* 
+ * After the initialization of the device and the initialization of the video
+ * stream, this function enables the stream.
+ */
+static int stk11xx_start_stream(struct stk11xx *dev)
+{
+	int ret = -1;
+
+	switch (dev->webcam_model) {
+	case SYNTEK_DC1125:
+		ret = stk1125_start_stream(dev);
+		break;
+	case SYNTEK_STK1135:
+		ret = stk1135_start_stream(dev);
+		break;
+	}
+
+	return ret;
+}
+
+/* before enabling the video stream, you have to reconfigure the device */
+static int stk11xx_reconf_camera(struct stk11xx *dev)
+{
+	int ret = -1;
+
+	switch (dev->webcam_model) {
+	case SYNTEK_DC1125:
+		ret = stk1125_reconf_camera(dev);
+		break;
+	case SYNTEK_STK1135:
+		ret = stk1135_reconf_camera(dev);
+		break;
+	}
+
+	return ret;
+}
+
+static int stk11xx_stop_stream(struct stk11xx *dev)
+{
+	int ret = -1;
+
+	switch (dev->webcam_model) {
+	case SYNTEK_DC1125:
+		ret = stk1125_stop_stream(dev);
+		break;
+	case SYNTEK_STK1135:
+		ret = stk1135_stop_stream(dev);
+		break;
+	}
+
+	return ret;
+}
+
+static void *stk11xx_rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long addr;
+
+	mem = vmalloc_user(size);
+
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size);
+
+	addr = (unsigned long)mem;
+
+	while (size > 0) {
+		SetPageReserved(vmalloc_to_page((void *)addr));
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	return mem;
+}
+
+static int stk11xx_free_buffers(struct stk11xx *dev);
+
+static int stk11xx_allocate_buffers(struct stk11xx *dev)
+{
+	unsigned int i;
+
+	dev_dbg(&dev->udev->dev, "%s\n", __FUNCTION__);
+
+	/* Allocate isochronous pipe buffers */
+	for (i = 0; i < MAX_ISO_BUFS; i++)
+		if (dev->isobuf[i].data == NULL) {
+			dev->isobuf[i].data = kzalloc(ISO_BUFFER_SIZE,
+					GFP_KERNEL);
+			if (dev->isobuf[i].data == NULL) {
+				dev_err(&dev->udev->dev, "failed to allocate "
+					"iso buffer %d\n", i);
+				goto err;
+			}
+		}
+
+	/* Allocate frame buffer structure */
+	if (dev->framebuf == NULL) {
+		dev->framebuf = kzalloc(default_nbrframebuf *
+			    sizeof(struct stk11xx_frame_buf), GFP_KERNEL);
+		if (dev->framebuf == NULL) {
+			dev_err(&dev->udev->dev, "failed to allocate frame "
+					"buffer structure\n");
+			goto err;
+		}
+	}
+	/* Create frame buffers and make circular ring */
+	for (i = 0; i < default_nbrframebuf; i++)
+		if (dev->framebuf[i].data == NULL) {
+			dev->framebuf[i].data = vmalloc(STK11XX_FRAME_SIZE);
+			if (dev->framebuf[i].data == NULL) {
+				dev_err(&dev->udev->dev, "failed to allocate "
+						"frame buffer %d\n", i);
+				goto err;
+			}
+			memset(dev->framebuf[i].data, 0, STK11XX_FRAME_SIZE);
+		}
+
+	/* Allocate decompressor table space */
+	dev->decompress_data = stk11xx_rvmalloc(dev->len_per_image);
+	if (dev->decompress_data == NULL) {
+		dev_err(&dev->udev->dev, "failed to allocate decompress "
+				"buffer(s). needed (%d)\n", dev->len_per_image);
+		goto err;
+	}
+
+	/* Allocate image buffer; double buffer for mmap() */
+	dev->image_data = stk11xx_rvmalloc(dev->nbuffers * dev->len_per_image);
+	if (dev->image_data == NULL) {
+		dev_err(&dev->udev->dev, "failed to allocate image buffer(s). "
+			"needed (%d)\n", dev->nbuffers * dev->len_per_image);
+		goto err;
+	}
+
+	for (i = 0; i < dev->nbuffers; i++) {
+		dev->images[i].offset = i * dev->len_per_image;
+		dev->images[i].vma_use_count = 0;
+	}
+
+	for (; i < STK11XX_MAX_IMAGES; i++)
+		dev->images[i].offset = 0;
+
+	return 0;
+err:
+	stk11xx_free_buffers(dev);
+	return -ENOMEM;
+}
+
+static void stk11xx_rvfree(void *mem, unsigned long size)
+{
+	unsigned long addr;
+
+	if (!mem)
+		return;
+
+	addr = (unsigned long)mem;
+
+	while ((long)size > 0) {
+		ClearPageReserved(vmalloc_to_page((void *)addr));
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	vfree(mem);
+}
+
+static int stk11xx_free_buffers(struct stk11xx *dev)
+{
+	unsigned int i;
+
+	dev_dbg(&dev->udev->dev, "%s\n", __FUNCTION__);
+
+	if (dev == NULL)
+		return -1;
+
+	/* Release iso pipe buffers */
+	for (i = 0; i < MAX_ISO_BUFS; i++)
+		if (dev->isobuf[i].data != NULL) {
+			kfree(dev->isobuf[i].data);
+			dev->isobuf[i].data = NULL;
+		}
+
+	/* Release frame buffers */
+	if (dev->framebuf != NULL) {
+		for (i = 0; i < default_nbrframebuf; i++)
+			if (dev->framebuf[i].data != NULL) {
+				vfree(dev->framebuf[i].data);
+				dev->framebuf[i].data = NULL;
+			}
+
+		kfree(dev->framebuf);
+	}
+	/* Release decompression buffers */
+	if (dev->decompress_data != NULL)
+		stk11xx_rvfree(dev->decompress_data, dev->len_per_image);
+
+	/* Release image buffers */
+	if (dev->image_data != NULL)
+		stk11xx_rvfree(dev->image_data,
+			       dev->nbuffers * dev->len_per_image);
+
+	dev->decompress_data = dev->framebuf = dev->image_data = NULL;
+
+	return 0;
+}
+
+static int stk11xx_reset_buffers(struct stk11xx *dev)
+{
+	unsigned long flags;
+	unsigned int i;
+
+	dev_dbg(&dev->udev->dev, "%s\n", __FUNCTION__);
+
+	spin_lock_irqsave(&dev->spinlock, flags);
+
+	dev->full_frames = NULL;
+	dev->full_frames_tail = NULL;
+
+	for (i = 0; i < dev->nbuffers; i++) {
+		dev->framebuf[i].filled = 0;
+
+		if (i > 0)
+			dev->framebuf[i].next = &dev->framebuf[i - 1];
+		else
+			dev->framebuf->next = NULL;
+	}
+
+	dev->empty_frames = &dev->framebuf[dev->nbuffers - 1];
+	dev->empty_frames_tail = dev->framebuf;
+	dev->read_frame = NULL;
+	dev->fill_frame = dev->empty_frames;
+	dev->empty_frames = dev->empty_frames->next;
+
+	dev->image_read_pos = 0;
+	dev->fill_image = 0;
+
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+
+	for (i = 0; i < dev->nbuffers; i++)
+		dev->image_f[i] = 0;
+
+	return 0;
+}
+
+/* called when an image is ready to prepare the next image */
+static void stk11xx_next_image(struct stk11xx *dev)
+{
+	STK_STREAM("Select next image\n");
+
+	dev->image_f[dev->fill_image] = 0;
+	dev->fill_image = (dev->fill_image + 1) % dev->nbuffers;
+}
+
+/* 
+ * This function reads periodically the value of register 0x0001.
+ * We don't know the purpose. I assume that it seems to a software watchdog.
+ */
+static int stk11xx_watchdog_camera(struct stk11xx *dev)
+{
+	int value;
+
+	stk11xx_read_registry(dev, 0x0001, &value);
+
+	if (value != 0x03)
+		dev_err(&dev->udev->dev, "Error: Register 0x0001 = %02X\n",
+				value);
+
+	return value;
+}
+
+/* 
+ * This function gets called for the isochronous pipe. This function is only
+ * called when a frame is ready. So we have to be fast to decompress the data.
+ */
+static int stk11xx_handle_frame(struct stk11xx *dev)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	STK_STREAM("Sync Handle Frame\n");
+
+	spin_lock_irqsave(&dev->spinlock, flags);
+
+	if (dev->read_frame != NULL) {
+		spin_unlock_irqrestore(&dev->spinlock, flags);
+		return ret;
+	}
+
+	if (dev->full_frames != NULL) {
+		dev->read_frame = dev->full_frames;
+		dev->full_frames = dev->full_frames->next;
+		dev->read_frame->next = NULL;
+	}
+
+	if (dev->read_frame != NULL) {
+		spin_unlock_irqrestore(&dev->spinlock, flags);
+		ret = stk11xx_decompress(dev);
+		spin_lock_irqsave(&dev->spinlock, flags);
+
+		if (dev->empty_frames == NULL) {
+			dev->empty_frames = dev->read_frame;
+			dev->empty_frames_tail = dev->empty_frames;
+		} else {
+			dev->empty_frames_tail->next = dev->read_frame;
+			dev->empty_frames_tail = dev->read_frame;
+		}
+
+		dev->read_frame = NULL;
+	}
+
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+
+	stk11xx_watchdog_camera(dev);
+
+	return ret;
+}
+
+static 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 -1;
+
+	/* Seek the best resolution */
+	switch (dev->webcam_model) {
+	case SYNTEK_DC1125:
+		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 -1;
+	}
+
+	/* 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 = width;
+	dev->view.y = height;
+
+	/* 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_1024x758:
+	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;
+}
+
+static int stk11xx_open(struct inode *inode, struct file *fp)
+{
+	struct video_device *vdev = video_devdata(fp);
+	struct stk11xx *dev = video_get_drvdata(vdev);
+	int retval;
+
+	BUG_ON(dev == NULL);
+
+	nonseekable_open(inode, fp);
+
+	if (mutex_lock_interruptible(&dev->open_lock))
+		return -ERESTARTSYS;
+
+	if (dev->vopen) {
+		retval = -EBUSY;
+		goto end;
+	}
+
+	retval = stk11xx_allocate_buffers(dev);
+	if (retval < 0) {
+		dev_err(&dev->udev->dev, "failed to allocate buffer memory\n");
+		goto end;
+	}
+
+	stk11xx_reset_buffers(dev);
+
+	stk11xx_select_video_mode(dev, 640, 480);
+
+	stk11xx_init_camera(dev);
+	stk11xx_camera_on(dev);
+	stk11xx_reconf_camera(dev);
+
+	dev->error_status = 0;
+	dev->vsettings.brightness = 200;
+	dev->vsettings.contrast = 0x7c;
+	dev->vsettings.whiteness = 0x80;
+	dev->vsettings.pixformat = V4L2_PIX_FMT_BGR24;
+
+	retval = stk11xx_isoc_init(dev);
+	if (retval) {
+		dev_err(&dev->udev->dev, "failed to init ISOC stuff\n");
+		stk11xx_isoc_cleanup(dev);
+		stk11xx_free_buffers(dev);
+		goto end;
+	}
+
+	stk11xx_start_stream(dev);
+
+	dev->vopen++;
+	fp->private_data = dev;
+	retval = 0;
+end:
+	mutex_unlock(&dev->open_lock);
+
+	return retval;
+}
+
+static int stk11xx_release(struct inode *inode, struct file *fp)
+{
+	struct stk11xx *dev = fp->private_data;
+
+	mutex_lock(&dev->open_lock);
+	if (dev->vopen == 0)
+		dev_warn(&dev->udev->dev, "v4l_release called on closed "
+				"device\n");
+
+	stk11xx_stop_stream(dev);
+	stk11xx_isoc_cleanup(dev);
+	stk11xx_free_buffers(dev);
+	stk11xx_camera_off(dev);
+	stk11xx_camera_asleep(dev);
+
+	dev->vopen--;
+	mutex_unlock(&dev->open_lock);
+
+	return 0;
+}
+
+static ssize_t stk11xx_read(struct file *fp, char __user *buf, size_t count,
+		loff_t *f_pos)
+{
+	struct stk11xx *dev = fp->private_data;
+	void *image_buffer_addr;
+	int bytes_to_read, retval;
+
+	STK_STREAM("Read vdev=0x%p, buf=0x%p, count=%zd\n", vdev, buf, count);
+
+	if (dev->image_read_pos == 0) {
+		if ((fp->f_flags & O_NONBLOCK) && dev->full_frames == NULL)
+			return -EWOULDBLOCK;
+
+		retval = wait_event_interruptible(dev->wait_frame,
+			dev->full_frames != NULL || dev->error_status);
+
+		if (retval)
+			return retval;
+		if (dev->error_status)
+			return -dev->error_status;
+
+		if (stk11xx_handle_frame(dev))
+			return -EFAULT;
+	}
+
+	bytes_to_read = dev->image_size;
+
+	if (count + dev->image_read_pos > bytes_to_read)
+		count = bytes_to_read - dev->image_read_pos;
+
+	image_buffer_addr = dev->image_data;
+	image_buffer_addr += dev->images[dev->fill_image].offset;
+	image_buffer_addr += dev->image_read_pos;
+
+	if (copy_to_user(buf, image_buffer_addr, count))
+		return -EFAULT;
+
+	dev->image_read_pos += count;
+
+	if (dev->image_read_pos >= bytes_to_read) {
+		dev->image_read_pos = 0;
+		stk11xx_next_image(dev);
+	}
+
+	return count;
+}
+
+static unsigned int stk11xx_poll(struct file *fp, poll_table * wait)
+{
+	struct stk11xx *dev = fp->private_data;
+
+	STK_STREAM("Poll\n");
+
+	poll_wait(fp, &dev->wait_frame, wait);
+
+	if (dev->error_status)
+		return POLLERR;
+
+	if (dev->full_frames != NULL)
+		return (POLLIN | POLLRDNORM);
+
+	return 0;
+}
+
+static int stk11xx_mmap(struct file *fp, struct vm_area_struct *vma)
+{
+	struct stk11xx *dev = fp->private_data;
+	unsigned long pos, size = vma->vm_end - vma->vm_start;
+	unsigned int i;
+
+	/* Find the buffer for this mapping... */
+	for (i = 0; i < dev->nbuffers; i++) {
+		pos = dev->images[i].offset;
+
+		if ((pos >> PAGE_SHIFT) == vma->vm_pgoff)
+			break;
+	}
+
+	if (i >= STK11XX_MAX_IMAGES) {
+		dev_err(&dev->udev->dev, "mmap no buffer found\n");
+		return -EINVAL;
+	}
+
+	/* map either whole space or only one buffer! */
+	if (size > dev->len_per_image && (i > 0 ||
+			(i == 0 && size != dev->nbuffers * dev->len_per_image)))
+		return -EINVAL;
+
+	vma->vm_flags |= VM_IO;
+
+	return remap_vmalloc_range(vma, dev->image_data, vma->vm_pgoff);
+}
+
+static struct v4l2_queryctrl stk11xx_controls[] = {
+	{
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 400,
+		.step    = 1,
+		.default_value = 200,
+	},
+	{
+		.id      = V4L2_CID_CONTRAST,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Contrast",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x7c,
+	},
+	{
+		.id      = V4L2_CID_WHITENESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Whiteness",
+		.minimum = 0,
+		.maximum = 0xff,
+		.step    = 1,
+		.default_value = 0x80,
+	},
+};
+
+static int stk11xx_querycap(struct file *file, void *fh,
+		struct v4l2_capability *cap)
+{
+	struct stk11xx *dev = fh;
+
+	strlcpy(cap->driver, "stk11xx", sizeof(cap->driver));
+
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+			V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+	cap->version = (u32)DRIVER_VERSION_NUM;
+	strlcpy(cap->card, dev->vdev->name, sizeof(cap->card));
+
+	if (usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)) < 0)
+		strlcpy(cap->bus_info, dev->vdev->name, sizeof(cap->bus_info));
+
+	return 0;
+}
+static int stk11xx_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+	if (i->index)
+		return -EINVAL;
+
+	strlcpy(i->name, "USB", sizeof(i->name));
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+
+	return 0;
+}
+
+static int stk11xx_g_input(struct file *file, void *fh, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int stk11xx_s_input(struct file *file, void *fh, unsigned int i)
+{
+	return i ? -EINVAL : 0;
+}
+
+static int stk11xx_queryctrl(struct file *file, void *fh,
+		struct v4l2_queryctrl *c)
+{
+	unsigned int i;
+
+	pr_debug("VIDIOC_QUERYCTRL id = %d\n", c->id);
+
+	for (i = 0; i < ARRAY_SIZE(stk11xx_controls); i++)
+		if (stk11xx_controls[i].id == c->id) {
+			pr_debug("VIDIOC_QUERYCTRL found\n");
+			memcpy(c, &stk11xx_controls[i], sizeof(*c));
+			break;
+		}
+
+	if (i >= ARRAY_SIZE(stk11xx_controls))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int stk11xx_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+	struct stk11xx *dev = fh;
+
+	dev_dbg(&dev->udev->dev, "GET CTRL id=%d\n", c->id);
+
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		c->value = dev->vsettings.brightness;
+		break;
+	case V4L2_CID_CONTRAST:
+		c->value = dev->vsettings.contrast;
+		break;
+	case V4L2_CID_WHITENESS:
+		c->value = dev->vsettings.whiteness;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int stk11xx_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+	struct stk11xx *dev = fh;
+
+	dev_dbg(&dev->udev->dev, "SET CTRL id=%d\n", c->id);
+
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		dev->vsettings.brightness = c->value;
+		break;
+	case V4L2_CID_CONTRAST:
+		dev->vsettings.contrast = c->value;
+		break;
+	case V4L2_CID_WHITENESS:
+		dev->vsettings.whiteness = c->value;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return stk11xx_setting_camera(dev) ? -EIO : 0;
+}
+
+static int stk11xx_enum_fmt_cap(struct file *file, void *fh,
+		struct v4l2_fmtdesc *fmtd)
+{
+	u32 index = fmtd->index;
+
+	pr_debug("VIDIOC_ENUM_FMT %d\n", index);
+
+	if (index)
+		return -EINVAL;
+
+	fmtd->pixelformat = V4L2_PIX_FMT_BGR24;
+	strcpy(fmtd->description, "rgb24");
+
+	return 0;
+}
+
+static int stk11xx_g_fmt_cap(struct file *file, void *fh,
+	   	struct v4l2_format *fmtd)
+{
+	struct stk11xx *dev = fh;
+	struct v4l2_pix_format *pix = &fmtd->fmt.pix;
+
+	pix->width = dev->view.x;
+	pix->height = dev->view.y;
+	pix->pixelformat = V4L2_PIX_FMT_BGR24;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = 3 * pix->width;
+	pix->sizeimage = pix->width * pix->height * 3;
+	pix->colorspace = V4L2_COLORSPACE_SRGB;
+	pix->priv = 0;
+
+	return 0;
+}
+
+static int stk11xx_s_fmt_cap(struct file *file, void *fh,
+	   	struct v4l2_format *fmtd)
+{
+	struct stk11xx *dev = fh;
+	struct v4l2_pix_format *pix = &fmtd->fmt.pix;
+	unsigned int a;
+
+	dev_dbg(&dev->udev->dev, "set width=%d, height=%d\n", pix->width,
+			pix->height);
+
+	if (pix->pixelformat && pix->pixelformat != V4L2_PIX_FMT_BGR24)
+		return -EINVAL;
+
+	for (a = 0; a < ARRAY_SIZE(stk11xx_image_sizes); a++)
+		if (pix->width == stk11xx_image_sizes[a].x &&
+				pix->height == stk11xx_image_sizes[a].y)
+			break;
+	if (a >= ARRAY_SIZE(stk11xx_image_sizes))
+		return -EINVAL;
+
+	stk11xx_stop_stream(dev);
+	stk11xx_isoc_cleanup(dev);
+	stk11xx_camera_off(dev);
+	stk11xx_camera_asleep(dev);
+
+	/* Reset buffers and parameters */
+	/*stk11xx_reset_buffers(dev); */
+
+	if (stk11xx_select_video_mode(dev, pix->width, pix->height)) {
+		dev_err(&dev->udev->dev, "Select video mode failed\n");
+		return -EINVAL;
+	}
+
+	stk11xx_init_camera(dev);
+	stk11xx_camera_on(dev);
+	stk11xx_reconf_camera(dev);
+	stk11xx_isoc_init(dev);
+	stk11xx_start_stream(dev);
+
+	return 0;
+}
+
+static int stk11xx_try_fmt_cap(struct file *file, void *fh,
+	   	struct v4l2_format *fmtd)
+{
+	struct v4l2_pix_format *pix = &fmtd->fmt.pix;
+
+	if (pix->pixelformat != V4L2_PIX_FMT_BGR24)
+		return -EINVAL;
+
+	if (pix->width > stk11xx_image_sizes[STK11XX_NBR_SIZES - 1].x)
+		pix->width = stk11xx_image_sizes[STK11XX_NBR_SIZES - 1].x;
+	else if (pix->width < stk11xx_image_sizes[0].x)
+		pix->width = stk11xx_image_sizes[0].x;
+
+	if (pix->height > stk11xx_image_sizes[STK11XX_NBR_SIZES - 1].y)
+		pix->height = stk11xx_image_sizes[STK11XX_NBR_SIZES - 1].y;
+	else if (pix->height < stk11xx_image_sizes[0].y)
+		pix->height = stk11xx_image_sizes[0].y;
+
+	return 0;
+}
+
+static int stk11xx_querystd(struct file *file, void *fh, v4l2_std_id *a)
+{
+	*a = V4L2_STD_UNKNOWN;
+	return 0;
+}
+
+static int stk11xx_s_std(struct file *file, void *fh, v4l2_std_id *a)
+{
+	return *a == V4L2_STD_UNKNOWN ? 0 : -EINVAL;
+}
+
+static int stk11xx_reqbufs(struct file *file, void *fh,
+		struct v4l2_requestbuffers *rb)
+{
+	struct stk11xx *dev = fh;
+	u32 nbuffers = rb->count;
+
+	if (rb->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	if (nbuffers < 2)
+		nbuffers = 2;
+	else if (nbuffers > dev->nbuffers)
+		nbuffers = dev->nbuffers;
+
+	rb->count = dev->nbuffers;
+
+	return 0;
+}
+
+static int stk11xx_querybuf(struct file *file, void *fh,
+		struct v4l2_buffer *buf)
+{
+	struct stk11xx *dev = fh;
+	u32 index = buf->index;
+
+	dev_dbg(&dev->udev->dev, "QUERY BUFFERS %d %d\n", buf->index,
+		  dev->nbuffers);
+
+	if (index >= dev->nbuffers)
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(struct v4l2_buffer));
+
+	buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	buf->index = index;
+	buf->memory = V4L2_MEMORY_MMAP;
+	buf->m.offset = index * dev->len_per_image;
+	buf->bytesused = dev->image_size;
+	buf->field = V4L2_FIELD_NONE;
+	buf->length = dev->len_per_image;
+	buf->flags = V4L2_BUF_FLAG_MAPPED | dev->image_f[index];
+	if (dev->full_frames != NULL)
+		buf->flags |= V4L2_BUF_FLAG_DONE;
+
+	return 0;
+}
+
+static int stk11xx_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	struct stk11xx *dev = fh;
+
+	dev_dbg(&dev->udev->dev, "VIDIOC_QBUF\n");
+
+	if (buf->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	if (buf->index >= dev->nbuffers)
+		return -EINVAL;
+
+	if (dev->image_f[buf->index] & V4L2_BUF_FLAG_QUEUED)
+		return -EBUSY;
+
+	dev->image_f[buf->index] |= V4L2_BUF_FLAG_QUEUED;
+	buf->flags |= V4L2_BUF_FLAG_QUEUED;
+	buf->flags &= ~V4L2_BUF_FLAG_DONE;
+
+	return 0;
+}
+
+static int stk11xx_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+	struct stk11xx *dev = fh;
+	int retval;
+
+	dev_dbg(&dev->udev->dev, "VIDIOC_DQBUF\n");
+
+	if (dev->full_frames == NULL && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	retval = wait_event_interruptible(dev->wait_frame,
+			dev->full_frames != NULL || dev->error_status);
+
+	if (retval)
+		return retval;
+	if (dev->error_status)
+		return -dev->error_status;
+
+	dev_dbg(&dev->udev->dev, "VIDIOC_DQBUF: frame ready\n");
+
+	retval = stk11xx_handle_frame(dev);
+
+	if (retval)
+		return -EFAULT;
+
+	buf->index = dev->fill_image;
+	buf->bytesused = dev->image_size;
+	buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+	buf->field = V4L2_FIELD_NONE;
+	do_gettimeofday(&buf->timestamp);
+	buf->sequence = 0;
+	buf->memory = V4L2_MEMORY_MMAP;
+	buf->m.offset = dev->fill_image * dev->len_per_image;
+	buf->length = buf->bytesused;
+
+	stk11xx_next_image(dev);
+
+	return 0;
+}
+
+static int stk11xx_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	return i == V4L2_BUF_TYPE_VIDEO_CAPTURE ? stk11xx_isoc_init(fh):-EINVAL;
+}
+
+static int stk11xx_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+	return i == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+		stk11xx_isoc_cleanup(fh), 0 : -EINVAL;
+}
+
+static int stk11xx_g_parm(struct file *file, void *fh,
+		struct v4l2_streamparm *sp)
+{
+	pr_debug("GET PARM %d\n", sp->type);
+
+	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	sp->parm.capture.capability = 0;
+	sp->parm.capture.capturemode = 0;
+	sp->parm.capture.timeperframe.numerator = 1;
+	sp->parm.capture.timeperframe.denominator = 30;
+	sp->parm.capture.readbuffers = 2;
+	sp->parm.capture.extendedmode = 0;
+
+	return 0;
+}
+/*
+static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cc)
+{
+	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	cc->pixelaspect.numerator = 1;
+	cc->pixelaspect.denominator = 1;
+	cc->bounds.top = 0;
+	cc->bounds.left = 0;
+	cc->bounds.width = 640;
+	cc->bounds.height = 480;
+	cc->defrect.top = 0;
+	cc->defrect.left = 0;
+	cc->defrect.width = 640;
+	cc->defrect.height = 480;
+
+	return 0;
+}
+*/
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int stk11xx_gmbuf(struct file *file, void *fh, struct video_mbuf *vm)
+{
+	struct stk11xx *dev = fh;
+	unsigned int i;
+
+	dev_dbg(&dev->udev->dev, "VIDIOCGMBUF\n");
+
+	vm->size = dev->nbuffers * dev->len_per_image;
+	vm->frames = dev->nbuffers;
+
+	for (i = 0; i < dev->nbuffers; i++)
+		vm->offsets[i] = i * dev->len_per_image;
+
+	return 0;
+}
+#else
+#define stk11xx_gmbuf NULL
+#endif
+
+static struct file_operations stk11xx_fops = {
+	.owner = THIS_MODULE,
+	.open = stk11xx_open,
+	.release = stk11xx_release,
+	.read = stk11xx_read,
+	.poll = stk11xx_poll,
+	.mmap = stk11xx_mmap,
+	.ioctl = video_ioctl2
+};
+
+static const struct video_device stk11xx_vdev_template = {
+	.name = DRIVER_DESC,
+
+	.type2 = VID_TYPE_CAPTURE,
+	.tvnorms = V4L2_STD_UNKNOWN,
+	.current_norm = V4L2_STD_UNKNOWN,
+	.fops = &stk11xx_fops,
+	.release = video_device_release,
+	.minor = -1,
+
+	.vidioc_querycap = stk11xx_querycap,
+	.vidioc_enum_input = stk11xx_enum_input,
+	.vidioc_g_input = stk11xx_g_input,
+	.vidioc_s_input = stk11xx_s_input,
+	.vidioc_queryctrl = stk11xx_queryctrl,
+	.vidioc_g_ctrl = stk11xx_g_ctrl,
+	.vidioc_s_ctrl = stk11xx_s_ctrl,
+	.vidioc_enum_fmt_cap = stk11xx_enum_fmt_cap,
+	.vidioc_g_fmt_cap = stk11xx_g_fmt_cap,
+	.vidioc_s_fmt_cap = stk11xx_s_fmt_cap,
+	.vidioc_try_fmt_cap = stk11xx_try_fmt_cap,
+	.vidioc_querystd = stk11xx_querystd,
+	.vidioc_s_std = stk11xx_s_std,
+	.vidioc_reqbufs = stk11xx_reqbufs,
+	.vidioc_querybuf = stk11xx_querybuf,
+	.vidioc_qbuf = stk11xx_qbuf,
+	.vidioc_dqbuf = stk11xx_dqbuf,
+	.vidioc_streamon = stk11xx_streamon,
+	.vidioc_streamoff = stk11xx_streamoff,
+	.vidioc_g_parm = stk11xx_g_parm,
+
+	.vidiocgmbuf = stk11xx_gmbuf,
+};
+
+/*
+ * sysfs stuff
+ */
+
+static ssize_t show_brightness(struct class_device *class, char *buf)
+{
+	struct stk11xx *dev = video_get_drvdata(to_video_device(class));
+
+	return sprintf(buf, "%X\n", dev->vsettings.brightness);
+}
+
+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(brightness, S_IRUGO, show_brightness, NULL);
+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
+ */
+
+/* this function is written from the USB log */
+static int stk1125_initialize_device(struct stk11xx *dev)
+{
+	unsigned int i;
+	int value;
+
+	const u8 values_1[] = {
+		0x24, 0x24, 0x26, 0x27, 0x26, 0x26, 0x27, 0x26, 0x24, 0x25,
+		0x24, 0x26, 0x27, 0x26, 0x24, 0x25, 0x24, 0x26, 0x27, 0x26,
+		0x24, 0x25, 0x24, 0x26, 0x27, 0x26, 0x24, 0x25
+	};
+	const u8 values_2[] = {
+		0x24, 0x24, 0x26, 0x27, 0x26, 0x26, 0x27, 0x26, 0x24, 0x25,
+		0x24, 0x24, 0x25, 0x24, 0x24, 0x25, 0x24, 0x26, 0x27, 0x26,
+		0x24, 0x25, 0x24, 0x26, 0x27, 0x26, 0x24, 0x25, 0x24, 0x26,
+		0x27, 0x26, 0x24, 0x25
+	};
+	const u8 values_3[] = {
+		0x24, 0x24, 0x26, 0x27, 0x26, 0x26, 0x27, 0x26, 0x24, 0x25,
+		0x24, 0x24, 0x25, 0x24, 0x24, 0x25, 0x24, 0x24, 0x25, 0x24,
+		0x24, 0x25, 0x24, 0x26, 0x27, 0x26, 0x24, 0x25, 0x24, 0x26,
+		0x27, 0x26, 0x24, 0x25, 0x24, 0x26, 0x27, 0x26, 0x24, 0x25
+	};
+
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0002, 0x0068);
+	stk11xx_write_registry(dev, 0x0003, 0x0080);
+
+	stk11xx_write_registry(dev, 0x0002, 0x006F);
+	for (i = 0; i < ARRAY_SIZE(values_1); i++)
+		stk11xx_write_registry(dev, 0x0000, values_1[i]);
+	stk11xx_write_registry(dev, 0x0002, 0x006D);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_registry(dev, 0x0000, 0x0025);
+		stk11xx_write_registry(dev, 0x0000, 0x0024);
+		stk11xx_read_registry(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 1: Read 0x0000 = %02x\n", value);
+	}
+
+	stk11xx_write_registry(dev, 0x0000, 0x0025);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk11xx_write_registry(dev, 0x0002, 0x006F);
+	for (i = 0; i < ARRAY_SIZE(values_2); i++)
+		stk11xx_write_registry(dev, 0x0000, values_2[i]);
+	stk11xx_write_registry(dev, 0x0002, 0x006D);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_registry(dev, 0x0000, 0x0025);
+		stk11xx_write_registry(dev, 0x0000, 0x0024);
+		stk11xx_read_registry(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 2: Read 0x0000 = %02x\n", value);
+	}
+
+	stk11xx_write_registry(dev, 0x0000, 0x0025);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk11xx_write_registry(dev, 0x0002, 0x006F);
+	for (i = 0; i < ARRAY_SIZE(values_3); i++)
+		stk11xx_write_registry(dev, 0x0000, values_3[i]);
+	stk11xx_write_registry(dev, 0x0002, 0x006D);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_registry(dev, 0x0000, 0x0025);
+		stk11xx_write_registry(dev, 0x0000, 0x0024);
+		stk11xx_read_registry(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 3: Read 0x0000 = %02x\n", value);
+	}
+
+	stk11xx_write_registry(dev, 0x0000, 0x0025);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+	stk11xx_write_registry(dev, 0x0002, 0x006F);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk11xx_write_registry(dev, 0x0117, 0x0000);
+	stk11xx_read_registry(dev, 0x0103, &value);
+	stk11xx_write_registry(dev, 0x0103, 0x0001);
+	stk11xx_read_registry(dev, 0x0103, &value);
+	stk11xx_write_registry(dev, 0x0103, 0x0000);
+
+	stk11xx_write_registry(dev, 0x0000, 0x00E0);
+	stk11xx_write_registry(dev, 0x0002, 0x00E8);
+	stk11xx_write_registry(dev, 0x0002, 0x0068);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk1125_configure_device(dev, 0);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1125_configure_device(dev, 1);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1125_configure_device(dev, 2);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x0013);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x000A);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x000B);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+	stk1125_configure_device(dev, 3);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1125_configure_device(dev, 4);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1125_configure_device(dev, 5);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x0013);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x000A);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x000B);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+	stk1125_configure_device(dev, 6);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x0013);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x000A);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x000B);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+	stk1125_configure_device(dev, 7);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x0013);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x000A);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_read_registry(dev, 0x02FF, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+	stk11xx_write_registry(dev, 0x0208, 0x000B);
+	stk11xx_write_registry(dev, 0x0200, 0x0020);
+	stk11xx_check_device(dev, 500);
+	stk11xx_read_registry(dev, 0x0209, &value);
+	stk11xx_write_registry(dev, 0x02FF, 0x0000);
+
+	stk11xx_write_registry(dev, 0x0002, 0x006F);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0002, 0x006D);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0000, 0x0025);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk1125_configure_device(dev, 8);
+
+	stk1125_camera_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+	dev_info(&dev->udev->dev, "syntek USB2.0 Camera is ready\n");
+
+	return 0;
+}
+
+/* this function is written from the USB log */
+static int stk1135_initialize_device(struct stk11xx *dev)
+{
+	unsigned int i;
+	int value;
+
+	const u8 values_1[] = {
+		0x24, 0x24, 0x26, 0x27, 0x26, 0x26, 0x27, 0x26, 0x24, 0x25,
+		0x24, 0x26, 0x27, 0x26, 0x24, 0x25, 0x24, 0x26, 0x27, 0x26,
+		0x24, 0x25, 0x24, 0x26, 0x27, 0x26, 0x24, 0x25
+	};
+	const u8 values_2[] = {
+		0x24, 0x24, 0x26, 0x27, 0x26, 0x26, 0x27, 0x26, 0x24, 0x25,
+		0x24, 0x24, 0x25, 0x24, 0x24, 0x25, 0x24, 0x26, 0x27, 0x26,
+		0x24, 0x25, 0x24, 0x26, 0x27, 0x26, 0x24, 0x25, 0x24, 0x26,
+		0x27, 0x26, 0x24, 0x25
+	};
+	const u8 values_3[] = {
+		0x24, 0x24, 0x26, 0x27, 0x26, 0x26, 0x27, 0x26, 0x24, 0x25,
+		0x24, 0x24, 0x25, 0x24, 0x24, 0x25, 0x24, 0x24, 0x25, 0x24,
+		0x24, 0x25, 0x24, 0x26, 0x27, 0x26, 0x24, 0x25, 0x24, 0x26,
+		0x27, 0x26, 0x24, 0x25, 0x24, 0x26, 0x27, 0x26, 0x24, 0x25
+	};
+
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0002, 0x0068);
+	stk11xx_write_registry(dev, 0x0003, 0x0080);
+
+	stk11xx_write_registry(dev, 0x0002, 0x006F);
+	for (i = 0; i < ARRAY_SIZE(values_1); i++)
+		stk11xx_write_registry(dev, 0x0000, values_1[i]);
+	stk11xx_write_registry(dev, 0x0002, 0x006D);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_registry(dev, 0x0000, 0x0025);
+		stk11xx_write_registry(dev, 0x0000, 0x0024);
+		stk11xx_read_registry(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 1: Read 0x0000 = %02x\n", value);
+	}
+
+	stk11xx_write_registry(dev, 0x0000, 0x0025);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk11xx_write_registry(dev, 0x0002, 0x006F);
+	for (i = 0; i < ARRAY_SIZE(values_2); i++)
+		stk11xx_write_registry(dev, 0x0000, values_2[i]);
+	stk11xx_write_registry(dev, 0x0002, 0x006D);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_registry(dev, 0x0000, 0x0025);
+		stk11xx_write_registry(dev, 0x0000, 0x0024);
+		stk11xx_read_registry(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 2: Read 0x0000 = %02x\n", value);
+	}
+
+	stk11xx_write_registry(dev, 0x0000, 0x0025);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk11xx_write_registry(dev, 0x0002, 0x006F);
+	for (i = 0; i < ARRAY_SIZE(values_3); i++)
+		stk11xx_write_registry(dev, 0x0000, values_3[i]);
+	stk11xx_write_registry(dev, 0x0002, 0x006D);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+
+	for (i = 0; i < 16; i++) {
+		stk11xx_write_registry(dev, 0x0000, 0x0025);
+		stk11xx_write_registry(dev, 0x0000, 0x0024);
+		stk11xx_read_registry(dev, 0x0000, &value);
+
+		dev_dbg(&dev->udev->dev, "Loop 3: Read 0x0000 = %02x\n", value);
+	}
+
+	stk11xx_write_registry(dev, 0x0000, 0x0025);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+	stk11xx_write_registry(dev, 0x0002, 0x006F);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk11xx_write_registry(dev, 0x0117, 0x0000);
+	stk11xx_read_registry(dev, 0x0103, &value);
+	stk11xx_write_registry(dev, 0x0103, 0x0001);
+	stk11xx_read_registry(dev, 0x0103, &value);
+	stk11xx_write_registry(dev, 0x0103, 0x0000);
+
+	stk11xx_write_registry(dev, 0x0000, 0x00E0);
+	stk11xx_write_registry(dev, 0x0002, 0x00E8);
+	stk11xx_write_registry(dev, 0x0002, 0x0068);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk1135_configure_device(dev, 0);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1135_configure_device(dev, 1);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1135_configure_device(dev, 2);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1135_configure_device(dev, 3);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1135_configure_device(dev, 4);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1135_configure_device(dev, 5);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1135_configure_device(dev, 6);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1135_configure_device(dev, 7);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1135_configure_device(dev, 8);
+	stk11xx_check_device(dev, 65);
+	stk11xx_write_registry(dev, 0x0200, 0x0008);
+
+	stk1135_configure_device(dev, 9);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0002, 0x006D);
+	stk11xx_write_registry(dev, 0x0000, 0x0024);
+	stk11xx_write_registry(dev, 0x0000, 0x0025);
+	stk11xx_write_registry(dev, 0x0000, 0x0020);
+
+	stk1135_configure_device(dev, 10);
+	stk11xx_write_registry(dev, 0x0200, 0x0080);
+	stk11xx_write_registry(dev, 0x0200, 0x0000);
+	stk11xx_write_registry(dev, 0x02FF, 0x0001);
+	stk11xx_write_registry(dev, 0x0203, 0x00A0);
+
+	stk1135_camera_asleep(dev);
+
+	stk11xx_set_feature(dev, 0);
+
+	dev_info(&dev->udev->dev, "syntek USB2.0 Camera is ready\n");
+
+	return 0;
+}
+
+/* 
+ * This function must be called at first. It's the start of the
+ * initialization process. After this process, the device is
+ * completly initalized and it's ready.
+ */
+static int stk11xx_initialize_device(struct stk11xx *dev)
+{
+	int ret = -1;
+
+	switch (dev->webcam_model) {
+	case SYNTEK_DC1125:
+		ret = stk1125_initialize_device(dev);
+		break;
+	case SYNTEK_STK1135:
+		ret = stk1135_initialize_device(dev);
+		break;
+	}
+
+	return ret;
+}
+
+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;
+	size_t buffer_size;
+	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_info(&udev->dev, "Syntek USB2.0 - STK-%.4u based webcam found\n",
+		id->driver_info == SYNTEK_DC1125 ? 1125 : 1135);
+
+	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);
+
+	dev->webcam_model = id->driver_info;
+	dev->udev = udev;
+
+	dev->vsettings.fps = default_fps;
+	dev->nbuffers = 2;
+	dev->len_per_image = PAGE_ALIGN((1280 * 1024 * 3));
+
+/* 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_camera_on(dev);
+
+	/* Set up the endpoint information */
+	/* use only the first int-in and isoc-in endpoints */
+	/* 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->int_in_endpointAddr && ((endpoint->bEndpointAddress &
+					USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
+				((endpoint->bmAttributes &
+					USB_ENDPOINT_XFERTYPE_MASK) ==
+				USB_ENDPOINT_XFER_INT)) {
+			/* we've found an interrupt in endpoint */
+			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+
+			dev->int_in_size = buffer_size;
+			dev->int_in_endpointAddr =
+					(endpoint->bEndpointAddress & 0xF);
+		}
+
+		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 */
+			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+
+			dev->isoc_in_size = buffer_size;
+			dev->isoc_in_endpointAddr =
+					(endpoint->bEndpointAddress & 0xF);
+		}
+	}
+
+	if (!(dev->int_in_endpointAddr && dev->isoc_in_endpointAddr)) {
+		dev_err(&udev->dev, "can't find both int-in and isoc-in "
+				"endpoints\n");
+		retval = -ENODEV;
+		goto err_free;
+	}
+
+	stk11xx_camera_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 = stk11xx_initialize_device(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_brightness);
+	stk11xx_create_sysfs_file(dev, &class_device_attr_contrast);
+	stk11xx_create_sysfs_file(dev, &class_device_attr_whitebalance);
+	usb_set_intfdata(interface, dev);
+
+	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);
+
+	class_device_remove_file(&dev->vdev->class_dev,
+					&class_device_attr_brightness);
+	class_device_remove_file(&dev->vdev->class_dev,
+					&class_device_attr_contrast);
+	class_device_remove_file(&dev->vdev->class_dev,
+					&class_device_attr_whitebalance);
+	video_unregister_device(dev->vdev);
+	kfree(dev);
+}
+
+static struct usb_device_id stk11xx_usb_ids[] = {
+	{ USB_DEVICE(USB_SYNTEK1_VENDOR_ID, USB_STK1125_PRODUCT_ID),
+		.driver_info = SYNTEK_DC1125 },
+	{ USB_DEVICE(USB_SYNTEK1_VENDOR_ID, USB_STK1135_PRODUCT_ID),
+		.driver_info = SYNTEK_STK1135 },
+	{ USB_DEVICE(USB_SYNTEK2_VENDOR_ID, USB_DC1125_PRODUCT_ID),
+		.driver_info = SYNTEK_DC1125 },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, stk11xx_usb_ids);
+
+static struct usb_driver stk11xx_usb_driver = {
+	.name = "usb_stk11xx_driver",
+	.probe = stk11xx_usb_probe,
+	.disconnect = stk11xx_usb_disconnect,
+	.id_table = stk11xx_usb_ids,
+};
+
+static int __init stk11xx_init(void)
+{
+	int result;
+
+	if (fps) {
+		if (fps < 5 || fps > 30) {
+			printk(KERN_ERR "stk11xx: framerate out of bounds "
+					"[5-30]\n");
+			return -EINVAL;
+		}
+
+		default_fps = fps;
+	}
+
+	result = usb_register(&stk11xx_usb_driver);
+	if (result)
+		printk(KERN_ERR "stk11xx: usb_register failed!\n");
+
+	return result;
+}
+
+static void __exit stk11xx_exit(void)
+{
+	usb_deregister(&stk11xx_usb_driver);
+}
+
+module_init(stk11xx_init);
+module_exit(stk11xx_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas VIVIEN");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_SUPPORTED_DEVICE("Syntek USB Camera: DC1125, STK1135");
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux