Commit c06ba280 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[media] gspca_zc3xx: Convert to the control framework



The initial version was done by HV, corrections were made by HdG, and some
final small changes again by HV.

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 1b3bbcf5
Loading
Loading
Loading
Loading
+170 −268
Original line number Diff line number Diff line
@@ -35,26 +35,23 @@ static int force_sensor = -1;
#define REG08_DEF 3		/* default JPEG compression (75%) */
#include "zc3xx-reg.h"

/* controls */
enum e_ctrl {
	BRIGHTNESS,
	CONTRAST,
	EXPOSURE,
	GAMMA,
	AUTOGAIN,
	LIGHTFREQ,
	SHARPNESS,
	QUALITY,
	NCTRLS		/* number of controls */
};

#define AUTOGAIN_DEF 1

/* 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 { /* gamma/brightness/contrast control cluster */
		struct v4l2_ctrl *gamma;
		struct v4l2_ctrl *brightness;
		struct v4l2_ctrl *contrast;
	};
	struct { /* autogain/exposure control cluster */
		struct v4l2_ctrl *autogain;
		struct v4l2_ctrl *exposure;
	};
	struct v4l2_ctrl *plfreq;
	struct v4l2_ctrl *sharpness;
	struct v4l2_ctrl *jpegqual;

	struct work_struct work;
	struct workqueue_struct *work_thread;
@@ -94,114 +91,6 @@ enum sensors {
	SENSOR_MAX
};

/* V4L2 controls supported by the driver */
static void setcontrast(struct gspca_dev *gspca_dev);
static void setexposure(struct gspca_dev *gspca_dev);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static void setlightfreq(struct gspca_dev *gspca_dev);
static void setsharpness(struct gspca_dev *gspca_dev);
static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val);

static const struct ctrl sd_ctrls[NCTRLS] = {
[BRIGHTNESS] = {
	    {
		.id      = V4L2_CID_BRIGHTNESS,
		.type    = V4L2_CTRL_TYPE_INTEGER,
		.name    = "Brightness",
		.minimum = 0,
		.maximum = 255,
		.step    = 1,
		.default_value = 128,
	    },
	    .set_control = setcontrast
	},
[CONTRAST] = {
	    {
		.id      = V4L2_CID_CONTRAST,
		.type    = V4L2_CTRL_TYPE_INTEGER,
		.name    = "Contrast",
		.minimum = 0,
		.maximum = 255,
		.step    = 1,
		.default_value = 128,
	    },
	    .set_control = setcontrast
	},
[EXPOSURE] = {
	    {
		.id      = V4L2_CID_EXPOSURE,
		.type    = V4L2_CTRL_TYPE_INTEGER,
		.name    = "Exposure",
		.minimum = 0x30d,
		.maximum	= 0x493e,
		.step		= 1,
		.default_value  = 0x927
	    },
	    .set_control = setexposure
	},
[GAMMA] = {
	    {
		.id      = V4L2_CID_GAMMA,
		.type    = V4L2_CTRL_TYPE_INTEGER,
		.name    = "Gamma",
		.minimum = 1,
		.maximum = 6,
		.step    = 1,
		.default_value = 4,
	    },
	    .set_control = setcontrast
	},
[AUTOGAIN] = {
	    {
		.id      = V4L2_CID_AUTOGAIN,
		.type    = V4L2_CTRL_TYPE_BOOLEAN,
		.name    = "Auto Gain",
		.minimum = 0,
		.maximum = 1,
		.step    = 1,
		.default_value = AUTOGAIN_DEF,
		.flags   = V4L2_CTRL_FLAG_UPDATE
	    },
	    .set = sd_setautogain
	},
[LIGHTFREQ] = {
	    {
		.id	 = V4L2_CID_POWER_LINE_FREQUENCY,
		.type    = V4L2_CTRL_TYPE_MENU,
		.name    = "Light frequency filter",
		.minimum = 0,
		.maximum = 2,	/* 0: 0, 1: 50Hz, 2:60Hz */
		.step    = 1,
		.default_value = 0,
	    },
	    .set_control = setlightfreq
	},
[SHARPNESS] = {
	    {
		.id	 = V4L2_CID_SHARPNESS,
		.type    = V4L2_CTRL_TYPE_INTEGER,
		.name    = "Sharpness",
		.minimum = 0,
		.maximum = 3,
		.step    = 1,
		.default_value = 2,
	    },
	    .set_control = setsharpness
	},
[QUALITY] = {
	    {
		.id	 = V4L2_CID_JPEG_COMPRESSION_QUALITY,
		.type    = V4L2_CTRL_TYPE_INTEGER,
		.name    = "Compression Quality",
		.minimum = 50,
		.maximum = 87,
		.step    = 1,
		.default_value = 75,
	    },
	    .set = sd_setquality
	},
};

