浏览代码

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (23 commits)
  V4L/DVB (8617): uvcvideo: don't use stack-based buffers for USB transfers.
  V4L/DVB (8616): uvcvideo: Add support for two Bison Electronics webcams
  V4L/DVB (8611): Add suspend/resume to pxa_camera driver
  V4L/DVB (8610): Add suspend/resume capabilities to soc_camera.
  V4L/DVB (8609): media: Clean up platform_driver_unregister() bogosity.
  V4L/DVB (8607): cxusb: fix OOPS and broken tuning regression on FusionHDTV Dual Digital 4
  V4L/DVB (8605): gspca: Fix of gspca_zc3xx oops - 2.6.27-rc1
  V4L/DVB (8604): gspca: Fix of "scheduling while atomic" crash.
  V4L/DVB (8602): gspca: Fix small bugs, simplify and cleanup ov519.
  V4L/DVB (8582): set mts_firmware for em2882 based Pinnacle Hybrid Pro
  V4L/DVB (8574): gspca: Bad bytesperlines of pixelformat in spca505/506/508 and vc023x.
  V4L/DVB (8573): gspca: Bad scan of frame in spca505/506/508.
  V4L/DVB (8572): gspca: Webcam 0c45:6143 in documentation.
  V4L/DVB (8571): gspca: Don't use CONFIG_VIDEO_ADV_DEBUG as a compile option.
  V4L/DVB (8569): gspca: Set back the old values of Sonix sn9c120 and cleanup source.
  V4L/DVB (8567): gspca: hflip and vflip controls added for ov519 - ov7670 plus init cleanup.
  V4L/DVB (8564): fix vino driver build error
  V4L/DVB (8563): fix drivers/media/video/arv.c compilation
  V4L/DVB (8562): DVB_DRX397XD: remove FW_LOADER select
  V4L/DVB (8558): media/video/Kconfig: fix a typo
  ...
Linus Torvalds 17 年之前
父节点
当前提交
b80b601f00

+ 1 - 0
Documentation/video4linux/gspca.txt

@@ -226,6 +226,7 @@ sonixj		0c45:6130	Sonix Pccam
 sonixj		0c45:6138	Sn9c120 Mo4000
 sonixj		0c45:613b	Surfer SN-206
 sonixj		0c45:613c	Sonix Pccam168
+sonixj		0c45:6143	Sonix Pccam168
 sunplus		0d64:0303	Sunplus FashionCam DXG
 etoms		102c:6151	Qcam Sangha CIF
 etoms		102c:6251	Qcam xxxxxx VGA

+ 4 - 3
drivers/media/dvb/dvb-usb/cxusb.c

@@ -565,7 +565,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 
 static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
 {
-	struct dvb_usb_device *d = ptr;
+	struct dvb_usb_adapter *adap = ptr;
+	struct dvb_usb_device *d = adap->dev;
 
 	switch (command) {
 	case XC2028_TUNER_RESET:
@@ -593,9 +594,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
 		.callback  = dvico_bluebird_xc2028_callback,
 	};
 	static struct xc2028_ctrl ctl = {
-		.fname       = "xc3028-dvico-au-01.fw",
+		.fname       = "xc3028-v27.fw",
 		.max_len     = 64,
-		.scode_table = XC3028_FE_ZARLINK456,
+		.demod       = XC3028_FE_ZARLINK456,
 	};
 
 	fe = dvb_attach(xc2028_attach, adap->fe, &cfg);

+ 1 - 2
drivers/media/dvb/frontends/Kconfig

@@ -135,9 +135,8 @@ config DVB_CX22702
 
 config DVB_DRX397XD
 	tristate "Micronas DRX3975D/DRX3977D based"
-	depends on DVB_CORE && I2C && HOTPLUG
+	depends on DVB_CORE && I2C
 	default m if DVB_FE_CUSTOMISE
-	select FW_LOADER
 	help
 	  A DVB-T tuner module. Say Y when you want to support this frontend.
 

+ 1 - 1
drivers/media/video/Kconfig

@@ -630,7 +630,7 @@ config VIDEO_ZORAN_ZR36060
 	depends on VIDEO_ZORAN
 	help
 	  Say Y to support Zoran boards based on 36060 chips.
-	  This includes Iomega Bus, Pinnacle DC10, Linux media Labs 33
+	  This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33
 	  and 33 R10 and AverMedia 6 boards.
 
 config VIDEO_ZORAN_BUZ

+ 1 - 1
drivers/media/video/arv.c

@@ -29,6 +29,7 @@
 #include <linux/sched.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
 #include <linux/mutex.h>
 
 #include <asm/uaccess.h>
@@ -755,7 +756,6 @@ static const struct file_operations ar_fops = {
 
 static struct video_device ar_template = {
 	.name		= "Colour AR VGA",
-	.type		= VID_TYPE_CAPTURE,
 	.fops		= &ar_fops,
 	.release	= ar_release,
 	.minor		= -1,

+ 1 - 0
drivers/media/video/em28xx/em28xx-cards.c

@@ -1015,6 +1015,7 @@ struct em28xx_board em28xx_boards[] = {
 		.valid        = EM28XX_BOARD_NOT_VALIDATED,
 		.vchannels    = 3,
 		.tuner_type   = TUNER_XC2028,
+		.mts_firmware = 1,
 		.decoder      = EM28XX_TVP5150,
 		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,

+ 2 - 2
drivers/media/video/gspca/conex.c

@@ -123,7 +123,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
 {
 	struct usb_device *dev = gspca_dev->dev;
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 	if (len > sizeof gspca_dev->usb_buf) {
 		err("reg_r: buffer overflow");
 		return;
@@ -163,7 +163,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
 {
 	struct usb_device *dev = gspca_dev->dev;
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 	if (len > sizeof gspca_dev->usb_buf) {
 		err("reg_w: buffer overflow");
 		return;

+ 74 - 63
drivers/media/video/gspca/etoms.c

@@ -233,7 +233,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
 {
 	struct usb_device *dev = gspca_dev->dev;
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 	if (len > sizeof gspca_dev->usb_buf) {
 		err("reg_r: buffer overflow");
 		return;
@@ -271,7 +271,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
 {
 	struct usb_device *dev = gspca_dev->dev;
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 	if (len > sizeof gspca_dev->usb_buf) {
 		err("reg_w: buffer overflow");
 		return;
@@ -461,6 +461,52 @@ static void Et_init2(struct gspca_dev *gspca_dev)
 	reg_w_val(gspca_dev, 0x80, 0x20);	/* 0x20; */
 }
 
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	__u8 brightness = sd->brightness;
+
+	for (i = 0; i < 4; i++)
+		reg_w_val(gspca_dev, ET_O_RED + i, brightness);
+}
+
+static void getbrightness(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	int brightness = 0;
+
+	for (i = 0; i < 4; i++) {
+		reg_r(gspca_dev, ET_O_RED + i, 1);
+		brightness += gspca_dev->usb_buf[0];
+	}
+	sd->brightness = brightness >> 3;
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
+	__u8 contrast = sd->contrast;
+
+	memset(RGBG, contrast, sizeof(RGBG) - 2);
+	reg_w(gspca_dev, ET_G_RED, RGBG, 6);
+}
+
+static void getcontrast(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+	int contrast = 0;
+
+	for (i = 0; i < 4; i++) {
+		reg_r(gspca_dev, ET_G_RED + i, 1);
+		contrast += gspca_dev->usb_buf[0];
+	}
+	sd->contrast = contrast >> 2;
+}
+
 static void setcolors(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -492,6 +538,16 @@ static void getcolors(struct gspca_dev *gspca_dev)
 	}
 }
 
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->autogain)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
+}
+
 static void Et_init1(struct gspca_dev *gspca_dev)
 {
 	__u8 value;
@@ -614,6 +670,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->contrast = CONTRAST_DEF;
 	sd->colors = COLOR_DEF;
 	sd->autogain = AUTOGAIN_DEF;
+	sd->ag_cnt = -1;
 	return 0;
 }
 
@@ -641,6 +698,8 @@ static void sd_start(struct gspca_dev *gspca_dev)
 	else
 		Et_init2(gspca_dev);
 
+	setautogain(gspca_dev);
+
 	reg_w_val(gspca_dev, ET_RESET_ALL, 0x08);
 	et_video(gspca_dev, 1);		/* video on */
 }
@@ -658,52 +717,6 @@ static void sd_close(struct gspca_dev *gspca_dev)
 {
 }
 
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	int i;
-	__u8 brightness = sd->brightness;
-
-	for (i = 0; i < 4; i++)
-		reg_w_val(gspca_dev, ET_O_RED + i, brightness);
-}
-
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	int i;
-	int brightness = 0;
-
-	for (i = 0; i < 4; i++) {
-		reg_r(gspca_dev, ET_O_RED + i, 1);
-		brightness += gspca_dev->usb_buf[0];
-	}
-	sd->brightness = brightness >> 3;
-}
-
-static void setcontrast(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	__u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 };
-	__u8 contrast = sd->contrast;
-
-	memset(RGBG, contrast, sizeof(RGBG) - 2);
-	reg_w(gspca_dev, ET_G_RED, RGBG, 6);
-}
-
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	int i;
-	int contrast = 0;
-
-	for (i = 0; i < 4; i++) {
-		reg_r(gspca_dev, ET_G_RED + i, 1);
-		contrast += gspca_dev->usb_buf[0];
-	}
-	sd->contrast = contrast >> 2;
-}
-
 static __u8 Et_getgainG(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -733,15 +746,22 @@ static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
 #define LIMIT(color) \
 	(unsigned char)((color > 0xff)?0xff:((color < 0)?0:color))
 
-static void setautogain(struct gspca_dev *gspca_dev)
+static void do_autogain(struct gspca_dev *gspca_dev)
 {
-	__u8 luma = 0;
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 luma;
 	__u8 luma_mean = 128;
 	__u8 luma_delta = 20;
 	__u8 spring = 4;
-	int Gbright = 0;
+	int Gbright;
 	__u8 r, g, b;
 
+	if (sd->ag_cnt < 0)
+		return;
+	if (--sd->ag_cnt >= 0)
+		return;
+	sd->ag_cnt = AG_CNT_START;
+
 	Gbright = Et_getgainG(gspca_dev);
 	reg_r(gspca_dev, ET_LUMA_CENTER, 4);
 	g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1;
@@ -768,7 +788,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			__u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
-	struct sd *sd;
 	int seqframe;
 
 	seqframe = data[0] & 0x3f;
@@ -783,13 +802,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
 					data, 0);
 		gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len);
-		sd = (struct sd *) gspca_dev;
-		if (sd->ag_cnt >= 0) {
-			if (--sd->ag_cnt < 0) {
-				sd->ag_cnt = AG_CNT_START;
-				setautogain(gspca_dev);
-			}
-		}
 		return;
 	}
 	if (len) {
@@ -862,10 +874,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->autogain = val;
-	if (val)
-		sd->ag_cnt = AG_CNT_START;
-	else
-		sd->ag_cnt = -1;
+	if (gspca_dev->streaming)
+		setautogain(gspca_dev);
 	return 0;
 }
 
@@ -889,6 +899,7 @@ static struct sd_desc sd_desc = {
 	.stop0 = sd_stop0,
 	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
+	.dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */

+ 6 - 6
drivers/media/video/gspca/gspca.c

@@ -47,7 +47,7 @@ MODULE_LICENSE("GPL");
 
 static int video_nr = -1;
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
 EXPORT_SYMBOL(gspca_debug);
 
@@ -677,7 +677,7 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
 	w = fmt->fmt.pix.width;
 	h = fmt->fmt.pix.height;
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 	if (gspca_debug & D_CONF)
 		PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
 #endif
@@ -785,7 +785,7 @@ static int dev_open(struct inode *inode, struct file *file)
 	}
 	gspca_dev->users++;
 	file->private_data = gspca_dev;
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 	/* activate the v4l2 debug */
 	if (gspca_debug & D_V4L2)
 		gspca_dev->vdev.debug |= 3;
@@ -904,7 +904,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 		if (ctrl->id != ctrls->qctrl.id)
 			continue;
 		if (ctrl->value < ctrls->qctrl.minimum
-		    && ctrl->value > ctrls->qctrl.maximum)
+		    || ctrl->value > ctrls->qctrl.maximum)
 			return -ERANGE;
 		PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
 		if (mutex_lock_interruptible(&gspca_dev->usb_lock))
