summary refs log tree commit diff
path: root/drivers/media/video/gspca/vc032x.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-12-30 17:41:32 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2008-12-30 17:41:32 -0800
commitf54a6ec0fd85002d94d05b4bb679508eeb066683 (patch)
tree0f24dd66cce563d2c5e7656c2489e5b96eef31f9 /drivers/media/video/gspca/vc032x.c
parent5ed1836814d908f45cafde0e79cb85314ab9d41d (diff)
parent134179823b3ca9c8b98e0631906459dbb022ff9b (diff)
downloadlinux-f54a6ec0fd85002d94d05b4bb679508eeb066683.tar.gz
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (583 commits)
  V4L/DVB (10130): use USB API functions rather than constants
  V4L/DVB (10129): dvb: remove deprecated use of RW_LOCK_UNLOCKED in frontends
  V4L/DVB (10128): modify V4L documentation to be a valid XHTML
  V4L/DVB (10127): stv06xx: Avoid having y unitialized
  V4L/DVB (10125): em28xx: Don't do AC97 vendor detection for i2s audio devices
  V4L/DVB (10124): em28xx: expand output formats available
  V4L/DVB (10123): em28xx: fix reversed definitions of I2S audio modes
  V4L/DVB (10122): em28xx: don't load em28xx-alsa for em2870 based devices
  V4L/DVB (10121): em28xx: remove worthless Pinnacle PCTV HD Mini 80e device profile
  V4L/DVB (10120): em28xx: remove redundant Pinnacle Dazzle DVC 100 profile
  V4L/DVB (10119): em28xx: fix corrupted XCLK value
  V4L/DVB (10118): zoran: fix warning for a variable not used
  V4L/DVB (10116): af9013: Fix gcc false warnings
  V4L/DVB (10111a): usbvideo.h: remove an useless blank line
  V4L/DVB (10111): quickcam_messenger.c: fix a warning
  V4L/DVB (10110): v4l2-ioctl: Fix warnings when using .unlocked_ioctl = __video_ioctl2
  V4L/DVB (10109): anysee: Fix usage of an unitialized function
  V4L/DVB (10104): uvcvideo: Add support for video output devices
  V4L/DVB (10102): uvcvideo: Ignore interrupt endpoint for built-in iSight webcams.
  V4L/DVB (10101): uvcvideo: Fix bulk URB processing when the header is erroneous
  ...
Diffstat (limited to 'drivers/media/video/gspca/vc032x.c')
-rw-r--r--drivers/media/video/gspca/vc032x.c819
1 files changed, 752 insertions, 67 deletions
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 17af353ddd1c..0525ea51a6de 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -32,44 +32,68 @@ MODULE_LICENSE("GPL");
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
 
-	unsigned char autogain;
-	unsigned char lightfreq;
+	__u8 hflip;
+	__u8 vflip;
+	__u8 lightfreq;
+	__u8 sharpness;
 
-	char qindex;
 	char bridge;
 #define BRIDGE_VC0321 0
 #define BRIDGE_VC0323 1
 	char sensor;
 #define SENSOR_HV7131R 0