static const struct v4l2_pix_format vga_mode[] = {
	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
		.bytesperline = 320,
@@ -5821,10 +5710,8 @@ static void setmatrix(struct gspca_dev *gspca_dev)
		reg_w(gspca_dev, matrix[i], 0x010a + i);
}

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;
	int sharpness;
	static const u8 sharpness_tb[][2] = {
		{0x02, 0x03},
		{0x04, 0x07},
@@ -5832,19 +5719,18 @@ static void setsharpness(struct gspca_dev *gspca_dev)
		{0x10, 0x1e}
	};

	sharpness = sd->ctrls[SHARPNESS].val;
	reg_w(gspca_dev, sharpness_tb[sharpness][0], 0x01c6);
	reg_w(gspca_dev, sharpness_tb[val][0], 0x01c6);
	reg_r(gspca_dev, 0x01c8);
	reg_r(gspca_dev, 0x01c9);
	reg_r(gspca_dev, 0x01ca);
	reg_w(gspca_dev, sharpness_tb[sharpness][1], 0x01cb);
	reg_w(gspca_dev, sharpness_tb[val][1], 0x01cb);
}

static void setcontrast(struct gspca_dev *gspca_dev)
static void setcontrast(struct gspca_dev *gspca_dev,
		s32 gamma, s32 brightness, s32 contrast)
{
	struct sd *sd = (struct sd *) gspca_dev;
	const u8 *Tgamma;
	int g, i, brightness, contrast, adj, gp1, gp2;
	int g, i, adj, gp1, gp2;
	u8 gr[16];
	static const u8 delta_b[16] =		/* delta for brightness */
		{0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d,
@@ -5867,10 +5753,10 @@ static void setcontrast(struct gspca_dev *gspca_dev)
		 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff},
	};

	Tgamma = gamma_tb[sd->ctrls[GAMMA].val - 1];
	Tgamma = gamma_tb[gamma - 1];

	contrast = ((int) sd->ctrls[CONTRAST].val - 128); /* -128 / 127 */
	brightness = ((int) sd->ctrls[BRIGHTNESS].val - 128); /* -128 / 92 */
	contrast -= 128; /* -128 / 127 */
	brightness -= 128; /* -128 / 92 */
	adj = 0;
	gp1 = gp2 = 0;
	for (i = 0; i < 16; i++) {
@@ -5897,25 +5783,15 @@ static void setcontrast(struct gspca_dev *gspca_dev)
		reg_w(gspca_dev, gr[i], 0x0130 + i);	/* gradient */
}

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

	if (sd->sensor != SENSOR_HV7131R)
		return;
	sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9)
	return (i2c_read(gspca_dev, 0x25) << 9)
		| (i2c_read(gspca_dev, 0x26) << 1)
		| (i2c_read(gspca_dev, 0x27) >> 7);
}

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

	if (sd->sensor != SENSOR_HV7131R)
		return;
	val = sd->ctrls[EXPOSURE].val;
	i2c_write(gspca_dev, 0x25, val >> 9, 0x00);
	i2c_write(gspca_dev, 0x26, val >> 1, 0x00);
	i2c_write(gspca_dev, 0x27, val << 7, 0x00);
