V4L/DVB (8825): gspca: More controls for pac73xx and new webcam 093a:2624.

-Add usb id for 093a:2624 (pac7302)
-Report some controls to userspace with 7302 only, as they are 7302 only
-Add gain and exposure controls
-Add autogain
-Fix 7302 imaged being mirrored by default

Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 2dd2f77..c503467 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -188,6 +188,7 @@
 pac7311		093a:260e	Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
 pac7311		093a:260f	SnakeCam
 pac7311		093a:2621	PAC731x
+pac7311		093a:2624	PAC7302
 zc3xx		0ac8:0302	Z-star Vimicro zc0302
 vc032x		0ac8:0321	Vimicro generic vc0321
 vc032x		0ac8:0323	Vimicro Vc0323
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index a15bcca..83b5f74 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -56,12 +56,6 @@
 #define PAC207_GAIN_KNEE		20
 
 #define PAC207_AUTOGAIN_DEADZONE	30
-/* We calculating the autogain at the end of the transfer of a frame, at this
-   moment a frame with the old settings is being transmitted, and a frame is
-   being captured with the old settings. So if we adjust the autogain we must
-   ignore atleast the 2 next frames for the new settings to come into effect
-   before doing any other adjustments */
-#define PAC207_AUTOGAIN_IGNORE_FRAMES	3
 
 /* specific webcam descriptor */
 struct sd {
@@ -338,6 +332,9 @@
 	pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
 }
 
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -351,12 +348,9 @@
 	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
 			100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
 			PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
-		sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
+		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
-/* Include pac common sof detection functions */
-#include "pac_common.h"
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,
 			__u8 *data,
@@ -500,7 +494,7 @@
 		sd->gain = PAC207_GAIN_DEFAULT;
 		if (gspca_dev->streaming) {
 			sd->autogain_ignore_frames =
-				PAC207_AUTOGAIN_IGNORE_FRAMES;
+				PAC_AUTOGAIN_IGNORE_FRAMES;
 			setexposure(gspca_dev);
 			setgain(gspca_dev);
 		}
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index e22ca61..14b9811 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -44,6 +44,9 @@
    0x10/-	Master gain 0-31
    -/0x10	Another gain 0-15, limited influence (1-2x gain I guess)
    0x21		Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+   -/0x27	Seems to toggle various gains on / off, Setting bit 7 seems to
+		completely disable the analog amplification block. Set to 0x68
+		for max gain, 0x14 for minimal gain.
 */
 
 #define MODULE_NAME "pac7311"
@@ -61,6 +64,8 @@
 	unsigned char brightness;
 	unsigned char contrast;
 	unsigned char colors;
+	unsigned char gain;
+	unsigned char exposure;
 	unsigned char autogain;
 	__u8 hflip;
 	__u8 vflip;
@@ -88,8 +93,14 @@
 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_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+/* This control is pac7302 only */