@@ -1080,7 +1080,7 @@ static int vidioc_streamon(struct file *file, void *priv,
 		if (ret < 0)
 			goto out;
 	}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 	if (gspca_debug & D_STREAM) {
 		PDEBUG_MODE("stream on OK",
 			gspca_dev->pixfmt,
@@ -1913,7 +1913,7 @@ static void __exit gspca_exit(void)
 module_init(gspca_init);
 module_exit(gspca_exit);
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 module_param_named(debug, gspca_debug, int, 0644);
 MODULE_PARM_DESC(debug,
 		"Debug (bit) 0x01:error 0x02:probe 0x04:config"

+ 4 - 1
drivers/media/video/gspca/gspca.h

@@ -9,7 +9,10 @@
 #include <media/v4l2-common.h>
 #include <linux/mutex.h>
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+/* compilation option */
+#define GSPCA_DEBUG 1
+
+#ifdef GSPCA_DEBUG
 /* GSPCA our debug messages */
 extern int gspca_debug;
 #define PDEBUG(level, fmt, args...) \

+ 225 - 251
drivers/media/video/gspca/ov519.c

@@ -40,14 +40,15 @@ struct sd {
 	struct gspca_dev gspca_dev;		/* !! must be the first item */
 
 	/* Determined by sensor type */
-	short maxwidth;
-	short maxheight;
+	char sif;
 
 	unsigned char primary_i2c_slave;	/* I2C write id of sensor */
 
 	unsigned char brightness;
 	unsigned char contrast;
 	unsigned char colors;
+	__u8 hflip;
+	__u8 vflip;
 
 	char compress;		/* Should the next frame be compressed? */
 	char compress_inited;	/* Are compression params uploaded? */
@@ -77,9 +78,12 @@ 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_setcolors(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcolors(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 struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
 	{
 	    {
 		.id      = V4L2_CID_BRIGHTNESS,
@@ -88,12 +92,12 @@ static struct ctrl sd_ctrls[] = {
 		.minimum = 0,
 		.maximum = 255,
 		.step    = 1,
-		.default_value = 127,
+#define BRIGHTNESS_DEF 127
+		.default_value = BRIGHTNESS_DEF,
 	    },
 	    .set = sd_setbrightness,
 	    .get = sd_getbrightness,
 	},
-#define SD_CONTRAST 1
 	{
 	    {
 		.id      = V4L2_CID_CONTRAST,
@@ -102,31 +106,61 @@ static struct ctrl sd_ctrls[] = {
 		.minimum = 0,
 		.maximum = 255,
 		.step    = 1,
-		.default_value = 127,
+#define CONTRAST_DEF 127
+		.default_value = CONTRAST_DEF,
 	    },
 	    .set = sd_setcontrast,
 	    .get = sd_getcontrast,
 	},
-#define SD_COLOR 2
 	{
 	    {
 		.id      = V4L2_CID_SATURATION,
 		.type    = V4L2_CTRL_TYPE_INTEGER,
-		.name    = "Saturation",
+		.name    = "Color",
 		.minimum = 0,
 		.maximum = 255,
 		.step    = 1,
-		.default_value = 127,
+#define COLOR_DEF 127
+		.default_value = COLOR_DEF,
 	    },
 	    .set = sd_setcolors,
 	    .get = sd_getcolors,
 	},
+/* next controls work with ov7670 only */
+	{
+	    {
+		.id      = V4L2_CID_HFLIP,
+		.type    = V4L2_CTRL_TYPE_BOOLEAN,
+		.name    = "Mirror",
+		.minimum = 0,
+		.maximum = 1,
+		.step    = 1,
+#define HFLIP_DEF 0
+		.default_value = HFLIP_DEF,
+	    },
+	    .set = sd_sethflip,
+	    .get = sd_gethflip,
+	},
+	{
+	    {
+		.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,
+	},
 };
 
 static struct v4l2_pix_format vga_mode[] = {
 	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 320,
-		.sizeimage = 320 * 240 * 3 / 8 + 589,
+		.sizeimage = 320 * 240 * 3 / 8 + 590,
 		.colorspace = V4L2_COLORSPACE_JPEG,
 		.priv = 1},
 	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -138,12 +172,12 @@ static struct v4l2_pix_format vga_mode[] = {
 static struct v4l2_pix_format sif_mode[] = {
 	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 176,
-		.sizeimage = 176 * 144 * 3 / 8 + 589,
+		.sizeimage = 176 * 144 * 3 / 8 + 590,
 		.colorspace = V4L2_COLORSPACE_JPEG,
 		.priv = 1},
 	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 		.bytesperline = 352,
-		.sizeimage = 352 * 288 * 3 / 8 + 589,
+		.sizeimage = 352 * 288 * 3 / 8 + 590,
 		.colorspace = V4L2_COLORSPACE_JPEG,
 		.priv = 0},
 };
@@ -225,6 +259,7 @@ static struct v4l2_pix_format sif_mode[] = {
 #define OV7670_REG_VSTART      0x19    /* Vert start high bits */
 #define OV7670_REG_VSTOP       0x1a    /* Vert stop high bits */
 #define OV7670_REG_MVFP        0x1e    /* Mirror / vflip */
+#define   OV7670_MVFP_VFLIP	 0x10    /* vertical flip */
 #define   OV7670_MVFP_MIRROR     0x20    /* Mirror image */
 #define OV7670_REG_AEW         0x24    /* AGC upper limit */
 #define OV7670_REG_AEB         0x25    /* AGC lower limit */
@@ -258,16 +293,6 @@ static struct v4l2_pix_format sif_mode[] = {
 #define OV7670_REG_HAECC7      0xaa    /* Hist AEC/AGC control 7 */
 #define OV7670_REG_BD60MAX     0xab    /* 60hz banding step limit */
 
-struct ovsensor_window {
-	short x;
-	short y;
-	short width;
-	short height;
-/*	int format; */
-	short quarter;		/* Scale width and height down 2x */
-	short clockdiv;		/* Clock divisor setting */
-};
-
 static unsigned char ov7670_abs_to_sm(unsigned char v)
 {
 	if (v > 127)
@@ -499,19 +524,6 @@ static int init_ov_sensor(struct sd *sd)
 	return 0;
 }
 
-/* Switch on standard JPEG compression. Returns 0 for success. */
-static int ov519_init_compression(struct sd *sd)
-{
-	if (!sd->compress_inited) {
-		if (reg_w_mask(sd, OV519_SYS_EN_CLK1, 1 << 2, 1 << 2) < 0) {
-			PDEBUG(D_ERR, "Error switching to compressed mode");
-			return -EIO;
-		}
-		sd->compress_inited = 1;
-	}
-	return 0;
-}
-
 /* Set the read and write slave IDs. The "slave" argument is the write slave,
  * and the read slave will be set to (slave + 1).
  * This should not be called from outside the i2c I/O functions.
@@ -681,21 +693,17 @@ static int ov8xx0_configure(struct sd *sd)
 		return -1;
 	}
 	if ((rc & 3) == 1) {
-		PDEBUG(D_PROBE, "Sensor is an OV8610");
 		sd->sensor = SEN_OV8610;
 	} else {
 		PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
 		return -1;
 	}
 	PDEBUG(D_PROBE, "Writing 8610 registers");
-	if (write_i2c_regvals(sd,
-			norm_8610,
-			sizeof norm_8610 / sizeof norm_8610[0]))
+	if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
 		return -1;
 
 	/* Set sensor-specific vars */
-	sd->maxwidth = 640;
-	sd->maxheight = 480;
+/*	sd->sif = 0;		already done */
 	return 0;
 }
 
@@ -825,7 +833,7 @@ static int ov7xx0_configure(struct sd *sd)
 		{ OV7670_REG_COM7, OV7670_COM7_RESET },
 		{ OV7670_REG_TSLB, 0x04 },		/* OV */
 		{ OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
-		{ OV7670_REG_CLKRC, 0x1 },
+		{ OV7670_REG_CLKRC, 0x01 },
 	/*
 	 * Set the hardware window.  These values from OV don't entirely
 	 * make sense - hstop is less than hstart.  But they work...
@@ -839,16 +847,12 @@ static int ov7xx0_configure(struct sd *sd)
 		{ 0x70, 0x3a },		{ 0x71, 0x35 },
 		{ 0x72, 0x11 },		{ 0x73, 0xf0 },
 		{ 0xa2, 0x02 },
-/* jfm */
-/* { OV7670_REG_COM10, 0x0 }, */
+/*		{ OV7670_REG_COM10, 0x0 }, */
 
 	/* Gamma curve values */
 		{ 0x7a, 0x20 },
-/* jfm:win 7b=1c */
 		{ 0x7b, 0x10 },
-/* jfm:win 7c=28 */
 		{ 0x7c, 0x1e },
-/* jfm:win 7d=3c */
 		{ 0x7d, 0x35 },
 		{ 0x7e, 0x5a },		{ 0x7f, 0x69 },
 		{ 0x80, 0x76 },		{ 0x81, 0x80 },
@@ -864,13 +868,11 @@ static int ov7xx0_configure(struct sd *sd)
 				 | OV7670_COM8_BFILT },
 		{ OV7670_REG_GAIN, 0 },	{ OV7670_REG_AECH, 0 },
 		{ OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
-/* jfm:win 14=38 */
 		{ OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
 		{ OV7670_REG_BD50MAX, 0x05 },	{ OV7670_REG_BD60MAX, 0x07 },
 		{ OV7670_REG_AEW, 0x95 },	{ OV7670_REG_AEB, 0x33 },
 		{ OV7670_REG_VPT, 0xe3 },	{ OV7670_REG_HAECC1, 0x78 },
 		{ OV7670_REG_HAECC2, 0x68 },
-/* jfm:win a1=0b */
 		{ 0xa1, 0x03 }, /* magic */
 		{ OV7670_REG_HAECC3, 0xd8 },	{ OV7670_REG_HAECC4, 0xd8 },
 		{ OV7670_REG_HAECC5, 0xf0 },	{ OV7670_REG_HAECC6, 0x90 },
@@ -884,8 +886,6 @@ static int ov7xx0_configure(struct sd *sd)
 	/* Almost all of these are magic "reserved" values.  */
 		{ OV7670_REG_COM5, 0x61 },	{ OV7670_REG_COM6, 0x4b },
 		{ 0x16, 0x02 },
-/* jfm */
-/*		{ OV7670_REG_MVFP, 0x07|OV7670_MVFP_MIRROR }, */
 		{ OV7670_REG_MVFP, 0x07 },
 		{ 0x21, 0x02 },		{ 0x22, 0x91 },
 		{ 0x29, 0x07 },		{ 0x33, 0x0b },
@@ -930,7 +930,10 @@ static int ov7xx0_configure(struct sd *sd)
 		{ OV7670_REG_EDGE, 0 },
 		{ 0x75, 0x05 },		{ 0x76, 0xe1 },
 		{ 0x4c, 0 },		{ 0x77, 0x01 },
-		{ OV7670_REG_COM13, 0xc3 },	{ 0x4b, 0x09 },
+		{ OV7670_REG_COM13, OV7670_COM13_GAMMA
+				  | OV7670_COM13_UVSAT
+				  | 2},		/* was 3 */
+		{ 0x4b, 0x09 },
 		{ 0xc9, 0x60 },		{ OV7670_REG_COM16, 0x38 },
 		{ 0x56, 0x40 },
 
@@ -956,30 +959,10 @@ static int ov7xx0_configure(struct sd *sd)
 		{ 0x79, 0x03 },		{ 0xc8, 0x40 },
 		{ 0x79, 0x05 },		{ 0xc8, 0x30 },
 		{ 0x79, 0x26 },
-
-	/* Format YUV422 */
-		{ OV7670_REG_COM7, OV7670_COM7_YUV },  /* Selects YUV mode */
-		{ OV7670_REG_RGB444, 0 },	/* No RGB444 please */
-		{ OV7670_REG_COM1, 0 },
-		{ OV7670_REG_COM15, OV7670_COM15_R00FF },
-		{ OV7670_REG_COM9, 0x18 },
-				/* 4x gain ceiling; 0x8 is reserved bit */
-		{ 0x4f, 0x80 }, 	/* "matrix coefficient 1" */
-		{ 0x50, 0x80 }, 	/* "matrix coefficient 2" */
-		{ 0x52, 0x22 }, 	/* "matrix coefficient 4" */
-		{ 0x53, 0x5e }, 	/* "matrix coefficient 5" */
-		{ 0x54, 0x80 }, 	/* "matrix coefficient 6" */
-		{ OV7670_REG_COM13, OV7670_COM13_GAMMA|OV7670_COM13_UVSAT },
-};
+	};
 
 	PDEBUG(D_PROBE, "starting OV7xx0 configuration");
 
-/* jfm:already done? */
-	if (init_ov_sensor(sd) < 0)
-		PDEBUG(D_ERR, "Failed to read sensor ID");
-	else
-		PDEBUG(D_PROBE, "OV7xx0 initialized");
-
 	/* Detect sensor (sub)type */
 	rc = i2c_r(sd, OV7610_REG_COM_I);
 
@@ -1025,20 +1008,25 @@ static int ov7xx0_configure(struct sd *sd)
 			return low;
 		}
 		if (high == 0x76) {
-			if (low == 0x30) {
+			switch (low) {
+			case 0x30:
 				PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
 				sd->sensor = SEN_OV7630;
-			} else if (low == 0x40) {
+				break;
+			case 0x40:
 				PDEBUG(D_PROBE, "Sensor is an OV7645");
 				sd->sensor = SEN_OV7640; /* FIXME */
-			} else if (low == 0x45) {
+				break;
+			case 0x45:
 				PDEBUG(D_PROBE, "Sensor is an OV7645B");
 				sd->sensor = SEN_OV7640; /* FIXME */
-			} else if (low == 0x48) {
+				break;
+			case 0x48:
 				PDEBUG(D_PROBE, "Sensor is an OV7648");
 				sd->sensor = SEN_OV7640; /* FIXME */
-			} else {
-				PDEBUG(D_PROBE, "Unknown sensor: 0x76%X", low);
+				break;
+			default:
+				PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
 				return -1;
 			}
 		} else {
@@ -1050,34 +1038,34 @@ static int ov7xx0_configure(struct sd *sd)
 		return -1;
 	}
 
-	if (sd->sensor == SEN_OV7620) {
+	switch (sd->sensor) {
+	case SEN_OV7620:
 		PDEBUG(D_PROBE, "Writing 7620 registers");
-		if (write_i2c_regvals(sd, norm_7620,
-				sizeof norm_7620 / sizeof norm_7620[0]))
+		if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
 			return -1;
-	} else if (sd->sensor == SEN_OV7630) {
+		break;
+	case SEN_OV7630:
 		PDEBUG(D_ERR, "7630 is not supported by this driver version");
 		return -1;
-	} else if (sd->sensor == SEN_OV7640) {
+	case SEN_OV7640:
 		PDEBUG(D_PROBE, "Writing 7640 registers");
-		if (write_i2c_regvals(sd, norm_7640,
-				sizeof norm_7640 / sizeof norm_7640[0]))
+		if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
 			return -1;
-	} else if (sd->sensor == SEN_OV7670) {
+		break;
+	case SEN_OV7670:
 		PDEBUG(D_PROBE, "Writing 7670 registers");
-		if (write_i2c_regvals(sd, norm_7670,
-				sizeof norm_7670 / sizeof norm_7670[0]))
+		if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
 			return -1;
-	} else {
+		break;
+	default:
 		PDEBUG(D_PROBE, "Writing 7610 registers");
-		if (write_i2c_regvals(sd, norm_7610,
-				sizeof norm_7610 / sizeof norm_7610[0]))
+		if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
 			return -1;
+		break;
 	}
 
 	/* Set sensor-specific vars */
-	sd->maxwidth = 640;
-	sd->maxheight = 480;
+/*	sd->sif = 0;		already done */
 	return 0;
 }
 
@@ -1231,43 +1219,45 @@ static int ov6xx0_configure(struct sd *sd)
 	/* Ugh. The first two bits are the version bits, but
 	 * the entire register value must be used. I guess OVT
 	 * underestimated how many variants they would make. */
-	if (rc == 0x00) {
+	switch (rc) {
+	case 0x00:
 		sd->sensor = SEN_OV6630;
 		PDEBUG(D_ERR,
 			"WARNING: Sensor is an OV66308. Your camera may have");
 		PDEBUG(D_ERR, "been misdetected in previous driver versions.");
-	} else if (rc == 0x01) {
+		break;
+	case 0x01:
 		sd->sensor = SEN_OV6620;
-		PDEBUG(D_PROBE, "Sensor is an OV6620");
-	} else if (rc == 0x02) {
+		break;
+	case 0x02:
 		sd->sensor = SEN_OV6630;
 		PDEBUG(D_PROBE, "Sensor is an OV66308AE");
-	} else if (rc == 0x03) {
+		break;
+	case 0x03:
 		sd->sensor = SEN_OV6630;
 		PDEBUG(D_PROBE, "Sensor is an OV66308AF");
-	} else if (rc == 0x90) {
+		break;
+	case 0x90:
 		sd->sensor = SEN_OV6630;
 		PDEBUG(D_ERR,
 			"WARNING: Sensor is an OV66307. Your camera may have");
 		PDEBUG(D_ERR, "been misdetected in previous driver versions.");
-	} else {
+		break;
+	default:
 		PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc);
 		return -1;
 	}
 
 	/* Set sensor-specific vars */
-	sd->maxwidth = 352;
-	sd->maxheight = 288;
+	sd->sif = 1;
 
 	if (sd->sensor == SEN_OV6620) {
 		PDEBUG(D_PROBE, "Writing 6x20 registers");
-		if (write_i2c_regvals(sd, norm_6x20,
-				sizeof norm_6x20 / sizeof norm_6x20[0]))
+		if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
 			return -1;
 	} else {
 		PDEBUG(D_PROBE, "Writing 6x30 registers");
-		if (write_i2c_regvals(sd, norm_6x30,
-				sizeof norm_6x30 / sizeof norm_6x30[0]))
+		if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
 			return -1;
 	}
 	return 0;
@@ -1276,14 +1266,8 @@ static int ov6xx0_configure(struct sd *sd)
 /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
 static void ov51x_led_control(struct sd *sd, int on)
 {
-	PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off");
-
-/*	if (sd->bridge == BRG_OV511PLUS) */
-/*		reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0); */
-/*	else if (sd->bridge == BRG_OV519) */
-		reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);	/* 0 / 1 */
-/*	else if (sd->bclass == BCL_OV518) */
-/*		reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); */
+/*	PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); */
+	reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);	/* 0 / 1 */
 }
 
 /* this function is called at probe time */
@@ -1293,11 +1277,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct cam *cam;
 
-/* (from ov519_configure) */
 	static const struct ov_regvals init_519[] = {
 		{ 0x5a,  0x6d }, /* EnableSystem */
-/* jfm trace usbsnoop3-1.txt */
-/* jfm 53 = fb */
 		{ 0x53,  0x9b },
 		{ 0x54,  0xff }, /* set bit2 to enable jpeg */
 		{ 0x5d,  0x03 },
@@ -1314,9 +1295,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
 	if (write_regvals(sd, init_519, ARRAY_SIZE(init_519)))
 		goto error;
-/* jfm: not seen in windows trace */
-	if (ov519_init_compression(sd))
-		goto error;
 	ov51x_led_control(sd, 0);	/* turn LED off */
 
 	/* Test for 76xx */
@@ -1365,16 +1343,18 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
 	cam = &gspca_dev->cam;
 	cam->epaddr = OV511_ENDPOINT_ADDRESS;
-	if (sd->maxwidth == 640) {
+	if (!sd->sif) {
 		cam->cam_mode = vga_mode;
-		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+		cam->nmodes = ARRAY_SIZE(vga_mode);
 	} else {
 		cam->cam_mode = sif_mode;
-		cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+		cam->nmodes = ARRAY_SIZE(sif_mode);
 	}
-	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
-	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
-	sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+	sd->brightness = BRIGHTNESS_DEF;
+	sd->contrast = CONTRAST_DEF;
+	sd->colors = COLOR_DEF;
+	sd->hflip = HFLIP_DEF;
+	sd->vflip = VFLIP_DEF;
 	return 0;
 error:
 	PDEBUG(D_ERR, "OV519 Config failed");
@@ -1394,8 +1374,7 @@ static int sd_open(struct gspca_dev *gspca_dev)
  *
  * Do not put any sensor-specific code in here (including I2C I/O functions)
  */
-static int ov519_mode_init_regs(struct sd *sd,
-				int width, int height)
+static int ov519_mode_init_regs(struct sd *sd)
 {
 	static const struct ov_regvals mode_init_519_ov7670[] = {
 		{ 0x5d,	0x03 }, /* Turn off suspend mode */
@@ -1441,36 +1420,23 @@ static int ov519_mode_init_regs(struct sd *sd,
 		/* windows reads 0x55 at this point, why? */
 	};
 
-/* int hi_res; */
-
-	PDEBUG(D_CONF, "mode init %dx%d", width, height);
-
-/*	if (width >= 800 && height >= 600)
-		hi_res = 1;
-	else
-		hi_res = 0; */
-
-/*	if (ov51x_stop(sd) < 0)
-		return -EIO; */
-
 	/******** Set the mode ********/
 	if (sd->sensor != SEN_OV7670) {
 		if (write_regvals(sd, mode_init_519,
 				  ARRAY_SIZE(mode_init_519)))
 			return -EIO;
+		if (sd->sensor == SEN_OV7640) {
+			/* Select 8-bit input mode */
+			reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10);
+		}
 	} else {
 		if (write_regvals(sd, mode_init_519_ov7670,
 				  ARRAY_SIZE(mode_init_519_ov7670)))
 			return -EIO;
 	}
 
-	if (sd->sensor == SEN_OV7640) {
-		/* Select 8-bit input mode */
-		reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10);
-	}
-
-	reg_w(sd, OV519_CAM_H_SIZE,	width >> 4);
-	reg_w(sd, OV519_CAM_V_SIZE,	height >> 3);
+	reg_w(sd, OV519_CAM_H_SIZE,	sd->gspca_dev.width >> 4);
+	reg_w(sd, OV519_CAM_V_SIZE,	sd->gspca_dev.height >> 3);
 	reg_w(sd, OV519_CAM_X_OFFSETL,	0x00);
 	reg_w(sd, OV519_CAM_X_OFFSETH,	0x00);
 	reg_w(sd, OV519_CAM_Y_OFFSETL,	0x00);
@@ -1485,9 +1451,10 @@ static int ov519_mode_init_regs(struct sd *sd,
 
 /* FIXME: These are only valid at the max resolution. */
 	sd->clockdiv = 0;
-	if (sd->sensor == SEN_OV7640) {
+	switch (sd->sensor) {
+	case SEN_OV7640:
 		switch (sd->frame_rate) {
-/*jfm: default was 30 fps */
+/*fixme: default was 30 fps */
 		case 30:
 			reg_w(sd, 0xa4, 0x0c);
 			reg_w(sd, 0x23, 0xff);
@@ -1517,7 +1484,8 @@ static int ov519_mode_init_regs(struct sd *sd,
 			sd->clockdiv = 1;
 			break;
 		}
-	} else if (sd->sensor == SEN_OV8610) {
+		break;
+	case SEN_OV8610:
 		switch (sd->frame_rate) {
 		default:	/* 15 fps */
 /*		case 15: */
@@ -1533,41 +1501,37 @@ static int ov519_mode_init_regs(struct sd *sd,
 			reg_w(sd, 0x23, 0x1b);
 			break;
 		}
-		sd->clockdiv = 0;
-	} else if (sd->sensor == SEN_OV7670) { /* guesses, based on 7640 */
+		break;
+	case SEN_OV7670:		/* guesses, based on 7640 */
 		PDEBUG(D_STREAM, "Setting framerate to %d fps",
 				 (sd->frame_rate == 0) ? 15 : sd->frame_rate);
+		reg_w(sd, 0xa4, 0x10);
 		switch (sd->frame_rate) {
 		case 30:
-			reg_w(sd, 0xa4, 0x10);
 			reg_w(sd, 0x23, 0xff);
 			break;
 		case 20:
-			reg_w(sd, 0xa4, 0x10);
 			reg_w(sd, 0x23, 0x1b);
 			break;
-		default: /* 15 fps */
-/*			case 15: */
-			reg_w(sd, 0xa4, 0x10);
+		default:
+/*		case 15: */
 			reg_w(sd, 0x23, 0xff);
 			sd->clockdiv = 1;
 			break;
 		}
+		break;
 	}
 
-/*	if (ov51x_restart(sd) < 0)
-		return -EIO; */
-
-	/* Reset it just for good measure */
-/*	if (ov51x_reset(sd, OV511_RESET_NOREGS) < 0)
-		return -EIO; */
 	return 0;
 }
 
-static int mode_init_ov_sensor_regs(struct sd *sd,
-				struct ovsensor_window *win)
+static int mode_init_ov_sensor_regs(struct sd *sd)
 {
-	int qvga = win->quarter;
+	struct gspca_dev *gspca_dev;
+	int qvga;
+
+	gspca_dev = &sd->gspca_dev;
+	qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
 
 	/******** Mode (VGA/QVGA) and sensor specific regs ********/
 	switch (sd->sensor) {
@@ -1611,8 +1575,6 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
 			 OV7670_COM7_FMT_MASK);
 		break;
 	case SEN_OV6620:
-		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
-		break;
 	case SEN_OV6630:
 		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
 		break;
@@ -1621,24 +1583,21 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
 	}
 
 	/******** Palette-specific regs ********/
-/* Need to do work here for the OV7670 */
-
-		if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
-			/* not valid on the OV6620/OV7620/6630? */
-			i2c_w_mask(sd, 0x0e, 0x00, 0x40);
-		}
+	if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
+		/* not valid on the OV6620/OV7620/6630? */
+		i2c_w_mask(sd, 0x0e, 0x00, 0x40);
+	}
 
-		/* The OV518 needs special treatment. Although both the OV518
-		 * and the OV6630 support a 16-bit video bus, only the 8 bit Y
-		 * bus is actually used. The UV bus is tied to ground.
-		 * Therefore, the OV6630 needs to be in 8-bit multiplexed
-		 * output mode */
+	/* The OV518 needs special treatment. Although both the OV518
+	 * and the OV6630 support a 16-bit video bus, only the 8 bit Y
+	 * bus is actually used. The UV bus is tied to ground.
+	 * Therefore, the OV6630 needs to be in 8-bit multiplexed
+	 * output mode */
 
-		/* OV7640 is 8-bit only */
+	/* OV7640 is 8-bit only */
 
-		if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640)
-			i2c_w_mask(sd, 0x13, 0x00, 0x20);
-/*	} */
+	if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640)
+		i2c_w_mask(sd, 0x13, 0x00, 0x20);
 
 	/******** Clock programming ********/
 	/* The OV6620 needs special handling. This prevents the
@@ -1647,14 +1606,14 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
 
 		/* Clock down */
 		i2c_w(sd, 0x2a, 0x04);
-		i2c_w(sd, 0x11, win->clockdiv);
+		i2c_w(sd, 0x11, sd->clockdiv);
 		i2c_w(sd, 0x2a, 0x84);
 		/* This next setting is critical. It seems to improve
 		 * the gain or the contrast. The "reserved" bits seem
 		 * to have some effect in this case. */
 		i2c_w(sd, 0x2d, 0x85);
-	} else if (win->clockdiv >= 0) {
-		i2c_w(sd, 0x11, win->clockdiv);
+	} else if (sd->clockdiv >= 0) {
+		i2c_w(sd, 0x11, sd->clockdiv);
 	}
 
 	/******** Special Features ********/
@@ -1674,7 +1633,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
 	/* is fully tested. */
 	/* 7620/6620/6630? don't have register 0x35, so play it safe */
 	if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) {
-		if (win->width == 640 /*&& win->height == 480*/)
+		if (!qvga)
 			i2c_w(sd, 0x35, 0x9e);
 		else
 			i2c_w(sd, 0x35, 0x1e);
@@ -1682,13 +1641,31 @@ static int mode_init_ov_sensor_regs(struct sd *sd,
 	return 0;
 }
 
-static int set_ov_sensor_window(struct sd *sd,
-				struct ovsensor_window *win)
+static void sethvflip(struct sd *sd)
 {
+	if (sd->sensor != SEN_OV7670)
+		return;
+	if (sd->gspca_dev.streaming)
+		ov51x_stop(sd);
+	i2c_w_mask(sd, OV7670_REG_MVFP,
+		OV7670_MVFP_MIRROR * sd->hflip
+			| OV7670_MVFP_VFLIP * sd->vflip,
+		OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP);
+	if (sd->gspca_dev.streaming)
+		ov51x_restart(sd);
+}
+
+static int set_ov_sensor_window(struct sd *sd)
+{
+	struct gspca_dev *gspca_dev;
+	int qvga;
 	int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
 	int ret, hstart, hstop, vstop, vstart;
 	__u8 v;
 
+	gspca_dev = &sd->gspca_dev;
+	qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+
 	/* The different sensor ICs handle setting up of window differently.
 	 * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
 	switch (sd->sensor) {
@@ -1733,7 +1710,7 @@ static int set_ov_sensor_window(struct sd *sd,
 	switch (sd->sensor) {
 	case SEN_OV6620:
 	case SEN_OV6630:
-		if (win->quarter) {	/* QCIF */
+		if (qvga) {		/* QCIF */
 			hwscale = 0;
 			vwscale = 0;
 		} else {		/* CIF */
@@ -1743,7 +1720,7 @@ static int set_ov_sensor_window(struct sd *sd,
 		}
 		break;
 	case SEN_OV8610:
-		if (win->quarter) {	/* QSVGA */
+		if (qvga) {		/* QSVGA */
 			hwscale = 1;
 			vwscale = 1;
 		} else {		/* SVGA */
@@ -1752,7 +1729,7 @@ static int set_ov_sensor_window(struct sd *sd,
 		}
 		break;
 	default:			/* SEN_OV7xx0 */
-		if (win->quarter) {	/* QVGA */
+		if (qvga) {		/* QVGA */
 			hwscale = 1;
 			vwscale = 0;
 		} else {		/* VGA */
@@ -1761,7 +1738,7 @@ static int set_ov_sensor_window(struct sd *sd,
 		}
 	}
 
-	ret = mode_init_ov_sensor_regs(sd, win);
+	ret = mode_init_ov_sensor_regs(sd);
 	if (ret < 0)
 		return ret;
 
@@ -1782,7 +1759,7 @@ static int set_ov_sensor_window(struct sd *sd,
 	/* I can hard code this for OV7670s */
 	/* Yes, these numbers do look odd, but they're tested and work! */
 	if (sd->sensor == SEN_OV7670) {
-		if (win->quarter) {	/* QVGA from ov7670.c by
+		if (qvga) {		/* QVGA from ov7670.c by
 					 * Jonathan Corbet */
 			hstart = 164;
 			hstop = 20;
@@ -1796,75 +1773,45 @@ static int set_ov_sensor_window(struct sd *sd,
 		}
 		/* OV7670 hardware window registers are split across
 		 * multiple locations */
-		i2c_w(sd, OV7670_REG_HSTART, (hstart >> 3) & 0xff);
-		i2c_w(sd, OV7670_REG_HSTOP, (hstop >> 3) & 0xff);
+		i2c_w(sd, OV7670_REG_HSTART, hstart >> 3);
+		i2c_w(sd, OV7670_REG_HSTOP, hstop >> 3);
 		v = i2c_r(sd, OV7670_REG_HREF);
 		v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07);
 		msleep(10);	/* need to sleep between read and write to
 				 * same reg! */
 		i2c_w(sd, OV7670_REG_HREF, v);
 
-		i2c_w(sd, OV7670_REG_VSTART, (vstart >> 2) & 0xff);
-		i2c_w(sd, OV7670_REG_VSTOP, (vstop >> 2) & 0xff);
+		i2c_w(sd, OV7670_REG_VSTART, vstart >> 2);
+		i2c_w(sd, OV7670_REG_VSTOP, vstop >> 2);
 		v = i2c_r(sd, OV7670_REG_VREF);
 		v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03);
 		msleep(10);	/* need to sleep between read and write to
 				 * same reg! */
 		i2c_w(sd, OV7670_REG_VREF, v);
-
+		sethvflip(sd);
 	} else {
-		i2c_w(sd, 0x17, hwsbase + (win->x >> hwscale));
-		i2c_w(sd, 0x18, hwebase + ((win->x + win->width) >> hwscale));
-		i2c_w(sd, 0x19, vwsbase + (win->y >> vwscale));
-		i2c_w(sd, 0x1a, vwebase + ((win->y + win->height) >> vwscale));
+		i2c_w(sd, 0x17, hwsbase);
+		i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale));
+		i2c_w(sd, 0x19, vwsbase);
+		i2c_w(sd, 0x1a, vwebase + (sd->gspca_dev.height >> vwscale));
 	}
 	return 0;
 }
 
-static int ov_sensor_mode_setup(struct sd *sd,
-				int width, int height)
-{
-	struct ovsensor_window win;
-
-/*	win.format = mode; */
-
-	/* Unless subcapture is enabled,
-	 * center the image window and downsample
-	 * if possible to increase the field of view */
-	/* NOTE: OV518(+) and OV519 does downsampling on its own */
-	win.width = width;
-	win.height = height;
-	if (width == sd->maxwidth)
-		win.quarter = 0;
-	else
-		win.quarter = 1;
-
-	/* Center it */
-	win.x = (win.width - width) / 2;
-	win.y = (win.height - height) / 2;
-
-	/* Clock is determined by OV519 frame rate code */
-	win.clockdiv = sd->clockdiv;
-
-	PDEBUG(D_CONF, "Setting clock divider to %d", win.clockdiv);
-	return set_ov_sensor_window(sd, &win);
-}
-
 /* -- start the camera -- */
 static void sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int ret;
 
-
-	ret = ov519_mode_init_regs(sd, gspca_dev->width, gspca_dev->height);
+	ret = ov519_mode_init_regs(sd);
 	if (ret < 0)
 		goto out;
-	ret = ov_sensor_mode_setup(sd, gspca_dev->width, gspca_dev->height);
+	ret = set_ov_sensor_window(sd);
 	if (ret < 0)
 		goto out;
 
-	ret = ov51x_restart((struct sd *) gspca_dev);
+	ret = ov51x_restart(sd);
 	if (ret < 0)
 		goto out;
 	PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
@@ -1938,12 +1885,10 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int val;
-/*	int was_streaming; */
 
 	val = sd->brightness;
 	PDEBUG(D_CONF, "brightness:%d", val);
-/*	was_streaming = gspca_dev->streaming;
- *	if (was_streaming)
+/*	if (gspca_dev->streaming)
  *		ov51x_stop(sd); */
 	switch (sd->sensor) {
 	case SEN_OV8610:
@@ -1961,12 +1906,12 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 			i2c_w(sd, OV7610_REG_BRT, val);
 		break;
 	case SEN_OV7670:
-/*jfm - from windblows
+/*win trace
  *		i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */
 		i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val));
 		break;
 	}
-/*	if (was_streaming)
+/*	if (gspca_dev->streaming)
  *		ov51x_restart(sd); */
 }
 
@@ -1974,12 +1919,10 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int val;
-/*	int was_streaming; */
 
 	val = sd->contrast;
 	PDEBUG(D_CONF, "contrast:%d", val);
-/*	was_streaming = gspca_dev->streaming;
-	if (was_streaming)
+/*	if (gspca_dev->streaming)
 		ov51x_stop(sd); */
 	switch (sd->sensor) {
 	case SEN_OV7610:
@@ -2016,7 +1959,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 		i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
 		break;
 	}
-/*	if (was_streaming)
+/*	if (gspca_dev->streaming)
 		ov51x_restart(sd); */
 }
 
@@ -2024,12 +1967,10 @@ static void setcolors(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int val;
-/*	int was_streaming; */
 
 	val = sd->colors;
 	PDEBUG(D_CONF, "saturation:%d", val);
-/*	was_streaming = gspca_dev->streaming;
-	if (was_streaming)
+/*	if (gspca_dev->streaming)
 		ov51x_stop(sd); */
 	switch (sd->sensor) {
 	case SEN_OV8610:
@@ -2055,7 +1996,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
 		/* set REG_COM13 values for UV sat auto mode */
 		break;
 	}
-/*	if (was_streaming)
+/*	if (gspca_dev->streaming)
 		ov51x_restart(sd); */
 }
 
@@ -2110,6 +2051,40 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
 	return 0;
 }
 
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->hflip = val;
+	sethvflip(sd);
+	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->vflip = val;
+	sethvflip(sd);
+	return 0;
+}
+
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->vflip;
+	return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
@@ -2178,4 +2153,3 @@ module_exit(sd_mod_exit);
 
 module_param(frame_rate, int, 0644);
 MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)");
-

+ 33 - 21
drivers/media/video/gspca/pac7311.c

@@ -31,7 +31,9 @@ MODULE_LICENSE("GPL");
 struct sd {
 	struct gspca_dev gspca_dev;		/* !! must be the first item */
 
-	int avg_lum;
+	int lum_sum;
+	atomic_t avg_lum;
+	atomic_t do_gain;
 
 	unsigned char brightness;
 	unsigned char contrast;
@@ -271,6 +273,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->contrast = CONTRAST_DEF;
 	sd->colors = COLOR_DEF;
 	sd->autogain = AUTOGAIN_DEF;
+	sd->ag_cnt = -1;
 	return 0;
 }
 
@@ -311,6 +314,18 @@ static void setcolors(struct gspca_dev *gspca_dev)
 	PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
 }
 
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->autogain) {
+		sd->lum_sum = 0;
+		sd->ag_cnt = AG_CNT_START;
+	} else {
+		sd->ag_cnt = -1;
+	}
+}
+
 /* this function is called at open time */
 static int sd_open(struct gspca_dev *gspca_dev)
 {
@@ -320,8 +335,6 @@ static int sd_open(struct gspca_dev *gspca_dev)
 
 static void sd_start(struct gspca_dev *gspca_dev)
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
 	reg_w(gspca_dev, 0xff, 0x01);
 	reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
 	reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
@@ -394,6 +407,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
 	setcontrast(gspca_dev);
 	setbrightness(gspca_dev);
 	setcolors(gspca_dev);
+	setautogain(gspca_dev);
 
 	/* set correct resolution */
 	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
@@ -431,13 +445,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
 	reg_w(gspca_dev, 0xff, 0x01);
 	reg_w(gspca_dev, 0x78, 0x04);
 	reg_w(gspca_dev, 0x78, 0x05);
-
-	if (sd->autogain) {
-		sd->ag_cnt = AG_CNT_START;
-		sd->avg_lum = 0;
-	} else {
-		sd->ag_cnt = -1;
-	}
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -473,13 +480,20 @@ static void sd_close(struct gspca_dev *gspca_dev)
 	reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
 }
 
-static void setautogain(struct gspca_dev *gspca_dev, int luma)
+static void do_autogain(struct gspca_dev *gspca_dev)
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+	int luma;
 	int luma_mean = 128;
 	int luma_delta = 20;
 	__u8 spring = 5;
 	int Gbright;
 
+	if (!atomic_read(&sd->do_gain))
+		return;
+	atomic_set(&sd->do_gain, 0);
+
+	luma = atomic_read(&sd->avg_lum);
 	Gbright = reg_r(gspca_dev, 0x02);
 	PDEBUG(D_FRAM, "luma mean %d", luma);
 	if (luma < luma_mean - luma_delta ||
@@ -523,12 +537,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 
 			/* start of frame */
 			if (sd->ag_cnt >= 0 && p > 28) {
-				sd->avg_lum += data[p - 23];
+				sd->lum_sum += data[p - 23];
 				if (--sd->ag_cnt < 0) {
 					sd->ag_cnt = AG_CNT_START;
-					setautogain(gspca_dev,
-						sd->avg_lum / AG_CNT_START);
-					sd->avg_lum = 0;
+					atomic_set(&sd->avg_lum,
+						sd->lum_sum / AG_CNT_START);
+					sd->lum_sum = 0;
+					atomic_set(&sd->do_gain, 1);
 				}
 			}
 
@@ -677,12 +692,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->autogain = val;
-	if (val) {
-		sd->ag_cnt = AG_CNT_START;
-		sd->avg_lum = 0;
-	} else {
-		sd->ag_cnt = -1;
-	}
+	if (gspca_dev->streaming)
+		setautogain(gspca_dev);
 	return 0;
 }
 