-#define SENSOR_MI1320 1
-#define SENSOR_MI1310_SOC 2
-#define SENSOR_OV7660 3
-#define SENSOR_OV7670 4
-#define SENSOR_PO3130NC 5
+#define SENSOR_MI0360 1
+#define SENSOR_MI1320 2
+#define SENSOR_MI1310_SOC 3
+#define SENSOR_OV7660 4
+#define SENSOR_OV7670 5
+#define SENSOR_PO1200 6
+#define SENSOR_PO3130NC 7
 };
 
 /* V4L2 controls supported by the driver */
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getfreq(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 struct ctrl sd_ctrls[] = {
+/* next 2 controls work with ov7660 and ov7670 only */
+#define HFLIP_IDX 0
 	{
 	    {
-		.id      = V4L2_CID_AUTOGAIN,
+		.id      = V4L2_CID_HFLIP,
 		.type    = V4L2_CTRL_TYPE_BOOLEAN,
-		.name    = "Auto Gain",
+		.name    = "Mirror",
 		.minimum = 0,
 		.maximum = 1,
 		.step    = 1,
-#define AUTOGAIN_DEF 1
-		.default_value = AUTOGAIN_DEF,
+#define HFLIP_DEF 0
+		.default_value = HFLIP_DEF,
 	    },
-	    .set = sd_setautogain,
-	    .get = sd_getautogain,
+	    .set = sd_sethflip,
+	    .get = sd_gethflip,
 	},
-#define LIGHTFREQ_IDX 1
+#define VFLIP_IDX 1
+	{
+	    {
+		.id      = V4L2_CID_VFLIP,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Vflip",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define VFLIP_DEF 0
+		.default_value = VFLIP_DEF,
+	    },
+	    .set = sd_setvflip,
+	    .get = sd_getvflip,
+	},
+#define LIGHTFREQ_IDX 2
 	{
 	    {
 		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -84,9 +108,25 @@ static struct ctrl sd_ctrls[] = {
 	    .set = sd_setfreq,
 	    .get = sd_getfreq,
 	},
+/* po1200 only */
+#define SHARPNESS_IDX 3
+	{
+	 {
+	  .id = V4L2_CID_SHARPNESS,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Sharpness",
+	  .minimum = 0,
+	  .maximum = 2,
+	  .step = 1,
+#define SHARPNESS_DEF 1
+	  .default_value = SHARPNESS_DEF,
+	  },
+	 .set = sd_setsharpness,
+	 .get = sd_getsharpness,
+	 },
 };
 
-static struct v4l2_pix_format vc0321_mode[] = {
+static const struct v4l2_pix_format vc0321_mode[] = {
 	{320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
 		.bytesperline = 320,
 		.sizeimage = 320 * 240 * 2,
@@ -98,7 +138,7 @@ static struct v4l2_pix_format vc0321_mode[] = {
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 0},
 };
-static struct v4l2_pix_format vc0323_mode[] = {
+static const struct v4l2_pix_format vc0323_mode[] = {
 	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 320,
 		.sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -111,6 +151,252 @@ static struct v4l2_pix_format vc0323_mode[] = {
 		.priv = 0},
 };
 
+static const struct v4l2_pix_format svga_mode[] = {
+	{800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+		.bytesperline = 800,
+		.sizeimage = 800 * 600 * 1 / 4 + 590,
+		.colorspace = V4L2_COLORSPACE_JPEG,
+		.priv = 0},
+};
+
+/* OV7660/7670 registers */
+#define OV7660_REG_MVFP 0x1e
+#define OV7660_MVFP_MIRROR	0x20
+#define OV7660_MVFP_VFLIP	0x10
+
+static const __u8 mi0360_matrix[9] = {
+	0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50
+};
+
+static const __u8 mi0360_initVGA_JPG[][4] = {
+	{0xb0, 0x03, 0x19, 0xcc},
+	{0xb0, 0x04, 0x02, 0xcc},
+	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},
+	{0xb3, 0x06, 0x03, 0xcc},
+	{0xb3, 0x03, 0x0a, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},
+	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x35, 0xdd, 0xcc},
+	{0xb3, 0x34, 0x02, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},
+	{0xbc, 0x00, 0x71, 0xcc},
+	{0xb8, 0x00, 0x13, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x2c, 0x50, 0xcc},
+	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},
+	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},
+	{0xb8, 0x31, 0xf8, 0xcc},
+	{0xb8, 0x32, 0xf8, 0xcc},
+	{0xb8, 0x33, 0xf8, 0xcc},
+	{0xb8, 0x34, 0x50, 0xcc},
+	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},
+	{0xb8, 0x37, 0x00, 0xcc},
+	{0xb8, 0x01, 0x79, 0xcc},
+	{0xb8, 0x08, 0xe0, 0xcc},
+	{0xb3, 0x01, 0x41, 0xcc},
+	{0xb8, 0x01, 0x79, 0xcc},
+	{0xb8, 0x14, 0x18, 0xcc},
+	{0xb8, 0xb2, 0x0a, 0xcc},
+	{0xb8, 0xb4, 0x0a, 0xcc},
+	{0xb8, 0xb5, 0x0a, 0xcc},
+	{0xb8, 0xfe, 0x00, 0xcc},
+	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},
+	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},
+	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},
+	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},
+	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},
+	{0xb8, 0x8e, 0x00, 0xcc},
+	{0xb8, 0x8f, 0xff, 0xcc},
+	{0xb8, 0x81, 0x09, 0xcc},
+	{0x31, 0x00, 0x00, 0xbb},
+	{0x09, 0x01, 0xc7, 0xbb},
+	{0x34, 0x01, 0x00, 0xbb},
+	{0x2b, 0x00, 0x28, 0xbb},
+	{0x2c, 0x00, 0x30, 0xbb},
+	{0x2d, 0x00, 0x30, 0xbb},
+	{0x2e, 0x00, 0x28, 0xbb},
+	{0x62, 0x04, 0x11, 0xbb},
+	{0x03, 0x01, 0xe0, 0xbb},
+	{0x2c, 0x00, 0x2c, 0xbb},
+	{0x20, 0xd0, 0x00, 0xbb},
+	{0x01, 0x00, 0x08, 0xbb},
+	{0x06, 0x00, 0x10, 0xbb},
+	{0x05, 0x00, 0x20, 0xbb},
+	{0x20, 0x00, 0x00, 0xbb},
+	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x02, 0xcc},
+	{0xb6, 0x02, 0x80, 0xcc},
+	{0xb6, 0x05, 0x01, 0xcc},
+	{0xb6, 0x04, 0xe0, 0xcc},
+	{0xb6, 0x12, 0x78, 0xcc},
+	{0xb6, 0x18, 0x02, 0xcc},
+	{0xb6, 0x17, 0x58, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},
+	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},
+	{0xb3, 0x02, 0x02, 0xcc},
+	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},
+	{0xbf, 0xcc, 0x10, 0xcc},
+	{0xb9, 0x12, 0x00, 0xcc},
+	{0xb9, 0x13, 0x0a, 0xcc},
+	{0xb9, 0x14, 0x0a, 0xcc},
+	{0xb9, 0x15, 0x0a, 0xcc},
+	{0xb9, 0x16, 0x0a, 0xcc},
+	{0xb9, 0x18, 0x00, 0xcc},
+	{0xb9, 0x19, 0x0f, 0xcc},
+	{0xb9, 0x1a, 0x0f, 0xcc},
+	{0xb9, 0x1b, 0x0f, 0xcc},
+	{0xb9, 0x1c, 0x0f, 0xcc},
+	{0xb8, 0x8e, 0x00, 0xcc},
+	{0xb8, 0x8f, 0xff, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},
+	{0xb8, 0x0c, 0x20, 0xcc},
+	{0xb8, 0x0d, 0x70, 0xcc},
+	{0xb6, 0x13, 0x13, 0xcc},
+	{0x35, 0x00, 0x60, 0xbb},
+	{0xb3, 0x5c, 0x01, 0xcc},
+	{}
+};
+static const __u8 mi0360_initQVGA_JPG[][4] = {
+	{0xb0, 0x03, 0x19, 0xcc},
+	{0xb0, 0x04, 0x02, 0xcc},
+	{0xb3, 0x00, 0x24, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},
+	{0xb3, 0x06, 0x03, 0xcc},
+	{0xb3, 0x03, 0x0a, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x01, 0xcc},
+	{0xb3, 0x23, 0xe0, 0xcc},
+	{0xb3, 0x04, 0x05, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x02, 0xcc},
+	{0xb3, 0x17, 0x7f, 0xcc},
+	{0xb3, 0x35, 0xdd, 0xcc},
+	{0xb3, 0x34, 0x02, 0xcc},
+	{0xb3, 0x00, 0x25, 0xcc},
+	{0xbc, 0x00, 0xd1, 0xcc},
+	{0xb8, 0x00, 0x13, 0xcc},
+	{0xb8, 0x27, 0x20, 0xcc},
+	{0xb8, 0x2c, 0x50, 0xcc},
+	{0xb8, 0x2d, 0xf8, 0xcc},
+	{0xb8, 0x2e, 0xf8, 0xcc},
+	{0xb8, 0x2f, 0xf8, 0xcc},
+	{0xb8, 0x30, 0x50, 0xcc},
+	{0xb8, 0x31, 0xf8, 0xcc},
+	{0xb8, 0x32, 0xf8, 0xcc},
+	{0xb8, 0x33, 0xf8, 0xcc},
+	{0xb8, 0x34, 0x50, 0xcc},
+	{0xb8, 0x35, 0x00, 0xcc},
+	{0xb8, 0x36, 0x00, 0xcc},
+	{0xb8, 0x37, 0x00, 0xcc},
+	{0xb8, 0x01, 0x79, 0xcc},
+	{0xb8, 0x08, 0xe0, 0xcc},
+	{0xb3, 0x01, 0x41, 0xcc},
+	{0xb8, 0x01, 0x79, 0xcc},
+	{0xb8, 0x14, 0x18, 0xcc},
+	{0xb8, 0xb2, 0x0a, 0xcc},
+	{0xb8, 0xb4, 0x0a, 0xcc},
+	{0xb8, 0xb5, 0x0a, 0xcc},
+	{0xb8, 0xfe, 0x00, 0xcc},
+	{0xb8, 0xff, 0x28, 0xcc},
+	{0xb9, 0x00, 0x28, 0xcc},
+	{0xb9, 0x01, 0x28, 0xcc},
+	{0xb9, 0x02, 0x28, 0xcc},
+	{0xb9, 0x03, 0x00, 0xcc},
+	{0xb9, 0x04, 0x00, 0xcc},
+	{0xb9, 0x05, 0x3c, 0xcc},
+	{0xb9, 0x06, 0x3c, 0xcc},
+	{0xb9, 0x07, 0x3c, 0xcc},
+	{0xb9, 0x08, 0x3c, 0xcc},
+	{0xb8, 0x8e, 0x00, 0xcc},
+	{0xb8, 0x8f, 0xff, 0xcc},
+	{0xb8, 0x81, 0x09, 0xcc},
+	{0x31, 0x00, 0x00, 0xbb},
+	{0x09, 0x01, 0xc7, 0xbb},
+	{0x34, 0x01, 0x00, 0xbb},
+	{0x2b, 0x00, 0x28, 0xbb},
+	{0x2c, 0x00, 0x30, 0xbb},
+	{0x2d, 0x00, 0x30, 0xbb},
+	{0x2e, 0x00, 0x28, 0xbb},
+	{0x62, 0x04, 0x11, 0xbb},
+	{0x03, 0x01, 0xe0, 0xbb},
+	{0x2c, 0x00, 0x2c, 0xbb},
+	{0x20, 0xd0, 0x00, 0xbb},
+	{0x01, 0x00, 0x08, 0xbb},
+	{0x06, 0x00, 0x10, 0xbb},
+	{0x05, 0x00, 0x20, 0xbb},
+	{0x20, 0x00, 0x00, 0xbb},
+	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x01, 0xcc},
+	{0xb6, 0x02, 0x40, 0xcc},
+	{0xb6, 0x05, 0x00, 0xcc},
+	{0xb6, 0x04, 0xf0, 0xcc},
+	{0xb6, 0x12, 0x78, 0xcc},
+	{0xb6, 0x18, 0x00, 0xcc},
+	{0xb6, 0x17, 0x96, 0xcc},
+	{0xb6, 0x16, 0x00, 0xcc},
+	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},
+	{0xb3, 0x02, 0x02, 0xcc},
+	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},
+	{0xbf, 0xcc, 0x10, 0xcc},
+	{0xb9, 0x12, 0x00, 0xcc},
+	{0xb9, 0x13, 0x0a, 0xcc},
+	{0xb9, 0x14, 0x0a, 0xcc},
+	{0xb9, 0x15, 0x0a, 0xcc},
+	{0xb9, 0x16, 0x0a, 0xcc},
+	{0xb9, 0x18, 0x00, 0xcc},
+	{0xb9, 0x19, 0x0f, 0xcc},
+	{0xb9, 0x1a, 0x0f, 0xcc},
+	{0xb9, 0x1b, 0x0f, 0xcc},
+	{0xb9, 0x1c, 0x0f, 0xcc},
+	{0xb8, 0x8e, 0x00, 0xcc},
+	{0xb8, 0x8f, 0xff, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},
+	{0xb6, 0x13, 0x13, 0xcc},
+	{0xbc, 0x02, 0x18, 0xcc},
+	{0xbc, 0x03, 0x50, 0xcc},
+	{0xbc, 0x04, 0x18, 0xcc},
+	{0xbc, 0x05, 0x00, 0xcc},
+	{0xbc, 0x06, 0x00, 0xcc},
+	{0xbc, 0x08, 0x30, 0xcc},
+	{0xbc, 0x09, 0x40, 0xcc},
+	{0xbc, 0x0a, 0x10, 0xcc},
+	{0xb8, 0x0c, 0x20, 0xcc},
+	{0xb8, 0x0d, 0x70, 0xcc},
+	{0xbc, 0x0b, 0x00, 0xcc},
+	{0xbc, 0x0c, 0x00, 0xcc},
+	{0x35, 0x00, 0xef, 0xbb},
+	{0xb3, 0x5c, 0x01, 0xcc},
+	{}
+};
+
 static const __u8 mi1310_socinitVGA_JPG[][4] = {
 	{0xb0, 0x03, 0x19, 0xcc},
 	{0xb0, 0x04, 0x02, 0xcc},
@@ -823,7 +1109,7 @@ static const __u8 ov7660_initVGA_data[][4] = {
 	{0x00, 0x01, 0x80, 0xaa},	{0x00, 0x02, 0x80, 0xaa},
 	{0x00, 0x12, 0x80, 0xaa},
 	{0x00, 0x12, 0x05, 0xaa},
-	{0x00, 0x1e, 0x01, 0xaa},
+	{0x00, 0x1e, 0x01, 0xaa},	/* MVFP */
 	{0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
 	{0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
 	{0x00, 0x0d, 0x48, 0xaa},	{0x00, 0x0e, 0x04, 0xaa},
@@ -877,7 +1163,7 @@ static const __u8 ov7660_initQVGA_data[][4] = {
 	{0xb8, 0x27, 0x20, 0xcc},	{0xb8, 0x8f, 0x50, 0xcc},
 	{0x00, 0x01, 0x80, 0xaa},	{0x00, 0x02, 0x80, 0xaa},
 	{0x00, 0x12, 0x80, 0xaa},	{0x00, 0x12, 0x05, 0xaa},
-	{0x00, 0x1e, 0x01, 0xaa},
+	{0x00, 0x1e, 0x01, 0xaa},	/* MVFP */
 	{0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
 	{0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
 	{0x00, 0x0d, 0x48, 0xaa},	{0x00, 0x0e, 0x04, 0xaa},
@@ -983,7 +1269,8 @@ static const __u8 ov7670_initVGA_JPG[][4] = {
 	{0x00, 0xa9, 0x90, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
 	{0x00, 0x13, 0xe5, 0xaa},	{0x00, 0x0e, 0x61, 0xaa},
 	{0x00, 0x0f, 0x4b, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
-	{0x00, 0x1e, 0x07, 0xaa},	{0x00, 0x21, 0x02, 0xaa},
+	{0x00, 0x1e, 0x07, 0xaa},	/* MVFP */
+	{0x00, 0x21, 0x02, 0xaa},
 	{0x00, 0x22, 0x91, 0xaa},	{0x00, 0x29, 0x07, 0xaa},
 	{0x00, 0x33, 0x0b, 0xaa},	{0x00, 0x35, 0x0b, 0xaa},
 	{0x00, 0x37, 0x1d, 0xaa},	{0x00, 0x38, 0x71, 0xaa},
@@ -1048,7 +1335,8 @@ static const __u8 ov7670_initVGA_JPG[][4] = {
 	{0x00, 0x71, 0x35, 0xaa},	{0x00, 0x72, 0x11, 0xaa},
 	{0x00, 0x73, 0xf0, 0xaa},	{0x00, 0xa2, 0x02, 0xaa},
 	{0x00, 0xb1, 0x00, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
-	{0x00, 0x1e, 0x37, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x1e, 0x37, 0xaa},	/* MVFP */
+	{0x00, 0xaa, 0x14, 0xaa},
 	{0x00, 0x24, 0x80, 0xaa},	{0x00, 0x25, 0x74, 0xaa},
 	{0x00, 0x26, 0xd3, 0xaa},	{0x00, 0x0d, 0x00, 0xaa},
 	{0x00, 0x14, 0x18, 0xaa},	{0x00, 0x9d, 0x99, 0xaa},
@@ -1110,7 +1398,8 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
 	{0x00, 0xa9, 0x90, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
 	{0x00, 0x13, 0xe5, 0xaa},	{0x00, 0x0e, 0x61, 0xaa},
 	{0x00, 0x0f, 0x4b, 0xaa},	{0x00, 0x16, 0x02, 0xaa},
-	{0x00, 0x1e, 0x07, 0xaa},	{0x00, 0x21, 0x02, 0xaa},
+	{0x00, 0x1e, 0x07, 0xaa},	/* MVFP */
+	{0x00, 0x21, 0x02, 0xaa},
 	{0x00, 0x22, 0x91, 0xaa},	{0x00, 0x29, 0x07, 0xaa},
 	{0x00, 0x33, 0x0b, 0xaa},	{0x00, 0x35, 0x0b, 0xaa},
 	{0x00, 0x37, 0x1d, 0xaa},	{0x00, 0x38, 0x71, 0xaa},
@@ -1175,7 +1464,8 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
 	{0x00, 0x71, 0x35, 0xaa},	{0x00, 0x72, 0x11, 0xaa},
 	{0x00, 0x73, 0xf0, 0xaa},	{0x00, 0xa2, 0x02, 0xaa},
 	{0x00, 0xb1, 0x00, 0xaa},	{0x00, 0xb1, 0x0c, 0xaa},
-	{0x00, 0x1e, 0x37, 0xaa},	{0x00, 0xaa, 0x14, 0xaa},
+	{0x00, 0x1e, 0x37, 0xaa},	/* MVFP */
+	{0x00, 0xaa, 0x14, 0xaa},
 	{0x00, 0x24, 0x80, 0xaa},	{0x00, 0x25, 0x74, 0xaa},
 	{0x00, 0x26, 0xd3, 0xaa},	{0x00, 0x0d, 0x00, 0xaa},
 	{0x00, 0x14, 0x18, 0xaa},	{0x00, 0x9d, 0x99, 0xaa},
@@ -1204,6 +1494,275 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
 	{},
 };
 
+/* PO1200 - values from usbvm326.inf and ms-win trace */
+static const __u8 po1200_gamma[17] = {
+	0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+	0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 po1200_matrix[9] = {
+	0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e
+};
+static const __u8 po1200_initVGA_data[][4] = {
+	{0xb0, 0x03, 0x19, 0xcc},	/* reset? */
+	{0xb0, 0x03, 0x19, 0xcc},
+/*	{0x00, 0x00, 0x33, 0xdd}, */
+	{0xb0, 0x04, 0x02, 0xcc},
+	{0xb0, 0x02, 0x02, 0xcc},
+	{0xb3, 0x5d, 0x00, 0xcc},
+	{0xb3, 0x01, 0x01, 0xcc},
+	{0xb3, 0x00, 0x64, 0xcc},
+	{0xb3, 0x00, 0x65, 0xcc},
+	{0xb3, 0x05, 0x01, 0xcc},
+	{0xb3, 0x06, 0x01, 0xcc},
+	{0xb3, 0x5c, 0x01, 0xcc},
+	{0xb3, 0x08, 0x01, 0xcc},
+	{0xb3, 0x09, 0x0c, 0xcc},
+	{0xb3, 0x00, 0x67, 0xcc},
+	{0xb3, 0x02, 0xb2, 0xcc},
+	{0xb3, 0x03, 0x18, 0xcc},
+	{0xb3, 0x04, 0x15, 0xcc},
+	{0xb3, 0x20, 0x00, 0xcc},
+	{0xb3, 0x21, 0x00, 0xcc},
+	{0xb3, 0x22, 0x02, 0xcc},
+	{0xb3, 0x23, 0x58, 0xcc},
+	{0xb3, 0x14, 0x00, 0xcc},
+	{0xb3, 0x15, 0x00, 0xcc},
+	{0xb3, 0x16, 0x03, 0xcc},
+	{0xb3, 0x17, 0x1f, 0xcc},
+	{0xbc, 0x00, 0x71, 0xcc},
+	{0xbc, 0x01, 0x01, 0xcc},
+	{0xb0, 0x54, 0x13, 0xcc},
+	{0xb3, 0x00, 0x67, 0xcc},
+	{0xb3, 0x34, 0x01, 0xcc},
+	{0xb3, 0x35, 0xdc, 0xcc},
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0x12, 0x05, 0xaa},
+	{0x00, 0x13, 0x02, 0xaa},
+	{0x00, 0x1e, 0xc6, 0xaa},	/* h/v flip */
+	{0x00, 0x21, 0x00, 0xaa},
+	{0x00, 0x25, 0x02, 0xaa},
+	{0x00, 0x3c, 0x4f, 0xaa},
+	{0x00, 0x3f, 0xe0, 0xaa},
+	{0x00, 0x42, 0xff, 0xaa},
+	{0x00, 0x45, 0x34, 0xaa},
+	{0x00, 0x55, 0xfe, 0xaa},
+	{0x00, 0x59, 0xd3, 0xaa},
+	{0x00, 0x5e, 0x04, 0xaa},
+	{0x00, 0x61, 0xb8, 0xaa},	/* sharpness */
+	{0x00, 0x62, 0x02, 0xaa},
+	{0x00, 0xa7, 0x31, 0xaa},
+	{0x00, 0xa9, 0x66, 0xaa},
+	{0x00, 0xb0, 0x00, 0xaa},
+	{0x00, 0xb1, 0x00, 0xaa},
+	{0x00, 0xb3, 0x11, 0xaa},
+	{0x00, 0xb6, 0x26, 0xaa},
+	{0x00, 0xb7, 0x20, 0xaa},
+	{0x00, 0xba, 0x04, 0xaa},
+	{0x00, 0x88, 0x42, 0xaa},
+	{0x00, 0x89, 0x9a, 0xaa},
+	{0x00, 0x8a, 0x88, 0xaa},
+	{0x00, 0x8b, 0x8e, 0xaa},
+	{0x00, 0x8c, 0x3e, 0xaa},
+	{0x00, 0x8d, 0x90, 0xaa},
+	{0x00, 0x8e, 0x87, 0xaa},
+	{0x00, 0x8f, 0x96, 0xaa},
+	{0x00, 0x90, 0x3d, 0xaa},
+	{0x00, 0x64, 0x00, 0xaa},
+	{0x00, 0x65, 0x10, 0xaa},
+	{0x00, 0x66, 0x20, 0xaa},
+	{0x00, 0x67, 0x2b, 0xaa},
+	{0x00, 0x68, 0x36, 0xaa},
+	{0x00, 0x69, 0x49, 0xaa},
+	{0x00, 0x6a, 0x5a, 0xaa},
+	{0x00, 0x6b, 0x7f, 0xaa},
+	{0x00, 0x6c, 0x9b, 0xaa},
+	{0x00, 0x6d, 0xba, 0xaa},
+	{0x00, 0x6e, 0xd4, 0xaa},
+	{0x00, 0x6f, 0xea, 0xaa},
+	{0x00, 0x70, 0x00, 0xaa},
+	{0x00, 0x71, 0x10, 0xaa},
+	{0x00, 0x72, 0x20, 0xaa},
+	{0x00, 0x73, 0x2b, 0xaa},
+	{0x00, 0x74, 0x36, 0xaa},
+	{0x00, 0x75, 0x49, 0xaa},
+	{0x00, 0x76, 0x5a, 0xaa},
+	{0x00, 0x77, 0x7f, 0xaa},
+	{0x00, 0x78, 0x9b, 0xaa},
+	{0x00, 0x79, 0xba, 0xaa},
+	{0x00, 0x7a, 0xd4, 0xaa},
+	{0x00, 0x7b, 0xea, 0xaa},
+	{0x00, 0x7c, 0x00, 0xaa},
+	{0x00, 0x7d, 0x10, 0xaa},
+	{0x00, 0x7e, 0x20, 0xaa},
+	{0x00, 0x7f, 0x2b, 0xaa},
+	{0x00, 0x80, 0x36, 0xaa},
+	{0x00, 0x81, 0x49, 0xaa},
+	{0x00, 0x82, 0x5a, 0xaa},
+	{0x00, 0x83, 0x7f, 0xaa},
+	{0x00, 0x84, 0x9b, 0xaa},
+	{0x00, 0x85, 0xba, 0xaa},
+	{0x00, 0x86, 0xd4, 0xaa},
+	{0x00, 0x87, 0xea, 0xaa},
+	{0x00, 0x57, 0x2a, 0xaa},
+	{0x00, 0x03, 0x01, 0xaa},
+	{0x00, 0x04, 0x10, 0xaa},
+	{0x00, 0x05, 0x10, 0xaa},
+	{0x00, 0x06, 0x10, 0xaa},
+	{0x00, 0x07, 0x10, 0xaa},
+	{0x00, 0x08, 0x13, 0xaa},
+	{0x00, 0x0a, 0x00, 0xaa},
+	{0x00, 0x0b, 0x10, 0xaa},
+	{0x00, 0x0c, 0x20, 0xaa},
+	{0x00, 0x0d, 0x18, 0xaa},
+	{0x00, 0x22, 0x01, 0xaa},
+	{0x00, 0x23, 0x60, 0xaa},
+	{0x00, 0x25, 0x08, 0xaa},
+	{0x00, 0x26, 0x82, 0xaa},
+	{0x00, 0x2e, 0x0f, 0xaa},
+	{0x00, 0x2f, 0x1e, 0xaa},
+	{0x00, 0x30, 0x2d, 0xaa},
+	{0x00, 0x31, 0x3c, 0xaa},
+	{0x00, 0x32, 0x4b, 0xaa},
+	{0x00, 0x33, 0x5a, 0xaa},
+	{0x00, 0x34, 0x69, 0xaa},
+	{0x00, 0x35, 0x78, 0xaa},
+	{0x00, 0x36, 0x87, 0xaa},
+	{0x00, 0x37, 0x96, 0xaa},
+	{0x00, 0x38, 0xa5, 0xaa},
+	{0x00, 0x39, 0xb4, 0xaa},
+	{0x00, 0x3a, 0xc3, 0xaa},
+	{0x00, 0x3b, 0xd2, 0xaa},
+	{0x00, 0x3c, 0xe1, 0xaa},
+	{0x00, 0x3e, 0xff, 0xaa},
+	{0x00, 0x3f, 0xff, 0xaa},
+	{0x00, 0x40, 0xff, 0xaa},
+	{0x00, 0x41, 0xff, 0xaa},
+	{0x00, 0x42, 0xff, 0xaa},
+	{0x00, 0x43, 0xff, 0xaa},
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0x20, 0xc4, 0xaa},
+	{0x00, 0x13, 0x03, 0xaa},
+	{0x00, 0x3c, 0x50, 0xaa},
+	{0x00, 0x61, 0x6a, 0xaa},	/* sharpness? */
+	{0x00, 0x51, 0x5b, 0xaa},
+	{0x00, 0x52, 0x91, 0xaa},
+	{0x00, 0x53, 0x4c, 0xaa},
+	{0x00, 0x54, 0x50, 0xaa},
+	{0x00, 0x56, 0x02, 0xaa},
+	{0xb6, 0x00, 0x00, 0xcc},
+	{0xb6, 0x03, 0x03, 0xcc},
+	{0xb6, 0x02, 0x20, 0xcc},
+	{0xb6, 0x05, 0x02, 0xcc},
+	{0xb6, 0x04, 0x58, 0xcc},
+	{0xb6, 0x12, 0xf8, 0xcc},
+	{0xb6, 0x13, 0x21, 0xcc},
+	{0xb6, 0x18, 0x03, 0xcc},
+	{0xb6, 0x17, 0xa9, 0xcc},
+	{0xb6, 0x16, 0x80, 0xcc},
+	{0xb6, 0x22, 0x12, 0xcc},
+	{0xb6, 0x23, 0x0b, 0xcc},
+	{0xbf, 0xc0, 0x39, 0xcc},
+	{0xbf, 0xc1, 0x04, 0xcc},
+	{0xbf, 0xcc, 0x00, 0xcc},
+	{0xb8, 0x06, 0x20, 0xcc},
+	{0xb8, 0x07, 0x03, 0xcc},
+	{0xb8, 0x08, 0x58, 0xcc},
+	{0xb8, 0x09, 0x02, 0xcc},
+	{0xb3, 0x01, 0x41, 0xcc},
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0xd9, 0x0f, 0xaa},
+	{0x00, 0xda, 0xaa, 0xaa},
+	{0x00, 0xd9, 0x10, 0xaa},
+	{0x00, 0xda, 0xaa, 0xaa},
+	{0x00, 0xd9, 0x11, 0xaa},
+	{0x00, 0xda, 0x00, 0xaa},
+	{0x00, 0xd9, 0x12, 0xaa},
+	{0x00, 0xda, 0xff, 0xaa},
+	{0x00, 0xd9, 0x13, 0xaa},
+	{0x00, 0xda, 0xff, 0xaa},
+	{0x00, 0xe8, 0x11, 0xaa},
+	{0x00, 0xe9, 0x12, 0xaa},
+	{0x00, 0xea, 0x5c, 0xaa},
+	{0x00, 0xeb, 0xff, 0xaa},
+	{0x00, 0xd8, 0x80, 0xaa},
+	{0x00, 0xe6, 0x02, 0xaa},
+	{0x00, 0xd6, 0x40, 0xaa},
+	{0x00, 0xe3, 0x05, 0xaa},
+	{0x00, 0xe0, 0x40, 0xaa},
+	{0x00, 0xde, 0x03, 0xaa},
+	{0x00, 0xdf, 0x03, 0xaa},
+	{0x00, 0xdb, 0x02, 0xaa},
+	{0x00, 0xdc, 0x00, 0xaa},
+	{0x00, 0xdd, 0x03, 0xaa},
+	{0x00, 0xe1, 0x08, 0xaa},
+	{0x00, 0xe2, 0x01, 0xaa},
+	{0x00, 0xd6, 0x40, 0xaa},
+	{0x00, 0xe4, 0x40, 0xaa},
+	{0x00, 0xa8, 0x8f, 0xaa},
+	{0x00, 0xb4, 0x16, 0xaa},
+	{0xb0, 0x02, 0x06, 0xcc},
+	{0xb0, 0x18, 0x06, 0xcc},
+	{0xb0, 0x19, 0x06, 0xcc},
+	{0xb3, 0x5d, 0x18, 0xcc},
+	{0xb3, 0x05, 0x00, 0xcc},
+	{0xb3, 0x06, 0x00, 0xcc},
+	{0x00, 0xb4, 0x0e, 0xaa},
+	{0x00, 0xb5, 0x49, 0xaa},
+	{0x00, 0xb6, 0x1c, 0xaa},
+	{0x00, 0xb7, 0x96, 0xaa},
+/* end of usbvm326.inf - start of ms-win trace */
+	{0xb6, 0x12, 0xf8, 0xcc},
+	{0xb6, 0x13, 0x3d, 0xcc},
+/*read b306*/
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0x1a, 0x09, 0xaa},
+	{0x00, 0x1b, 0x8a, 0xaa},
+/*read b827*/
+	{0xb8, 0x27, 0x00, 0xcc},
+	{0xb8, 0x26, 0x60, 0xcc},
+	{0xb8, 0x26, 0x60, 0xcc},
+/*gamma - to do?*/
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0xae, 0x84, 0xaa},
+/*gamma again*/
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0x96, 0xa0, 0xaa},
+/*matrix*/
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0x91, 0x35, 0xaa},
+	{0x00, 0x92, 0x22, 0xaa},
+/*gamma*/
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0x95, 0x85, 0xaa},
+/*matrix*/
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0x4d, 0x20, 0xaa},
+	{0xb8, 0x22, 0x40, 0xcc},
+	{0xb8, 0x23, 0x40, 0xcc},
+	{0xb8, 0x24, 0x40, 0xcc},
+	{0xb8, 0x81, 0x09, 0xcc},
+	{0x00, 0x00, 0x64, 0xdd},
+	{0x00, 0x03, 0x01, 0xaa},
+/*read 46*/
+	{0x00, 0x46, 0x3c, 0xaa},
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0x16, 0x40, 0xaa},
+	{0x00, 0x17, 0x40, 0xaa},
+	{0x00, 0x18, 0x40, 0xaa},
+	{0x00, 0x19, 0x41, 0xaa},
+	{0x00, 0x03, 0x01, 0xaa},
+	{0x00, 0x46, 0x3c, 0xaa},
+	{0x00, 0x00, 0x18, 0xdd},
+/*read bfff*/
+	{0x00, 0x03, 0x00, 0xaa},
+	{0x00, 0xb4, 0x1c, 0xaa},
+	{0x00, 0xb5, 0x92, 0xaa},
+	{0x00, 0xb6, 0x39, 0xaa},
+	{0x00, 0xb7, 0x24, 0xaa},
+/*write 89 0400 1415*/
+};
+
 struct sensor_info {
 	int sensorId;
 	__u8 I2cAdd;
@@ -1222,6 +1781,9 @@ static const struct sensor_info sensor_info_data[] = {
 	{SENSOR_MI1320,     0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
 	{SENSOR_OV7670,     0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
 	{SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+/* (tested in vc032x_probe_sensor) */
+/*	{SENSOR_MI0360,	    0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
+	{SENSOR_PO1200,     0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
 };
 
 /* read 'len' bytes in gspca_dev->usb_buf */
@@ -1278,18 +1840,18 @@ static void read_sensor_register(struct gspca_dev *gspca_dev,
 		msleep(1);
 	}
 	reg_r(gspca_dev, 0xa1, 0xb33e, 1);
-	hdata = gspca_dev->usb_buf[0];
+	ldata = gspca_dev->usb_buf[0];
 	reg_r(gspca_dev, 0xa1, 0xb33d, 1);
 	mdata = gspca_dev->usb_buf[0];
 	reg_r(gspca_dev, 0xa1, 0xb33c, 1);
-	ldata = gspca_dev->usb_buf[0];
-	PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)",
+	hdata = gspca_dev->usb_buf[0];
+	PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x",
 		hdata, mdata, ldata);
 	reg_r(gspca_dev, 0xa1, 0xb334, 1);
 	if (gspca_dev->usb_buf[0] == 0x02)
-		*value = (ldata << 8) + mdata;
+		*value = (hdata << 8) + mdata;
 	else
-		*value = ldata;
+		*value = hdata;
 }
 
 static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
@@ -1300,7 +1862,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
 	const struct sensor_info *ptsensor_info;
 
 	reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
-	PDEBUG(D_PROBE, "check sensor header %d", gspca_dev->usb_buf[0]);
+	PDEBUG(D_PROBE, "check sensor header %02x", gspca_dev->usb_buf[0]);
 	for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
 		ptsensor_info = &sensor_info_data[i];
 		reg_w(dev, 0xa0, 0x02, 0xb334);
@@ -1309,16 +1871,15 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
 		reg_w(dev, 0xa0, 0x01, 0xb308);
 		reg_w(dev, 0xa0, 0x0c, 0xb309);
 		reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
-/*		PDEBUG(D_PROBE,
-			"check sensor VC032X -> %d Add -> ox%02X!",
-			i, ptsensor_info->I2cAdd); */
 		reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
 		read_sensor_register(gspca_dev, ptsensor_info->IdAdd, &value);
-		if (value == ptsensor_info->VpId) {
-/*			PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!",
-				ptsensor_info->VpId); */
+		if (value == ptsensor_info->VpId)
 			return ptsensor_info->sensorId;
-		}
+
+		/* special case for MI0360 */
+		if (ptsensor_info->sensorId == SENSOR_MI1310_SOC
+		    && value == 0x8243)
+			return SENSOR_MI0360;
 	}
 	return -1;
 }
@@ -1420,13 +1981,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	cam = &gspca_dev->cam;
 	cam->epaddr = 0x02;
 	sd->bridge = id->driver_info;
-	if (sd->bridge == BRIDGE_VC0321) {
-		cam->cam_mode = vc0321_mode;
-		cam->nmodes = ARRAY_SIZE(vc0321_mode);
-	} else {
-		cam->cam_mode = vc0323_mode;
-		cam->nmodes = ARRAY_SIZE(vc0323_mode);
-	}
 
 	vc0321_reset(gspca_dev);
 	sensor = vc032x_probe_sensor(gspca_dev);
@@ -1436,35 +1990,66 @@ static int sd_config(struct gspca_dev *gspca_dev,
 		return -EINVAL;
 	case SENSOR_HV7131R:
 		PDEBUG(D_PROBE, "Find Sensor HV7131R");
-		sd->sensor = SENSOR_HV7131R;
+		break;
+	case SENSOR_MI0360:
+		PDEBUG(D_PROBE, "Find Sensor MI0360");
+		sd->bridge = BRIDGE_VC0323;
 		break;
 	case SENSOR_MI1310_SOC:
 		PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
-		sd->sensor = SENSOR_MI1310_SOC;
 		break;
 	case SENSOR_MI1320:
 		PDEBUG(D_PROBE, "Find Sensor MI1320");
-		sd->sensor = SENSOR_MI1320;
 		break;
 	case SENSOR_OV7660:
 		PDEBUG(D_PROBE, "Find Sensor OV7660");
-		sd->sensor = SENSOR_OV7660;
 		break;
 	case SENSOR_OV7670:
 		PDEBUG(D_PROBE, "Find Sensor OV7670");
-		sd->sensor = SENSOR_OV7670;
+		break;
+	case SENSOR_PO1200:
+		PDEBUG(D_PROBE, "Find Sensor PO1200");
 		break;
 	case SENSOR_PO3130NC:
 		PDEBUG(D_PROBE, "Find Sensor PO3130NC");
-		sd->sensor = SENSOR_PO3130NC;
 		break;
 	}
+	sd->sensor = sensor;
 
-	sd->qindex = 7;
-	sd->autogain = AUTOGAIN_DEF;
+	if (sd->bridge == BRIDGE_VC0321) {
+		cam->cam_mode = vc0321_mode;
+		cam->nmodes = ARRAY_SIZE(vc0321_mode);
+	} else {
+		if (sensor != SENSOR_PO1200) {
+			cam->cam_mode = vc0323_mode;
+			cam->nmodes = ARRAY_SIZE(vc0323_mode);
+		} else {
+			cam->cam_mode = svga_mode;
+			cam->nmodes = ARRAY_SIZE(svga_mode);
+		}
+	}
+
+	sd->hflip = HFLIP_DEF;
+	sd->vflip = VFLIP_DEF;
+	if (sd->sensor == SENSOR_OV7670) {
+		sd->hflip = 1;
+		sd->vflip = 1;
+	}
 	sd->lightfreq = FREQ_DEF;
 	if (sd->sensor != SENSOR_OV7670)
 		gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
+	switch (sd->sensor) {
+	case SENSOR_OV7660:
+	case SENSOR_OV7670:
+	case SENSOR_PO1200:
+		break;
+	default:
+		gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
+					| (1 << VFLIP_IDX);
+		break;
+	}
+
+	sd->sharpness = SHARPNESS_DEF;
 
 	if (sd->bridge == BRIDGE_VC0321) {
 		reg_r(gspca_dev, 0x8a, 0, 3);
@@ -1482,12 +2067,33 @@ static int sd_init(struct gspca_dev *gspca_dev)
 	return 0;
 }
 
-static void setquality(struct gspca_dev *gspca_dev)
+/* for OV7660 and OV7670 only */
+static void sethvflip(struct gspca_dev *gspca_dev)
 {
-}
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 data;
 
-static void setautogain(struct gspca_dev *gspca_dev)
-{
+	switch (sd->sensor) {
+	case SENSOR_OV7660:
+		data = 1;
+		break;
+	case SENSOR_OV7670:
+		data = 7;
+		break;
+	case SENSOR_PO1200:
+		data = 0;
+		i2c_write(gspca_dev, 0x03, &data, 1);
+		data = 0x80 * sd->hflip
+			| 0x40 * sd->vflip
+			| 0x06;
+		i2c_write(gspca_dev, 0x1e, &data, 1);
+		return;
+	default:
+		return;
+	}
+	data |= OV7660_MVFP_MIRROR * sd->hflip
+		| OV7660_MVFP_VFLIP * sd->vflip;
+	i2c_write(gspca_dev, OV7660_REG_MVFP, &data, 1);
 }
 
 static void setlightfreq(struct gspca_dev *gspca_dev)
@@ -1501,6 +2107,20 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
 	usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
 }
 
+/* po1200 only */
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 data;
+
+	if (sd->sensor != SENSOR_PO1200)
+		return;
+	data = 0;
+	i2c_write(gspca_dev, 0x03, &data, 1);
+	data = 0xb5 + sd->sharpness * 3;
+	i2c_write(gspca_dev, 0x61, &data, 1);
+}
+
 static int sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -1551,6 +2171,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
 			usb_exchange(gspca_dev, ov7670_initVGA_JPG);
 		}
 		break;