+#define BRIGHTNESS_IDX 0
 	{
 	    {
 		.id      = V4L2_CID_BRIGHTNESS,
@@ -105,6 +116,7 @@
 	    .set = sd_setbrightness,
 	    .get = sd_getbrightness,
 	},
+/* This control is for both the 7302 and the 7311 */
 	{
 	    {
 		.id      = V4L2_CID_CONTRAST,
@@ -120,6 +132,8 @@
 	    .set = sd_setcontrast,
 	    .get = sd_getcontrast,
 	},
+/* This control is pac7302 only */
+#define SATURATION_IDX 2
 	{
 	    {
 		.id      = V4L2_CID_SATURATION,
@@ -135,6 +149,39 @@
 	    .set = sd_setcolors,
 	    .get = sd_getcolors,
 	},
+/* All controls below are for both the 7302 and the 7311 */
+	{
+	    {
+		.id      = V4L2_CID_GAIN,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Gain",
+		.minimum = 0,
+#define GAIN_MAX 255
+		.maximum = GAIN_MAX,
+		.step    = 1,
+#define GAIN_DEF 127
+#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
+		.default_value = GAIN_DEF,
+	    },
+	    .set = sd_setgain,
+	    .get = sd_getgain,
+	},
+	{
+	    {
+		.id      = V4L2_CID_EXPOSURE,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Exposure",
+		.minimum = 0,
+#define EXPOSURE_MAX 255
+		.maximum = EXPOSURE_MAX,
+		.step    = 1,
+#define EXPOSURE_DEF  16 /*  32 ms / 30 fps */
+#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+		.default_value = EXPOSURE_DEF,
+	    },
+	    .set = sd_setexposure,
+	    .get = sd_getexposure,
+	},
 	{
 	    {
 		.id      = V4L2_CID_AUTOGAIN,
@@ -149,8 +196,6 @@
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
-/* next controls work with pac7302 only */
-#define HFLIP_IDX 4
 	{
 	    {
 		.id      = V4L2_CID_HFLIP,
@@ -165,7 +210,6 @@
 	    .set = sd_sethflip,
 	    .get = sd_gethflip,
 	},
-#define VFLIP_IDX 5
 	{
 	    {
 		.id      = V4L2_CID_VFLIP,
@@ -345,7 +389,7 @@
 	0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
 	0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
-	0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
+	0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68,
 	0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
 	0x23, 0x28, 0x04, 0x11, 0x00, 0x00
 };
@@ -374,7 +418,7 @@
 			usb_sndctrlpipe(gspca_dev->dev, 0),
 			0,			/* request */
 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-			value, index, gspca_dev->usb_buf, 1,
+			0, index, gspca_dev->usb_buf, 1,
 			500);
 }
 
@@ -469,20 +513,22 @@
 
 		cam->cam_mode = vga_mode;
 		cam->nmodes = ARRAY_SIZE(vga_mode);
-		gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
-				| (1 << VFLIP_IDX);
+		gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
+				| (1 << SATURATION_IDX);
 	}
 
 	sd->brightness = BRIGHTNESS_DEF;
 	sd->contrast = CONTRAST_DEF;
 	sd->colors = COLOR_DEF;
+	sd->gain = GAIN_DEF;
+	sd->exposure = EXPOSURE_DEF;
 	sd->autogain = AUTOGAIN_DEF;
 	sd->hflip = HFLIP_DEF;
 	sd->vflip = VFLIP_DEF;
 	return 0;
 }
 
-/* rev 12a only */
+/* This function is used by pac7302 only */
 static void setbrightcont(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -509,37 +555,11 @@
 	reg_w(gspca_dev, 0xdc, 0x01);
 }
 
-/* This function is used by pac7302 only */
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
-	struct sd *sd = (struct sd *) gspca_dev;
-	int brightness;
-
-	if (sd->sensor == SENSOR_PAC7302) {
-		setbrightcont(gspca_dev);
-		return;
-	}
-/* HDG: this is not brightness but gain, I'll add gain and exposure controls
-   in a next patch */
-	return;
-
-	brightness = BRIGHTNESS_MAX - sd->brightness;
-	reg_w(gspca_dev, 0xff, 0x04);
-	reg_w(gspca_dev, 0x0e, 0x00);
-	reg_w(gspca_dev, 0x0f, brightness);
-	/* load registers to sensor (Bit 0, auto clear) */
-	reg_w(gspca_dev, 0x11, 0x01);
-	PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
-}
-
+/* This function is used by pac7311 only */
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	if (sd->sensor == SENSOR_PAC7302) {
-		setbrightcont(gspca_dev);
-		return;
-	}
 	reg_w(gspca_dev, 0xff, 0x04);
 	reg_w(gspca_dev, 0x10, sd->contrast >> 4);
 	/* load registers to sensor (Bit 0, auto clear) */
@@ -550,26 +570,80 @@
 static void setcolors(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	int i, v;
+	static const int a[9] =
+		{217, -212, 0, -101, 170, -67, -38, -315, 355};
+	static const int b[9] =
+		{19, 106, 0, 19, 106, 1, 19, 106, 1};
+
+	reg_w(gspca_dev, 0xff, 0x03);	/* page 3 */
+	reg_w(gspca_dev, 0x11, 0x01);
+	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
+	for (i = 0; i < 9; i++) {
+		v = a[i] * sd->colors / COLOR_MAX + b[i];
+		reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
+		reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
+	}
+	reg_w(gspca_dev, 0xdc, 0x01);
+	PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
 
 	if (sd->sensor == SENSOR_PAC7302) {
-		int i, v;
-		static const int a[9] =
-			{217, -212, 0, -101, 170, -67, -38, -315, 355};
-		static const int b[9] =
-			{19, 106, 0, 19, 106, 1, 19, 106, 1};
-
-		reg_w(gspca_dev, 0xff, 0x03);	/* page 3 */
-		reg_w(gspca_dev, 0x11, 0x01);
-		reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
-		reg_w(gspca_dev, 0xff, 0x00);	/* page 0 */
-		for (i = 0; i < 9; i++) {
-			v = a[i] * sd->colors / COLOR_MAX + b[i];
-			reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
-			reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
-		}
-		reg_w(gspca_dev, 0xdc, 0x01);
-		PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
+		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
+		reg_w(gspca_dev, 0x10, sd->gain >> 3);
+	} else {
+		int gain = GAIN_MAX - sd->gain;
+		if (gain < 1)
+			gain = 1;
+		else if (gain > 245)
+			gain = 245;
+		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
+		reg_w(gspca_dev, 0x0e, 0x00);
+		reg_w(gspca_dev, 0x0f, gain);
 	}
+	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0x11, 0x01);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	__u8 reg;
+
+	/* register 2 of frame 3/4 contains the clock divider configuring the
+	   no fps according to the formula: 60 / reg. sd->exposure is the
+	   desired exposure time in ms. */
+	reg = 120 * sd->exposure / 1000;
+	if (reg < 2)
+		reg = 2;
+	else if (reg > 63)
+		reg = 63;
+
+	if (sd->sensor == SENSOR_PAC7302) {
+		/* On the pac7302 reg2 MUST be a multiple of 3, so round it to
+		   the nearest multiple of 3 */
+		reg = ((reg + 1) / 3) * 3;
+		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
+		reg_w(gspca_dev, 0x02, reg);
+	} else {
+		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
+		reg_w(gspca_dev, 0x02, reg);
+		/* Page 1 register 8 must always be 0x08 except when not in
+		   640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
+		reg_w(gspca_dev, 0xff, 0x01);
+		if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
+				reg <= 3)
+			reg_w(gspca_dev, 0x08, 0x09);
+		else
+			reg_w(gspca_dev, 0x08, 0x08);
+	}
+	/* load registers to sensor (Bit 0, auto clear) */
+	reg_w(gspca_dev, 0x11, 0x01);
 }
 
 static void sethvflip(struct gspca_dev *gspca_dev)
@@ -579,14 +653,15 @@
 
 	if (sd->sensor == SENSOR_PAC7302) {
 		reg_w(gspca_dev, 0xff, 0x03);		/* page 3 */
-		data = (sd->hflip ? 0x00 : 0x08)
+		data = (sd->hflip ? 0x08 : 0x00)
 			| (sd->vflip ? 0x04 : 0x00);
 	} else {
-		reg_w(gspca_dev, 0xff, 0x04);		/* page 3 */
+		reg_w(gspca_dev, 0xff, 0x04);		/* page 4 */
 		data = (sd->hflip ? 0x04 : 0x00)
 			| (sd->vflip ? 0x08 : 0x00);
 	}
 	reg_w(gspca_dev, 0x21, data);
+	/* load registers to sensor (Bit 0, auto clear) */
 	reg_w(gspca_dev, 0x11, 0x01);
 }
 
@@ -602,61 +677,49 @@
 
 	sd->sof_read = 0;
 
-	if (sd->sensor == SENSOR_PAC7302)
+	if (sd->sensor == SENSOR_PAC7302) {
 		reg_w_var(gspca_dev, start_7302);
-	else
+		setbrightcont(gspca_dev);
+		setcolors(gspca_dev);
+	} else {
 		reg_w_var(gspca_dev, start_7311);
-
-	setcontrast(gspca_dev);
-	setbrightness(gspca_dev);
-	setcolors(gspca_dev);
+		setcontrast(gspca_dev);
+	}
+	setgain(gspca_dev);
+	setexposure(gspca_dev);
+	sethvflip(gspca_dev);
 
 	/* set correct resolution */
 	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
 	case 2:					/* 160x120 pac7311 */
-		reg_w(gspca_dev, 0xff, 0x04);
-		reg_w(gspca_dev, 0x02, 0x03);
 		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x08, 0x09);
 		reg_w(gspca_dev, 0x17, 0x20);
