Re: [RFC PATCH 06/12] mt9t031: convert to the control framework.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Same questions as to the previous ones:

1. how is V4L2_CID_EXPOSURE taken care of? I see, that the functionality 
is provided by the control cluster, but, AFAIU, user just issuing that 
control will not get the desired result?

2. separate handlers

3. v4l2_device_unregister_subdev()

Thanks
Guennadi

On Wed, 12 Jan 2011, Hans Verkuil wrote:

> Signed-off-by: Hans Verkuil <hverkuil@xxxxxxxxx>
> ---
>  drivers/media/video/mt9t031.c |  229 +++++++++++++++--------------------------
>  1 files changed, 81 insertions(+), 148 deletions(-)
> 
> diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
> index 7ce279c..cd73ef1 100644
> --- a/drivers/media/video/mt9t031.c
> +++ b/drivers/media/video/mt9t031.c
> @@ -18,6 +18,7 @@
>  #include <media/soc_camera.h>
>  #include <media/v4l2-chip-ident.h>
>  #include <media/v4l2-subdev.h>
> +#include <media/v4l2-ctrls.h>
>  
>  /*
>   * mt9t031 i2c address 0x5d
> @@ -64,14 +65,17 @@
>  
>  struct mt9t031 {
>  	struct v4l2_subdev subdev;
> +	struct v4l2_ctrl_handler hdl;
> +	struct {
> +		/* exposure/auto-exposure cluster */
> +		struct v4l2_ctrl *autoexposure;
> +		struct v4l2_ctrl *exposure;
> +	};
>  	struct v4l2_rect rect;	/* Sensor window */
>  	int model;	/* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
>  	u16 xskip;
>  	u16 yskip;
> -	unsigned int gain;
>  	unsigned short y_skip_top;	/* Lines to skip at the top */
> -	unsigned int exposure;
> -	unsigned char autoexposure;
>  };
>  
>  static struct mt9t031 *to_mt9t031(const struct i2c_client *client)
> @@ -211,61 +215,9 @@ enum {
>  	MT9T031_CTRL_EXPOSURE_AUTO,
>  };
>  
> -static const struct v4l2_queryctrl mt9t031_controls[] = {
> -	[MT9T031_CTRL_VFLIP] = {
> -		.id		= V4L2_CID_VFLIP,
> -		.type		= V4L2_CTRL_TYPE_BOOLEAN,
> -		.name		= "Flip Vertically",
> -		.minimum	= 0,
> -		.maximum	= 1,
> -		.step		= 1,
> -		.default_value	= 0,
> -	},
> -	[MT9T031_CTRL_HFLIP] = {
> -		.id		= V4L2_CID_HFLIP,
> -		.type		= V4L2_CTRL_TYPE_BOOLEAN,
> -		.name		= "Flip Horizontally",
> -		.minimum	= 0,
> -		.maximum	= 1,
> -		.step		= 1,
> -		.default_value	= 0,
> -	},
> -	[MT9T031_CTRL_GAIN] = {
> -		.id		= V4L2_CID_GAIN,
> -		.type		= V4L2_CTRL_TYPE_INTEGER,
> -		.name		= "Gain",
> -		.minimum	= 0,
> -		.maximum	= 127,
> -		.step		= 1,
> -		.default_value	= 64,
> -		.flags		= V4L2_CTRL_FLAG_SLIDER,
> -	},
> -	[MT9T031_CTRL_EXPOSURE] = {
> -		.id		= V4L2_CID_EXPOSURE,
> -		.type		= V4L2_CTRL_TYPE_INTEGER,
> -		.name		= "Exposure",
> -		.minimum	= 1,
> -		.maximum	= 255,
> -		.step		= 1,
> -		.default_value	= 255,
> -		.flags		= V4L2_CTRL_FLAG_SLIDER,
> -	},
> -	[MT9T031_CTRL_EXPOSURE_AUTO] = {
> -		.id		= V4L2_CID_EXPOSURE_AUTO,
> -		.type		= V4L2_CTRL_TYPE_BOOLEAN,
> -		.name		= "Automatic Exposure",
> -		.minimum	= 0,
> -		.maximum	= 1,
> -		.step		= 1,
> -		.default_value	= 1,
> -	}
> -};
> -
>  static struct soc_camera_ops mt9t031_ops = {
>  	.set_bus_param		= mt9t031_set_bus_param,
>  	.query_bus_param	= mt9t031_query_bus_param,
> -	.controls		= mt9t031_controls,
> -	.num_controls		= ARRAY_SIZE(mt9t031_controls),
>  };
>  
>  /* target must be _even_ */
> @@ -364,18 +316,20 @@ static int mt9t031_set_params(struct i2c_client *client,
>  	if (ret >= 0)
>  		ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
>  				rect->height + mt9t031->y_skip_top - 1);
> -	if (ret >= 0 && mt9t031->autoexposure) {
> +	v4l2_ctrl_lock(mt9t031->autoexposure);
> +	if (ret >= 0 && mt9t031->autoexposure->cur.val == V4L2_EXPOSURE_AUTO) {
>  		unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank;
>  		ret = set_shutter(client, total_h);
>  		if (ret >= 0) {
>  			const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
> -			const struct v4l2_queryctrl *qctrl =
> -				&mt9t031_controls[MT9T031_CTRL_EXPOSURE];
> -			mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
> -				 (qctrl->maximum - qctrl->minimum)) /
> -				shutter_max + qctrl->minimum;
> +			struct v4l2_ctrl *ctrl = mt9t031->exposure;
> +
> +			ctrl->cur.val = (shutter_max / 2 + (total_h - 1) *
> +				 (ctrl->maximum - ctrl->minimum)) /
> +				shutter_max + ctrl->minimum;
>  		}
>  	}
> +	v4l2_ctrl_unlock(mt9t031->autoexposure);
>  
>  	/* Re-enable register update, commit all changes */
>  	if (ret >= 0)
> @@ -543,71 +497,38 @@ static int mt9t031_s_register(struct v4l2_subdev *sd,
>  }
>  #endif
>  
> -static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
> -{
> -	struct i2c_client *client = v4l2_get_subdevdata(sd);
> -	struct mt9t031 *mt9t031 = to_mt9t031(client);
> -	int data;
> -
> -	switch (ctrl->id) {
> -	case V4L2_CID_VFLIP:
> -		data = reg_read(client, MT9T031_READ_MODE_2);
> -		if (data < 0)
> -			return -EIO;
> -		ctrl->value = !!(data & 0x8000);
> -		break;
> -	case V4L2_CID_HFLIP:
> -		data = reg_read(client, MT9T031_READ_MODE_2);
> -		if (data < 0)
> -			return -EIO;
> -		ctrl->value = !!(data & 0x4000);
> -		break;
> -	case V4L2_CID_EXPOSURE_AUTO:
> -		ctrl->value = mt9t031->autoexposure;
> -		break;
> -	case V4L2_CID_GAIN:
> -		ctrl->value = mt9t031->gain;
> -		break;
> -	case V4L2_CID_EXPOSURE:
> -		ctrl->value = mt9t031->exposure;
> -		break;
> -	}
> -	return 0;
> -}
> -
> -static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
> +static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
>  {
> +	struct v4l2_subdev *sd =
> +		&container_of(ctrl->handler, struct mt9t031, hdl)->subdev;
>  	struct i2c_client *client = v4l2_get_subdevdata(sd);
>  	struct mt9t031 *mt9t031 = to_mt9t031(client);
> -	const struct v4l2_queryctrl *qctrl;
> +	struct v4l2_ctrl *exp = mt9t031->exposure;
>  	int data;
>  
>  	switch (ctrl->id) {
>  	case V4L2_CID_VFLIP:
> -		if (ctrl->value)
> +		if (ctrl->val)
>  			data = reg_set(client, MT9T031_READ_MODE_2, 0x8000);
>  		else
>  			data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000);
>  		if (data < 0)
>  			return -EIO;
> -		break;
> +		return 0;
>  	case V4L2_CID_HFLIP:
> -		if (ctrl->value)
> +		if (ctrl->val)
>  			data = reg_set(client, MT9T031_READ_MODE_2, 0x4000);
>  		else
>  			data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000);
>  		if (data < 0)
>  			return -EIO;
> -		break;
> +		return 0;
>  	case V4L2_CID_GAIN:
> -		qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN];
> -		if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
> -			return -EINVAL;
>  		/* See Datasheet Table 7, Gain settings. */
> -		if (ctrl->value <= qctrl->default_value) {
> +		if (ctrl->val <= ctrl->default_value) {
>  			/* Pack it into 0..1 step 0.125, register values 0..8 */
> -			unsigned long range = qctrl->default_value - qctrl->minimum;
> -			data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
> +			unsigned long range = ctrl->default_value - ctrl->minimum;
> +			data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
>  
>  			dev_dbg(&client->dev, "Setting gain %d\n", data);
>  			data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
> @@ -616,9 +537,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
>  		} else {
>  			/* Pack it into 1.125..128 variable step, register values 9..0x7860 */
>  			/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
> -			unsigned long range = qctrl->maximum - qctrl->default_value - 1;
> +			unsigned long range = ctrl->maximum - ctrl->default_value - 1;
>  			/* calculated gain: map 65..127 to 9..1024 step 0.125 */
> -			unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
> +			unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
>  					       1015 + range / 2) / range + 9;
>  
>  			if (gain <= 32)		/* calculated gain 9..32 -> 9..32 */
> @@ -635,19 +556,16 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
>  			if (data < 0)
>  				return -EIO;
>  		}
> +		return 0;
>  
> -		/* Success */
> -		mt9t031->gain = ctrl->value;
> -		break;
> -	case V4L2_CID_EXPOSURE:
> -		qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE];
> -		/* mt9t031 has maximum == default */
> -		if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
> -			return -EINVAL;
> -		else {
> -			const unsigned long range = qctrl->maximum - qctrl->minimum;
> -			const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 +
> -					     range / 2) / range + 1;
> +	case V4L2_CID_EXPOSURE_AUTO:
> +		/* Force manual exposure if only the exposure was changed */
> +		if (!ctrl->has_new)
> +			ctrl->val = V4L2_EXPOSURE_MANUAL;
> +		if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
> +			unsigned int range = exp->maximum - exp->minimum;
> +			unsigned int shutter = ((exp->val - exp->minimum) * 1048 +
> +						 range / 2) / range + 1;
>  			u32 old;
>  
>  			get_shutter(client, &old);
> @@ -655,12 +573,8 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
>  				old, shutter);
>  			if (set_shutter(client, shutter) < 0)
>  				return -EIO;
> -			mt9t031->exposure = ctrl->value;
> -			mt9t031->autoexposure = 0;
> -		}
> -		break;
> -	case V4L2_CID_EXPOSURE_AUTO:
> -		if (ctrl->value) {
> +			ctrl->val = V4L2_EXPOSURE_MANUAL;
> +		} else {
>  			const u16 vblank = MT9T031_VERTICAL_BLANK;
>  			const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
>  			unsigned int total_h = mt9t031->rect.height +
> @@ -668,14 +582,11 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
>  
>  			if (set_shutter(client, total_h) < 0)
>  				return -EIO;
> -			qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE];
> -			mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
> -				 (qctrl->maximum - qctrl->minimum)) /
> -				shutter_max + qctrl->minimum;
> -			mt9t031->autoexposure = 1;
> -		} else
> -			mt9t031->autoexposure = 0;
> -		break;
> +			exp->val = (shutter_max / 2 + (total_h - 1) *
> +				 (exp->maximum - exp->minimum)) /
> +				shutter_max + exp->minimum;
> +		}
> +		return 0;
>  	default:
>  		return -EINVAL;
>  	}
> @@ -766,15 +677,12 @@ static int mt9t031_video_probe(struct i2c_client *client)
>  	dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
>  
>  	ret = mt9t031_idle(client);
> -	if (ret < 0)
> +	if (ret < 0) {
>  		dev_err(&client->dev, "Failed to initialise the camera\n");
> -	else
> +	} else {
>  		vdev->dev.type = &mt9t031_dev_type;
> -
> -	/* mt9t031_idle() has reset the chip to default. */
> -	mt9t031->exposure = 255;
> -	mt9t031->gain = 64;
> -
> +		v4l2_ctrl_handler_setup(&mt9t031->hdl);
> +	}
>  	return ret;
>  }
>  
> @@ -788,9 +696,11 @@ static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
>  	return 0;
>  }
>  
> +static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = {
> +	.s_ctrl = mt9t031_s_ctrl,
> +};
> +
>  static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
> -	.g_ctrl		= mt9t031_g_ctrl,
> -	.s_ctrl		= mt9t031_s_ctrl,
>  	.g_chip_ident	= mt9t031_g_chip_ident,
>  #ifdef CONFIG_VIDEO_ADV_DEBUG
>  	.g_register	= mt9t031_g_register,
> @@ -858,6 +768,32 @@ static int mt9t031_probe(struct i2c_client *client,
>  		return -ENOMEM;
>  
>  	v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops);
> +	v4l2_ctrl_handler_init(&mt9t031->hdl, 5);
> +	v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
> +			V4L2_CID_VFLIP, 0, 1, 1, 0);
> +	v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
> +			V4L2_CID_HFLIP, 0, 1, 1, 0);
> +	v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
> +			V4L2_CID_GAIN, 0, 127, 1, 64);
> +
> +	/*
> +	 * Simulated autoexposure. If enabled, we calculate shutter width
> +	 * ourselves in the driver based on vertical blanking and frame width
> +	 */
> +	mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl,
> +			&mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
> +			V4L2_EXPOSURE_AUTO);
> +	mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops,
> +			V4L2_CID_EXPOSURE, 1, 255, 1, 255);
> +
> +	mt9t031->subdev.ctrl_handler = &mt9t031->hdl;
> +	if (mt9t031->hdl.error) {
> +		int err = mt9t031->hdl.error;
> +
> +		kfree(mt9t031);
> +		return err;
> +	}
> +	v4l2_ctrl_cluster(2, &mt9t031->autoexposure);
>  
>  	mt9t031->y_skip_top	= 0;
>  	mt9t031->rect.left	= MT9T031_COLUMN_SKIP;
> @@ -865,12 +801,6 @@ static int mt9t031_probe(struct i2c_client *client,
>  	mt9t031->rect.width	= MT9T031_MAX_WIDTH;
>  	mt9t031->rect.height	= MT9T031_MAX_HEIGHT;
>  
> -	/*
> -	 * Simulated autoexposure. If enabled, we calculate shutter width
> -	 * ourselves in the driver based on vertical blanking and frame width
> -	 */
> -	mt9t031->autoexposure = 1;
> -
>  	mt9t031->xskip = 1;
>  	mt9t031->yskip = 1;
>  
> @@ -883,6 +813,7 @@ static int mt9t031_probe(struct i2c_client *client,
>  	if (ret) {
>  		if (icd)
>  			icd->ops = NULL;
> +		v4l2_ctrl_handler_free(&mt9t031->hdl);
>  		kfree(mt9t031);
>  	}
>  
> @@ -894,8 +825,10 @@ static int mt9t031_remove(struct i2c_client *client)
>  	struct mt9t031 *mt9t031 = to_mt9t031(client);
>  	struct soc_camera_device *icd = client->dev.platform_data;
>  
> +	v4l2_device_unregister_subdev(&mt9t031->subdev);
>  	if (icd)
>  		icd->ops = NULL;
> +	v4l2_ctrl_handler_free(&mt9t031->hdl);
>  	kfree(mt9t031);
>  
>  	return 0;
> -- 
> 1.7.0.4
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux