Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1bd7d6ad authored by Antonio Ospite's avatar Antonio Ospite Committed by Mauro Carvalho Chehab
Browse files

[media] gspca_ov534: Convert to the control framework

parent 463023b0
Loading
Loading
Loading
Loading
+267 −302
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include "gspca.h"

#include <linux/fixp-arith.h>
#include <media/v4l2-ctrls.h>

#define OV534_REG_ADDRESS	0xf1	/* sensor address */
#define OV534_REG_SUBADDR	0xf2
@@ -53,29 +54,28 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver");
MODULE_LICENSE("GPL");

/* controls */
enum e_ctrl {
	HUE,
	SATURATION,
	BRIGHTNESS,
	CONTRAST,
	GAIN,
	EXPOSURE,
	AGC,
	AWB,
	AEC,
	SHARPNESS,
	HFLIP,
	VFLIP,
	LIGHTFREQ,
	NCTRLS		/* number of controls */
};

/* specific webcam descriptor */
struct sd {
	struct gspca_dev gspca_dev;	/* !! must be the first item */

	struct gspca_ctrl ctrls[NCTRLS];
	struct v4l2_ctrl_handler ctrl_handler;
	struct v4l2_ctrl *hue;
	struct v4l2_ctrl *saturation;
	struct v4l2_ctrl *brightness;
	struct v4l2_ctrl *contrast;
	struct { /* gain control cluster */
		struct v4l2_ctrl *autogain;
		struct v4l2_ctrl *gain;
	};
	struct v4l2_ctrl *autowhitebalance;
	struct { /* exposure control cluster */
		struct v4l2_ctrl *autoexposure;
		struct v4l2_ctrl *exposure;
	};
	struct v4l2_ctrl *sharpness;
	struct v4l2_ctrl *hflip;
	struct v4l2_ctrl *vflip;
	struct v4l2_ctrl *plfreq;

	__u32 last_pts;
	u16 last_fid;
@@ -89,181 +89,9 @@ enum sensors {
	NSENSORS
};

/* V4L2 controls supported by the driver */
static void sethue(struct gspca_dev *gspca_dev);
static void setsaturation(struct gspca_dev *gspca_dev);
static void setbrightness(struct gspca_dev *gspca_dev);
static void setcontrast(struct gspca_dev *gspca_dev);
static void setgain(struct gspca_dev *gspca_dev);
static void setexposure(struct gspca_dev *gspca_dev);
static void setagc(struct gspca_dev *gspca_dev);
static void setawb(struct gspca_dev *gspca_dev);
static void setaec(struct gspca_dev *gspca_dev);
static void setsharpness(struct gspca_dev *gspca_dev);
static void sethvflip(struct gspca_dev *gspca_dev);
static void setlightfreq(struct gspca_dev *gspca_dev);

static int sd_start(struct gspca_dev *gspca_dev);
static void sd_stopN(struct gspca_dev *gspca_dev);

static const struct ctrl sd_ctrls[] = {
[HUE] = {
		{
			.id      = V4L2_CID_HUE,
			.type    = V4L2_CTRL_TYPE_INTEGER,
			.name    = "Hue",
			.minimum = -90,
			.maximum = 90,
			.step    = 1,
			.default_value = 0,
		},
		.set_control = sethue
	},
[SATURATION] = {
		{
			.id      = V4L2_CID_SATURATION,
			.type    = V4L2_CTRL_TYPE_INTEGER,
			.name    = "Saturation",
			.minimum = 0,
			.maximum = 255,
			.step    = 1,
			.default_value = 64,
		},
		.set_control = setsaturation
	},
[BRIGHTNESS] = {
		{
			.id      = V4L2_CID_BRIGHTNESS,
			.type    = V4L2_CTRL_TYPE_INTEGER,
			.name    = "Brightness",
			.minimum = 0,
			.maximum = 255,
			.step    = 1,
			.default_value = 0,
		},
		.set_control = setbrightness
	},
[CONTRAST] = {
		{
			.id      = V4L2_CID_CONTRAST,
			.type    = V4L2_CTRL_TYPE_INTEGER,
			.name    = "Contrast",
			.minimum = 0,
			.maximum = 255,
			.step    = 1,
			.default_value = 32,
		},
		.set_control = setcontrast
	},
[GAIN] = {
		{
			.id      = V4L2_CID_GAIN,
			.type    = V4L2_CTRL_TYPE_INTEGER,
			.name    = "Main Gain",
			.minimum = 0,
			.maximum = 63,
			.step    = 1,
			.default_value = 20,
		},
		.set_control = setgain
	},
[EXPOSURE] = {
		{
			.id      = V4L2_CID_EXPOSURE,
			.type    = V4L2_CTRL_TYPE_INTEGER,
			.name    = "Exposure",
			.minimum = 0,
			.maximum = 255,
			.step    = 1,
			.default_value = 120,
		},
		.set_control = setexposure
	},
[AGC] = {
		{
			.id      = V4L2_CID_AUTOGAIN,
			.type    = V4L2_CTRL_TYPE_BOOLEAN,
			.name    = "Auto Gain",
			.minimum = 0,
			.maximum = 1,
			.step    = 1,
			.default_value = 1,
		},
		.set_control = setagc
	},
[AWB] = {
		{
			.id      = V4L2_CID_AUTO_WHITE_BALANCE,
			.type    = V4L2_CTRL_TYPE_BOOLEAN,
			.name    = "Auto White Balance",
			.minimum = 0,
			.maximum = 1,
			.step    = 1,
			.default_value = 1,
		},
		.set_control = setawb
	},
[AEC] = {
		{
			.id      = V4L2_CID_EXPOSURE_AUTO,
			.type    = V4L2_CTRL_TYPE_BOOLEAN,
			.name    = "Auto Exposure",
			.minimum = 0,
			.maximum = 1,
			.step    = 1,
			.default_value = 1,
		},
		.set_control = setaec
	},
[SHARPNESS] = {
		{
			.id      = V4L2_CID_SHARPNESS,
			.type    = V4L2_CTRL_TYPE_INTEGER,
			.name    = "Sharpness",
			.minimum = 0,
			.maximum = 63,
			.step    = 1,
			.default_value = 0,
		},
		.set_control = setsharpness
	},
[HFLIP] = {
		{
			.id      = V4L2_CID_HFLIP,
			.type    = V4L2_CTRL_TYPE_BOOLEAN,
			.name    = "HFlip",
			.minimum = 0,
			.maximum = 1,
			.step    = 1,
			.default_value = 0,
		},
		.set_control = sethvflip
	},
[VFLIP] = {
		{
			.id      = V4L2_CID_VFLIP,
			.type    = V4L2_CTRL_TYPE_BOOLEAN,
			.name    = "VFlip",
			.minimum = 0,
			.maximum = 1,
			.step    = 1,
			.default_value = 0,
		},
		.set_control = sethvflip
	},
[LIGHTFREQ] = {
		{
			.id      = V4L2_CID_POWER_LINE_FREQUENCY,
			.type    = V4L2_CTRL_TYPE_MENU,
			.name    = "Light Frequency Filter",
			.minimum = 0,
			.maximum = 1,
			.step    = 1,
			.default_value = 0,
		},
		.set_control = setlightfreq
	},
};

static const struct v4l2_pix_format ov772x_mode[] = {
	{320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
@@ -972,12 +800,10 @@ static void set_frame_rate(struct gspca_dev *gspca_dev)
	PDEBUG(D_PROBE, "frame_rate: %d", r->fps);
}

static void sethue(struct gspca_dev *gspca_dev)
static void sethue(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;
	int val;

	val = sd->ctrls[HUE].val;
	if (sd->sensor == SENSOR_OV767x) {
		/* TBD */
	} else {
@@ -1014,12 +840,10 @@ static void sethue(struct gspca_dev *gspca_dev)
	}
}

static void setsaturation(struct gspca_dev *gspca_dev)
static void setsaturation(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;
	int val;

	val = sd->ctrls[SATURATION].val;
	if (sd->sensor == SENSOR_OV767x) {
		int i;
		static u8 color_tb[][6] = {
@@ -1040,12 +864,10 @@ static void setsaturation(struct gspca_dev *gspca_dev)
	}
}

static void setbrightness(struct gspca_dev *gspca_dev)
static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;
	int val;

	val = sd->ctrls[BRIGHTNESS].val;
	if (sd->sensor == SENSOR_OV767x) {
		if (val < 0)
			val = 0x80 - val;
@@ -1055,27 +877,18 @@ static void setbrightness(struct gspca_dev *gspca_dev)
	}
}

static void setcontrast(struct gspca_dev *gspca_dev)
static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;
	u8 val;

	val = sd->ctrls[CONTRAST].val;
	if (sd->sensor == SENSOR_OV767x)
		sccb_reg_write(gspca_dev, 0x56, val);	/* contras */
	else
		sccb_reg_write(gspca_dev, 0x9c, val);
}

static void setgain(struct gspca_dev *gspca_dev)
static void setgain(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;
	u8 val;

	if (sd->ctrls[AGC].val)
		return;

	val = sd->ctrls[GAIN].val;
	switch (val & 0x30) {
	case 0x00:
		val &= 0x0f;
@@ -1097,15 +910,15 @@ static void setgain(struct gspca_dev *gspca_dev)
	sccb_reg_write(gspca_dev, 0x00, val);
}

static void setexposure(struct gspca_dev *gspca_dev)
static s32 getgain(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	u8 val;
	return sccb_reg_read(gspca_dev, 0x00);
}

	if (sd->ctrls[AEC].val)
		return;
static void setexposure(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	val = sd->ctrls[EXPOSURE].val;
	if (sd->sensor == SENSOR_OV767x) {

		/* set only aec[9:2] */
@@ -1123,11 +936,23 @@ static void setexposure(struct gspca_dev *gspca_dev)
	}
}

static void setagc(struct gspca_dev *gspca_dev)
static s32 getexposure(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;

	if (sd->ctrls[AGC].val) {
	if (sd->sensor == SENSOR_OV767x) {
		/* get only aec[9:2] */
		return sccb_reg_read(gspca_dev, 0x10);	/* aech */
	} else {
		u8 hi = sccb_reg_read(gspca_dev, 0x08);
		u8 lo = sccb_reg_read(gspca_dev, 0x10);
		return (hi << 8 | lo) >> 1;
	}
}

static void setagc(struct gspca_dev *gspca_dev, s32 val)
{
	if (val) {
		sccb_reg_write(gspca_dev, 0x13,
				sccb_reg_read(gspca_dev, 0x13) | 0x04);
		sccb_reg_write(gspca_dev, 0x64,
@@ -1137,16 +962,14 @@ static void setagc(struct gspca_dev *gspca_dev)
				sccb_reg_read(gspca_dev, 0x13) & ~0x04);
		sccb_reg_write(gspca_dev, 0x64,
				sccb_reg_read(gspca_dev, 0x64) & ~0x03);

		setgain(gspca_dev);
	}
}

static void setawb(struct gspca_dev *gspca_dev)
static void setawb(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	if (sd->ctrls[AWB].val) {
	if (val) {
		sccb_reg_write(gspca_dev, 0x13,
				sccb_reg_read(gspca_dev, 0x13) | 0x02);
		if (sd->sensor == SENSOR_OV772x)
@@ -1161,7 +984,7 @@ static void setawb(struct gspca_dev *gspca_dev)
	}
}

static void setaec(struct gspca_dev *gspca_dev)
static void setaec(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;
	u8 data;
@@ -1169,31 +992,25 @@ static void setaec(struct gspca_dev *gspca_dev)
	data = sd->sensor == SENSOR_OV767x ?
			0x05 :		/* agc + aec */
			0x01;		/* agc */
	if (sd->ctrls[AEC].val)
	switch (val) {
	case V4L2_EXPOSURE_AUTO:
		sccb_reg_write(gspca_dev, 0x13,
				sccb_reg_read(gspca_dev, 0x13) | data);
	else {
		break;
	case V4L2_EXPOSURE_MANUAL:
		sccb_reg_write(gspca_dev, 0x13,
				sccb_reg_read(gspca_dev, 0x13) & ~data);
		if (sd->sensor == SENSOR_OV767x)
			sd->ctrls[EXPOSURE].val =
				sccb_reg_read(gspca_dev, 10);	/* aech */
		else
			setexposure(gspca_dev);
		break;
	}
}

static void setsharpness(struct gspca_dev *gspca_dev)
static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;
	u8 val;

	val = sd->ctrls[SHARPNESS].val;
	sccb_reg_write(gspca_dev, 0x91, val);	/* Auto de-noise threshold */
	sccb_reg_write(gspca_dev, 0x8e, val);	/* De-noise threshold */
}

static void sethvflip(struct gspca_dev *gspca_dev)
static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
{
	struct sd *sd = (struct sd *) gspca_dev;
	u8 val;
@@ -1201,28 +1018,27 @@ static void sethvflip(struct gspca_dev *gspca_dev)
	if (sd->sensor == SENSOR_OV767x) {
		val = sccb_reg_read(gspca_dev, 0x1e);	/* mvfp */
		val &= ~0x30;
		if (sd->ctrls[HFLIP].val)
		if (hflip)
			val |= 0x20;
		if (sd->ctrls[VFLIP].val)
		if (vflip)
			val |= 0x10;
		sccb_reg_write(gspca_dev, 0x1e, val);
	} else {
		val = sccb_reg_read(gspca_dev, 0x0c);
		val &= ~0xc0;
		if (sd->ctrls[HFLIP].val == 0)
		if (hflip == 0)
			val |= 0x40;
		if (sd->ctrls[VFLIP].val == 0)
		if (vflip == 0)
			val |= 0x80;
		sccb_reg_write(gspca_dev, 0x0c, val);
	}
}

static void setlightfreq(struct gspca_dev *gspca_dev)
static void setlightfreq(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;
	u8 val;

	val = sd->ctrls[LIGHTFREQ].val ? 0x9e : 0x00;
	val = val ? 0x9e : 0x00;
	if (sd->sensor == SENSOR_OV767x) {
		sccb_reg_write(gspca_dev, 0x2a, 0x00);
		if (val)
@@ -1241,8 +1057,6 @@ static int sd_config(struct gspca_dev *gspca_dev,

	cam = &gspca_dev->cam;

	cam->ctrls = sd->ctrls;

	cam->cam_mode = ov772x_mode;
	cam->nmodes = ARRAY_SIZE(ov772x_mode);

@@ -1251,6 +1065,195 @@ static int sd_config(struct gspca_dev *gspca_dev,
	return 0;
}

static int ov534_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
	struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler);
	struct gspca_dev *gspca_dev = &sd->gspca_dev;

	switch (ctrl->id) {
	case V4L2_CID_AUTOGAIN:
		gspca_dev->usb_err = 0;
		if (ctrl->val && sd->gain && gspca_dev->streaming)
			sd->gain->val = getgain(gspca_dev);
		return gspca_dev->usb_err;

	case V4L2_CID_EXPOSURE_AUTO:
		gspca_dev->usb_err = 0;
		if (ctrl->val == V4L2_EXPOSURE_AUTO && sd->exposure &&
		    gspca_dev->streaming)
			sd->exposure->val = getexposure(gspca_dev);
		return gspca_dev->usb_err;
	}
	return -EINVAL;
}

static int ov534_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler);
	struct gspca_dev *gspca_dev = &sd->gspca_dev;

	gspca_dev->usb_err = 0;
	if (!gspca_dev->streaming)
		return 0;

	switch (ctrl->id) {
	case V4L2_CID_HUE:
		sethue(gspca_dev, ctrl->val);
		break;
	case V4L2_CID_SATURATION:
		setsaturation(gspca_dev, ctrl->val);
		break;
	case V4L2_CID_BRIGHTNESS:
		setbrightness(gspca_dev, ctrl->val);
		break;
	case V4L2_CID_CONTRAST:
		setcontrast(gspca_dev, ctrl->val);
		break;
	case V4L2_CID_AUTOGAIN:
	/* case V4L2_CID_GAIN: */
		setagc(gspca_dev, ctrl->val);
		if (!gspca_dev->usb_err && !ctrl->val && sd->gain)
			setgain(gspca_dev, sd->gain->val);
		break;
	case V4L2_CID_AUTO_WHITE_BALANCE:
		setawb(gspca_dev, ctrl->val);
		break;
	case V4L2_CID_EXPOSURE_AUTO:
	/* case V4L2_CID_EXPOSURE: */
		setaec(gspca_dev, ctrl->val);
		if (!gspca_dev->usb_err && ctrl->val == V4L2_EXPOSURE_MANUAL &&
		    sd->exposure)
			setexposure(gspca_dev, sd->exposure->val);
		break;
	case V4L2_CID_SHARPNESS:
		setsharpness(gspca_dev, ctrl->val);
		break;
	case V4L2_CID_HFLIP:
		sethvflip(gspca_dev, ctrl->val, sd->vflip->val);
		break;
	case V4L2_CID_VFLIP:
		sethvflip(gspca_dev, sd->hflip->val, ctrl->val);
		break;
	case V4L2_CID_POWER_LINE_FREQUENCY:
		setlightfreq(gspca_dev, ctrl->val);
		break;
	}
	return gspca_dev->usb_err;
}

static const struct v4l2_ctrl_ops ov534_ctrl_ops = {
	.g_volatile_ctrl = ov534_g_volatile_ctrl,
	.s_ctrl = ov534_s_ctrl,
};

static int sd_init_controls(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct v4l2_ctrl_handler *hdl = &sd->ctrl_handler;
	/* parameters with different values between the supported sensors */
	int saturation_min;
	int saturation_max;
	int saturation_def;
	int brightness_min;
	int brightness_max;
	int brightness_def;
	int contrast_max;
	int contrast_def;
	int exposure_min;
	int exposure_max;
	int exposure_def;
	int hflip_def;

	if (sd->sensor == SENSOR_OV767x) {
		saturation_min = 0,
		saturation_max = 6,
		saturation_def = 3,
		brightness_min = -127;
		brightness_max = 127;
		brightness_def = 0;
		contrast_max = 0x80;
		contrast_def = 0x40;
		exposure_min = 0x08;
		exposure_max = 0x60;
		exposure_def = 0x13;
		hflip_def = 1;
	} else {
		saturation_min = 0,
		saturation_max = 255,
		saturation_def = 64,
		brightness_min = 0;
		brightness_max = 255;
		brightness_def = 0;
		contrast_max = 255;
		contrast_def = 32;
		exposure_min = 0;
		exposure_max = 255;
		exposure_def = 120;
		hflip_def = 0;
	}

	gspca_dev->vdev.ctrl_handler = hdl;

	v4l2_ctrl_handler_init(hdl, 13);

	if (sd->sensor == SENSOR_OV772x)
		sd->hue = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
				V4L2_CID_HUE, -90, 90, 1, 0);

	sd->saturation = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
			V4L2_CID_SATURATION, saturation_min, saturation_max, 1,
			saturation_def);
	sd->brightness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
			V4L2_CID_BRIGHTNESS, brightness_min, brightness_max, 1,
			brightness_def);
	sd->contrast = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
			V4L2_CID_CONTRAST, 0, contrast_max, 1, contrast_def);

	if (sd->sensor == SENSOR_OV772x) {
		sd->autogain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
				V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
		sd->gain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
				V4L2_CID_GAIN, 0, 63, 1, 20);
	}

	sd->autoexposure = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops,
			V4L2_CID_EXPOSURE_AUTO,
			V4L2_EXPOSURE_MANUAL, 0,
			V4L2_EXPOSURE_AUTO);
	sd->exposure = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
			V4L2_CID_EXPOSURE, exposure_min, exposure_max, 1,
			exposure_def);

	sd->autowhitebalance = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
			V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);

	if (sd->sensor == SENSOR_OV772x)
		sd->sharpness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
				V4L2_CID_SHARPNESS, 0, 63, 1, 0);

	sd->hflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
			V4L2_CID_HFLIP, 0, 1, 1, hflip_def);
	sd->vflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops,
			V4L2_CID_VFLIP, 0, 1, 1, 0);
	sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops,
			V4L2_CID_POWER_LINE_FREQUENCY,
			V4L2_CID_POWER_LINE_FREQUENCY_50HZ, 0,
			V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);

	if (hdl->error) {
		pr_err("Could not initialize controls\n");
		return hdl->error;
	}

	if (sd->sensor == SENSOR_OV772x)
		v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true);

	v4l2_ctrl_auto_cluster(2, &sd->autoexposure, V4L2_EXPOSURE_MANUAL,
			       true);

	return 0;
}