-		reg_w(gspca_dev, 0x1b, 0x00);
 		reg_w(gspca_dev, 0x87, 0x10);
 		break;
 	case 1:					/* 320x240 pac7311 */
-		reg_w(gspca_dev, 0xff, 0x04);
-		reg_w(gspca_dev, 0x02, 0x03);
 		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x08, 0x09);
 		reg_w(gspca_dev, 0x17, 0x30);
 		reg_w(gspca_dev, 0x87, 0x11);
 		break;
 	case 0:					/* 640x480 */
 		if (sd->sensor == SENSOR_PAC7302)
 			break;
-		reg_w(gspca_dev, 0xff, 0x04);
-		reg_w(gspca_dev, 0x02, 0x07);
 		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x08, 0x08);
 		reg_w(gspca_dev, 0x17, 0x00);
 		reg_w(gspca_dev, 0x87, 0x12);
 		break;
 	}
 
-	/* start stream */
-	reg_w(gspca_dev, 0xff, 0x01);
-	if (sd->sensor == SENSOR_PAC7302) {
-		sethvflip(gspca_dev);
-		reg_w(gspca_dev, 0x78, 0x01);
-		reg_w(gspca_dev, 0xff, 0x01);
-		reg_w(gspca_dev, 0x78, 0x01);
-	} else {
-		reg_w(gspca_dev, 0x78, 0x44);
-		reg_w(gspca_dev, 0x78, 0x45);
-	}
-
 	sd->sof_read = 0;
 	sd->autogain_ignore_frames = 0;
 	atomic_set(&sd->avg_lum, -1);
