All of lore.kernel.org
 help / color / mirror / Atom feed
* Syntek webcams and out-of-tree driver
@ 2013-08-05 21:19 Ondrej Zary
  2013-08-06  6:10 ` Hans de Goede
  0 siblings, 1 reply; 4+ messages in thread
From: Ondrej Zary @ 2013-08-05 21:19 UTC (permalink / raw)
  To: linux-media; +Cc: Jaime Velasco Juan, syntekdriver-devel

Hello,
the in-kernel stkwebcam driver (by Jaime Velasco Juan and Nicolas VIVIEN)
supports only two webcam types (USB IDs 0x174f:0xa311 and 0x05e1:0x0501).
There are many other Syntek webcam types that are not supported by this
driver (such as 0x174f:0x6a31 in Asus F5RL laptop).

There is an out-of-tree GPL driver called stk11xx (by Martin Roos and also
Nicolas VIVIEN) at http://sourceforge.net/projects/syntekdriver/ which
supports more webcams. It can be even compiled for the latest kernels using
the patch below and seems to work somehow (slow and buggy but better than
nothing) with the Asus F5RL.

Is there any possibility that this driver could be merged into the kernel?
The code could probably be simplified a lot and integrated into gspca.


diff -urp syntekdriver-code-107-trunk-orig/driver/stk11xx.h syntekdriver-code-107-trunk//driver/stk11xx.h
--- syntekdriver-code-107-trunk-orig/driver/stk11xx.h	2012-03-10 10:03:12.000000000 +0100
+++ syntekdriver-code-107-trunk//driver/stk11xx.h	2013-08-05 22:50:00.000000000 +0200
@@ -33,6 +33,7 @@
 
 #ifndef STK11XX_H
 #define STK11XX_H
+#include <media/v4l2-device.h>
 
 #define DRIVER_NAME					"stk11xx"					/**< Name of this driver */
 #define DRIVER_VERSION				"v3.0.0"					/**< Version of this driver */
@@ -316,6 +317,7 @@ struct stk11xx_video {
  * @struct usb_stk11xx
  */
 struct usb_stk11xx {
+	struct v4l2_device v4l2_dev;
 	struct video_device *vdev; 			/**< Pointer on a V4L2 video device */
 	struct usb_device *udev;			/**< Pointer on a USB device */
 	struct usb_interface *interface;	/**< Pointer on a USB interface */
diff -urp syntekdriver-code-107-trunk-orig/driver/stk11xx-v4l.c syntekdriver-code-107-trunk//driver/stk11xx-v4l.c
--- syntekdriver-code-107-trunk-orig/driver/stk11xx-v4l.c	2012-03-10 09:54:57.000000000 +0100
+++ syntekdriver-code-107-trunk//driver/stk11xx-v4l.c	2013-08-05 22:51:12.000000000 +0200
@@ -1498,9 +1498,17 @@ int v4l_stk11xx_register_video_device(st
 {
 	int err;
 
+	err = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
+	if (err < 0) {
+		STK_ERROR("couldn't register v4l2_device\n");
+		kfree(dev);
+		return err;
+	}
+
 	strcpy(dev->vdev->name, DRIVER_DESC);
 
-	dev->vdev->parent = &dev->interface->dev;
+//	dev->vdev->parent = &dev->interface->dev;
+	dev->vdev->v4l2_dev = &dev->v4l2_dev;
 	dev->vdev->fops = &v4l_stk11xx_fops;
 	dev->vdev->release = video_device_release;
 	dev->vdev->minor = -1;
@@ -1533,6 +1541,7 @@ int v4l_stk11xx_unregister_video_device(
 
 	video_set_drvdata(dev->vdev, NULL);
 	video_unregister_device(dev->vdev);
+	v4l2_device_unregister(&dev->v4l2_dev);
 
 	return 0;
 }



-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Syntek webcams and out-of-tree driver
  2013-08-05 21:19 Syntek webcams and out-of-tree driver Ondrej Zary
@ 2013-08-06  6:10 ` Hans de Goede
  2013-08-06 13:05   ` Ondrej Zary
  2013-08-07 21:30   ` Ondrej Zary
  0 siblings, 2 replies; 4+ messages in thread
From: Hans de Goede @ 2013-08-06  6:10 UTC (permalink / raw)
  To: Ondrej Zary; +Cc: linux-media, Jaime Velasco Juan, syntekdriver-devel

Hi,

On 08/05/2013 11:19 PM, Ondrej Zary wrote:
> Hello,
> the in-kernel stkwebcam driver (by Jaime Velasco Juan and Nicolas VIVIEN)
> supports only two webcam types (USB IDs 0x174f:0xa311 and 0x05e1:0x0501).
> There are many other Syntek webcam types that are not supported by this
> driver (such as 0x174f:0x6a31 in Asus F5RL laptop).
>
> There is an out-of-tree GPL driver called stk11xx (by Martin Roos and also
> Nicolas VIVIEN) at http://sourceforge.net/projects/syntekdriver/ which
> supports more webcams. It can be even compiled for the latest kernels using
> the patch below and seems to work somehow (slow and buggy but better than
> nothing) with the Asus F5RL.

I took a quick look and there are a number of issues with this driver:

1) It conflicts usb-id wise with the new stk1160 driver (which supports
usb-id 05e1:0408) so support for that usb-id, and any code only used for
that id will need to be removed

2) "seems to work somehow (slow and buggy)" is not really the quality
we aim for with in kernel drivers. We definitely will want to remove
any usb-ids, and any code only used for those ids, where there is overlap
with the existing stkwebcam driver, to avoid regressions

3) It does in kernel bayer decoding, this is not acceptable, it needs to
be modified to produce buffers with raw bayer data (libv4l will take care
of the bater decoding in userspace).

4) It is not using any of the new kernel infrastructure we have been adding
over time, like the control-framework, videobuf2, etc. It would be best
to convert this to a gspca sub driver (of which there are many already,
which can serve as examples), so that it will use all the existing framework
code.

As a minimum issues 1-3 needs to be addressed before this can be merged. An
alternative /  better approach might be to simply only lift the code for your
camera, and add a new gspca driver supporting only your camera.

Either way since non of the v4l developers have a laptop which such a camera,
you will need to do most of the work yourself, as we cannot test.

So congratulations, you've just become a v4l kernel developer :)

Regards,

Hans


