V4L/DVB: gspca_xirlink_cit: New gspca subdriver replacing v4l1 usbvideo/ibmcam.c
authorHans de Goede <hdegoede@redhat.com>
Sun, 5 Sep 2010 19:05:22 +0000 (16:05 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 21 Oct 2010 03:04:44 +0000 (01:04 -0200)
The old usbvideo ibmcam driver needs to be replaced with a v4l2 driver
preferably using the gspca webcam framework rather then the old usbvideo
framework.

This new gspca sub driver sets a first step in that direction. The ibmcam
driver supports 4 different model webcams. This new driver (for now) only
supports Model 3 cameras, as my test cam is a Model 3 cam, or so I thought.

Upon reading:
http://www.linux-usb.org/ibmcam/
I learned that the IBM Netcamera Pro I have even though having the same
usb id and the same bcd version is different from the Model 3 cameras
supported by the ibmcam driver. So this new gscpa subdriver supports Model 3
cameras (untested), and the IBM Netcamera Pro. Currently use with the
IBM Netcamera Pro requires a module parameter. I hope to be able to
autodetect which is which in the future.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/xirlink_cit.c [new file with mode: 0644]
include/linux/videodev2.h

index 23db0c2..cab7be7 100644 (file)
@@ -337,6 +337,15 @@ config USB_GSPCA_VC032X
          To compile this driver as a module, choose M here: the
          module will be called gspca_vc032x.
 
+config USB_GSPCA_XIRLINK_CIT
+       tristate "Xirlink C-It USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for Xirlink C-It bases cameras.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_xirlink_cit.
+
 config USB_GSPCA_ZC3XX
        tristate "ZC3XX USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index f6616db..ea89ac1 100644 (file)
@@ -33,6 +33,7 @@ obj-$(CONFIG_USB_GSPCA_STV0680)  += gspca_stv0680.o
 obj-$(CONFIG_USB_GSPCA_T613)     += gspca_t613.o
 obj-$(CONFIG_USB_GSPCA_TV8532)   += gspca_tv8532.o
 obj-$(CONFIG_USB_GSPCA_VC032X)   += gspca_vc032x.o
+obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o
 obj-$(CONFIG_USB_GSPCA_ZC3XX)    += gspca_zc3xx.o
 
 gspca_main-objs     := gspca.o
@@ -70,6 +71,7 @@ gspca_sunplus-objs  := sunplus.o
 gspca_t613-objs     := t613.o
 gspca_tv8532-objs   := tv8532.o
 gspca_vc032x-objs   := vc032x.o
+gspca_xirlink_cit-objs := xirlink_cit.o
 gspca_zc3xx-objs    := zc3xx.o
 
 obj-$(CONFIG_USB_M5602)   += m5602/
diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c
new file mode 100644 (file)
index 0000000..3525e78
--- /dev/null
@@ -0,0 +1,1765 @@
+/*
+ * USB IBM C-It Video Camera driver
+ *
+ * Supports Xirlink C-It Video Camera, IBM PC Camera,
+ * IBM NetCamera and Veo Stingray.
+ *
+ * Copyright (C) 2010 Hans de Goede <hdgoede@redhat.com>
+ *
+ * This driver is based on earlier work of:
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ *
+ * 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.
+ *
+ * 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 MODULE_NAME "xirlink-cit"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_DESCRIPTION("Xirlink C-IT");
+MODULE_LICENSE("GPL");
+
+/* FIXME we should autodetect this */
+static int ibm_netcam_pro;
+module_param(ibm_netcam_pro, int, 0);
+MODULE_PARM_DESC(ibm_netcam_pro,
+                "Use IBM Netcamera Pro init sequences for Model 3 cams");
+
+/* FIXME this should be handled through the V4L2 input selection API */
+static int rca_input;
+module_param(rca_input, int, 0644);
+MODULE_PARM_DESC(rca_input,
+                "Use rca input instead of ccd sensor on Model 3 cams");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;             /* !! must be the first item */
+       u8 model;
+#define CIT_MODEL1 0 /* The model 1 - 4 nomenclature comes from the old */
+#define CIT_MODEL2 1 /* ibmcam driver */
+#define CIT_MODEL3 2
+#define CIT_MODEL4 3
+#define CIT_IBM_NETCAM_PRO 4
+       u8 input_index;
+       u8 sof_read;
+       u8 contrast;
+       u8 brightness;
+       u8 hue;
+       u8 sharpness;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static void sd_stop0(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0x0c,
+               .maximum = 0x3f,
+               .step = 1,
+#define BRIGHTNESS_DEFAULT 0x20
+               .default_value = BRIGHTNESS_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+#define SD_CONTRAST 1
+       {
+           {
+               .id = V4L2_CID_CONTRAST,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "contrast",
+               .minimum = 0,
+               .maximum = 20,
+               .step = 1,
+#define CONTRAST_DEFAULT 10
+               .default_value = CONTRAST_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setcontrast,
+           .get = sd_getcontrast,
+       },
+#define SD_HUE 2
+       {
+           {
+               .id     = V4L2_CID_HUE,
+               .type   = V4L2_CTRL_TYPE_INTEGER,
+               .name   = "Hue",
+               .minimum = 0x05,
+               .maximum = 0x37,
+               .step   = 1,
+#define HUE_DEFAULT 0x20
+               .default_value = HUE_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_sethue,
+           .get = sd_gethue,
+       },
+#define SD_SHARPNESS 3
+       {
+           {
+               .id = V4L2_CID_SHARPNESS,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Sharpness",
+               .minimum = 0,
+               .maximum = 6,
+               .step = 1,
+#define SHARPNESS_DEFAULT 3
+               .default_value = SHARPNESS_DEFAULT,
+               .flags = 0,
+           },
+           .set = sd_setsharpness,
+           .get = sd_getsharpness,
+       },
+};
+
+static const struct v4l2_pix_format vga_yuv_mode[] = {
+       {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 160,
+               .sizeimage = 160 * 120 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+       {640, 480, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 2,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+/*
+ * 01.01.08 - Added for RCA video in support -LO
+ * This struct is used to init the Model3 cam to use the RCA video in port
+ * instead of the CCD sensor.
+ */
+static const u16 rca_initdata[][3] = {
+       {0, 0x0000, 0x010c},
+       {0, 0x0006, 0x012c},
+       {0, 0x0078, 0x012d},
+       {0, 0x0046, 0x012f},
+       {0, 0xd141, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfea8, 0x0124},
+       {1, 0x0000, 0x0116},
+       {0, 0x0064, 0x0116},
+       {1, 0x0000, 0x0115},
+       {0, 0x0003, 0x0115},
+       {0, 0x0008, 0x0123},
+       {0, 0x0000, 0x0117},
+       {0, 0x0000, 0x0112},
+       {0, 0x0080, 0x0100},
+       {0, 0x0000, 0x0100},
+       {1, 0x0000, 0x0116},
+       {0, 0x0060, 0x0116},
+       {0, 0x0002, 0x0112},
+       {0, 0x0000, 0x0123},
+       {0, 0x0001, 0x0117},
+       {0, 0x0040, 0x0108},
+       {0, 0x0019, 0x012c},
+       {0, 0x0040, 0x0116},
+       {0, 0x000a, 0x0115},
+       {0, 0x000b, 0x0115},
+       {0, 0x0078, 0x012d},
+       {0, 0x0046, 0x012f},
+       {0, 0xd141, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfea8, 0x0124},
+       {0, 0x0064, 0x0116},
+       {0, 0x0000, 0x0115},
+       {0, 0x0001, 0x0115},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00aa, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00f2, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x000f, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00f8, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00fc, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00f9, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x003c, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xffff, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0027, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0019, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0021, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0006, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0045, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002a, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x000e, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002b, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00f4, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002c, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0004, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002d, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0014, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002e, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0003, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x002f, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0003, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0014, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0053, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0x0000, 0x0101},
+       {0, 0x00a0, 0x0103},
+       {0, 0x0078, 0x0105},
+       {0, 0x0000, 0x010a},
+       {0, 0x0024, 0x010b},
+       {0, 0x0028, 0x0119},
+       {0, 0x0088, 0x011b},
+       {0, 0x0002, 0x011d},
+       {0, 0x0003, 0x011e},
+       {0, 0x0000, 0x0129},
+       {0, 0x00fc, 0x012b},
+       {0, 0x0008, 0x0102},
+       {0, 0x0000, 0x0104},
+       {0, 0x0008, 0x011a},
+       {0, 0x0028, 0x011c},
+       {0, 0x0021, 0x012a},
+       {0, 0x0000, 0x0118},
+       {0, 0x0000, 0x0132},
+       {0, 0x0000, 0x0109},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0031, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x00dc, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0032, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0020, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0001, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0040, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0037, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0030, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0xfff9, 0x0124},
+       {0, 0x0086, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0038, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0008, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0x0000, 0x0127},
+       {0, 0xfff8, 0x0124},
+       {0, 0xfffd, 0x0124},
+       {0, 0xfffa, 0x0124},
+       {0, 0x0003, 0x0111},
+};
+
+static int cit_write_reg(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+       struct usb_device *udev = gspca_dev->dev;
+       int err;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       value, index, NULL, 0, 1000);
+       if (err < 0)
+               PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
+                       " value 0x%02X, error %d)", index, value, err);
+
+       return 0;
+}
+
+static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index)
+{
+       struct usb_device *udev = gspca_dev->dev;
+       __u8 *buf = gspca_dev->usb_buf;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x01,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       0x00, index, buf, 8, 1000);
+       if (res < 0) {
+               PDEBUG(D_ERR,
+                       "Failed to read a register (index 0x%04X, error %d)",
+                       index, res);
+               return res;
+       }
+
+       PDEBUG(D_PROBE,
+              "Register %04x value: %02x %02x %02x %02x %02x %02x %02x %02x",
+              index,
+              buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+
+       return 0;
+}
+
+/*
+ * ibmcam_model3_Packet1()
+ *
+ * 00_0078_012d
+ * 00_0097_012f
+ * 00_d141_0124
+ * 00_0096_0127
+ * 00_fea8_0124
+*/
+static void cit_model3_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2)
+{
+       cit_write_reg(gspca_dev, 0x0078, 0x012d);
+       cit_write_reg(gspca_dev, v1,     0x012f);
+       cit_write_reg(gspca_dev, 0xd141, 0x0124);
+       cit_write_reg(gspca_dev, v2,     0x0127);
+       cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                    const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+       sd->model = id->driver_info;
+       if (sd->model == CIT_MODEL3 && ibm_netcam_pro)
+               sd->model = CIT_IBM_NETCAM_PRO;
+
+       cam = &gspca_dev->cam;
+       switch (sd->model) {
+       case CIT_MODEL3:
+               cam->cam_mode = vga_yuv_mode;
+               cam->nmodes = ARRAY_SIZE(vga_yuv_mode);
+               gspca_dev->ctrl_dis = (1 << SD_HUE);
+               break;
+       case CIT_IBM_NETCAM_PRO:
+               cam->cam_mode = vga_yuv_mode;
+               cam->nmodes = 2; /* no 640 x 480 */
+               cam->input_flags = V4L2_IN_ST_VFLIP;
+               gspca_dev->ctrl_dis = ~(1 << SD_CONTRAST);
+               break;
+       }
+
+       sd->brightness = BRIGHTNESS_DEFAULT;
+       sd->contrast = CONTRAST_DEFAULT;
+       sd->hue = HUE_DEFAULT;
+       sd->sharpness = SHARPNESS_DEFAULT;
+
+       return 0;
+}
+
+static int cit_init_ibm_netcam_pro(struct gspca_dev *gspca_dev)
+{
+       cit_read_reg(gspca_dev, 0x128);
+       cit_write_reg(gspca_dev, 0x0003, 0x0133);
+       cit_write_reg(gspca_dev, 0x0000, 0x0117);
+       cit_write_reg(gspca_dev, 0x0008, 0x0123);
+       cit_write_reg(gspca_dev, 0x0000, 0x0100);
+       cit_read_reg(gspca_dev, 0x0116);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       cit_write_reg(gspca_dev, 0x0002, 0x0112);
+       cit_write_reg(gspca_dev, 0x0000, 0x0133);
+       cit_write_reg(gspca_dev, 0x0000, 0x0123);
+       cit_write_reg(gspca_dev, 0x0001, 0x0117);
+       cit_write_reg(gspca_dev, 0x0040, 0x0108);
+       cit_write_reg(gspca_dev, 0x0019, 0x012c);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       cit_write_reg(gspca_dev, 0x0002, 0x0115);
+       cit_write_reg(gspca_dev, 0x000b, 0x0115);
+
+       cit_write_reg(gspca_dev, 0x0078, 0x012d);
+       cit_write_reg(gspca_dev, 0x0001, 0x012f);
+       cit_write_reg(gspca_dev, 0xd141, 0x0124);
+       cit_write_reg(gspca_dev, 0x0079, 0x012d);
+       cit_write_reg(gspca_dev, 0x00ff, 0x0130);
+       cit_write_reg(gspca_dev, 0xcd41, 0x0124);
+       cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+       cit_read_reg(gspca_dev, 0x0126);
+
+       cit_model3_Packet1(gspca_dev, 0x0000, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0000, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x000b, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x000c, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x000d, 0x003a);
+       cit_model3_Packet1(gspca_dev, 0x000e, 0x0060);
+       cit_model3_Packet1(gspca_dev, 0x000f, 0x0060);
+       cit_model3_Packet1(gspca_dev, 0x0010, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x0011, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x0012, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x0013, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0014, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0015, 0x00fb);
+       cit_model3_Packet1(gspca_dev, 0x0016, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0017, 0x0037);
+       cit_model3_Packet1(gspca_dev, 0x0018, 0x0036);
+       cit_model3_Packet1(gspca_dev, 0x001e, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x001f, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x0020, 0x00c1);
+       cit_model3_Packet1(gspca_dev, 0x0021, 0x0034);
+       cit_model3_Packet1(gspca_dev, 0x0022, 0x0034);
+       cit_model3_Packet1(gspca_dev, 0x0025, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0028, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x0029, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x002b, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x002c, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x002d, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x002e, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x002f, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x0030, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x0031, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x0032, 0x0007);
+       cit_model3_Packet1(gspca_dev, 0x0033, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x0037, 0x0040);
+       cit_model3_Packet1(gspca_dev, 0x0039, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x003a, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x003b, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x003c, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0040, 0x000c);
+       cit_model3_Packet1(gspca_dev, 0x0041, 0x00fb);
+       cit_model3_Packet1(gspca_dev, 0x0042, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0043, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0045, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0046, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0047, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0048, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0049, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x004a, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x004b, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x004c, 0x00ff);
+       cit_model3_Packet1(gspca_dev, 0x004f, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0050, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0051, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0055, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0056, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0057, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0058, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0059, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x005c, 0x0016);
+       cit_model3_Packet1(gspca_dev, 0x005d, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x005e, 0x003c);
+       cit_model3_Packet1(gspca_dev, 0x005f, 0x0050);
+       cit_model3_Packet1(gspca_dev, 0x0060, 0x0044);
+       cit_model3_Packet1(gspca_dev, 0x0061, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x006a, 0x007e);
+       cit_model3_Packet1(gspca_dev, 0x006f, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0072, 0x001b);
+       cit_model3_Packet1(gspca_dev, 0x0073, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x0074, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0075, 0x001b);
+       cit_model3_Packet1(gspca_dev, 0x0076, 0x002a);
+       cit_model3_Packet1(gspca_dev, 0x0077, 0x003c);
+       cit_model3_Packet1(gspca_dev, 0x0078, 0x0050);
+       cit_model3_Packet1(gspca_dev, 0x007b, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x007c, 0x0011);
+       cit_model3_Packet1(gspca_dev, 0x007d, 0x0024);
+       cit_model3_Packet1(gspca_dev, 0x007e, 0x0043);
+       cit_model3_Packet1(gspca_dev, 0x007f, 0x005a);
+       cit_model3_Packet1(gspca_dev, 0x0084, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x0085, 0x0033);
+       cit_model3_Packet1(gspca_dev, 0x0086, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0087, 0x0030);
+       cit_model3_Packet1(gspca_dev, 0x0088, 0x0070);
+       cit_model3_Packet1(gspca_dev, 0x008b, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x008f, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0090, 0x0006);
+       cit_model3_Packet1(gspca_dev, 0x0091, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x0092, 0x005a);
+       cit_model3_Packet1(gspca_dev, 0x0093, 0x0082);
+       cit_model3_Packet1(gspca_dev, 0x0096, 0x0014);
+       cit_model3_Packet1(gspca_dev, 0x0097, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x0098, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00b0, 0x0046);
+       cit_model3_Packet1(gspca_dev, 0x00b1, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00b2, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00b3, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x00b4, 0x0007);
+       cit_model3_Packet1(gspca_dev, 0x00b6, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x00b7, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x00bb, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00bc, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00bd, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00bf, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00c0, 0x00c8);
+       cit_model3_Packet1(gspca_dev, 0x00c1, 0x0014);
+       cit_model3_Packet1(gspca_dev, 0x00c2, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00c3, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00c4, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x00cb, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00cc, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00cd, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00ce, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00cf, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x00d0, 0x0040);
+       cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00d2, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00d3, 0x00bf);
+       cit_model3_Packet1(gspca_dev, 0x00ea, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x00eb, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00ec, 0x00e8);
+       cit_model3_Packet1(gspca_dev, 0x00ed, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00ef, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x00f0, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00f2, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x00f4, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x00f5, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00fa, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00fb, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00fc, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00fd, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00fe, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00ff, 0x0000);
+
+       cit_model3_Packet1(gspca_dev, 0x00be, 0x0003);
+       cit_model3_Packet1(gspca_dev, 0x00c8, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00c9, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x00ca, 0x0040);
+       cit_model3_Packet1(gspca_dev, 0x0053, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0082, 0x000e);
+       cit_model3_Packet1(gspca_dev, 0x0083, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x0034, 0x003c);
+       cit_model3_Packet1(gspca_dev, 0x006e, 0x0055);
+       cit_model3_Packet1(gspca_dev, 0x0062, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x0063, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x0066, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0067, 0x0006);
+       cit_model3_Packet1(gspca_dev, 0x006b, 0x0010);
+       cit_model3_Packet1(gspca_dev, 0x005a, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x005b, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0023, 0x0006);
+       cit_model3_Packet1(gspca_dev, 0x0026, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x0036, 0x0069);
+       cit_model3_Packet1(gspca_dev, 0x0038, 0x0064);
+       cit_model3_Packet1(gspca_dev, 0x003d, 0x0003);
+       cit_model3_Packet1(gspca_dev, 0x003e, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00b8, 0x0014);
+       cit_model3_Packet1(gspca_dev, 0x00b9, 0x0014);
+       cit_model3_Packet1(gspca_dev, 0x00e6, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x00e8, 0x0001);
+
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+               break; /* All is done in sd_start */
+       case CIT_IBM_NETCAM_PRO:
+               cit_init_ibm_netcam_pro(gspca_dev);
+               sd_stop0(gspca_dev);
+               break;
+       }
+       return 0;
+}
+
+static int cit_set_brightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+               /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
+               cit_model3_Packet1(gspca_dev, 0x0036, sd->brightness);
+               break;
+       case CIT_IBM_NETCAM_PRO:
+               /* No (known) brightness control for ibm netcam pro */
+               break;
+       }
+
+       return 0;
+}
+
+static int cit_set_contrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+       {       /* Preset hardware values */
+               static const struct {
+                       unsigned short cv1;
+                       unsigned short cv2;
+                       unsigned short cv3;
+               } cv[7] = {
+                       { 0x05, 0x05, 0x0f },   /* Minimum */
+                       { 0x04, 0x04, 0x16 },
+                       { 0x02, 0x03, 0x16 },
+                       { 0x02, 0x08, 0x16 },
+                       { 0x01, 0x0c, 0x16 },
+                       { 0x01, 0x0e, 0x16 },
+                       { 0x01, 0x10, 0x16 }    /* Maximum */
+               };
+               int i = sd->contrast / 3;
+               cit_model3_Packet1(gspca_dev, 0x0067, cv[i].cv1);
+               cit_model3_Packet1(gspca_dev, 0x005b, cv[i].cv2);
+               cit_model3_Packet1(gspca_dev, 0x005c, cv[i].cv3);
+               break;
+       }
+       case CIT_IBM_NETCAM_PRO:
+               cit_model3_Packet1(gspca_dev, 0x005b, sd->contrast + 1);
+               break;
+       }
+       return 0;
+}
+
+static int cit_set_hue(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+               /* according to the ibmcam driver this does not work 8/
+               /* cit_model3_Packet1(gspca_dev, 0x007e, sd->hue); */
+               break;
+       case CIT_IBM_NETCAM_PRO:
+               /* No hue control for ibm netcam pro */
+               break;
+       }
+       return 0;
+}
+
+static int cit_set_sharpness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+       {       /*
+                * "Use a table of magic numbers.
+                *  This setting doesn't really change much.
+                *  But that's how Windows does it."
+                */
+               static const struct {
+                       unsigned short sv1;
+                       unsigned short sv2;
+                       unsigned short sv3;
+                       unsigned short sv4;
+               } sv[7] = {
+                       { 0x00, 0x00, 0x05, 0x14 },     /* Smoothest */
+                       { 0x01, 0x04, 0x05, 0x14 },
+                       { 0x02, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x05, 0x05, 0x14 },
+                       { 0x03, 0x06, 0x05, 0x14 },
+                       { 0x03, 0x07, 0x05, 0x14 }      /* Sharpest */
+               };
+               cit_model3_Packet1(gspca_dev, 0x0060, sv[sd->sharpness].sv1);
+               cit_model3_Packet1(gspca_dev, 0x0061, sv[sd->sharpness].sv2);
+               cit_model3_Packet1(gspca_dev, 0x0062, sv[sd->sharpness].sv3);
+               cit_model3_Packet1(gspca_dev, 0x0063, sv[sd->sharpness].sv4);
+               break;
+       }
+       case CIT_IBM_NETCAM_PRO:
+               /* No sharpness setting on ibm netcamera pro */
+               break;
+       }
+       return 0;
+}
+
+static int cit_restart_stream(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+       case CIT_IBM_NETCAM_PRO:
+               cit_write_reg(gspca_dev, 0x0001, 0x0114);
+               cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */
+               usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
+               cit_write_reg(gspca_dev, 0x0001, 0x0113);
+       }
+
+       sd->sof_read = 0;
+
+       return 0;
+}
+
+static int cit_start_model3(struct gspca_dev *gspca_dev)
+{
+       const unsigned short compression = 0; /* 0=none, 7=best frame rate */
+       int i, clock_div = 0;
+
+       /* HDG not in ibmcam driver, added to see if it helps with
+          auto-detecting between model3 and ibm netcamera pro */
+       cit_read_reg(gspca_dev, 0x128);
+
+       cit_write_reg(gspca_dev, 0x0000, 0x0100);
+       cit_read_reg(gspca_dev, 0x0116);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       cit_write_reg(gspca_dev, 0x0002, 0x0112);
+       cit_write_reg(gspca_dev, 0x0000, 0x0123);
+       cit_write_reg(gspca_dev, 0x0001, 0x0117);
+       cit_write_reg(gspca_dev, 0x0040, 0x0108);
+       cit_write_reg(gspca_dev, 0x0019, 0x012c);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       cit_write_reg(gspca_dev, 0x0002, 0x0115);
+       cit_write_reg(gspca_dev, 0x0003, 0x0115);
+       cit_read_reg(gspca_dev, 0x0115);
+       cit_write_reg(gspca_dev, 0x000b, 0x0115);
+
+       /* HDG not in ibmcam driver, added to see if it helps with
+          auto-detecting between model3 and ibm netcamera pro */
+       if (0) {
+               cit_write_reg(gspca_dev, 0x0078, 0x012d);
+               cit_write_reg(gspca_dev, 0x0001, 0x012f);
+               cit_write_reg(gspca_dev, 0xd141, 0x0124);
+               cit_write_reg(gspca_dev, 0x0079, 0x012d);
+               cit_write_reg(gspca_dev, 0x00ff, 0x0130);
+               cit_write_reg(gspca_dev, 0xcd41, 0x0124);
+               cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+               cit_read_reg(gspca_dev, 0x0126);
+       }
+
+       cit_model3_Packet1(gspca_dev, 0x000a, 0x0040);
+       cit_model3_Packet1(gspca_dev, 0x000b, 0x00f6);
+       cit_model3_Packet1(gspca_dev, 0x000c, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x000d, 0x0020);
+       cit_model3_Packet1(gspca_dev, 0x000e, 0x0033);
+       cit_model3_Packet1(gspca_dev, 0x000f, 0x0007);
+       cit_model3_Packet1(gspca_dev, 0x0010, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0011, 0x0070);
+       cit_model3_Packet1(gspca_dev, 0x0012, 0x0030);
+       cit_model3_Packet1(gspca_dev, 0x0013, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0014, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0015, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0016, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0017, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0018, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x001e, 0x00c3);
+       cit_model3_Packet1(gspca_dev, 0x0020, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0028, 0x0010);
+       cit_model3_Packet1(gspca_dev, 0x0029, 0x0054);
+       cit_model3_Packet1(gspca_dev, 0x002a, 0x0013);
+       cit_model3_Packet1(gspca_dev, 0x002b, 0x0007);
+       cit_model3_Packet1(gspca_dev, 0x002d, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x002e, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0031, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0032, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0033, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0034, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0035, 0x0038);
+       cit_model3_Packet1(gspca_dev, 0x003a, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x003c, 0x001e);
+       cit_model3_Packet1(gspca_dev, 0x003f, 0x000a);
+       cit_model3_Packet1(gspca_dev, 0x0041, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0046, 0x003f);
+       cit_model3_Packet1(gspca_dev, 0x0047, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0050, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x0052, 0x001a);
+       cit_model3_Packet1(gspca_dev, 0x0053, 0x0003);
+       cit_model3_Packet1(gspca_dev, 0x005a, 0x006b);
+       cit_model3_Packet1(gspca_dev, 0x005d, 0x001e);
+       cit_model3_Packet1(gspca_dev, 0x005e, 0x0030);
+       cit_model3_Packet1(gspca_dev, 0x005f, 0x0041);
+       cit_model3_Packet1(gspca_dev, 0x0064, 0x0008);
+       cit_model3_Packet1(gspca_dev, 0x0065, 0x0015);
+       cit_model3_Packet1(gspca_dev, 0x0068, 0x000f);
+       cit_model3_Packet1(gspca_dev, 0x0079, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x007a, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x007c, 0x003f);
+       cit_model3_Packet1(gspca_dev, 0x0082, 0x000f);
+       cit_model3_Packet1(gspca_dev, 0x0085, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0099, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x009b, 0x0023);
+       cit_model3_Packet1(gspca_dev, 0x009c, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x009d, 0x0096);
+       cit_model3_Packet1(gspca_dev, 0x009e, 0x0096);
+       cit_model3_Packet1(gspca_dev, 0x009f, 0x000a);
+
+       switch (gspca_dev->width) {
+       case 160:
+               cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+               cit_write_reg(gspca_dev, 0x0024, 0x010b); /* Differs everywhere */
+               cit_write_reg(gspca_dev, 0x00a9, 0x0119);
+               cit_write_reg(gspca_dev, 0x0016, 0x011b);
+               cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */
+               cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+               cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+               cit_write_reg(gspca_dev, 0x0018, 0x0102);
+               cit_write_reg(gspca_dev, 0x0004, 0x0104);
+               cit_write_reg(gspca_dev, 0x0004, 0x011a);
+               cit_write_reg(gspca_dev, 0x0028, 0x011c);
+               cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+               cit_write_reg(gspca_dev, 0x0000, 0x0118);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132);
+               cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */
+               cit_write_reg(gspca_dev, compression, 0x0109);
+               clock_div = 3;
+               break;
+       case 320:
+               cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */
+               cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+               cit_write_reg(gspca_dev, 0x0028, 0x010b); /* Differs everywhere */
+               cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same */
+               cit_write_reg(gspca_dev, 0x0000, 0x011e);
+               cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+               cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+               /* 4 commands from 160x120 skipped */
+               cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */
+               cit_write_reg(gspca_dev, compression, 0x0109);
+               cit_write_reg(gspca_dev, 0x00d9, 0x0119);
+               cit_write_reg(gspca_dev, 0x0006, 0x011b);
+               cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0010, 0x0104);
+               cit_write_reg(gspca_dev, 0x0004, 0x011a);
+               cit_write_reg(gspca_dev, 0x003f, 0x011c);
+               cit_write_reg(gspca_dev, 0x001c, 0x0118);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132);
+               clock_div = 5;
+               break;
+       case 640:
+               cit_write_reg(gspca_dev, 0x00f0, 0x0105);
+               cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+               cit_write_reg(gspca_dev, 0x0038, 0x010b); /* Differs everywhere */
+               cit_write_reg(gspca_dev, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0004, 0x011d); /* NC */
+               cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */
+               cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+               cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+               cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0016, 0x0104); /* NC */
+               cit_write_reg(gspca_dev, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
+               cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+               cit_write_reg(gspca_dev, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
+               cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */
+               cit_write_reg(gspca_dev, compression, 0x0109);
+               cit_write_reg(gspca_dev, 0x0040, 0x0101);
+               cit_write_reg(gspca_dev, 0x0040, 0x0103);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
+               clock_div = 7;
+               break;
+       }
+
+       cit_model3_Packet1(gspca_dev, 0x007e, 0x000e);  /* Hue */
+       cit_model3_Packet1(gspca_dev, 0x0036, 0x0011);  /* Brightness */
+       cit_model3_Packet1(gspca_dev, 0x0060, 0x0002);  /* Sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0061, 0x0004);  /* Sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0062, 0x0005);  /* Sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0063, 0x0014);  /* Sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0);  /* Red sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0097, 0x0096);  /* Blue sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0067, 0x0001);  /* Contrast */
+       cit_model3_Packet1(gspca_dev, 0x005b, 0x000c);  /* Contrast */
+       cit_model3_Packet1(gspca_dev, 0x005c, 0x0016);  /* Contrast */
+       cit_model3_Packet1(gspca_dev, 0x0098, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x002c, 0x0003);  /* Was 1, broke 640x480 */
+       cit_model3_Packet1(gspca_dev, 0x002f, 0x002a);
+       cit_model3_Packet1(gspca_dev, 0x0030, 0x0029);
+       cit_model3_Packet1(gspca_dev, 0x0037, 0x0002);
+       cit_model3_Packet1(gspca_dev, 0x0038, 0x0059);
+       cit_model3_Packet1(gspca_dev, 0x003d, 0x002e);
+       cit_model3_Packet1(gspca_dev, 0x003e, 0x0028);
+       cit_model3_Packet1(gspca_dev, 0x0078, 0x0005);
+       cit_model3_Packet1(gspca_dev, 0x007b, 0x0011);
+       cit_model3_Packet1(gspca_dev, 0x007d, 0x004b);
+       cit_model3_Packet1(gspca_dev, 0x007f, 0x0022);
+       cit_model3_Packet1(gspca_dev, 0x0080, 0x000c);
+       cit_model3_Packet1(gspca_dev, 0x0081, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x0083, 0x00fd);
+       cit_model3_Packet1(gspca_dev, 0x0086, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x0087, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x007e, 0x000e);
+       cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0);  /* Red sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0097, 0x0096);  /* Blue sharpness */
+       cit_model3_Packet1(gspca_dev, 0x0098, 0x000b);
+
+       cit_write_reg(gspca_dev, clock_div, 0x0111); /* Clock Divider */
+
+       switch (gspca_dev->width) {
+       case 160:
+               cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0040, 0x000a);
+               cit_model3_Packet1(gspca_dev, 0x0051, 0x000a);
+               break;
+       case 320:
+               cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */
+               cit_model3_Packet1(gspca_dev, 0x0040, 0x0008);
+               cit_model3_Packet1(gspca_dev, 0x0051, 0x000b);
+               break;
+       case 640:
+               cit_model3_Packet1(gspca_dev, 0x001f, 0x0002);  /* !Same */
+               cit_model3_Packet1(gspca_dev, 0x0039, 0x003e);  /* !Same */
+               cit_model3_Packet1(gspca_dev, 0x0040, 0x0008);
+               cit_model3_Packet1(gspca_dev, 0x0051, 0x000a);
+               break;
+       }
+
+/*     if (sd->input_index) { */
+       if (rca_input) {
+               for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) {
+                       if (rca_initdata[i][0])
+                               cit_read_reg(gspca_dev, rca_initdata[i][2]);
+                       else
+                               cit_write_reg(gspca_dev, rca_initdata[i][1],
+                                             rca_initdata[i][2]);
+               }
+       }
+
+       return 0;
+}
+
+static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev)
+{
+       const unsigned short compression = 0; /* 0=none, 7=best frame rate */
+       int i, clock_div = 0;
+
+       cit_write_reg(gspca_dev, 0x0003, 0x0133);
+       cit_write_reg(gspca_dev, 0x0000, 0x0117);
+       cit_write_reg(gspca_dev, 0x0008, 0x0123);
+       cit_write_reg(gspca_dev, 0x0000, 0x0100);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       /* cit_write_reg(gspca_dev, 0x0002, 0x0112); see sd_stop0 */
+       cit_write_reg(gspca_dev, 0x0000, 0x0133);
+       cit_write_reg(gspca_dev, 0x0000, 0x0123);
+       cit_write_reg(gspca_dev, 0x0001, 0x0117);
+       cit_write_reg(gspca_dev, 0x0040, 0x0108);
+       cit_write_reg(gspca_dev, 0x0019, 0x012c);
+       cit_write_reg(gspca_dev, 0x0060, 0x0116);
+       /* cit_write_reg(gspca_dev, 0x000b, 0x0115); see sd_stop0 */
+
+       cit_model3_Packet1(gspca_dev, 0x0049, 0x0000);
+
+       cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
+       cit_write_reg(gspca_dev, 0x003a, 0x0102); /* Hstart */
+       cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
+       cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */
+       cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+       cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */
+       cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+       cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+       cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+
+       switch (gspca_dev->width) {
+       case 160:
+               cit_write_reg(gspca_dev, 0x0024, 0x010b);
+               cit_write_reg(gspca_dev, 0x0089, 0x0119);
+               cit_write_reg(gspca_dev, 0x000a, 0x011b);
+               cit_write_reg(gspca_dev, 0x0003, 0x011e);
+               cit_write_reg(gspca_dev, 0x0007, 0x0104);
+               cit_write_reg(gspca_dev, 0x0009, 0x011a);
+               cit_write_reg(gspca_dev, 0x008b, 0x011c);
+               cit_write_reg(gspca_dev, 0x0008, 0x0118);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132);
+               clock_div = 3;
+               break;
+       case 320:
+               cit_write_reg(gspca_dev, 0x0028, 0x010b);
+               cit_write_reg(gspca_dev, 0x00d9, 0x0119);
+               cit_write_reg(gspca_dev, 0x0006, 0x011b);
+               cit_write_reg(gspca_dev, 0x0000, 0x011e);
+               cit_write_reg(gspca_dev, 0x000e, 0x0104);
+               cit_write_reg(gspca_dev, 0x0004, 0x011a);
+               cit_write_reg(gspca_dev, 0x003f, 0x011c);
+               cit_write_reg(gspca_dev, 0x000c, 0x0118);
+               cit_write_reg(gspca_dev, 0x0000, 0x0132);
+               clock_div = 5;
+               break;
+       }
+
+       cit_model3_Packet1(gspca_dev, 0x0019, 0x0031);
+       cit_model3_Packet1(gspca_dev, 0x001a, 0x0003);
+       cit_model3_Packet1(gspca_dev, 0x001b, 0x0038);
+       cit_model3_Packet1(gspca_dev, 0x001c, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0024, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0027, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x002a, 0x0004);
+       cit_model3_Packet1(gspca_dev, 0x0035, 0x000b);
+       cit_model3_Packet1(gspca_dev, 0x003f, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x0044, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x0054, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00c4, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00e7, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00e9, 0x0001);
+       cit_model3_Packet1(gspca_dev, 0x00ee, 0x0000);
+       cit_model3_Packet1(gspca_dev, 0x00f3, 0x00c0);
+
+       cit_write_reg(gspca_dev, compression, 0x0109);
+       cit_write_reg(gspca_dev, clock_div, 0x0111);
+
+/*     if (sd->input_index) { */
+       if (rca_input) {
+               for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) {
+                       if (rca_initdata[i][0])
+                               cit_read_reg(gspca_dev, rca_initdata[i][2]);
+                       else
+                               cit_write_reg(gspca_dev, rca_initdata[i][1],
+                                             rca_initdata[i][2]);
+               }
+       }
+
+       return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_host_interface *alt;
+       struct usb_interface *intf;
+       int packet_size;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+               cit_start_model3(gspca_dev);
+               break;
+       case CIT_IBM_NETCAM_PRO:
+               cit_start_ibm_netcam_pro(gspca_dev);
+               break;
+       }
+
+       cit_set_brightness(gspca_dev);
+       cit_set_contrast(gspca_dev);
+       cit_set_hue(gspca_dev);
+       cit_set_sharpness(gspca_dev);
+
+       /* Program max isoc packet size, one day we should use this to
+          allow us to work together with other isoc devices on the same
+          root hub. */
+       intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+       alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+       if (!alt) {
+               PDEBUG(D_ERR, "Couldn't get altsetting");
+               return -EIO;
+       }
+
+       packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+       cit_write_reg(gspca_dev, packet_size >> 8, 0x0106);
+       cit_write_reg(gspca_dev, packet_size & 0xff, 0x0107);
+
+       cit_restart_stream(gspca_dev);
+
+       return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+       case CIT_IBM_NETCAM_PRO:
+               cit_write_reg(gspca_dev, 0x0000, 0x010c);
+               break;
+       }
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* We cannot use gspca_dev->present here as that is not set when
+          sd_init gets called and we get called from sd_init */
+       if (!gspca_dev->dev)
+               return;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+               cit_write_reg(gspca_dev, 0x0006, 0x012c);
+               cit_model3_Packet1(gspca_dev, 0x0046, 0x0000);
+               cit_read_reg(gspca_dev, 0x0116);
+               cit_write_reg(gspca_dev, 0x0064, 0x0116);
+               cit_read_reg(gspca_dev, 0x0115);
+               cit_write_reg(gspca_dev, 0x0003, 0x0115);
+               cit_write_reg(gspca_dev, 0x0008, 0x0123);
+               cit_write_reg(gspca_dev, 0x0000, 0x0117);
+               cit_write_reg(gspca_dev, 0x0000, 0x0112);
+               cit_write_reg(gspca_dev, 0x0080, 0x0100);
+               break;
+       case CIT_IBM_NETCAM_PRO:
+               cit_model3_Packet1(gspca_dev, 0x0049, 0x00ff);
+               cit_write_reg(gspca_dev, 0x0006, 0x012c);
+               cit_write_reg(gspca_dev, 0x0000, 0x0116);
+               /* HDG windows does this, but I cannot get the camera
+                  to restart with this without redoing the entire init
+                  sequence which makes switching modes really slow */
+               /* cit_write_reg(gspca_dev, 0x0006, 0x0115); */
+               cit_write_reg(gspca_dev, 0x0008, 0x0123);
+               cit_write_reg(gspca_dev, 0x0000, 0x0117);
+               cit_write_reg(gspca_dev, 0x0003, 0x0133);
+               cit_write_reg(gspca_dev, 0x0000, 0x0111);
+               /* HDG windows does this, but I get a green picture when
+                  restarting the stream after this */
+               /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */
+               cit_write_reg(gspca_dev, 0x00c0, 0x0100);
+               break;
+       }
+}
+
+static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i;
+
+       switch (sd->model) {
+       case CIT_MODEL3:
+       case CIT_IBM_NETCAM_PRO:
+               for (i = 0; i < len; i++) {
+                       switch (sd->sof_read) {
+                       case 0:
+                               if (data[i] == 0x00)
+                                       sd->sof_read++;
+                               break;
+                       case 1:
+                               if (data[i] == 0xff)
+                                       sd->sof_read++;
+                               else
+                                       sd->sof_read = 0;
+                               break;
+                       case 2:
+                               sd->sof_read = 0;
+                               if (data[i] != 0xff) {
+                                       if (i >= 4)
+                                               PDEBUG(D_FRAM,
+                                                      "header found at offset: %d: %02x %02x 00 ff %02x %02x\n",
+                                                      i - 2,
+                                                      data[i - 4],
+                                                      data[i - 3],
+                                                      data[i],
+                                                      data[i + 1]);
+                                       return data + i + 2;
+                               }
+                               break;
+                       }
+               }
+               break;
+       }
+       return NULL;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       u8 *data, int len)
+{
+       unsigned char *sof;
+
+       sof = cit_find_sof(gspca_dev, data, len);
+       if (sof) {
+               int n;
+
+               /* finish decoding current frame */
+               n = sof - data;
+               if (n > 4)
+                       n -= 4;
+               else
+                       n = 0;
+               gspca_frame_add(gspca_dev, LAST_PACKET,
+                               data, n);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+               len -= sof - data;
+               data = sof;
+       }
+
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming) {
+               sd_stopN(gspca_dev);
+               cit_set_brightness(gspca_dev);
+               cit_restart_stream(gspca_dev);
+       }
+
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+
+       return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->contrast = val;
+       if (gspca_dev->streaming) {
+               sd_stopN(gspca_dev);
+               cit_set_contrast(gspca_dev);
+               cit_restart_stream(gspca_dev);
+       }
+
+       return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->contrast;
+
+       return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hue = val;
+       if (gspca_dev->streaming) {
+               sd_stopN(gspca_dev);
+               cit_set_hue(gspca_dev);
+               cit_restart_stream(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->hue;
+
+       return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->sharpness = val;
+       if (gspca_dev->streaming) {
+               sd_stopN(gspca_dev);
+               cit_set_sharpness(gspca_dev);
+               cit_restart_stream(gspca_dev);
+       }
+       return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+
+       return 0;
+}
+
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .stop0 = sd_stop0,
+       .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+       { USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002), .driver_info = CIT_MODEL1 },
+       { USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a), .driver_info = CIT_MODEL2 },
+       { USB_DEVICE_VER(0x0545, 0x8080, 0x0301, 0x0301), .driver_info = CIT_MODEL3 },
+       { USB_DEVICE_VER(0x0545, 0x8002, 0x030a, 0x030a), .driver_info = CIT_MODEL4 },
+       { USB_DEVICE_VER(0x0545, 0x800c, 0x030a, 0x030a), .driver_info = CIT_MODEL2 },
+       { USB_DEVICE_VER(0x0545, 0x800d, 0x030a, 0x030a), .driver_info = CIT_MODEL4 },
+       {}
+};
+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_probe2(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,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
+       PDEBUG(D_PROBE, "registered");
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index 61490c6..0aef67e 100644 (file)
@@ -363,6 +363,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
 #define V4L2_PIX_FMT_STV0680  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
 #define V4L2_PIX_FMT_TM6000   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
+#define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
 
 /*
  *     F O R M A T   E N U M E R A T I O N