@@ -706,6 +717,7 @@ static struct sd_desc sd_desc = {
 	.stop0 = sd_stop0,
 	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
+	.dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */

+ 1 - 1
drivers/media/video/gspca/sonixb.c

@@ -408,7 +408,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
 		  const __u8 *buffer,
 		  int len)
 {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 	if (len > sizeof gspca_dev->usb_buf) {
 		PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow");
 		return;

+ 120 - 167
drivers/media/video/gspca/sonixj.c

@@ -32,7 +32,7 @@ MODULE_LICENSE("GPL");
 struct sd {
 	struct gspca_dev gspca_dev;	/* !! must be the first item */
 
-	int avg_lum;
+	atomic_t avg_lum;
 	unsigned int exposure;
 
 	unsigned short brightness;
@@ -148,55 +148,58 @@ static struct v4l2_pix_format vga_mode[] = {
 
 /*Data from sn9c102p+hv71331r */
 static const __u8 sn_hv7131[] = {
-/*	reg0  reg1  reg2  reg3  reg4  reg5  reg6  reg7  reg8  reg9 */
-	0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11,
-/*	rega  regb  regc  regd  rege  regf  reg10 reg11 */
-	0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,		/* 00 */
-/*	reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
-	0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00,
-/*	reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x03,	0x64,	0x00,	0x1a,	0x20,	0x20,	0x20,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0xa1,	0x11,	0x02,	0x09,	0x00,	0x00,	0x00,	0x10,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x00,	0x01,	0x03,	0x28,	0x1e,	0x41,
+/*	reg18	reg19	reg1a	reg1b	reg1c	reg1d	reg1e	reg1f */
+	0x0a,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00
 };
 
 static const __u8 sn_mi0360[] = {
-/*	reg0  reg1  reg2  reg3  reg4  reg5  reg6  reg7  reg8  reg9 */
-	0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d,
-/*	rega  regb  regc  regd  rege  regf  reg10 reg11 */
-	0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00,
-/*	reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */
-	0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00,
-/*	reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x61,	0x44,	0x00,	0x1a,	0x20,	0x20,	0x20,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0xb1,	0x5d,	0x07,	0x00,	0x00,	0x00,	0x00,	0x10,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x00,	0x02,	0x0a,	0x28,	0x1e,	0x61,
+/*	reg18	reg19	reg1a	reg1b	reg1c	reg1d	reg1e	reg1f */
+	0x06,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00
 };
 
 static const __u8 sn_mo4000[] = {
-/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7	reg8 */
-	0x12,	0x23,	0x60,	0x00,	0x1A,	0x00,	0x20,	0x18,	0x81,
-/*	reg9	rega	regb	regc	regd	rege	regf	reg10	reg11*/
-	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x03,	0x00,
-/*	reg12	reg13	reg14	reg15	reg16	reg17	reg18	reg19	reg1a*/
-	0x0b,	0x0f,	0x14,	0x28,	0x1e,	0x40,	0x08,	0x00,	0x00,
-/*	reg1b	reg1c	reg1d	reg1e	reg1f	reg20	reg21	reg22	reg23*/
-	0x00,	0x00,	0x00,	0x00,	0x00,	0x08,	0x25,	0x39,	0x4b,
-	0x5c,	0x6b,	0x79,	0x87,	0x95,	0xa2,	0xaf,	0xbb,	0xc7,
-	0xd3,	0xdf,	0xea,	0xf5
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x12,	0x23,	0x60,	0x00,	0x1a,	0x00,	0x20,	0x18,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0x81,	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	 0x00,	0x0b,	0x0f,	0x14,	0x28,	0x1e,	0x40,
+/*	reg18	reg19	reg1a	reg1b	reg1c	reg1d	reg1e	reg1f */
+	0x08,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00
 };
 
 static const __u8 sn_ov7648[] = {
-	0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65,
-	0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82,
-	0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x21,	0x62,	0x00,	0x1a,	0x20,	0x20,	0x20,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0xa1,	0x6e,	0x18,	0x65,	0x00,	0x00,	0x00,	0x10,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x00,	0x06,	0x06,	0x28,	0x1e,	0x82,
+/*	reg18	reg19	reg1a	reg1b	reg1c	reg1d	reg1e	reg1f */
+	0x07,	0x00,	0x00,	0x00,	0x00,	0x00
 };
 
 static const __u8 sn_ov7660[]	= {
-/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7	reg8 */
-	0x00,	0x61,	0x40,	0x00,	0x1a,	0x00,	0x00,	0x00,	0x81,
-/* 	reg9	rega	regb	regc	regd	rege	regf	reg10	reg11*/
-	0x21,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x03,	0x00,
-/*	reg12	reg13	reg14	reg15	reg16	reg17	reg18	reg19	reg1a*/
-	0x01,	0x01,	0x14,	0x28,	0x1e,	0x00,	0x07,	0x00,	0x00,
-/*	reg1b	reg1c	reg1d	reg1e	reg1f	reg20	reg21	reg22	reg23*/
-	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00
+/*	reg0	reg1	reg2	reg3	reg4	reg5	reg6	reg7 */
+	0x00,	0x61,	0x40,	0x00,	0x1a,	0x20,	0x20,	0x20,
+/*	reg8	reg9	rega	regb	regc	regd	rege	regf */
+	0x81,	0x21,	0x07,	0x00,	0x00,	0x00,	0x00,	0x10,
+/*	reg10	reg11	reg12	reg13	reg14	reg15	reg16	reg17 */
+	0x03,	0x00,	0x01,	0x01,	0x08,	0x28,	0x1e,	0x20,
+/*	reg18	reg19	reg1a	reg1b	reg1c	reg1d	reg1e	reg1f */
+	0x07,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
 };
 
 /* sequence specific to the sensors - !! index = SENSOR_xxx */
@@ -212,10 +215,6 @@ static const __u8 regsn20[] = {
 	0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99,
 	0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff
 };
-static const __u8 regsn20_sn9c120[] = {
-	0x00, 0x25, 0x3c, 0x50, 0x62, 0x72, 0x81, 0x90,
-	0x9e, 0xab, 0xb8, 0xc5, 0xd1, 0xdd, 0xe9, 0xf4, 0xff
-};
 static const __u8 regsn20_sn9c325[] = {
 	0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4,
 	0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5
@@ -227,21 +226,6 @@ static const __u8 reg84[] = {
 /*	0x00, 0x00, 0x00, 0x00, 0x00 */
 	0xf7, 0x0f, 0x0a, 0x00, 0x00
 };
-static const __u8 reg84_sn9c120_1[] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x0c, 0x00, 0x00
-};
-static const __u8 reg84_sn9c120_2[] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x0c, 0x02, 0x3b
-};
-static const __u8 reg84_sn9c120_3[] = {
-	0x14, 0x00, 0x27, 0x00, 0x08, 0x00, 0xeb, 0x0f,
-	0xd5, 0x0f, 0x42, 0x00, 0x41, 0x00, 0xca, 0x0f,
-	0xf5, 0x0f, 0x0c, 0x02, 0x3b
-};
 static const __u8 reg84_sn9c325[] = {
 	0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f,
 	0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f,
@@ -360,17 +344,15 @@ static const __u8 ov7660_sensor_init[][8] = {
 	{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
 /*		(delay 20ms) */
 	{0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
-						/* Outformat ?? rawRGB */
+						/* Outformat = rawRGB */
 	{0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
-	{0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10},
-/*	{0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10}, */
+	{0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10},
 						/* GAIN BLUE RED VREF */
 	{0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10},
 						/* COM 1 BAVE GEAVE AECHH */
 	{0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */
 	{0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */
-	{0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10},
-/*	{0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, */
+	{0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10},
 						/* AECH CLKRC COM7 COM8 */
 	{0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */
 	{0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10},
@@ -379,8 +361,8 @@ static const __u8 ov7660_sensor_init[][8] = {
 	{0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */
 	{0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10},
 					/* BOS GBOS GROS ROS (BGGR offset) */
-	{0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10},
-/*	{0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, */
+/*	{0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10}, */
+	{0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10},
 						/* AEW AEB VPT BBIAS */
 	{0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10},
 						/* GbBIAS RSVD EXHCH EXHCL */
@@ -407,9 +389,9 @@ static const __u8 ov7660_sensor_init[][8] = {
 	{0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10},
 						/* LCC1 LCC2 LCC3 LCC4 */
 	{0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */
-	{0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10},
+	{0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10}, /* MANU */
 	{0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10},
-					/* band gap reference [0..3] DBLV */
+					/* band gap reference [0:3] DBLV */
 	{0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */
 	{0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */
 	{0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */
@@ -419,37 +401,35 @@ static const __u8 ov7660_sensor_init[][8] = {
 	{0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */
 	{0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
 	{0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
-	{0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10},
+	{0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */
 /****** (some exchanges in the win trace) ******/
-	{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
 						/* bits[3..0]reserved */
 	{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
 						/* VREF vertical frame ctrl */
 	{0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10},
-	{0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */
-	{0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10},
-	{0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10},
-/*	{0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, */
-	{0xa1, 0x21, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10},
-	{0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* AECH 0x20 */
+	{0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFL */
+	{0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFH */
+	{0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, /* GAIN */
+/*	{0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, * BLUE */
 /****** (some exchanges in the win trace) ******/
 	{0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */
-	{0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */
-	{0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
-	{0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10},
-	{0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10},
+	{0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10}, /* dummy line low */
+	{0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCH */
+	{0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCL */
+/*	{0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10},  * RED */
 /****** (some exchanges in the win trace) ******/
-/**********startsensor KO if changed !!****/
+/******!! startsensor KO if changed !!****/
 	{0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10},
 	{0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
-/* here may start the isoc exchanges */
 	{}
 };
-/* reg0x04		reg0x07		reg 0x10 */
-/* expo  = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */
+/*	  reg 0x04	  reg 0x07		   reg 0x10 */
+/* expo = (COM1 & 0x02) | ((AECHH & 0x2f) << 10) | (AECh << 2) */
 
 static const __u8 ov7648_sensor_init[][8] = {
 	{0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
@@ -680,13 +660,12 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
 	const __u8 *reg9a;
 	static const __u8 reg9a_def[] =
 		{0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
-	static const __u8 reg9a_sn9c120[] =		/* from win trace */
-		{0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
 	static const __u8 reg9a_sn9c325[] =
 		{0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+	static const __u8 regd4[] = {0x60, 0x00, 0x00};
 
 	reg_w1(gspca_dev, 0xf1, 0x00);
-	reg_w1(gspca_dev, 0x01, sn9c1xx[0]);	/*fixme:jfm was [1] en v1*/
+	reg_w1(gspca_dev, 0x01, 0x00);		/*jfm was sn9c1xx[1] in v1*/
 
 	/* configure gpio */
 	reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
@@ -696,25 +675,17 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
 	case BRIDGE_SN9C325:
 		reg9a = reg9a_sn9c325;
 		break;
-	case BRIDGE_SN9C120:
-		reg9a = reg9a_sn9c120;
-		break;
 	default:
 		reg9a = reg9a_def;
 		break;
 	}
 	reg_w(gspca_dev, 0x9a, reg9a, 6);
 
-	reg_w1(gspca_dev, 0xd4, 0x60);	/*fixme:jfm 60 00 00 (3) ? */
+	reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); /*fixme:jfm was 60 only*/
 
 	reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
 
 	switch (sd->bridge) {
-	case BRIDGE_SN9C120:			/* from win trace */
-		reg_w1(gspca_dev, 0x01, 0x61);
-		reg_w1(gspca_dev, 0x17, 0x20);
-		reg_w1(gspca_dev, 0x01, 0x60);
-		break;
 	case BRIDGE_SN9C325:
 		reg_w1(gspca_dev, 0x01, 0x43);
 		reg_w1(gspca_dev, 0x17, 0xae);
@@ -810,6 +781,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->contrast = CONTRAST_DEF;
 	sd->colors = COLOR_DEF;
 	sd->autogain = AUTOGAIN_DEF;
+	sd->ag_cnt = -1;
+
 	return 0;
 }
 
@@ -823,10 +796,11 @@ static int sd_open(struct gspca_dev *gspca_dev)
 
 	/* setup a selector by bridge */
 	reg_w1(gspca_dev, 0xf1, 0x01);
-	reg_r(gspca_dev, 0x00, 1);		/* -> regF1 = 0x00 */
-	reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]);
 	reg_r(gspca_dev, 0x00, 1);
+	reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]);
+	reg_r(gspca_dev, 0x00, 1);		/* get sonix chip id */
 	regF1 = gspca_dev->usb_buf[0];
+	PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1);
 	switch (sd->bridge) {
 	case BRIDGE_SN9C102P:
 		if (regF1 != 0x11)
@@ -937,15 +911,10 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 		sd->exposure = setexposure(gspca_dev, expo);
 		break;
 	case SENSOR_MI0360:
-		expo = sd->brightness >> 4;
-		sd->exposure = setexposure(gspca_dev, expo);
-		break;
 	case SENSOR_MO4000:
 		expo = sd->brightness >> 4;
 		sd->exposure = setexposure(gspca_dev, expo);
 		break;
-	case SENSOR_OV7660:
-		return;				/*jfm??*/
 	}
 
 	k2 = sd->brightness >> 10;
@@ -958,8 +927,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 	__u8 k2;
 	__u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
 
-	if (sd->sensor == SENSOR_OV7660)
-		return;				/*jfm??*/
 	k2 = sd->contrast;
 	contrast[2] = k2;
 	contrast[0] = (k2 + 1) >> 1;
@@ -981,20 +948,32 @@ static void setcolors(struct gspca_dev *gspca_dev)
 	reg_w1(gspca_dev, 0x05, data);
 }
 
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	switch (sd->sensor) {
+	case SENSOR_HV7131R:
+	case SENSOR_MO4000:
+	case SENSOR_MI0360:
+		if (sd->autogain)
+			sd->ag_cnt = AG_CNT_START;
+		else
+			sd->ag_cnt = -1;
+		break;
+	}
+}
+
 /* -- start the camera -- */
 static void sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 	int i;
-	__u8 data;
-	__u8 reg1;
-	__u8 reg17;
+	__u8 reg1, reg17, reg18;
 	const __u8 *sn9c1xx;
 	int mode;
 	static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
 	static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
-	static const __u8 CA_sn9c120[] =
-				 { 0x14, 0xec, 0x0a, 0xf6 };	/* SN9C120 */
 	static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd };	/* MI0360 */
 	static const __u8 CE_sn9c325[] =
 			{ 0x32, 0xdd, 0x32, 0xdd };	/* OV7648 - SN9C325 */
@@ -1002,9 +981,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
 	sn9c1xx = sn_tb[(int) sd->sensor];
 	configure_gpio(gspca_dev, sn9c1xx);
 
-/*fixme:jfm this sequence should appear at end of sd_start */
-/* with
-	reg_w1(gspca_dev, 0x01, 0x44); */
+/*	reg_w1(gspca_dev, 0x01, 0x44);		jfm from win trace*/
 	reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
 	reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
 	reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]);
@@ -1016,20 +993,16 @@ static void sd_start(struct gspca_dev *gspca_dev)
 	reg_w1(gspca_dev, 0xc7, 0x00);
 	reg_w1(gspca_dev, 0xc8, 0x50);
 	reg_w1(gspca_dev, 0xc9, 0x3c);
-/*fixme:jfm end of ending sequence */
 	reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
 	switch (sd->bridge) {
 	case BRIDGE_SN9C325:
-		data = 0xae;
-		break;
-	case BRIDGE_SN9C120:
-		data = 0xa0;
+		reg17 = 0xae;
 		break;
 	default:
-		data = 0x60;
+		reg17 = 0x60;
 		break;
 	}
-	reg_w1(gspca_dev, 0x17, data);
+	reg_w1(gspca_dev, 0x17, reg17);
 	reg_w1(gspca_dev, 0x05, sn9c1xx[5]);
 	reg_w1(gspca_dev, 0x07, sn9c1xx[7]);
 	reg_w1(gspca_dev, 0x06, sn9c1xx[6]);
@@ -1044,20 +1017,6 @@ static void sd_start(struct gspca_dev *gspca_dev)
 		reg_w1(gspca_dev, 0x9a, 0x0a);
 		reg_w1(gspca_dev, 0x99, 0x60);
 		break;
-	case BRIDGE_SN9C120:
-		reg_w(gspca_dev, 0x20, regsn20_sn9c120,
-				sizeof regsn20_sn9c120);
-		for (i = 0; i < 2; i++)
-			reg_w(gspca_dev, 0x84, reg84_sn9c120_1,
-					sizeof reg84_sn9c120_1);
-		for (i = 0; i < 6; i++)
-			reg_w(gspca_dev, 0x84, reg84_sn9c120_2,
-					sizeof reg84_sn9c120_2);
-		reg_w(gspca_dev, 0x84, reg84_sn9c120_3,
-				sizeof reg84_sn9c120_3);
-		reg_w1(gspca_dev, 0x9a, 0x05);
-		reg_w1(gspca_dev, 0x99, 0x5b);
-		break;
 	default:
 		reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20);
 		for (i = 0; i < 8; i++)
@@ -1107,22 +1066,14 @@ static void sd_start(struct gspca_dev *gspca_dev)
 /*			reg1 = 0x44; */
 /*			reg1 = 0x46;	(done) */
 		} else {
-			reg17 = 0xa2;	/* 640 */
-			reg1 = 0x40;
+			reg17 = 0x22;	/* 640 MCKSIZE */
+			reg1 = 0x06;
 		}
 		break;
 	}
 	reg_w(gspca_dev, 0xc0, C0, 6);
+	reg_w(gspca_dev, 0xca, CA, 4);
 	switch (sd->bridge) {
-	case BRIDGE_SN9C120:			/*jfm ?? */
-		reg_w(gspca_dev, 0xca, CA_sn9c120, 4);
-		break;
-	default:
-		reg_w(gspca_dev, 0xca, CA, 4);
-		break;
-	}
-	switch (sd->bridge) {
-	case BRIDGE_SN9C120:			/*jfm ?? */
 	case BRIDGE_SN9C325:
 		reg_w(gspca_dev, 0xce, CE_sn9c325, 4);
 		break;
@@ -1133,19 +1084,19 @@ static void sd_start(struct gspca_dev *gspca_dev)
 	}
 
 	/* here change size mode 0 -> VGA; 1 -> CIF */
-	data = 0x40 | sn9c1xx[0x18] | (mode << 4);
-	reg_w1(gspca_dev, 0x18, data);
+	reg18 = sn9c1xx[0x18] | (mode << 4);
+	reg_w1(gspca_dev, 0x18, reg18 | 0x40);
 
 	reg_w(gspca_dev, 0x100, qtable4, 0x40);
 	reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40);
 
-	data = sn9c1xx[0x18] | (mode << 4);
-	reg_w1(gspca_dev, 0x18, data);
+	reg_w1(gspca_dev, 0x18, reg18);
 
 	reg_w1(gspca_dev, 0x17, reg17);
 	reg_w1(gspca_dev, 0x01, reg1);
 	setbrightness(gspca_dev);
 	setcontrast(gspca_dev);
+	setautogain(gspca_dev);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1168,12 +1119,11 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 		i2c_w8(gspca_dev, stopmi0360);
 		data = 0x29;
 		break;
-	case SENSOR_MO4000:
-		break;
 	case SENSOR_OV7648:
 		data = 0x29;
 		break;
 	default:
+/*	case SENSOR_MO4000: */
 /*	case SENSOR_OV7660: */
 		break;
 	}
@@ -1193,16 +1143,23 @@ static void sd_close(struct gspca_dev *gspca_dev)
 {
 }
 
-static void setautogain(struct gspca_dev *gspca_dev)
+static void do_autogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	/* Thanks S., without your advice, autobright should not work :) */
 	int delta;
-	int expotimes = 0;
+	int expotimes;
 	__u8 luma_mean = 130;
 	__u8 luma_delta = 20;
 
-	delta = sd->avg_lum;
+	/* Thanks S., without your advice, autobright should not work :) */
+	if (sd->ag_cnt < 0)
+		return;
+	if (--sd->ag_cnt >= 0)
+		return;
+	sd->ag_cnt = AG_CNT_START;
+
+	delta = atomic_read(&sd->avg_lum);
+	PDEBUG(D_FRAM, "mean lum %d", delta);
 	if (delta < luma_mean - luma_delta ||
 	    delta > luma_mean + luma_delta) {
 		switch (sd->sensor) {
@@ -1214,8 +1171,9 @@ static void setautogain(struct gspca_dev *gspca_dev)
 			sd->exposure = setexposure(gspca_dev,
 					(unsigned int) (expotimes << 8));
 			break;
-		case SENSOR_MO4000:
-		case SENSOR_MI0360:
+		default:
+/*		case SENSOR_MO4000: */
+/*		case SENSOR_MI0360: */
 			expotimes = sd->exposure;
 			expotimes += (luma_mean - delta) >> 6;
 			if (expotimes < 0)
@@ -1228,6 +1186,8 @@ static void setautogain(struct gspca_dev *gspca_dev)
 	}
 }
 
+/* scan the URB packets */
+/* This function is run at interrupt level. */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
@@ -1244,9 +1204,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 				frame, data, sof + 2);
 		if (sd->ag_cnt < 0)
 			return;
-		if (--sd->ag_cnt >= 0)
-			return;
-		sd->ag_cnt = AG_CNT_START;
 /* w1 w2 w3 */
 /* w4 w5 w6 */
 /* w7 w8 */
@@ -1261,9 +1218,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 /* w5 */
 		avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
 		avg_lum >>= 4;
-		sd->avg_lum = avg_lum;
-		PDEBUG(D_PACK, "mean lum %d", avg_lum);
-		setautogain(gspca_dev);
+		atomic_set(&sd->avg_lum, avg_lum);
 		return;
 	}
 	if (gspca_dev->last_packet_type == LAST_PACKET) {
@@ -1300,6 +1255,7 @@ static unsigned int getexposure(struct gspca_dev *gspca_dev)
 			(hexpo << 10) | (mexpo << 2) | lexpo);
 		return (hexpo << 10) | (mexpo << 2) | lexpo;
 	default:
+/*	case SENSOR_OV7648:		* jfm: is it ok for 7648? */
 /*	case SENSOR_OV7660: */
 		/* read sensor exposure */
 		i2c_r5(gspca_dev, 0x04);
@@ -1318,14 +1274,12 @@ static void getbrightness(struct gspca_dev *gspca_dev)
 	/* hardcoded registers seem not readable */
 	switch (sd->sensor) {
 	case SENSOR_HV7131R:
-/*		sd->brightness = 0x7fff; */
 		sd->brightness = getexposure(gspca_dev) >> 4;
 		break;
 	case SENSOR_MI0360:
 		sd->brightness = getexposure(gspca_dev) << 4;
 		break;
 	case SENSOR_MO4000:
-/*		sd->brightness = 0x1fff; */
 		sd->brightness = getexposure(gspca_dev) << 4;
 		break;
 	}
@@ -1391,10 +1345,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->autogain = val;
-	if (val)
-		sd->ag_cnt = AG_CNT_START;
-	else
-		sd->ag_cnt = -1;
+	if (gspca_dev->streaming)
+		setautogain(gspca_dev);
 	return 0;
 }
 
@@ -1418,6 +1370,7 @@ static const struct sd_desc sd_desc = {
 	.stop0 = sd_stop0,
 	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
+	.dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */

+ 6 - 6
drivers/media/video/gspca/spca505.c

@@ -61,27 +61,27 @@ static struct ctrl sd_ctrls[] = {
 
 static struct v4l2_pix_format vga_mode[] = {
 	{160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 160 * 3,
+		.bytesperline = 160,
 		.sizeimage = 160 * 120 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 5},
 	{176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 176 * 3,
+		.bytesperline = 176,
 		.sizeimage = 176 * 144 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 4},
 	{320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 320 * 3,
+		.bytesperline = 320,
 		.sizeimage = 320 * 240 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 2},
 	{352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 352 * 3,
+		.bytesperline = 352,
 		.sizeimage = 352 * 288 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1},
 	{640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 640 * 3,
+		.bytesperline = 640,
 		.sizeimage = 640 * 480 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 0},
@@ -776,7 +776,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	default:
 		data += 1;
 		len -= 1;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame,
 				data, len);
 		break;
 	}

+ 6 - 6
drivers/media/video/gspca/spca506.c

@@ -112,27 +112,27 @@ static struct ctrl sd_ctrls[] = {
 
 static struct v4l2_pix_format vga_mode[] = {
 	{160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 160 * 3,
+		.bytesperline = 160,
 		.sizeimage = 160 * 120 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 5},
 	{176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 176 * 3,
+		.bytesperline = 176,
 		.sizeimage = 176 * 144 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 4},
 	{320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 320 * 3,
+		.bytesperline = 320,
 		.sizeimage = 320 * 240 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 2},
 	{352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 352 * 3,
+		.bytesperline = 352,
 		.sizeimage = 352 * 288 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1},
 	{640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
-		.bytesperline = 640 * 3,
+		.bytesperline = 640,
 		.sizeimage = 640 * 480 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 0},
@@ -588,7 +588,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	default:
 		data += 1;
 		len -= 1;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame,
 				data, len);
 		break;
 	}

+ 9 - 9
drivers/media/video/gspca/spca508.c

@@ -63,23 +63,23 @@ static struct ctrl sd_ctrls[] = {
 };
 
 static struct v4l2_pix_format sif_mode[] = {
-	{160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
-		.bytesperline = 160 * 3,
+	{160, 120, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE,
+		.bytesperline = 160,
 		.sizeimage = 160 * 120 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 3},
-	{176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
-		.bytesperline = 176 * 3,
+	{176, 144, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE,
+		.bytesperline = 176,
 		.sizeimage = 176 * 144 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 2},
-	{320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
-		.bytesperline = 320 * 3,
+	{320, 240, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE,
+		.bytesperline = 320,
 		.sizeimage = 320 * 240 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1},
-	{352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
-		.bytesperline = 352 * 3,
+	{352, 288, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE,
+		.bytesperline = 352,
 		.sizeimage = 352 * 288 * 3 / 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 0},
@@ -1583,7 +1583,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 	default:
 		data += 1;
 		len -= 1;
-		gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+		gspca_frame_add(gspca_dev, INTER_PACKET, frame,
 				data, len);
 		break;
 	}

+ 26 - 16
drivers/media/video/gspca/spca561.c

@@ -644,6 +644,18 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 	}
 }
 
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->chip_revision == Rev072A) {
+		if (sd->autogain)
+			sd->ag_cnt = AG_CNT_START;
+		else
+			sd->ag_cnt = -1;
+	}
+}
+
 static void sd_start(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -671,6 +683,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
 		reg_w_val(dev, 0x8500, mode);	/* mode */
 		reg_w_val(dev, 0x8700, Clck);	/* 0x27 clock */
 		reg_w_val(dev, 0x8112, 0x10 | 0x20);
+		setautogain(gspca_dev);
 		break;
 	default:
 /*	case Rev012A: */
@@ -720,18 +733,24 @@ static void sd_close(struct gspca_dev *gspca_dev)
 	reg_w_val(gspca_dev->dev, 0x8114, 0);
 }
 
-static void setautogain(struct gspca_dev *gspca_dev)
+static void do_autogain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	int expotimes = 0;
-	int pixelclk = 0;
-	int gainG = 0;
+	int expotimes;
+	int pixelclk;
+	int gainG;
 	__u8 R, Gr, Gb, B;
 	int y;
 	__u8 luma_mean = 110;
 	__u8 luma_delta = 20;
 	__u8 spring = 4;
 
+	if (sd->ag_cnt < 0)
+		return;
+	if (--sd->ag_cnt >= 0)
+		return;
+	sd->ag_cnt = AG_CNT_START;
+
 	switch (sd->chip_revision) {
 	case Rev072A:
 		reg_r(gspca_dev, 0x8621, 1);
@@ -795,18 +814,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			__u8 *data,		/* isoc packet */
 			int len)		/* iso packet length */
 {
-	struct sd *sd = (struct sd *) gspca_dev;
-
 	switch (data[0]) {
 	case 0:		/* start of frame */
 		frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
 					data, 0);
-		if (sd->ag_cnt >= 0) {
-			if (--sd->ag_cnt < 0) {
-				sd->ag_cnt = AG_CNT_START;
-				setautogain(gspca_dev);
-			}
-		}
 		data += SPCA561_OFFSET_DATA;
 		len -= SPCA561_OFFSET_DATA;
 		if (data[1] & 0x10) {
@@ -944,10 +955,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->autogain = val;
-	if (val)
-		sd->ag_cnt = AG_CNT_START;
-	else
-		sd->ag_cnt = -1;
+	if (gspca_dev->streaming)
+		setautogain(gspca_dev);
 	return 0;
 }
 
@@ -971,6 +980,7 @@ static const struct sd_desc sd_desc = {
 	.stop0 = sd_stop0,
 	.close = sd_close,
 	.pkt_scan = sd_pkt_scan,
+	.dq_callback = do_autogain,
 };
 
 /* -- module initialisation -- */

+ 2 - 2
drivers/media/video/gspca/vc032x.c

@@ -88,12 +88,12 @@ static struct ctrl sd_ctrls[] = {
 
 static struct v4l2_pix_format vc0321_mode[] = {
 	{320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
-		.bytesperline = 320 * 2,
+		.bytesperline = 320,
 		.sizeimage = 320 * 240 * 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1},
 	{640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
-		.bytesperline = 640 * 2,
+		.bytesperline = 640,
 		.sizeimage = 640 * 480 * 2,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 0},

+ 3 - 3
drivers/media/video/gspca/zc3xx.c

@@ -6469,7 +6469,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 		NULL, Tgradient_1, Tgradient_2,
 		Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6
 	};
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 	__u8 v[16];
 #endif
 
@@ -6487,7 +6487,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 		else if (g <= 0)
 			g = 1;
 		reg_w(dev, g, 0x0120 + i);	/* gamma */
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 		if (gspca_debug & D_CONF)
 			v[i] = g;
 #endif
@@ -6507,7 +6507,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 				g = 1;
 		}
 		reg_w(dev, g, 0x0130 + i);	/* gradient */
-#ifdef CONFIG_VIDEO_ADV_DEBUG
+#ifdef GSPCA_DEBUG
 		if (gspca_debug & D_CONF)
 			v[i] = g;
 #endif

+ 57 - 1
drivers/media/video/pxa_camera.c

@@ -128,6 +128,8 @@ struct pxa_camera_dev {
 
 	struct pxa_buffer	*active;
 	struct pxa_dma_desc	*sg_tail[3];
+
+	u32			save_cicr[5];
 };
 
 static const char *pxa_cam_driver_description = "PXA_Camera";
@@ -997,10 +999,64 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
 	return 0;
 }
 
+static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
+{
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	int i = 0, ret = 0;
+
+	pcdev->save_cicr[i++] = CICR0;
+	pcdev->save_cicr[i++] = CICR1;
+	pcdev->save_cicr[i++] = CICR2;
+	pcdev->save_cicr[i++] = CICR3;
+	pcdev->save_cicr[i++] = CICR4;
+
+	if ((pcdev->icd) && (pcdev->icd->ops->suspend))
+		ret = pcdev->icd->ops->suspend(pcdev->icd, state);
+
+	return ret;
+}
+
+static int pxa_camera_resume(struct soc_camera_device *icd)
+{
+	struct soc_camera_host *ici =
+		to_soc_camera_host(icd->dev.parent);
+	struct pxa_camera_dev *pcdev = ici->priv;
+	int i = 0, ret = 0;
+
+	DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD;
+	DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD;
+	DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD;
+
+	CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB;
+	CICR1 = pcdev->save_cicr[i++];
+	CICR2 = pcdev->save_cicr[i++];
+	CICR3 = pcdev->save_cicr[i++];
+	CICR4 = pcdev->save_cicr[i++];
+
+	if ((pcdev->icd) && (pcdev->icd->ops->resume))
+		ret = pcdev->icd->ops->resume(pcdev->icd);
+
+	/* Restart frame capture if active buffer exists */
+	if (!ret && pcdev->active) {
+		/* Reset the FIFOs */
+		CIFR |= CIFR_RESET_F;
+		/* Enable End-Of-Frame Interrupt */
+		CICR0 &= ~CICR0_EOFM;
+		/* Restart the Capture Interface */
+		CICR0 |= CICR0_ENB;
+	}
+
+	return ret;
+}
+
 static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
 	.owner		= THIS_MODULE,
 	.add		= pxa_camera_add_device,
 	.remove		= pxa_camera_remove_device,
+	.suspend	= pxa_camera_suspend,
+	.resume		= pxa_camera_resume,
 	.set_fmt_cap	= pxa_camera_set_fmt_cap,
 	.try_fmt_cap	= pxa_camera_try_fmt_cap,
 	.init_videobuf	= pxa_camera_init_videobuf,
@@ -1198,7 +1254,7 @@ static int __devinit pxa_camera_init(void)
 
 static void __exit pxa_camera_exit(void)
 {
-	return platform_driver_unregister(&pxa_camera_driver);
+	platform_driver_unregister(&pxa_camera_driver);
 }
 
 module_init(pxa_camera_init);

+ 1 - 1
drivers/media/video/sh_mobile_ceu_camera.c

@@ -647,7 +647,7 @@ static int __init sh_mobile_ceu_init(void)
 
 static void __exit sh_mobile_ceu_exit(void)
 {
-	return platform_driver_unregister(&sh_mobile_ceu_driver);
+	platform_driver_unregister(&sh_mobile_ceu_driver);
 }
 
 module_init(sh_mobile_ceu_init);

+ 26 - 0
drivers/media/video/soc_camera.c

@@ -732,10 +732,36 @@ static int soc_camera_remove(struct device *dev)
 	return 0;
 }
 
+static int soc_camera_suspend(struct device *dev, pm_message_t state)
+{
+	struct soc_camera_device *icd = to_soc_camera_dev(dev);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	int ret = 0;
+
+	if (ici->ops->suspend)
+		ret = ici->ops->suspend(icd, state);
+
+	return ret;
+}
+
+static int soc_camera_resume(struct device *dev)
+{
+	struct soc_camera_device *icd = to_soc_camera_dev(dev);
+	struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+	int ret = 0;
+
+	if (ici->ops->resume)
+		ret = ici->ops->resume(icd);
+
+	return ret;
+}
+
 static struct bus_type soc_camera_bus_type = {
 	.name		= "soc-camera",
 	.probe		= soc_camera_probe,
 	.remove		= soc_camera_remove,
+	.suspend	= soc_camera_suspend,
+	.resume		= soc_camera_resume,
 };
 
 static struct device_driver ic_drv = {

+ 1 - 1
drivers/media/video/soc_camera_platform.c

@@ -187,7 +187,7 @@ static int __init soc_camera_platform_module_init(void)
 
 static void __exit soc_camera_platform_module_exit(void)
 {
-	return platform_driver_unregister(&soc_camera_platform_driver);
+	platform_driver_unregister(&soc_camera_platform_driver);
 }
 
 module_init(soc_camera_platform_module_init);

+ 21 - 12
drivers/media/video/uvc/uvc_ctrl.c

@@ -585,13 +585,17 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
 	struct uvc_control_mapping *mapping;
 	struct uvc_menu_info *menu;
 	unsigned int i;
-	__u8 data[8];
+	__u8 *data;
 	int ret;
 
 	ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping);
 	if (ctrl == NULL)
 		return -EINVAL;
 
+	data = kmalloc(8, GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
 	memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
 	v4l2_ctrl->id = mapping->id;
 	v4l2_ctrl->type = mapping->v4l2_type;
@@ -604,8 +608,8 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
 	if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
 		if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,
 				video->dev->intfnum, ctrl->info->selector,
-				&data, ctrl->info->size)) < 0)
-			return ret;
+				data, ctrl->info->size)) < 0)
+			goto out;
 		v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);
 	}
 
@@ -623,13 +627,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
 			}
 		}
 
-		return 0;
+		ret = 0;
+		goto out;
 
 	case V4L2_CTRL_TYPE_BOOLEAN:
 		v4l2_ctrl->minimum = 0;
 		v4l2_ctrl->maximum = 1;
 		v4l2_ctrl->step = 1;
-		return 0;
+		ret = 0;
+		goto out;
 
 	default:
 		break;
@@ -638,26 +644,29 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
 	if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
 		if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,
 				video->dev->intfnum, ctrl->info->selector,
-				&data, ctrl->info->size)) < 0)
-			return ret;
+				data, ctrl->info->size)) < 0)
+			goto out;
 		v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);
 	}
 	if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
 		if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
 				video->dev->intfnum, ctrl->info->selector,
-				&data, ctrl->info->size)) < 0)
-			return ret;
+				data, ctrl->info->size)) < 0)
+			goto out;
 		v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);
 	}
 	if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
 		if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
 				video->dev->intfnum, ctrl->info->selector,