>
> Is there any possibility that this driver could be merged into the kernel?
> The code could probably be simplified a lot and integrated into gspca.
>
>
> diff -urp syntekdriver-code-107-trunk-orig/driver/stk11xx.h syntekdriver-code-107-trunk//driver/stk11xx.h
> --- syntekdriver-code-107-trunk-orig/driver/stk11xx.h	2012-03-10 10:03:12.000000000 +0100
> +++ syntekdriver-code-107-trunk//driver/stk11xx.h	2013-08-05 22:50:00.000000000 +0200
> @@ -33,6 +33,7 @@
>
>   #ifndef STK11XX_H
>   #define STK11XX_H
> +#include <media/v4l2-device.h>
>
>   #define DRIVER_NAME					"stk11xx"					/**< Name of this driver */
>   #define DRIVER_VERSION				"v3.0.0"					/**< Version of this driver */
> @@ -316,6 +317,7 @@ struct stk11xx_video {
>    * @struct usb_stk11xx
>    */
>   struct usb_stk11xx {
> +	struct v4l2_device v4l2_dev;
>   	struct video_device *vdev; 			/**< Pointer on a V4L2 video device */
>   	struct usb_device *udev;			/**< Pointer on a USB device */
>   	struct usb_interface *interface;	/**< Pointer on a USB interface */
> diff -urp syntekdriver-code-107-trunk-orig/driver/stk11xx-v4l.c syntekdriver-code-107-trunk//driver/stk11xx-v4l.c
> --- syntekdriver-code-107-trunk-orig/driver/stk11xx-v4l.c	2012-03-10 09:54:57.000000000 +0100
> +++ syntekdriver-code-107-trunk//driver/stk11xx-v4l.c	2013-08-05 22:51:12.000000000 +0200
> @@ -1498,9 +1498,17 @@ int v4l_stk11xx_register_video_device(st
>   {
>   	int err;
>
> +	err = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
> +	if (err < 0) {
> +		STK_ERROR("couldn't register v4l2_device\n");
> +		kfree(dev);
> +		return err;
> +	}
> +
>   	strcpy(dev->vdev->name, DRIVER_DESC);
>
> -	dev->vdev->parent = &dev->interface->dev;
> +//	dev->vdev->parent = &dev->interface->dev;
> +	dev->vdev->v4l2_dev = &dev->v4l2_dev;
>   	dev->vdev->fops = &v4l_stk11xx_fops;
>   	dev->vdev->release = video_device_release;
>   	dev->vdev->minor = -1;
> @@ -1533,6 +1541,7 @@ int v4l_stk11xx_unregister_video_device(
>
>   	video_set_drvdata(dev->vdev, NULL);
>   	video_unregister_device(dev->vdev);
> +	v4l2_device_unregister(&dev->v4l2_dev);
>
>   	return 0;
>   }
>
>
>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Syntek webcams and out-of-tree driver
  2013-08-06  6:10 ` Hans de Goede
@ 2013-08-06 13:05   ` Ondrej Zary
  2013-08-07 21:30   ` Ondrej Zary
  1 sibling, 0 replies; 4+ messages in thread
From: Ondrej Zary @ 2013-08-06 13:05 UTC (permalink / raw)
  To: Hans de Goede; +Cc: linux-media, Jaime Velasco Juan, syntekdriver-devel

On Tuesday 06 August 2013, Hans de Goede wrote:
> Hi,
>
> On 08/05/2013 11:19 PM, Ondrej Zary wrote:
> > Hello,
> > the in-kernel stkwebcam driver (by Jaime Velasco Juan and Nicolas VIVIEN)
> > supports only two webcam types (USB IDs 0x174f:0xa311 and 0x05e1:0x0501).
> > There are many other Syntek webcam types that are not supported by this
> > driver (such as 0x174f:0x6a31 in Asus F5RL laptop).
> >
> > There is an out-of-tree GPL driver called stk11xx (by Martin Roos and
> > also Nicolas VIVIEN) at http://sourceforge.net/projects/syntekdriver/
> > which supports more webcams. It can be even compiled for the latest
> > kernels using the patch below and seems to work somehow (slow and buggy
> > but better than nothing) with the Asus F5RL.
>
> I took a quick look and there are a number of issues with this driver:
>
> 1) It conflicts usb-id wise with the new stk1160 driver (which supports
> usb-id 05e1:0408) so support for that usb-id, and any code only used for
> that id will need to be removed
>
> 2) "seems to work somehow (slow and buggy)" is not really the quality
> we aim for with in kernel drivers. We definitely will want to remove
> any usb-ids, and any code only used for those ids, where there is overlap
> with the existing stkwebcam driver, to avoid regressions
>
> 3) It does in kernel bayer decoding, this is not acceptable, it needs to
> be modified to produce buffers with raw bayer data (libv4l will take care
> of the bater decoding in userspace).
>
> 4) It is not using any of the new kernel infrastructure we have been adding
> over time, like the control-framework, videobuf2, etc. It would be best
> to convert this to a gspca sub driver (of which there are many already,
> which can serve as examples), so that it will use all the existing
> framework code.

Yes, this would be the best way - only extract the HW-dependent parts.

> As a minimum issues 1-3 needs to be addressed before this can be merged. An
> alternative /  better approach might be to simply only lift the code for
> your camera, and add a new gspca driver supporting only your camera.
>
> Either way since non of the v4l developers have a laptop which such a
> camera, you will need to do most of the work yourself, as we cannot test.
>
> So congratulations, you've just become a v4l kernel developer :)

Unfortunately the laptop isn't mine. I'll have it only for a while but will 
try to do something.

> Regards,
>
> Hans
>
> > Is there any possibility that this driver could be merged into the
> > kernel? The code could probably be simplified a lot and integrated into
> > gspca.
> >
> >
> > diff -urp syntekdriver-code-107-trunk-orig/driver/stk11xx.h
> > syntekdriver-code-107-trunk//driver/stk11xx.h ---
> > syntekdriver-code-107-trunk-orig/driver/stk11xx.h	2012-03-10
> > 10:03:12.000000000 +0100 +++
> > syntekdriver-code-107-trunk//driver/stk11xx.h	2013-08-05
> > 22:50:00.000000000 +0200 @@ -33,6 +33,7 @@
> >
> >   #ifndef STK11XX_H
> >   #define STK11XX_H
> > +#include <media/v4l2-device.h>
> >
> >   #define DRIVER_NAME					"stk11xx"					/**< Name of this driver */
> >   #define DRIVER_VERSION				"v3.0.0"					/**< Version of this driver */
> > @@ -316,6 +317,7 @@ struct stk11xx_video {
> >    * @struct usb_stk11xx
> >    */
> >   struct usb_stk11xx {
> > +	struct v4l2_device v4l2_dev;
> >   	struct video_device *vdev; 			/**< Pointer on a V4L2 video device */
> >   	struct usb_device *udev;			/**< Pointer on a USB device */
> >   	struct usb_interface *interface;	/**< Pointer on a USB interface */
> > diff -urp syntekdriver-code-107-trunk-orig/driver/stk11xx-v4l.c
> > syntekdriver-code-107-trunk//driver/stk11xx-v4l.c ---
> > syntekdriver-code-107-trunk-orig/driver/stk11xx-v4l.c	2012-03-10
> > 09:54:57.000000000 +0100 +++
> > syntekdriver-code-107-trunk//driver/stk11xx-v4l.c	2013-08-05
> > 22:51:12.000000000 +0200 @@ -1498,9 +1498,17 @@ int
> > v4l_stk11xx_register_video_device(st
> >   {
> >   	int err;
> >
> > +	err = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
> > +	if (err < 0) {
> > +		STK_ERROR("couldn't register v4l2_device\n");
> > +		kfree(dev);
> > +		return err;
> > +	}
> > +
> >   	strcpy(dev->vdev->name, DRIVER_DESC);
> >
> > -	dev->vdev->parent = &dev->interface->dev;
> > +//	dev->vdev->parent = &dev->interface->dev;
> > +	dev->vdev->v4l2_dev = &dev->v4l2_dev;
> >   	dev->vdev->fops = &v4l_stk11xx_fops;
> >   	dev->vdev->release = video_device_release;
> >   	dev->vdev->minor = -1;
> > @@ -1533,6 +1541,7 @@ int v4l_stk11xx_unregister_video_device(
> >
> >   	video_set_drvdata(dev->vdev, NULL);
> >   	video_unregister_device(dev->vdev);
> > +	v4l2_device_unregister(&dev->v4l2_dev);
> >
> >   	return 0;
> >   }



-- 
Ondrej Zary

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Syntek webcams and out-of-tree driver
  2013-08-06  6:10 ` Hans de Goede
  2013-08-06 13:05   ` Ondrej Zary
@ 2013-08-07 21:30   ` Ondrej Zary
  1 sibling, 0 replies; 4+ messages in thread
From: Ondrej Zary @ 2013-08-07 21:30 UTC (permalink / raw)
  To: Hans de Goede; +Cc: linux-media, Jaime Velasco Juan, syntekdriver-devel

On Tuesday 06 August 2013 08:10:38 Hans de Goede wrote:
> Hi,
>
> On 08/05/2013 11:19 PM, Ondrej Zary wrote:
> > Hello,
> > the in-kernel stkwebcam driver (by Jaime Velasco Juan and Nicolas VIVIEN)
> > supports only two webcam types (USB IDs 0x174f:0xa311 and 0x05e1:0x0501).
> > There are many other Syntek webcam types that are not supported by this
> > driver (such as 0x174f:0x6a31 in Asus F5RL laptop).
> >
> > There is an out-of-tree GPL driver called stk11xx (by Martin Roos and
> > also Nicolas VIVIEN) at http://sourceforge.net/projects/syntekdriver/
> > which supports more webcams. It can be even compiled for the latest
> > kernels using the patch below and seems to work somehow (slow and buggy
> > but better than nothing) with the Asus F5RL.
>
> I took a quick look and there are a number of issues with this driver:
>
> 1) It conflicts usb-id wise with the new stk1160 driver (which supports
> usb-id 05e1:0408) so support for that usb-id, and any code only used for
> that id will need to be removed
>
> 2) "seems to work somehow (slow and buggy)" is not really the quality
> we aim for with in kernel drivers. We definitely will want to remove
> any usb-ids, and any code only used for those ids, where there is overlap
> with the existing stkwebcam driver, to avoid regressions
>
> 3) It does in kernel bayer decoding, this is not acceptable, it needs to
> be modified to produce buffers with raw bayer data (libv4l will take care
> of the bater decoding in userspace).
>
> 4) It is not using any of the new kernel infrastructure we have been adding
> over time, like the control-framework, videobuf2, etc. It would be best
> to convert this to a gspca sub driver (of which there are many already,
> which can serve as examples), so that it will use all the existing
> framework code.