@@ -5934,7 +5810,7 @@ static void setquality(struct gspca_dev *gspca_dev)
 *	60Hz, for American lighting
 *	0 = No Fliker (for outdoore usage)
 */
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;
	int i, mode;
@@ -6018,7 +5894,7 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
		 tas5130c_60HZ, tas5130c_60HZScale},
	};

	i = sd->ctrls[LIGHTFREQ].val * 2;
	i = val * 2;
	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
	if (mode)
		i++;			/* 320x240 */
@@ -6029,13 +5905,13 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
	switch (sd->sensor) {
	case SENSOR_GC0305:
		if (mode		/* if 320x240 */
		    && sd->ctrls[LIGHTFREQ].val == 1)	/* and 50Hz */
		    && val == 1)	/* and 50Hz */
			reg_w(gspca_dev, 0x85, 0x018d);
					/* win: 0x80, 0x018d */
		break;
	case SENSOR_OV7620:
		if (!mode) {		/* if 640x480 */
			if (sd->ctrls[LIGHTFREQ].val != 0) /* and filter */
			if (val != 0)	/* and filter */
				reg_w(gspca_dev, 0x40, 0x0002);
			else
				reg_w(gspca_dev, 0x44, 0x0002);
@@ -6047,16 +5923,9 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
	}
}

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

	if (sd->ctrls[AUTOGAIN].val)
		autoval = 0x42;
	else
		autoval = 0x02;
	reg_w(gspca_dev, autoval, 0x0180);
	reg_w(gspca_dev, val ? 0x42 : 0x02, 0x0180);
}

/*
@@ -6450,7 +6319,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
	/* define some sensors from the vendor/product */
	sd->sensor = id->driver_info;

	gspca_dev->cam.ctrls = sd->ctrls;
	sd->reg08 = REG08_DEF;

	INIT_WORK(&sd->work, transfer_update);
@@ -6458,12 +6326,85 @@ static int sd_config(struct gspca_dev *gspca_dev,
	return 0;
}

/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
static int zcxx_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->exposure && gspca_dev->streaming)
			sd->exposure->val = getexposure(gspca_dev);
		return gspca_dev->usb_err;
	}
	return -EINVAL;
}

static int zcxx_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;
	int i, qual;

	gspca_dev->usb_err = 0;

	if (ctrl->id == V4L2_CID_JPEG_COMPRESSION_QUALITY) {
		qual = sd->reg08 >> 1;

		for (i = 0; i < ARRAY_SIZE(jpeg_qual); i++) {
			if (ctrl->val <= jpeg_qual[i])
				break;
		}
		if (i > 0 && i == qual && ctrl->val < jpeg_qual[i])
			i--;

		/* With high quality settings we need max bandwidth */
		if (i >= 2 && gspca_dev->streaming &&
		    !gspca_dev->cam.needs_full_bandwidth)
			return -EBUSY;

		sd->reg08 = (i << 1) | 1;
		ctrl->val = jpeg_qual[i];
	}

	if (!gspca_dev->streaming)
		return 0;

	switch (ctrl->id) {
	/* gamma/brightness/contrast cluster */
	case V4L2_CID_GAMMA:
		setcontrast(gspca_dev, sd->gamma->val,
				sd->brightness->val, sd->contrast->val);
		break;
	/* autogain/exposure cluster */
	case V4L2_CID_AUTOGAIN:
		setautogain(gspca_dev, ctrl->val);
		if (!gspca_dev->usb_err && !ctrl->val && sd->exposure)
			setexposure(gspca_dev, sd->exposure->val);
		break;
	case V4L2_CID_POWER_LINE_FREQUENCY:
		setlightfreq(gspca_dev, ctrl->val);
		break;
	case V4L2_CID_SHARPNESS:
		setsharpness(gspca_dev, ctrl->val);
		break;
	case V4L2_CID_JPEG_COMPRESSION_QUALITY:
		setquality(gspca_dev);
		break;
	}
	return gspca_dev->usb_err;
}