/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
@@ -1286,24 +1289,6 @@ static int sd_init(struct gspca_dev *gspca_dev)

	if ((sensor_id & 0xfff0) == 0x7670) {
		sd->sensor = SENSOR_OV767x;
		gspca_dev->ctrl_dis = (1 << HUE) |
					(1 << GAIN) |
					(1 << AGC) |
					(1 << SHARPNESS);	/* auto */
		sd->ctrls[SATURATION].min = 0,
		sd->ctrls[SATURATION].max = 6,
		sd->ctrls[SATURATION].def = 3,
		sd->ctrls[BRIGHTNESS].min = -127;
		sd->ctrls[BRIGHTNESS].max = 127;
		sd->ctrls[BRIGHTNESS].def = 0;
		sd->ctrls[CONTRAST].max = 0x80;
		sd->ctrls[CONTRAST].def = 0x40;
		sd->ctrls[EXPOSURE].min = 0x08;
		sd->ctrls[EXPOSURE].max = 0x60;
		sd->ctrls[EXPOSURE].def = 0x13;
		sd->ctrls[SHARPNESS].max = 9;
		sd->ctrls[SHARPNESS].def = 4;
		sd->ctrls[HFLIP].def = 1;
		gspca_dev->cam.cam_mode = ov767x_mode;
		gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode);
	} else {
@@ -1366,22 +1351,23 @@ static int sd_start(struct gspca_dev *gspca_dev)

	set_frame_rate(gspca_dev);

	if (!(gspca_dev->ctrl_dis & (1 << HUE)))
		sethue(gspca_dev);
	setsaturation(gspca_dev);
	if (!(gspca_dev->ctrl_dis & (1 << AGC)))
		setagc(gspca_dev);
	setawb(gspca_dev);
	setaec(gspca_dev);
	if (!(gspca_dev->ctrl_dis & (1 << GAIN)))
		setgain(gspca_dev);
	setexposure(gspca_dev);
	setbrightness(gspca_dev);
	setcontrast(gspca_dev);
	if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS)))
		setsharpness(gspca_dev);
	sethvflip(gspca_dev);
	setlightfreq(gspca_dev);
	if (sd->hue)
		sethue(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue));
	setsaturation(gspca_dev, v4l2_ctrl_g_ctrl(sd->saturation));
	if (sd->autogain)
		setagc(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));
	setawb(gspca_dev, v4l2_ctrl_g_ctrl(sd->autowhitebalance));
	setaec(gspca_dev, v4l2_ctrl_g_ctrl(sd->autoexposure));
	if (sd->gain)
		setgain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
	setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
	setbrightness(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness));
	setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast));
	if (sd->sharpness)
		setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness));
	sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
		  v4l2_ctrl_g_ctrl(sd->vflip));
	setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq));

	ov534_set_led(gspca_dev, 1);
	ov534_reg_write(gspca_dev, 0xe0, 0x00);