Here's a proof of concept that this can be done. HW dependent code copied from
stk11xx and modified a bit. Userspace bayer decoding works fine - I get
correct image in cheese (or mplayer with LD_PRELOAD)!

I've also found the STK1135 datasheet!
http://wenku.baidu.com/view/028c3459be23482fb4da4c5d
https://anonfiles.com/file/3b813f8e4c848ed26aaec804e0afa092

So I can clean up the driver now.

---
 drivers/media/usb/gspca/Kconfig   |    9 +
 drivers/media/usb/gspca/Makefile  |    2 +
 drivers/media/usb/gspca/stk1135.c |  968 +++++++++++++++++++++++++++++++++++++
 3 files changed, 979 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/usb/gspca/stk1135.c

diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig
index 6345f93..4f0c6d5 100644
--- a/drivers/media/usb/gspca/Kconfig
+++ b/drivers/media/usb/gspca/Kconfig
@@ -338,6 +338,15 @@ config USB_GSPCA_STK014
 	  To compile this driver as a module, choose M here: the
 	  module will be called gspca_stk014.
 
+config USB_GSPCA_STK1135
+	tristate "Syntek STK1135 USB Camera Driver"
+	depends on VIDEO_V4L2 && USB_GSPCA
+	help
+	  Say Y here if you want support for cameras based on the STK1135 chip.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gspca_stk1135.
+
 config USB_GSPCA_STV0680
 	tristate "STV0680 USB Camera Driver"
 	depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/usb/gspca/Makefile b/drivers/media/usb/gspca/Makefile
index c901da0..5855131 100644
--- a/drivers/media/usb/gspca/Makefile
+++ b/drivers/media/usb/gspca/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_USB_GSPCA_SQ905C)   += gspca_sq905c.o
 obj-$(CONFIG_USB_GSPCA_SQ930X)   += gspca_sq930x.o
 obj-$(CONFIG_USB_GSPCA_SUNPLUS)  += gspca_sunplus.o
 obj-$(CONFIG_USB_GSPCA_STK014)   += gspca_stk014.o
+obj-$(CONFIG_USB_GSPCA_STK1135)  += gspca_stk1135.o
 obj-$(CONFIG_USB_GSPCA_STV0680)  += gspca_stv0680.o
 obj-$(CONFIG_USB_GSPCA_T613)     += gspca_t613.o
 obj-$(CONFIG_USB_GSPCA_TOPRO)    += gspca_topro.o
@@ -78,6 +79,7 @@ gspca_sq905-objs    := sq905.o
 gspca_sq905c-objs   := sq905c.o
 gspca_sq930x-objs   := sq930x.o
 gspca_stk014-objs   := stk014.o