static const struct v4l2_ctrl_ops zcxx_ctrl_ops = {
	.g_volatile_ctrl = zcxx_g_volatile_ctrl,
	.s_ctrl = zcxx_s_ctrl,
};

static int sd_init_controls(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *)gspca_dev;
	struct cam *cam;
	int sensor;
	struct v4l2_ctrl_handler *hdl = &sd->ctrl_handler;
	static const u8 gamma[SENSOR_MAX] = {
		[SENSOR_ADCM2700] =	4,
		[SENSOR_CS2102] =	4,
@@ -6485,6 +6426,48 @@ static int sd_init(struct gspca_dev *gspca_dev)
		[SENSOR_PO2030] =	4,
		[SENSOR_TAS5130C] =	3,
	};

	gspca_dev->vdev.ctrl_handler = hdl;
	v4l2_ctrl_handler_init(hdl, 8);
	sd->brightness = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
	sd->contrast = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
			V4L2_CID_CONTRAST, 0, 255, 1, 128);
	sd->gamma = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
			V4L2_CID_GAMMA, 1, 6, 1, gamma[sd->sensor]);
	if (sd->sensor == SENSOR_HV7131R)
		sd->exposure = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
			V4L2_CID_EXPOSURE, 0x30d, 0x493e, 1, 0x927);
	sd->autogain = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
	if (sd->sensor != SENSOR_OV7630C)
		sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &zcxx_ctrl_ops,
			V4L2_CID_POWER_LINE_FREQUENCY,
			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
			V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
	sd->sharpness = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
			V4L2_CID_SHARPNESS, 0, 3, 1,
			sd->sensor == SENSOR_PO2030 ? 0 : 2);
	sd->jpegqual = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
			V4L2_CID_JPEG_COMPRESSION_QUALITY,
			jpeg_qual[0], jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1], 1,
			jpeg_qual[REG08_DEF >> 1]);
	if (hdl->error) {
		pr_err("Could not initialize controls\n");
		return hdl->error;
	}
	v4l2_ctrl_cluster(3, &sd->gamma);
	if (sd->sensor == SENSOR_HV7131R)
		v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true);
	return 0;
}

/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct cam *cam;
	int sensor;
	static const u8 mode_tb[SENSOR_MAX] = {
		[SENSOR_ADCM2700] =	2,
		[SENSOR_CS2102] =	1,
@@ -6614,7 +6597,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
		case 0x2030:
			PDEBUG(D_PROBE, "Find Sensor PO2030");
			sd->sensor = SENSOR_PO2030;
			sd->ctrls[SHARPNESS].def = 0;	/* from win traces */
			break;
		case 0x7620:
			PDEBUG(D_PROBE, "Find Sensor OV7620");
@@ -6656,26 +6638,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
		break;
	}

	sd->ctrls[GAMMA].def = gamma[sd->sensor];
	sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08 >> 1];
	sd->ctrls[QUALITY].min = jpeg_qual[0];
	sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1];

	switch (sd->sensor) {
	case SENSOR_HV7131R:
		break;
	case SENSOR_OV7630C:
		gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
		break;
	default:
		gspca_dev->ctrl_dis = (1 << EXPOSURE);
		break;
	}
#if AUTOGAIN_DEF
	if (sd->ctrls[AUTOGAIN].val)
		gspca_dev->ctrl_inac = (1 << EXPOSURE);
#endif

	/* switch off the led */
	reg_w(gspca_dev, 0x01, 0x0000);
	return gspca_dev->usb_err;
@@ -6792,7 +6754,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
		reg_w(gspca_dev, 0x03, 0x0008);
		break;
	}
	setsharpness(gspca_dev);
	setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness));

	/* set the gamma tables when not set */
	switch (sd->sensor) {
@@ -6801,7 +6763,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
	case SENSOR_OV7630C:
		break;
	default:
		setcontrast(gspca_dev);
		setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma),
				v4l2_ctrl_g_ctrl(sd->brightness),
				v4l2_ctrl_g_ctrl(sd->contrast));
		break;
	}
	setmatrix(gspca_dev);			/* one more time? */