+	case SENSOR_MI0360:
+		GammaT = mi1320_gamma;
+		MatrixT = mi0360_matrix;
+		if (mode) {
+			/* 320x240 */
+			usb_exchange(gspca_dev, mi0360_initQVGA_JPG);
+		} else {
+			/* 640x480 */
+			usb_exchange(gspca_dev, mi0360_initVGA_JPG);
+		}
+		break;
 	case SENSOR_MI1310_SOC:
 		if (mode) {
 			/* 320x240 */
@@ -1583,6 +2214,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		}
 		usb_exchange(gspca_dev, po3130_rundata);
 		break;
+	case SENSOR_PO1200:
+		GammaT = po1200_gamma;
+		MatrixT = po1200_matrix;
+		usb_exchange(gspca_dev, po1200_initVGA_data);
+		break;
 	default:
 		PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
 		return -EMEDIUMTYPE;
@@ -1615,11 +2251,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
 		*/
 		/* set the led on 0x0892 0x0896 */
-		reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
-		msleep(100);
-		setquality(gspca_dev);
-		setautogain(gspca_dev);
-		setlightfreq(gspca_dev);
+		if (sd->sensor != SENSOR_PO1200) {
+			reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+			msleep(100);
+			sethvflip(gspca_dev);
+			setlightfreq(gspca_dev);
+		} else {
+			setsharpness(gspca_dev);
+			sethvflip(gspca_dev);
+			reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+		}
 	}
 	return 0;
 }