+gspca_stk1135-objs  := stk1135.o
 gspca_stv0680-objs  := stv0680.o
 gspca_sunplus-objs  := sunplus.o
 gspca_t613-objs     := t613.o
diff --git a/drivers/media/usb/gspca/stk1135.c b/drivers/media/usb/gspca/stk1135.c
new file mode 100644
index 0000000..ce17202
--- /dev/null
+++ b/drivers/media/usb/gspca/stk1135.c
@@ -0,0 +1,968 @@
+/*
+ * Syntek STK1135 subdriver
+ *
+ * Copyright (c) 2013 Ondrej Zary
+ *
+ * Based on Syntekdriver by Nicolas VIVIEN:
+ *   http://syntekdriver.sourceforge.net
+ *
+ * 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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#define MODULE_NAME "stk1135"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Ondrej Zary");
+MODULE_DESCRIPTION("Syntek STK1135 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+
+/* specific webcam descriptor */
+struct sd {
+	struct gspca_dev gspca_dev;	/* !! must be the first item */
+};
+
+static const struct v4l2_pix_format stk1135_modes[] = {
+	{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+		.bytesperline = 640,
+		.sizeimage = 640 * 480,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+};
+
+/* -- read a register -- */
+static u8 reg_r(struct gspca_dev *gspca_dev, __u16 index)
+{
+	struct usb_device *dev = gspca_dev->dev;
+	int ret;
+
+	if (gspca_dev->usb_err < 0)
+		return 0;
+	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			0x00,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0x00,
+			index,
+			gspca_dev->usb_buf, 1,
+			500);
+
+	printk("reg_r 0x%x=0x%02x\n", index, gspca_dev->usb_buf[0]);
+	if (ret < 0) {
+		pr_err("reg_r 0x%x err %d\n", index, ret);
+		gspca_dev->usb_err = ret;
+		return 0;
+	}
+
+	return gspca_dev->usb_buf[0];
+}
+
+/* -- write a register -- */
+static void reg_w(struct gspca_dev *gspca_dev, __u16 index, __u8 value)
+{
+	int ret;
+	struct usb_device *dev = gspca_dev->dev;
+
+	if (gspca_dev->usb_err < 0)
+		return;
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			0x01,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value,
+			index,
+			NULL,
+			0,
+			500);
+	printk("reg_w 0x%x:=0x%02x\n", index, value);
+	if (ret < 0) {
+		pr_err("reg_w 0x%x err %d\n", index, ret);
+		gspca_dev->usb_err = ret;
+	}
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+			const struct usb_device_id *id)
+{
+	gspca_dev->cam.cam_mode = stk1135_modes;
+	gspca_dev->cam.nmodes = ARRAY_SIZE(stk1135_modes);
+	return 0;
+}
+
+int dev_stk11xx_check_device(struct gspca_dev *gspca_dev, int nbr)
+{
+	int i;
+	int value;
+
+	for (i=0; i<nbr; i++) {
+		value = reg_r(gspca_dev, 0x201);
+		
+		if (value == 0x00) {
+		}
+		else if ((value == 0x11) || (value == 0x14)) {
+		}
+		else if ((value == 0x30) || (value == 0x31)) {
+		}
+		else if ((value == 0x51)) {
+		}
+		else if ((value == 0x70) || (value == 0x71)) {
+		}
+		else if ((value == 0x91)) {
+		}
+		else if (value == 0x01) {
+			return 1;
+		}
+		else if ((value == 0x04) || (value == 0x05))
+			return 1;
+		else if (value == 0x15) 
+			return 1;
+		else {
+			pr_err("Check device return error (0x0201 = %02X) !\n", value);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int dev_stk6a31_sensor_settings(struct gspca_dev *gspca_dev)
+{
+	int i;
+	int retok;
+
+	int asize;
+	static const int values_204[] = {
+		0xf0, 0xf1, 0x0d, 0xf1, 0x0d, 0xf1, 0xf0, 0xf1, 0x35, 0xf1,
+		0xf0, 0xf1, 0x06, 0xf1, 0xf0, 0xf1, 0xdd, 0xf1, 0xf0, 0xf1,
+		0x1f, 0xf1, 0x20, 0xf1, 0x21, 0xf1, 0x22, 0xf1, 0x23, 0xf1,
+		0x24, 0xf1, 0x28, 0xf1, 0x29, 0xf1, 0x5e, 0xf1, 0x5f, 0xf1, 
+		0x60, 0xf1, 0xef, 0xf1, 0xf2, 0xf1, 0x02, 0xf1, 0x03, 0xf1,
+		0x04, 0xf1, 0x09, 0xf1, 0x0a, 0xf1, 0x0b, 0xf1, 0x0c, 0xf1,
+		0x0d, 0xf1, 0x0e, 0xf1, 0x0f, 0xf1, 0x10, 0xf1, 0x11, 0xf1, 
+		0x15, 0xf1, 0x16, 0xf1, 0x17, 0xf1, 0x18, 0xf1, 0x19, 0xf1,
+		0x1a, 0xf1, 0x1b, 0xf1, 0x1c, 0xf1, 0x1d, 0xf1, 0x1e, 0xf1,
+		0xf0, 0xf1, 0x06, 0xf1, 0x06, 0xf1, 0xf0, 0xf1, 0x80, 0xf1,
+		0x81, 0xf1, 0x82, 0xf1, 0x83, 0xf1, 0x84, 0xf1, 0x85, 0xf1,
+		0x86, 0xf1, 0x87, 0xf1, 0x88, 0xf1, 0x89, 0xf1, 0x8a, 0xf1, 
+		0x8b, 0xf1, 0x8c, 0xf1, 0x8d, 0xf1, 0x8e, 0xf1, 0x8f, 0xf1,
+		0x90, 0xf1, 0x91, 0xf1, 0x92, 0xf1, 0x93, 0xf1, 0x94, 0xf1,
+		0x95, 0xf1, 0xb6, 0xf1, 0xb7, 0xf1, 0xb8, 0xf1, 0xb9, 0xf1,
+		0xba, 0xf1, 0xbb, 0xf1, 0xbc, 0xf1, 0xbd, 0xf1, 0xbe, 0xf1,
+		0xbf, 0xf1, 0xc0, 0xf1, 0xc1, 0xf1, 0xc2, 0xf1, 0xc3, 0xf1,
+		0xc4, 0xf1, 0x06, 0xf1, 0xf0, 0xf1, 0x53, 0xf1, 0x54, 0xf1,
+		0x55, 0xf1, 0x56, 0xf1, 0x57, 0xf1, 0x58, 0xf1, 0xdc, 0xf1,
+		0xdd, 0xf1, 0xde, 0xf1, 0xdf, 0xf1, 0xe0, 0xf1, 0xe1, 0xf1,
+		0xf0, 0xf1, 0xa7, 0xf1, 0xaa, 0xf1, 0x3a, 0xf1, 0xa1, 0xf1,
+		0xa4, 0xf1, 0x9b, 0xf1, 0x08, 0xf1, 0xf0, 0xf1, 0x2f, 0xf1,
+		0x9c, 0xf1, 0xd2, 0xf1, 0xcc, 0xf1, 0xcb, 0xf1, 0x2e, 0xf1,
+		0x67, 0xf1, 0xf0, 0xf1, 0x65, 0xf1, 0x66, 0xf1, 0x67, 0xf1,
+		0x65, 0xf1, 0xf0, 0xf1, 0x05, 0xf1, 0x07, 0xf1, 0xf0, 0xf1,
+		0x39, 0xf1, 0x3b, 0xf1, 0x3a, 0xf1, 0x3c, 0xf1, 0x57, 0xf1,
+		0x58, 0xf1, 0x59, 0xf1, 0x5a, 0xf1, 0x5c, 0xf1, 0x5d, 0xf1,
+		0x64, 0xf1, 0xf0, 0xf1, 0x5b, 0xf1, 0xf0, 0xf1, 0x36, 0xf1,
+		0x37, 0xf1, 0xf0, 0xf1, 0x08, 0xf1
+	};
+	static const int values_205[] = {
+		0x00, 0x00, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x00, 0x00, 0x22,
+		0x00, 0x01, 0x70, 0x0e, 0x00, 0x02, 0x18, 0xe0, 0x00, 0x02,
+		0x01, 0x80, 0xc8, 0x14, 0x80, 0x80, 0xa0, 0x78, 0xa0, 0x78,
+		0x5f, 0x20, 0xea, 0x02, 0x86, 0x7a, 0x59, 0x4c, 0x4d, 0x51,
+		0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0xee, 0x39, 0x23,
+		0x07, 0x24, 0x00, 0xcd, 0x00, 0x93, 0x00, 0x04, 0x00, 0x5c,
+		0x00, 0xd9, 0x00, 0x53, 0x00, 0x08, 0x00, 0x91, 0x00, 0xcf,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x01, 0xf0, 0x0e, 0x70, 0x0e, 0x00, 0x01, 0x00, 0x07,
+		0xde, 0x13, 0xeb, 0xe2, 0x00, 0xf6, 0xe1, 0x14, 0xea, 0xdd,
+		0xfd, 0xf6, 0xe5, 0x11, 0xed, 0xe6, 0xfb, 0xf7, 0xd6, 0x13, 
+		0xed, 0xec, 0xf9, 0xf2, 0x00, 0x00, 0xd8, 0x15, 0xe9, 0xea, 
+		0xf9, 0xf1, 0x00, 0x02, 0xde, 0x10, 0xef, 0xef, 0xfb, 0xf4,
+		0x00, 0x02, 0x0e, 0x06, 0x27, 0x13, 0x11, 0x06, 0x27, 0x13,
+		0x0c, 0x03, 0x2a, 0x0f, 0x12, 0x08, 0x1a, 0x16, 0x00, 0x22,
+		0x15, 0x0a, 0x1c, 0x1a, 0x00, 0x2d, 0x11, 0x09, 0x14, 0x14,
+		0x00, 0x2a, 0x74, 0x0e, 0x00, 0x01, 0x0b, 0x03, 0x47, 0x22,
+		0xac, 0x82, 0xda, 0xc7, 0xf5, 0xe9, 0xff, 0x00, 0x0b, 0x03,
+		0x47, 0x22, 0xac, 0x82, 0xda, 0xc7, 0xf5, 0xe9, 0xff, 0x00,
+		0x00, 0x01, 0x02, 0x80, 0x01, 0xe0, 0x43, 0x00, 0x05, 0x00,
+		0x04, 0x00, 0x43, 0x00, 0x01, 0x80, 0x00, 0x02, 0xd1, 0x00,
+		0xd1, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x0c, 0x3c,
+		0x10, 0x10, 0x00, 0x00, 0xa0, 0x00, 0x20, 0x03, 0x05, 0x01,
+		0x20, 0x00, 0x00, 0x00, 0x01, 0xb8, 0x00, 0xd8, 0x00, 0x02,
+		0x06, 0xc0, 0x04, 0x0e, 0x06, 0xc0, 0x05, 0x64, 0x02, 0x08,
+		0x02, 0x71, 0x02, 0x09, 0x02, 0x71, 0x12, 0x0d, 0x17, 0x12,
+		0x5e, 0x1c, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x78, 0x10,
+		0x83, 0x04, 0x00, 0x00, 0x00, 0x21
+	};
+
+
+	asize = ARRAY_SIZE(values_204);
+
+	for(i=0; i<asize; i++) {
+		reg_r(gspca_dev, 0x02ff);
+		reg_w(gspca_dev, 0x02ff, 0x00);
+
+		reg_w(gspca_dev, 0x0203, 0xba);
+
+		reg_w(gspca_dev, 0x0204, values_204[i]);
+		reg_w(gspca_dev, 0x0205, values_205[i]);
+		reg_w(gspca_dev, 0x0200, 0x01);
+
+		retok = dev_stk11xx_check_device(gspca_dev, 500);
+
+		if (retok != 1) {
+			pr_err("Load default sensor settings fail !\n");
+			return -1;
+		}
+
+		reg_w(gspca_dev, 0x02ff, 0x00);
+	}
+
+	retok = dev_stk11xx_check_device(gspca_dev, 500);
+
+	return 0;
+}
+
+
+int dev_stk6a31_configure_device(struct gspca_dev *gspca_dev, int step)
+{
+	//     0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,   16
+	static const int values_001B[] = {
+		0x03, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
+	};
+	static const int values_001C[] = {
+		0x02, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06
+	};
+	static const int values_0202[] = {
+		0x0a, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0a, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f
+	};
+	static const int values_0110[] = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+	static const int values_0112[] = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+	static const int values_0114[] = {
+		0x80, 0x80, 0x80, 0x80, 0x00, 0xbe, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80
+	};
+	static const int values_0115[] = {
+		0x02, 0x02, 0x02, 0x02, 0x05, 0x02, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x05, 0x02, 0x02, 0x02, 0x02
+	};
+	static const int values_0116[] = {
+		0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe9, 0xe0, 0xe0, 0x00, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0
+	};
+	static const int values_0117[] = {
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+	};
+	static const int values_0100[] = {
+		0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
+	};
+
+
+	pr_debug("dev_stk6a31_configure_device : %d\n", step);
+
+	reg_w(gspca_dev, 0x0000, 0x24);
+	reg_w(gspca_dev, 0x0002, 0x78);
+	reg_w(gspca_dev, 0x0003, 0x80);
+	reg_w(gspca_dev, 0x0005, 0x00);
+	
+	reg_w(gspca_dev, 0x0007, 0x03);
+	reg_w(gspca_dev, 0x000d, 0x00);
+	reg_w(gspca_dev, 0x000f, 0x02);
+	reg_w(gspca_dev, 0x0300, 0x12);
+	reg_w(gspca_dev, 0x0350, 0x41);
+	
+	reg_w(gspca_dev, 0x0351, 0x00);
+	reg_w(gspca_dev, 0x0352, 0x00);
+	reg_w(gspca_dev, 0x0353, 0x00);
+	reg_w(gspca_dev, 0x0018, 0x10);
+	reg_w(gspca_dev, 0x0019, 0x00);
+	
+	reg_w(gspca_dev, 0x001b, values_001B[step]);
+	reg_w(gspca_dev, 0x001c, values_001C[step]);
+	reg_w(gspca_dev, 0x0300, 0x80);
+	reg_w(gspca_dev, 0x001a, 0x04);
+	reg_w(gspca_dev, 0x0202, values_0202[step]);
+	
+	reg_w(gspca_dev, 0x0110, values_0110[step]);
+	reg_w(gspca_dev, 0x0111, 0x00);
+	reg_w(gspca_dev, 0x0112, values_0112[step]);
+	reg_w(gspca_dev, 0x0113, 0x00);
+	reg_w(gspca_dev, 0x0114, values_0114[step]);
+	
+	reg_w(gspca_dev, 0x0115, values_0115[step]);
+	reg_w(gspca_dev, 0x0116, values_0116[step]);
+	reg_w(gspca_dev, 0x0117, values_0117[step]);
+
+	reg_r(gspca_dev, 0x0100);
+	reg_w(gspca_dev, 0x0100, values_0100[step]);
+
+//	reg_w(gspca_dev, 0x0200, 0x80); 
+//	reg_w(gspca_dev, 0x0200, 0x00); 
+	reg_w(gspca_dev, 0x02ff, 0x00); 
+
+
+	switch (step) {
+		case 0:
+			reg_w(gspca_dev, 0x0203, 0x22); 
+
+			reg_w(gspca_dev, 0x0204, 0x27); 
+			reg_w(gspca_dev, 0x0205, 0xa5); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+	
+		case 1:
+			reg_w(gspca_dev, 0x0203, 0x60); 
+
+			reg_w(gspca_dev, 0x0204, 0x12); 
+			reg_w(gspca_dev, 0x0205, 0x80); 
+			reg_w(gspca_dev, 0x0204, 0x13); 
+			reg_w(gspca_dev, 0x0205, 0xbf); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+
+		case 2:
+			reg_w(gspca_dev, 0x0203, 0x42); 
+
+			reg_w(gspca_dev, 0x0204, 0x12); 
+			reg_w(gspca_dev, 0x0205, 0x80); 
+			reg_w(gspca_dev, 0x0204, 0x24); 
+			reg_w(gspca_dev, 0x0205, 0xa5); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+
+		case 3:
+			reg_w(gspca_dev, 0x0203, 0x42); 
+
+			reg_w(gspca_dev, 0x0204, 0x12); 
+			reg_w(gspca_dev, 0x0205, 0x80); 
+			reg_w(gspca_dev, 0x0204, 0x13); 
+			reg_w(gspca_dev, 0x0205, 0xe0); 
+			reg_w(gspca_dev, 0x0204, 0x24); 
+			reg_w(gspca_dev, 0x0205, 0xa5); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+
+		case 4:
+			reg_w(gspca_dev, 0x0203, 0x42); 
+
+			reg_w(gspca_dev, 0x0204, 0x12); 
+			reg_w(gspca_dev, 0x0205, 0x80); 
+			reg_w(gspca_dev, 0x0204, 0x13); 
+			reg_w(gspca_dev, 0x0205, 0xbf); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+
+		case 5:
+			reg_w(gspca_dev, 0x0203, 0x60); 
+
+			reg_w(gspca_dev, 0x0204, 0x12); 
+			reg_w(gspca_dev, 0x0205, 0x80); 
+			reg_w(gspca_dev, 0x0204, 0x13); 
+			reg_w(gspca_dev, 0x0205, 0xff); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+
+		case 6:
+			reg_w(gspca_dev, 0x0203, 0x60); 
+
+			reg_w(gspca_dev, 0x0204, 0x12); 
+			reg_w(gspca_dev, 0x0205, 0x80); 
+			reg_w(gspca_dev, 0x0204, 0x13); 
+			reg_w(gspca_dev, 0x0205, 0xb7); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+
+		case 7:
+			reg_w(gspca_dev, 0x0203, 0x60); 
+
+			reg_w(gspca_dev, 0x0204, 0x12); 
+			reg_w(gspca_dev, 0x0205, 0x80); 
+			reg_w(gspca_dev, 0x0204, 0x13); 
+			reg_w(gspca_dev, 0x0205, 0xb7); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+
+		case 8:
+			reg_w(gspca_dev, 0x0203, 0x60); 
+
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+
+			reg_w(gspca_dev, 0x0203, 0x60); 
+			reg_w(gspca_dev, 0x0204, 0xff); 
+			reg_w(gspca_dev, 0x0205, 0x01); 
+			reg_w(gspca_dev, 0x0200, 0x01); 
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+
+			reg_w(gspca_dev, 0x0203, 0x60); 
+			reg_w(gspca_dev, 0x0208, 0x0a); 
+			reg_w(gspca_dev, 0x0200, 0x20); 
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+
+			reg_w(gspca_dev, 0x0203, 0x60); 
+			reg_w(gspca_dev, 0x0208, 0x0b); 
+			reg_w(gspca_dev, 0x0200, 0x20); 
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+
+			reg_w(gspca_dev, 0x0203, 0x60); 
+			reg_w(gspca_dev, 0x0208, 0x1c); 
+			reg_w(gspca_dev, 0x0200, 0x20); 
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+
+			reg_w(gspca_dev, 0x0203, 0x60); 
+			reg_w(gspca_dev, 0x0208, 0x1d); 
+			reg_w(gspca_dev, 0x0200, 0x20); 
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00); 
+
+			break;
+
+		case 9:
+			reg_w(gspca_dev, 0x0203, 0xdc); 
+
+			reg_w(gspca_dev, 0x0204, 0x15); 
+			reg_w(gspca_dev, 0x0205, 0x80); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+
+		case 10:
+			reg_w(gspca_dev, 0x0203, 0xec); 
+
+			reg_w(gspca_dev, 0x0204, 0x15); 
+			reg_w(gspca_dev, 0x0205, 0x80); 
+
+			reg_w(gspca_dev, 0x0200, 0x05); 
+
+			break;
+
+		case 11:
+			reg_w(gspca_dev, 0x0203, 0xba); 
+
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			reg_w(gspca_dev, 0x0203, 0xba); 
+
+			reg_w(gspca_dev, 0x0208, 0x00);
+			reg_w(gspca_dev, 0x0200, 0x20);
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			break;
+
+		case 12:
+			reg_w(gspca_dev, 0x0203, 0xba); 
+
+			reg_w(gspca_dev, 0x0204, 0xf0); 
+			reg_w(gspca_dev, 0x0205, 0x00); 
+			reg_w(gspca_dev, 0x0200, 0x05);
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_w(gspca_dev, 0x0204, 0xf1); 
+			reg_w(gspca_dev, 0x0205, 0x00); 
+			reg_w(gspca_dev, 0x0200, 0x05);
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			reg_w(gspca_dev, 0x0203, 0xba); 
+			reg_w(gspca_dev, 0x0208, 0x00);
+			reg_w(gspca_dev, 0x0200, 0x20);
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			reg_w(gspca_dev, 0x0203, 0xba); 
+			reg_w(gspca_dev, 0x0208, 0xf1);
+			reg_w(gspca_dev, 0x0200, 0x20);
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			break;
+
+		case 13:
+			reg_w(gspca_dev, 0x0203, 0xba); 
+
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			reg_w(gspca_dev, 0x0203, 0xba); 
+			reg_w(gspca_dev, 0x0208, 0x00);
+			reg_w(gspca_dev, 0x0200, 0x20);
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			reg_w(gspca_dev, 0x0203, 0xba); 
+			reg_w(gspca_dev, 0x0208, 0xf1);
+			reg_w(gspca_dev, 0x0200, 0x20);
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			break;
+
+		case 14:
+			reg_w(gspca_dev, 0x0203, 0xba); 
+
+			reg_w(gspca_dev, 0x0204, 0x01); 
+			reg_w(gspca_dev, 0x0205, 0x00); 
+			reg_w(gspca_dev, 0x0200, 0x05); 
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_w(gspca_dev, 0x0204, 0xf1); 
+			reg_w(gspca_dev, 0x0205, 0x00); 
+			reg_w(gspca_dev, 0x0200, 0x05); 
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			reg_w(gspca_dev, 0x0203, 0xba); 
+			reg_w(gspca_dev, 0x0208, 0x00);
+			reg_w(gspca_dev, 0x0200, 0x20);
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+			reg_r(gspca_dev, 0x02ff);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			reg_w(gspca_dev, 0x0203, 0xba); 
+			reg_w(gspca_dev, 0x0208, 0xf1);
+			reg_w(gspca_dev, 0x0200, 0x20);
+			dev_stk11xx_check_device(gspca_dev, 500);
+			reg_r(gspca_dev, 0x0209);
+			reg_w(gspca_dev, 0x02ff, 0x00);
+
+			break;
+
+		case 15:
+			reg_w(gspca_dev, 0x0203, 0xba); 
+
+			dev_stk6a31_sensor_settings(gspca_dev);
+
+			reg_w(gspca_dev, 0x0200, 0x80);
+			reg_w(gspca_dev, 0x0200, 0x00);
+			reg_w(gspca_dev, 0x02ff, 0x01);
+			reg_w(gspca_dev, 0x0203, 0xa0);
+
+
+			break;
+
+		case 16:
+			reg_w(gspca_dev, 0x0203, 0xba); 
+
+			dev_stk6a31_sensor_settings(gspca_dev);
+
+			break;
+	}
+	
+	return 0;
+}
+
+int dev_stk6a31_camera_wake(struct gspca_dev *gspca_dev)
+{
+	reg_r(gspca_dev, 0x0104);
+	reg_r(gspca_dev, 0x0105);
+	reg_r(gspca_dev, 0x0106);
+
+	reg_w(gspca_dev, 0x0100, 0x21);
+	reg_w(gspca_dev, 0x0116, 0x00);
+	reg_w(gspca_dev, 0x0117, 0x00);
+	reg_w(gspca_dev, 0x0018, 0x00);
+
+	reg_r(gspca_dev, 0x0000);
+	reg_w(gspca_dev, 0x0000, 0x49);
+
+	return 0;
+}
+
+static int stk1135_set_feature(struct gspca_dev *gspca_dev, int index)
+{
+	int result;
+	struct usb_device *dev = gspca_dev->dev;
+
+	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 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)
+		pr_err("SET FEATURE fail !\n");
+	else 
+		pr_debug("SET FEATURE\n");
+
+	return result;
+}
+
+int dev_stk6a31_camera_settings(struct gspca_dev *gspca_dev)
+{
+	int i;
+
+	int asize;
+	static const int values_204[] = {
+		0xf0, 0xf1, 0x2e, 0xf1, 0xf0, 0xf1, 0x5b, 0xf1, 0xf0, 0xf1, 0x36, 0xf1, 0x37, 0xf1, 0xf0, 0xf1, 0x08, 0xf1
+	};
+	static const int values_205[] = {
+		0x00, 0x02, 0x0c, 0x3c, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x78, 0x10, 0x83, 0x04, 0x00, 0x00, 0x00, 0x21
+	};
+
+
+	asize = ARRAY_SIZE(values_204);
+
+	// Contrast register
+	for (i=0; i<asize; i++) {
+		reg_r(gspca_dev, 0x02ff);
+		reg_w(gspca_dev, 0x02ff, 0x00);
+
+		reg_w(gspca_dev, 0x0204, values_204[i]);
+		reg_w(gspca_dev, 0x0205, values_205[i]);
+
+		reg_w(gspca_dev, 0x0200, 0x01);
+		dev_stk11xx_check_device(gspca_dev, 500);
+		reg_w(gspca_dev, 0x02ff, 0x00);
+	}
+
+	return 0;
+}
+
+int dev_stk6a31_reconf_camera(struct gspca_dev *gspca_dev)
+{
+	dev_stk6a31_configure_device(gspca_dev, 16);
+
+	dev_stk6a31_camera_settings(gspca_dev);
+
+	return 0;
+}
+
+/** 
+ * @param dev Device structure
+ * 
+ * @returns 0 if all is OK
+ *
+ * @brief This function initializes the device for the stream.
+ *
+ * It's the start. This function has to be called at first, before
+ * enabling the video stream.
+ */
+int dev_stk6a31_init_camera(struct gspca_dev *gspca_dev)
+{
+//	int retok;
+//	int value;
+
+	dev_stk6a31_camera_wake(gspca_dev);
+
+	stk1135_set_feature(gspca_dev, 0);
+
+	dev_stk6a31_camera_wake(gspca_dev);
+
+	reg_w(gspca_dev, 0x0000, 0xe0);
+	reg_w(gspca_dev, 0x0002, 0xf8);
+	reg_w(gspca_dev, 0x0002, 0x78);
+	reg_w(gspca_dev, 0x0000, 0x20);
+
+	dev_stk6a31_configure_device(gspca_dev, 15);
+
+//	dev_stk11xx_camera_off(dev); is this:
+	usb_set_interface(gspca_dev->dev, 0, 0);
+
+	return 0;
+}
+
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+	reg_w(gspca_dev, 0x0000, 0xe0);
+	reg_w(gspca_dev, 0x0002, 0xf8);
+	reg_w(gspca_dev, 0x0002, 0x78);
+	reg_w(gspca_dev, 0x0000, 0x20);
+
+	dev_stk6a31_configure_device(gspca_dev, 0);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 1);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 2);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 3);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 4);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 5);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 6);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 7);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 8);
+
+	dev_stk6a31_configure_device(gspca_dev, 9);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 10);
+	dev_stk11xx_check_device(gspca_dev, 65);
+	reg_w(gspca_dev, 0x0200, 0x08);
+
+	dev_stk6a31_configure_device(gspca_dev, 11);
+
+	dev_stk6a31_configure_device(gspca_dev, 12);
+
+	dev_stk6a31_configure_device(gspca_dev, 13);
+
+	dev_stk6a31_configure_device(gspca_dev, 14);
+
+	dev_stk6a31_camera_wake(gspca_dev);
+
+	stk1135_set_feature(gspca_dev, 0);
+
+	return gspca_dev->usb_err;
+}
+
+/* -- start the camera -- */
+
+int dev_stk6a31_start_stream(struct gspca_dev *gspca_dev)
+{
+	int value_116, value_117;
+
+	reg_r(gspca_dev, 0x0114); // read 0x80
+	reg_r(gspca_dev, 0x0115); // read 0x02
+
+	value_116 = reg_r(gspca_dev, 0x0116);
+	value_117 = reg_r(gspca_dev, 0x0117);
+
+	reg_w(gspca_dev, 0x0116, 0x00);
+	reg_w(gspca_dev, 0x0117, 0x00);
+
+	reg_r(gspca_dev, 0x0100); // read 0x21
+	reg_w(gspca_dev, 0x0100, 0xa0);
+
+	reg_w(gspca_dev, 0x0116, value_116);
+	reg_w(gspca_dev, 0x0117, value_117);
+
+	return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int ret, value;
+
+	/* work on alternate 1 */
+//	usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+
+//	ret = usb_set_interface(gspca_dev->dev,
+//					gspca_dev->iface,
+//					gspca_dev->alt);
+//	if (ret < 0) {
+//		pr_err("set intf %d %d failed\n",
+//		       gspca_dev->iface, gspca_dev->alt);
+//		gspca_dev->usb_err = ret;
+//		goto out;
+//	}
+	dev_stk6a31_init_camera(gspca_dev);
+//	camera_on(gspca_dev); is:
+	usb_set_interface(gspca_dev->dev, 0, 5);
+	dev_stk6a31_reconf_camera(gspca_dev);
+	dev_stk6a31_start_stream(gspca_dev);
+	dev_stk6a31_camera_settings(gspca_dev);
+
+
+	if (gspca_dev->usb_err >= 0)
+		PDEBUG(D_STREAM, "camera started alt: 0x%02x",
+				gspca_dev->alt);
+out:
+	return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+	struct usb_device *dev = gspca_dev->dev;
+
+	usb_set_interface(dev, gspca_dev->iface, 1);
+	PDEBUG(D_STREAM, "camera stopped");
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+			u8 *data,			/* isoc packet */
+			int len)			/* iso packet length */
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i, skip;
+
+	printk("pkt: len=%d\n", len);
+//	for (i = 0; i < len; i++)
+//		printk("%02x ", data[i]);
+//	printk("\n");
+
+	if (len > 4) {
+		/* skip header */
+		skip = 4;
+		if (data[0] & 0x80)
+			skip = 8;
+		if (gspca_dev->last_packet_type == LAST_PACKET) {
+			printk("first\n");
+			gspca_frame_add(gspca_dev, FIRST_PACKET, data + skip, len - skip);
+		} else {
+			printk("inter\n");
+			gspca_frame_add(gspca_dev, INTER_PACKET, data + skip, len - skip);
+		}
+	}
+
+	if (len == 4 && gspca_dev->last_packet_type != LAST_PACKET) {
+		printk("last\n");
+		gspca_frame_add(gspca_dev, LAST_PACKET, data, 0);
+	}
+}
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct gspca_dev *gspca_dev =
+		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+
+	gspca_dev->usb_err = 0;
+
+	if (!gspca_dev->streaming)
+		return 0;
+
+	return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+	.s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 127);
+	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 127);
+	v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
+			V4L2_CID_POWER_LINE_FREQUENCY,
+			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1,
+			V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
+
+	if (hdl->error) {
+		pr_err("Could not initialize controls\n");
+		return hdl->error;
+	}
+	return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+	.name = MODULE_NAME,
+	.config = sd_config,
+	.init = sd_init,
+//	.init_controls = sd_init_controls,
+	.start = sd_start,
+	.stopN = sd_stopN,
+	.pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+	{USB_DEVICE(0x174f, 0x6a31)},
+	{}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+			const struct usb_device_id *id)
+{
+	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+				THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+	.name = MODULE_NAME,
+	.id_table = device_table,
+	.probe = sd_probe,
+	.disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+	.suspend = gspca_suspend,
+	.resume = gspca_resume,
+	.reset_resume = gspca_resume,
+#endif
+};
+
+module_usb_driver(sd_driver);
-- 
Ondrej Zary

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-08-07 21:30 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-05 21:19 Syntek webcams and out-of-tree driver Ondrej Zary
2013-08-06  6:10 ` Hans de Goede
2013-08-06 13:05   ` Ondrej Zary
2013-08-07 21:30   ` Ondrej Zary

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.