-				&data, ctrl->info->size)) < 0)
-			return ret;
+				data, ctrl->info->size)) < 0)
+			goto out;
 		v4l2_ctrl->step = uvc_get_le_value(data, mapping);
 	}
 
-	return 0;
+	ret = 0;
+out:
+	kfree(data);
+	return ret;
 }
 
 

+ 22 - 4
drivers/media/video/uvc/uvc_driver.c

@@ -1884,7 +1884,7 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
-	/* Packard Bell OEM Webcam */
+	/* Packard Bell OEM Webcam - Bison Electronics */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
 	  .idVendor		= 0x5986,
@@ -1893,7 +1893,7 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
-	/* Acer Crystal Eye webcam */
+	/* Acer Crystal Eye webcam - Bison Electronics */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
 	  .idVendor		= 0x5986,
@@ -1902,7 +1902,7 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
-	/* Medion Akoya Mini E1210 */
+	/* Medion Akoya Mini E1210 - Bison Electronics */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
 	  .idVendor		= 0x5986,
@@ -1911,7 +1911,7 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
-	/* Acer OrbiCam - Unknown vendor */
+	/* Acer OrbiCam - Bison Electronics */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
 	  .idVendor		= 0x5986,
@@ -1920,6 +1920,24 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Bison Electronics */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0300,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Clevo M570TU - Bison Electronics */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0303,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
 	/* Generic USB Video Class */
 	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
 	{}