@@ -6815,7 +6779,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
	setquality(gspca_dev);
	/* Start with BRC disabled, transfer_update will enable it if needed */
	reg_w(gspca_dev, 0x00, 0x0007);
	setlightfreq(gspca_dev);
	if (sd->plfreq)
		setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq));

	switch (sd->sensor) {
	case SENSOR_ADCM2700:
@@ -6826,7 +6791,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
		reg_w(gspca_dev, 0x40, 0x0117);
		break;
	case SENSOR_HV7131R:
		setexposure(gspca_dev);
		setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
		reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
		break;
	case SENSOR_GC0305:
@@ -6850,7 +6815,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
		break;
	}

	setautogain(gspca_dev);
	setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));

	if (gspca_dev->usb_err < 0)
		return gspca_dev->usb_err;
@@ -6911,79 +6876,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}

static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->ctrls[AUTOGAIN].val = val;
	if (val) {
		gspca_dev->ctrl_inac |= (1 << EXPOSURE);
	} else {
		gspca_dev->ctrl_inac &= ~(1 << EXPOSURE);
		if (gspca_dev->streaming)
			getexposure(gspca_dev);
	}
	if (gspca_dev->streaming)
		setautogain(gspca_dev);
	return gspca_dev->usb_err;
}

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, "NoFliker");
			return 0;
		case 1:		/* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
			strcpy((char *) menu->name, "50 Hz");
			return 0;
		case 2:		/* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
			strcpy((char *) menu->name, "60 Hz");
			return 0;
		}
		break;
	}
	return -EINVAL;
}

static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;
	int i, qual = sd->reg08 >> 1;

	for (i = 0; i < ARRAY_SIZE(jpeg_qual); i++) {
		if (val <= jpeg_qual[i])
			break;
	}
	if (i > 0
	 && i == qual
	 && val < jpeg_qual[i])
		i--;

	/* With high quality settings we need max bandwidth */
	if (i >= 2 && gspca_dev->streaming &&
	    !gspca_dev->cam.needs_full_bandwidth)
		return -EBUSY;

	sd->reg08 = (i << 1) | 1;
	sd->ctrls[QUALITY].val = jpeg_qual[i];

	if (gspca_dev->streaming)
		setquality(gspca_dev);
	return gspca_dev->usb_err;
}

static int sd_set_jcomp(struct gspca_dev *gspca_dev,
			struct v4l2_jpegcompression *jcomp)
{
	struct sd *sd = (struct sd *) gspca_dev;
	int ret;

	sd_setquality(gspca_dev, jcomp->quality);
	jcomp->quality = sd->ctrls[QUALITY].val;
	return gspca_dev->usb_err;
	ret = v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
	if (ret)
		return ret;
	jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
	return 0;
}

static int sd_get_jcomp(struct gspca_dev *gspca_dev,
@@ -6992,7 +6895,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
	struct sd *sd = (struct sd *) gspca_dev;

	memset(jcomp, 0, sizeof *jcomp);
	jcomp->quality = sd->ctrls[QUALITY].val;
	jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
	jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
			| V4L2_JPEG_MARKER_DQT;
	return 0;
@@ -7016,15 +6919,13 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,

static const struct sd_desc sd_desc = {
	.name = KBUILD_MODNAME,
	.ctrls = sd_ctrls,
	.nctrls = ARRAY_SIZE(sd_ctrls),
	.config = sd_config,
	.init = sd_init,
	.init_controls = sd_init_controls,
	.isoc_init = sd_pre_start,
	.start = sd_start,
	.stop0 = sd_stop0,
	.pkt_scan = sd_pkt_scan,
	.querymenu = sd_querymenu,
	.get_jcomp = sd_get_jcomp,
	.set_jcomp = sd_set_jcomp,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
@@ -7108,6 +7009,7 @@ static struct usb_driver sd_driver = {
#ifdef CONFIG_PM
	.suspend = gspca_suspend,
	.resume = gspca_resume,
	.reset_resume = gspca_resume,
#endif
};