@@ -1665,24 +2306,48 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 				data, len);
 		return;
 	}
+
+	/* The vc0321 sends some additional data after sending the complete
+	 * frame, we ignore this. */
+	if (sd->bridge == BRIDGE_VC0321
+	    && len > frame->v4l2_buf.length - (frame->data_end - frame->data))
+		len = frame->v4l2_buf.length - (frame->data_end - frame->data);
 	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hflip = val;
+	if (gspca_dev->streaming)
+		sethvflip(gspca_dev);
+	return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->hflip;
+	return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->autogain = val;
+	sd->vflip = val;
 	if (gspca_dev->streaming)
-		setautogain(gspca_dev);
+		sethvflip(gspca_dev);
 	return 0;
 }
 
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	*val = sd->autogain;
+	*val = sd->vflip;
 	return 0;
 }
 
@@ -1704,6 +2369,24 @@ static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
 	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)
+		setsharpness(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;
+}
+
 static int sd_querymenu(struct gspca_dev *gspca_dev,
 			struct v4l2_querymenu *menu)
 {
@@ -1743,11 +2426,13 @@ static const struct sd_desc sd_desc = {
 static const __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321},
 	{USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321},
+	{USB_DEVICE(0x046d, 0x0897), .driver_info = BRIDGE_VC0321},
 	{USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321},
 	{USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323},
 	{USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321},
 	{USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321},
 	{USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321},
+	{USB_DEVICE(0x15b8, 0x6002), .driver_info = BRIDGE_VC0323},
 	{USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323},
 	{}
 };