@@ -1483,25 +1469,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
	} while (remaining_len > 0);
}

static int sd_querymenu(struct gspca_dev *gspca_dev,
		struct v4l2_querymenu *menu)
{
	switch (menu->id) {
	case V4L2_CID_POWER_LINE_FREQUENCY:
		switch (menu->index) {
		case 0:         /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
			strcpy((char *) menu->name, "Disabled");
			return 0;
		case 1:         /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
			strcpy((char *) menu->name, "50 Hz");
			return 0;
		}
		break;
	}

	return -EINVAL;
}

/* get stream parameters (framerate) */
static void sd_get_streamparm(struct gspca_dev *gspca_dev,
			     struct v4l2_streamparm *parm)
@@ -1536,14 +1503,12 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev,
/* sub-driver description */
static const struct sd_desc sd_desc = {
	.name     = MODULE_NAME,
	.ctrls    = sd_ctrls,
	.nctrls   = ARRAY_SIZE(sd_ctrls),
	.config   = sd_config,
	.init     = sd_init,
	.init_controls = sd_init_controls,
	.start    = sd_start,
	.stopN    = sd_stopN,
	.pkt_scan = sd_pkt_scan,
	.querymenu = sd_querymenu,
	.get_streamparm = sd_get_streamparm,
	.set_streamparm = sd_set_streamparm,
};