From f50ba1bed3cfd65d6899afc4cb77299ee5c297ae Mon Sep 17 00:00:00 2001
From: Jean-Francois Moine <moinejf@free.fr>
Date: Wed, 3 Sep 2008 17:12:14 -0300
Subject: [PATCH] V4L/DVB (8814): gspca: Set DISABLED the disabled controls at
 query control time.

Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
 drivers/media/video/gspca/etoms.c   |  2 ++
 drivers/media/video/gspca/gspca.c   | 33 +++++++++++++++++------------
 drivers/media/video/gspca/gspca.h   |  1 +
 drivers/media/video/gspca/pac7311.c |  4 ++++
 drivers/media/video/gspca/sonixj.c  | 25 +++++++++++++---------
 drivers/media/video/gspca/vc032x.c  |  3 +++
 drivers/media/video/gspca/zc3xx.c   | 16 ++++++++++++++
 7 files changed, 61 insertions(+), 23 deletions(-)

diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
index a3cccab7b814..e5a9eee673a9 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/video/gspca/etoms.c
@@ -81,6 +81,7 @@ static struct ctrl sd_ctrls[] = {
 	 .set = sd_setcontrast,
 	 .get = sd_getcontrast,
 	 },
+#define COLOR_IDX 2
 	{
 	 {
 	  .id = V4L2_CID_SATURATION,
@@ -665,6 +666,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	} else {
 		cam->cam_mode = vga_mode;
 		cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+		gspca_dev->ctrl_dis = (1 << COLOR_IDX);
 	}
 	sd->brightness = BRIGHTNESS_DEF;
 	sd->contrast = CONTRAST_DEF;
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 28842ed24c09..33161e1e0bcc 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -856,37 +856,44 @@ static int vidioc_querycap(struct file *file, void  *priv,
 	return 0;
 }
 
-/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */
 static int vidioc_queryctrl(struct file *file, void *priv,
 			   struct v4l2_queryctrl *q_ctrl)
 {
 	struct gspca_dev *gspca_dev = priv;
-	int i;
+	int i, ix;
 	u32 id;
 
+	ix = -1;
 	id = q_ctrl->id;
 	if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
 		id &= V4L2_CTRL_ID_MASK;
 		id++;
 		for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-			if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) {
-				memcpy(q_ctrl,
-					&gspca_dev->sd_desc->ctrls[i].qctrl,
-					sizeof *q_ctrl);
-				return 0;
+			if (id < gspca_dev->sd_desc->ctrls[i].qctrl.id)
+				continue;
+			if (ix < 0) {
+				ix = i;
+				continue;
 			}
+			if (gspca_dev->sd_desc->ctrls[i].qctrl.id
+				    > gspca_dev->sd_desc->ctrls[ix].qctrl.id)
+				continue;
+			ix = i;
 		}
-		return -EINVAL;
 	}
 	for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
 		if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
-			memcpy(q_ctrl,
-				&gspca_dev->sd_desc->ctrls[i].qctrl,
-				sizeof *q_ctrl);
-			return 0;
+			ix = i;
+			break;
 		}
 	}
-	return -EINVAL;
+	if (ix < 0)
+		return -EINVAL;
+	memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl,
+		sizeof *q_ctrl);
+	if (gspca_dev->ctrl_dis & (1 << ix))
+		q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+	return 0;
 }
 
 static int vidioc_s_ctrl(struct file *file, void *priv,
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 2596568e82fd..a804ef18b8da 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -126,6 +126,7 @@ struct gspca_dev {
 
 	struct cam cam;				/* device information */
 	const struct sd_desc *sd_desc;		/* subdriver description */
+	unsigned ctrl_dis;		/* disabled controls (bit map) */
 
 	__u8 usb_buf[8];			/* buffer for USB exchanges */
 	struct urb *urb[MAX_NURBS];
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 3c5142852f27..69d610062d00 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -150,6 +150,7 @@ static struct ctrl sd_ctrls[] = {
 	    .get = sd_getautogain,
 	},
 /* next controls work with pac7302 only */
+#define HFLIP_IDX 4
 	{
 	    {
 		.id      = V4L2_CID_HFLIP,
@@ -164,6 +165,7 @@ static struct ctrl sd_ctrls[] = {
 	    .set = sd_sethflip,
 	    .get = sd_gethflip,
 	},
+#define VFLIP_IDX 5
 	{
 	    {
 		.id      = V4L2_CID_VFLIP,
@@ -467,6 +469,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
 		cam->cam_mode = vga_mode;
 		cam->nmodes = ARRAY_SIZE(vga_mode);
+		gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
+				| (1 << VFLIP_IDX);
 	}
 
 	sd->brightness = BRIGHTNESS_DEF;
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 0d4677688c91..e657b8ba6db7 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -116,6 +116,7 @@ static struct ctrl sd_ctrls[] = {
 	    .set = sd_setcolors,
 	    .get = sd_getcolors,
 	},
+#define AUTOGAIN_IDX 3
 	{
 	    {
 		.id      = V4L2_CID_AUTOGAIN,
@@ -936,6 +937,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->autogain = AUTOGAIN_DEF;
 	sd->ag_cnt = -1;
 
+	switch (sd->sensor) {
+	case SENSOR_OV7630:
+	case SENSOR_OV7648:
+	case SENSOR_OV7660:
+		gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX);
+		break;
+	}
+
 	return 0;
 }
 
@@ -1150,16 +1159,12 @@ 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;
-	}
+	if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+		return;
+	if (sd->autogain)
+		sd->ag_cnt = AG_CNT_START;
+	else
+		sd->ag_cnt = -1;
 }
 
 /* -- start the camera -- */
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 47c7ce641d99..5454f0eb0077 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -69,6 +69,7 @@ static struct ctrl sd_ctrls[] = {
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
+#define LIGHTFREQ_IDX 1
 	{
 	    {
 		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -1463,6 +1464,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->qindex = 7;
 	sd->autogain = AUTOGAIN_DEF;
 	sd->lightfreq = FREQ_DEF;
+	if (sd->sensor != SENSOR_OV7670)
+		gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
 
 	if (sd->bridge == BRIDGE_VC0321) {
 		reg_r(gspca_dev, 0x8a, 0, 3);
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 79436f27cd4e..e78b9b7591d5 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -85,6 +85,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+#define BRIGHTNESS_IDX 0
 #define SD_BRIGHTNESS 0
 	{
 	    {
@@ -141,6 +142,7 @@ static struct ctrl sd_ctrls[] = {
 	    .set = sd_setautogain,
 	    .get = sd_getautogain,
 	},
+#define LIGHTFREQ_IDX 4
 #define SD_FREQ 4
 	{
 	    {
@@ -7150,6 +7152,20 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
 	sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
 
+	switch (sd->sensor) {
+	case SENSOR_GC0305:
+	case SENSOR_OV7620:
+	case SENSOR_PO2030:
+		gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
+		break;
+	case SENSOR_HDCS2020:
+	case SENSOR_HV7131B:
+	case SENSOR_HV7131C:
+	case SENSOR_OV7630C:
+		gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
+		break;
+	}
+
 	/* switch the led off */
 	reg_w(gspca_dev->dev, 0x01, 0x0000);
 	return 0;