+ 22 - 11
drivers/media/video/uvc/uvc_video.c

@@ -90,17 +90,20 @@ static void uvc_fixup_buffer_size(struct uvc_video_device *video,
 static int uvc_get_video_ctrl(struct uvc_video_device *video,
 	struct uvc_streaming_control *ctrl, int probe, __u8 query)
 {
-	__u8 data[34];
-	__u8 size;
+	__u8 *data;
+	__u16 size;
 	int ret;
 
 	size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+	data = kmalloc(size, GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
 	ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
-		probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+		probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
 		UVC_CTRL_STREAMING_TIMEOUT);
-
 	if (ret < 0)
-		return ret;
+		goto out;
 
 	ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
 	ctrl->bFormatIndex = data[2];
@@ -136,17 +139,22 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
 	 */
 	uvc_fixup_buffer_size(video, ctrl);
 
-	return 0;
+out:
+	kfree(data);
+	return ret;
 }
 
 int uvc_set_video_ctrl(struct uvc_video_device *video,
 	struct uvc_streaming_control *ctrl, int probe)
 {
-	__u8 data[34];
-	__u8 size;
+	__u8 *data;
+	__u16 size;
+	int ret;
 
 	size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
-	memset(data, 0, sizeof data);
+	data = kzalloc(size, GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
 
 	*(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
 	data[2] = ctrl->bFormatIndex;
@@ -174,10 +182,13 @@ int uvc_set_video_ctrl(struct uvc_video_device *video,
 		data[33] = ctrl->bMaxVersion;
 	}
 
-	return __uvc_query_ctrl(video->dev, SET_CUR, 0,
+	ret = __uvc_query_ctrl(video->dev, SET_CUR, 0,
 		video->streaming->intfnum,
-		probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+		probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
 		UVC_CTRL_STREAMING_TIMEOUT);
+
+	kfree(data);
+	return ret;
 }
 
 int uvc_probe_video(struct uvc_video_device *video,

+ 3 - 1
drivers/media/video/v4l2-dev.c

@@ -222,11 +222,13 @@ int video_register_device(struct video_device *vfd, int type, int nr)
 EXPORT_SYMBOL(video_register_device);
 
 /**
- *	video_register_device - register video4linux devices
+ *	video_register_device_index - register video4linux devices
  *	@vfd:  video device structure we want to register
  *	@type: type of device to register
  *	@nr:   which device number (0 == /dev/video0, 1 == /dev/video1, ...
  *             -1 == first free)
+ *	@index: stream number based on parent device;
+ *		-1 if auto assign, requested number otherwise
  *
  *	The registration code assigns minor numbers based on the type
  *	requested. -ENFILE is returned in all the device slots for this

+ 1 - 0
drivers/media/video/vino.c

@@ -41,6 +41,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
 #include <linux/video_decoder.h>
 #include <linux/mutex.h>
 

+ 5 - 0
include/media/soc_camera.h

@@ -14,6 +14,7 @@
 
 #include <linux/videodev2.h>
 #include <media/videobuf-core.h>
+#include <linux/pm.h>
 
 struct soc_camera_device {
 	struct list_head list;
@@ -63,6 +64,8 @@ struct soc_camera_host_ops {
 	struct module *owner;
 	int (*add)(struct soc_camera_device *);
 	void (*remove)(struct soc_camera_device *);
+	int (*suspend)(struct soc_camera_device *, pm_message_t state);
+	int (*resume)(struct soc_camera_device *);
 	int (*set_fmt_cap)(struct soc_camera_device *, __u32,
 			   struct v4l2_rect *);
 	int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
@@ -111,6 +114,8 @@ struct soc_camera_ops {
 	struct module *owner;
 	int (*probe)(struct soc_camera_device *);
 	void (*remove)(struct soc_camera_device *);
+	int (*suspend)(struct soc_camera_device *, pm_message_t state);
+	int (*resume)(struct soc_camera_device *);
 	int (*init)(struct soc_camera_device *);
 	int (*release)(struct soc_camera_device *);
 	int (*start_capture)(struct soc_camera_device *);