diff options
Diffstat (limited to 'drivers/media/usb/gspca/m5602/m5602_po1030.c')
| -rw-r--r-- | drivers/media/usb/gspca/m5602/m5602_po1030.c | 461 | 
1 files changed, 108 insertions, 353 deletions
diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c index b8771698cbc..4bf5c43424b 100644 --- a/drivers/media/usb/gspca/m5602/m5602_po1030.c +++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c @@ -20,28 +20,8 @@  #include "m5602_po1030.h" -static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, -					 __s32 val); -static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, -					 __s32 *val); -static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, -					 __s32 val); -static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, -					 __s32 *val); +static int po1030_s_ctrl(struct v4l2_ctrl *ctrl); +static void po1030_dump_registers(struct sd *sd);  static struct v4l2_pix_format po1030_modes[] = {  	{ @@ -56,146 +36,26 @@ static struct v4l2_pix_format po1030_modes[] = {  	}  }; -static const struct ctrl po1030_ctrls[] = { -#define GAIN_IDX 0 -	{ -		{ -			.id		= V4L2_CID_GAIN, -			.type		= V4L2_CTRL_TYPE_INTEGER, -			.name		= "gain", -			.minimum	= 0x00, -			.maximum	= 0x4f, -			.step		= 0x1, -			.default_value	= PO1030_GLOBAL_GAIN_DEFAULT, -			.flags		= V4L2_CTRL_FLAG_SLIDER -		}, -		.set = po1030_set_gain, -		.get = po1030_get_gain -	}, -#define EXPOSURE_IDX 1 -	{ -		{ -			.id		= V4L2_CID_EXPOSURE, -			.type		= V4L2_CTRL_TYPE_INTEGER, -			.name		= "exposure", -			.minimum	= 0x00, -			.maximum	= 0x02ff, -			.step		= 0x1, -			.default_value	= PO1030_EXPOSURE_DEFAULT, -			.flags		= V4L2_CTRL_FLAG_SLIDER -		}, -		.set = po1030_set_exposure, -		.get = po1030_get_exposure -	}, -#define RED_BALANCE_IDX 2 -	{ -		{ -			.id		= V4L2_CID_RED_BALANCE, -			.type		= V4L2_CTRL_TYPE_INTEGER, -			.name		= "red balance", -			.minimum	= 0x00, -			.maximum	= 0xff, -			.step		= 0x1, -			.default_value	= PO1030_RED_GAIN_DEFAULT, -			.flags		= V4L2_CTRL_FLAG_SLIDER -		}, -		.set = po1030_set_red_balance, -		.get = po1030_get_red_balance -	}, -#define BLUE_BALANCE_IDX 3 -	{ -		{ -			.id		= V4L2_CID_BLUE_BALANCE, -			.type		= V4L2_CTRL_TYPE_INTEGER, -			.name		= "blue balance", -			.minimum	= 0x00, -			.maximum	= 0xff, -			.step		= 0x1, -			.default_value	= PO1030_BLUE_GAIN_DEFAULT, -			.flags		= V4L2_CTRL_FLAG_SLIDER -		}, -		.set = po1030_set_blue_balance, -		.get = po1030_get_blue_balance -	}, -#define HFLIP_IDX 4 -	{ -		{ -			.id		= V4L2_CID_HFLIP, -			.type		= V4L2_CTRL_TYPE_BOOLEAN, -			.name		= "horizontal flip", -			.minimum	= 0, -			.maximum	= 1, -			.step		= 1, -			.default_value	= 0, -		}, -		.set = po1030_set_hflip, -		.get = po1030_get_hflip -	}, -#define VFLIP_IDX 5 -	{ -		{ -			.id		= V4L2_CID_VFLIP, -			.type		= V4L2_CTRL_TYPE_BOOLEAN, -			.name		= "vertical flip", -			.minimum	= 0, -			.maximum	= 1, -			.step		= 1, -			.default_value	= 0, -		}, -		.set = po1030_set_vflip, -		.get = po1030_get_vflip -	}, -#define AUTO_WHITE_BALANCE_IDX 6 -	{ -		{ -			.id		= V4L2_CID_AUTO_WHITE_BALANCE, -			.type		= V4L2_CTRL_TYPE_BOOLEAN, -			.name		= "auto white balance", -			.minimum	= 0, -			.maximum	= 1, -			.step		= 1, -			.default_value	= 0, -		}, -		.set = po1030_set_auto_white_balance, -		.get = po1030_get_auto_white_balance -	}, -#define AUTO_EXPOSURE_IDX 7 -	{ -		{ -			.id		= V4L2_CID_EXPOSURE_AUTO, -			.type		= V4L2_CTRL_TYPE_BOOLEAN, -			.name		= "auto exposure", -			.minimum	= 0, -			.maximum	= 1, -			.step		= 1, -			.default_value	= 0, -		}, -		.set = po1030_set_auto_exposure, -		.get = po1030_get_auto_exposure -	}, -#define GREEN_BALANCE_IDX 8 -	{ -		{ -			.id		= M5602_V4L2_CID_GREEN_BALANCE, -			.type		= V4L2_CTRL_TYPE_INTEGER, -			.name		= "green balance", -			.minimum	= 0x00, -			.maximum	= 0xff, -			.step		= 0x1, -			.default_value	= PO1030_GREEN_GAIN_DEFAULT, -			.flags		= V4L2_CTRL_FLAG_SLIDER -		}, -		.set = po1030_set_green_balance, -		.get = po1030_get_green_balance -	}, +static const struct v4l2_ctrl_ops po1030_ctrl_ops = { +	.s_ctrl = po1030_s_ctrl,  }; -static void po1030_dump_registers(struct sd *sd); +static const struct v4l2_ctrl_config po1030_greenbal_cfg = { +	.ops	= &po1030_ctrl_ops, +	.id	= M5602_V4L2_CID_GREEN_BALANCE, +	.name	= "Green Balance", +	.type	= V4L2_CTRL_TYPE_INTEGER, +	.min	= 0, +	.max	= 255, +	.step	= 1, +	.def	= PO1030_GREEN_GAIN_DEFAULT, +	.flags	= V4L2_CTRL_FLAG_SLIDER, +};  int po1030_probe(struct sd *sd)  {  	u8 dev_id_h = 0, i; -	s32 *sensor_settings; +	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;  	if (force_sensor) {  		if (force_sensor == PO1030_SENSOR) { @@ -229,26 +89,14 @@ int po1030_probe(struct sd *sd)  	return -ENODEV;  sensor_found: -	sensor_settings = kmalloc( -		ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL); -	if (!sensor_settings) -		return -ENOMEM; -  	sd->gspca_dev.cam.cam_mode = po1030_modes;  	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes); -	sd->desc->ctrls = po1030_ctrls; -	sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls); - -	for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++) -		sensor_settings[i] = po1030_ctrls[i].qctrl.default_value; -	sd->sensor_priv = sensor_settings;  	return 0;  }  int po1030_init(struct sd *sd)  { -	s32 *sensor_settings = sd->sensor_priv;  	int i, err = 0;  	/* Init the sensor */ @@ -279,46 +127,50 @@ int po1030_init(struct sd *sd)  	if (dump_sensor)  		po1030_dump_registers(sd); -	err = po1030_set_exposure(&sd->gspca_dev, -				   sensor_settings[EXPOSURE_IDX]); -	if (err < 0) -		return err; +	return 0; +} -	err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); -	if (err < 0) -		return err; +int po1030_init_controls(struct sd *sd) +{ +	struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; -	err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); -	if (err < 0) -		return err; +	sd->gspca_dev.vdev.ctrl_handler = hdl; +	v4l2_ctrl_handler_init(hdl, 9); -	err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); -	if (err < 0) -		return err; +	sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, +					       V4L2_CID_AUTO_WHITE_BALANCE, +					       0, 1, 1, 0); +	sd->green_bal = v4l2_ctrl_new_custom(hdl, &po1030_greenbal_cfg, NULL); +	sd->red_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, +					V4L2_CID_RED_BALANCE, 0, 255, 1, +					PO1030_RED_GAIN_DEFAULT); +	sd->blue_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, +					V4L2_CID_BLUE_BALANCE, 0, 255, 1, +					PO1030_BLUE_GAIN_DEFAULT); -	err = po1030_set_red_balance(&sd->gspca_dev, -				      sensor_settings[RED_BALANCE_IDX]); -	if (err < 0) -		return err; +	sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &po1030_ctrl_ops, +			  V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_MANUAL); +	sd->expo = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_EXPOSURE, +			  0, 0x2ff, 1, PO1030_EXPOSURE_DEFAULT); -	err = po1030_set_blue_balance(&sd->gspca_dev, -				      sensor_settings[BLUE_BALANCE_IDX]); -	if (err < 0) -		return err; +	sd->gain = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_GAIN, 0, +				     0x4f, 1, PO1030_GLOBAL_GAIN_DEFAULT); -	err = po1030_set_green_balance(&sd->gspca_dev, -				       sensor_settings[GREEN_BALANCE_IDX]); -	if (err < 0) -		return err; +	sd->hflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_HFLIP, +				      0, 1, 1, 0); +	sd->vflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_VFLIP, +				      0, 1, 1, 0); -	err = po1030_set_auto_white_balance(&sd->gspca_dev, -				sensor_settings[AUTO_WHITE_BALANCE_IDX]); -	if (err < 0) -		return err; +	if (hdl->error) { +		pr_err("Could not initialize controls\n"); +		return hdl->error; +	} -	err = po1030_set_auto_exposure(&sd->gspca_dev, -				sensor_settings[AUTO_EXPOSURE_IDX]); -	return err; +	v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false); +	v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false); +	v4l2_ctrl_cluster(2, &sd->hflip); + +	return 0;  }  int po1030_start(struct sd *sd) @@ -448,28 +300,16 @@ int po1030_start(struct sd *sd)  	return err;  } -static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; - -	*val = sensor_settings[EXPOSURE_IDX]; -	PDEBUG(D_V4L2, "Exposure read as %d", *val); -	return 0; -} -  static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)  {  	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv;  	u8 i2c_data;  	int err; -	sensor_settings[EXPOSURE_IDX] = val; -	PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff); +	PDEBUG(D_CONF, "Set exposure to %d", val & 0xffff);  	i2c_data = ((val & 0xff00) >> 8); -	PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x", +	PDEBUG(D_CONF, "Set exposure to high byte to 0x%x",  	       i2c_data);  	err = m5602_write_sensor(sd, PO1030_INTEGLINES_H, @@ -478,7 +318,7 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)  		return err;  	i2c_data = (val & 0xff); -	PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x", +	PDEBUG(D_CONF, "Set exposure to low byte to 0x%x",  	       i2c_data);  	err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,  				  &i2c_data, 1); @@ -486,91 +326,32 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)  	return err;  } -static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; - -	*val = sensor_settings[GAIN_IDX]; -	PDEBUG(D_V4L2, "Read global gain %d", *val); -	return 0; -} -  static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)  {  	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv;  	u8 i2c_data;  	int err; -	sensor_settings[GAIN_IDX] = val; -  	i2c_data = val & 0xff; -	PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); +	PDEBUG(D_CONF, "Set global gain to %d", i2c_data);  	err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,  				 &i2c_data, 1);  	return err;  } -static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; - -	*val = sensor_settings[HFLIP_IDX]; -	PDEBUG(D_V4L2, "Read hflip %d", *val); - -	return 0; -} - -static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; -	u8 i2c_data; -	int err; - -	sensor_settings[HFLIP_IDX] = val; - -	PDEBUG(D_V4L2, "Set hflip %d", val); -	err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); -	if (err < 0) -		return err; - -	i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7); - -	err = m5602_write_sensor(sd, PO1030_CONTROL2, -				 &i2c_data, 1); - -	return err; -} - -static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; - -	*val = sensor_settings[VFLIP_IDX]; -	PDEBUG(D_V4L2, "Read vflip %d", *val); - -	return 0; -} - -static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +static int po1030_set_hvflip(struct gspca_dev *gspca_dev)  {  	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv;  	u8 i2c_data;  	int err; -	sensor_settings[VFLIP_IDX] = val; - -	PDEBUG(D_V4L2, "Set vflip %d", val); +	PDEBUG(D_CONF, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val);  	err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);  	if (err < 0)  		return err; -	i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6); +	i2c_data = (0x3f & i2c_data) | (sd->hflip->val << 7) | +		   (sd->vflip->val << 6);  	err = m5602_write_sensor(sd, PO1030_CONTROL2,  				 &i2c_data, 1); @@ -578,81 +359,41 @@ static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)  	return err;  } -static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; - -	*val = sensor_settings[RED_BALANCE_IDX]; -	PDEBUG(D_V4L2, "Read red gain %d", *val); -	return 0; -} -  static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)  {  	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv;  	u8 i2c_data;  	int err; -	sensor_settings[RED_BALANCE_IDX] = val; -  	i2c_data = val & 0xff; -	PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); +	PDEBUG(D_CONF, "Set red gain to %d", i2c_data);  	err = m5602_write_sensor(sd, PO1030_RED_GAIN,  				  &i2c_data, 1);  	return err;  } -static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; - -	*val = sensor_settings[BLUE_BALANCE_IDX]; -	PDEBUG(D_V4L2, "Read blue gain %d", *val); - -	return 0; -} -  static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)  {  	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv;  	u8 i2c_data;  	int err; -	sensor_settings[BLUE_BALANCE_IDX] = val; -  	i2c_data = val & 0xff; -	PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); +	PDEBUG(D_CONF, "Set blue gain to %d", i2c_data);  	err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,  				  &i2c_data, 1);  	return err;  } -static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; - -	*val = sensor_settings[GREEN_BALANCE_IDX]; -	PDEBUG(D_V4L2, "Read green gain %d", *val); - -	return 0; -} -  static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)  {  	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv;  	u8 i2c_data;  	int err; -	sensor_settings[GREEN_BALANCE_IDX] = val;  	i2c_data = val & 0xff; -	PDEBUG(D_V4L2, "Set green gain to %d", i2c_data); +	PDEBUG(D_CONF, "Set green gain to %d", i2c_data);  	err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,  			   &i2c_data, 1); @@ -663,63 +404,36 @@ static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)  				 &i2c_data, 1);  } -static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, -					 __s32 *val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; - -	*val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; -	PDEBUG(D_V4L2, "Auto white balancing is %d", *val); - -	return 0; -} -  static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,  					 __s32 val)  {  	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv;  	u8 i2c_data;  	int err; -	sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; -  	err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);  	if (err < 0)  		return err; -	PDEBUG(D_V4L2, "Set auto white balance to %d", val); +	PDEBUG(D_CONF, "Set auto white balance to %d", val);  	i2c_data = (i2c_data & 0xfe) | (val & 0x01);  	err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);  	return err;  } -static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, -				    __s32 *val) -{ -	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv; - -	*val = sensor_settings[AUTO_EXPOSURE_IDX]; -	PDEBUG(D_V4L2, "Auto exposure is %d", *val); -	return 0; -} -  static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,  				    __s32 val)  {  	struct sd *sd = (struct sd *) gspca_dev; -	s32 *sensor_settings = sd->sensor_priv;  	u8 i2c_data;  	int err; -	sensor_settings[AUTO_EXPOSURE_IDX] = val;  	err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);  	if (err < 0)  		return err; -	PDEBUG(D_V4L2, "Set auto exposure to %d", val); +	PDEBUG(D_CONF, "Set auto exposure to %d", val); +	val = (val == V4L2_EXPOSURE_AUTO);  	i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);  	return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);  } @@ -727,7 +441,48 @@ static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,  void po1030_disconnect(struct sd *sd)  {  	sd->sensor = NULL; -	kfree(sd->sensor_priv); +} + +static int po1030_s_ctrl(struct v4l2_ctrl *ctrl) +{ +	struct gspca_dev *gspca_dev = +		container_of(ctrl->handler, struct gspca_dev, ctrl_handler); +	struct sd *sd = (struct sd *) gspca_dev; +	int err; + +	if (!gspca_dev->streaming) +		return 0; + +	switch (ctrl->id) { +	case V4L2_CID_AUTO_WHITE_BALANCE: +		err = po1030_set_auto_white_balance(gspca_dev, ctrl->val); +		if (err || ctrl->val) +			return err; +		err = po1030_set_green_balance(gspca_dev, sd->green_bal->val); +		if (err) +			return err; +		err = po1030_set_red_balance(gspca_dev, sd->red_bal->val); +		if (err) +			return err; +		err = po1030_set_blue_balance(gspca_dev, sd->blue_bal->val); +		break; +	case V4L2_CID_EXPOSURE_AUTO: +		err = po1030_set_auto_exposure(gspca_dev, ctrl->val); +		if (err || ctrl->val == V4L2_EXPOSURE_AUTO) +			return err; +		err = po1030_set_exposure(gspca_dev, sd->expo->val); +		break; +	case V4L2_CID_GAIN: +		err = po1030_set_gain(gspca_dev, ctrl->val); +		break; +	case V4L2_CID_HFLIP: +		err = po1030_set_hvflip(gspca_dev); +		break; +	default: +		return -EINVAL; +	} + +	return err;  }  static void po1030_dump_registers(struct sd *sd)  |