+
+	/* start stream */
+	reg_w(gspca_dev, 0xff, 0x01);
+	if (sd->sensor == SENSOR_PAC7302)
+		reg_w(gspca_dev, 0x78, 0x01);
+	else
+		reg_w(gspca_dev, 0x78, 0x05);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -691,8 +754,28 @@
 	}
 }
 
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+	int avg_lum = atomic_read(&sd->avg_lum);
+	int desired_lum;
+
+	if (avg_lum == -1)
+		return;
+
+	if (sd->sensor == SENSOR_PAC7302)
+		desired_lum = 70 + sd->brightness * 2;
+	else
+		desired_lum = 200;
+
+	if (sd->autogain_ignore_frames > 0)
+		sd->autogain_ignore_frames--;
+	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+			10, GAIN_KNEE, EXPOSURE_KNEE))
+		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
 static const unsigned char pac7311_jpeg_header1[] = {
@@ -704,9 +787,6 @@
   0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
 };
 
-/* Include pac common sof detection functions */
-#include "pac_common.h"
-
 /* this function is run at interrupt level */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
@@ -790,7 +870,7 @@
 
 	sd->brightness = val;
 	if (gspca_dev->streaming)
-		setbrightness(gspca_dev);
+		setbrightcont(gspca_dev);
 	return 0;
 }
 
@@ -807,8 +887,12 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->contrast = val;
-	if (gspca_dev->streaming)
-		setcontrast(gspca_dev);
+	if (gspca_dev->streaming) {
+		if (sd->sensor == SENSOR_PAC7302)
+			setbrightcont(gspca_dev);
+		else
+			setcontrast(gspca_dev);
+	}
 	return 0;
 }
 
@@ -838,11 +922,61 @@
 	return 0;
 }
 
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->gain = val;
+	if (gspca_dev->streaming)
+		setgain(gspca_dev);
+	return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->gain;
+	return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->exposure = val;
+	if (gspca_dev->streaming)
+		setexposure(gspca_dev);
+	return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->exposure;
+	return 0;
+}
+
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	sd->autogain = val;
+	/* when switching to autogain set defaults to make sure
+	   we are on a valid point of the autogain gain /
+	   exposure knee graph, and give this change time to
+	   take effect before doing autogain. */
+	if (sd->autogain) {
+		sd->exposure = EXPOSURE_DEF;
+		sd->gain = GAIN_DEF;
+		if (gspca_dev->streaming) {
+			sd->autogain_ignore_frames =
+				PAC_AUTOGAIN_IGNORE_FRAMES;
+			setexposure(gspca_dev);
+			setgain(gspca_dev);
+		}
+	}
 
 	return 0;
 }
@@ -914,6 +1048,7 @@
 	{USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
 	{USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
 	{USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
+	{USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
 	{}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h
index a19b5d4..34d4b14 100644
--- a/drivers/media/video/gspca/pac_common.h
+++ b/drivers/media/video/gspca/pac_common.h
@@ -23,6 +23,13 @@
  *
  */
 
+/* We calculate the autogain at the end of the transfer of a frame, at this
+   moment a frame with the old settings is being transmitted, and a frame is
+   being captured with the old settings. So if we adjust the autogain we must
+   ignore atleast the 2 next frames for the new settings to come into effect
+   before doing any other adjustments */
+#define PAC_AUTOGAIN_IGNORE_FRAMES	3
+
 static const unsigned char pac_sof_marker[5] =
 		{ 0xff, 0xff, 0x00, 0xff, 0x96 };
 
@@ -37,7 +44,7 @@
 		if (m[i] == pac_sof_marker[sd->sof_read]) {
 			sd->sof_read++;
 			if (sd->sof_read == sizeof(pac_sof_marker)) {
-				PDEBUG(D_STREAM,
+				PDEBUG(D_FRAM,
 					"SOF found, bytes to analyze: %u."
 					" Frame starts at byte #%u",
 					len, i + 1);