[media] m5mols: Protect driver data with a mutex
Without the locking the driver's data could get corrupted when the subdev is accessed from user space and from host driver by multiple processes. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
		
					parent
					
						
							
								05fb4da441
							
						
					
				
			
			
				commit
				
					
						5565a2ad47
					
				
			
		
					 2 changed files with 63 additions and 34 deletions
				
			
		| 
						 | 
					@ -155,8 +155,6 @@ struct m5mols_version {
 | 
				
			||||||
 * @pdata: platform data
 | 
					 * @pdata: platform data
 | 
				
			||||||
 * @sd: v4l-subdev instance
 | 
					 * @sd: v4l-subdev instance
 | 
				
			||||||
 * @pad: media pad
 | 
					 * @pad: media pad
 | 
				
			||||||
 * @ffmt: current fmt according to resolution type
 | 
					 | 
				
			||||||
 * @res_type: current resolution type
 | 
					 | 
				
			||||||
 * @irq_waitq: waitqueue for the capture
 | 
					 * @irq_waitq: waitqueue for the capture
 | 
				
			||||||
 * @irq_done: set to 1 in the interrupt handler
 | 
					 * @irq_done: set to 1 in the interrupt handler
 | 
				
			||||||
 * @handle: control handler
 | 
					 * @handle: control handler
 | 
				
			||||||
| 
						 | 
					@ -174,6 +172,10 @@ struct m5mols_version {
 | 
				
			||||||
 * @wdr: wide dynamic range control
 | 
					 * @wdr: wide dynamic range control
 | 
				
			||||||
 * @stabilization: image stabilization control
 | 
					 * @stabilization: image stabilization control
 | 
				
			||||||
 * @jpeg_quality: JPEG compression quality control
 | 
					 * @jpeg_quality: JPEG compression quality control
 | 
				
			||||||
 | 
					 * @set_power: optional power callback to the board code
 | 
				
			||||||
 | 
					 * @lock: mutex protecting the structure fields below
 | 
				
			||||||
 | 
					 * @ffmt: current fmt according to resolution type
 | 
				
			||||||
 | 
					 * @res_type: current resolution type
 | 
				
			||||||
 * @ver: information of the version
 | 
					 * @ver: information of the version
 | 
				
			||||||
 * @cap: the capture mode attributes
 | 
					 * @cap: the capture mode attributes
 | 
				
			||||||
 * @isp_ready: 1 when the ISP controller has completed booting
 | 
					 * @isp_ready: 1 when the ISP controller has completed booting
 | 
				
			||||||
| 
						 | 
					@ -181,14 +183,11 @@ struct m5mols_version {
 | 
				
			||||||
 * @ctrl_sync: 1 when the control handler state is restored in H/W
 | 
					 * @ctrl_sync: 1 when the control handler state is restored in H/W
 | 
				
			||||||
 * @resolution:	register value for current resolution
 | 
					 * @resolution:	register value for current resolution
 | 
				
			||||||
 * @mode: register value for current operation mode
 | 
					 * @mode: register value for current operation mode
 | 
				
			||||||
 * @set_power: optional power callback to the board code
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct m5mols_info {
 | 
					struct m5mols_info {
 | 
				
			||||||
	const struct m5mols_platform_data *pdata;
 | 
						const struct m5mols_platform_data *pdata;
 | 
				
			||||||
	struct v4l2_subdev sd;
 | 
						struct v4l2_subdev sd;
 | 
				
			||||||
	struct media_pad pad;
 | 
						struct media_pad pad;
 | 
				
			||||||
	struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
 | 
					 | 
				
			||||||
	int res_type;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wait_queue_head_t irq_waitq;
 | 
						wait_queue_head_t irq_waitq;
 | 
				
			||||||
	atomic_t irq_done;
 | 
						atomic_t irq_done;
 | 
				
			||||||
| 
						 | 
					@ -216,6 +215,13 @@ struct m5mols_info {
 | 
				
			||||||
	struct v4l2_ctrl *stabilization;
 | 
						struct v4l2_ctrl *stabilization;
 | 
				
			||||||
	struct v4l2_ctrl *jpeg_quality;
 | 
						struct v4l2_ctrl *jpeg_quality;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int (*set_power)(struct device *dev, int on);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mutex lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
 | 
				
			||||||
 | 
						int res_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct m5mols_version ver;
 | 
						struct m5mols_version ver;
 | 
				
			||||||
	struct m5mols_capture cap;
 | 
						struct m5mols_capture cap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -225,8 +231,6 @@ struct m5mols_info {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u8 resolution;
 | 
						u8 resolution;
 | 
				
			||||||
	u8 mode;
 | 
						u8 mode;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	int (*set_power)(struct device *dev, int on);
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define is_available_af(__info)	(__info->ver.af)
 | 
					#define is_available_af(__info)	(__info->ver.af)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -551,13 +551,18 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct m5mols_info *info = to_m5mols(sd);
 | 
						struct m5mols_info *info = to_m5mols(sd);
 | 
				
			||||||
	struct v4l2_mbus_framefmt *format;
 | 
						struct v4l2_mbus_framefmt *format;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&info->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	format = __find_format(info, fh, fmt->which, info->res_type);
 | 
						format = __find_format(info, fh, fmt->which, info->res_type);
 | 
				
			||||||
	if (!format)
 | 
						if (!format)
 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		fmt->format = *format;
 | 
							fmt->format = *format;
 | 
				
			||||||
	return 0;
 | 
						else
 | 
				
			||||||
 | 
							ret = -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&info->lock);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 | 
					static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 | 
				
			||||||
| 
						 | 
					@ -578,6 +583,7 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 | 
				
			||||||
	if (!sfmt)
 | 
						if (!sfmt)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&info->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	format->code = m5mols_default_ffmt[type].code;
 | 
						format->code = m5mols_default_ffmt[type].code;
 | 
				
			||||||
	format->colorspace = V4L2_COLORSPACE_JPEG;
 | 
						format->colorspace = V4L2_COLORSPACE_JPEG;
 | 
				
			||||||
| 
						 | 
					@ -589,7 +595,8 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 | 
				
			||||||
		info->res_type = type;
 | 
							info->res_type = type;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						mutex_unlock(&info->lock);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
 | 
					static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
 | 
				
			||||||
| 
						 | 
					@ -661,20 +668,25 @@ static int m5mols_start_monitor(struct m5mols_info *info)
 | 
				
			||||||
static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
 | 
					static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct m5mols_info *info = to_m5mols(sd);
 | 
						struct m5mols_info *info = to_m5mols(sd);
 | 
				
			||||||
	u32 code = info->ffmt[info->res_type].code;
 | 
						u32 code;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&info->lock);
 | 
				
			||||||
 | 
						code = info->ffmt[info->res_type].code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (enable) {
 | 
						if (enable) {
 | 
				
			||||||
		int ret = -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (is_code(code, M5MOLS_RESTYPE_MONITOR))
 | 
							if (is_code(code, M5MOLS_RESTYPE_MONITOR))
 | 
				
			||||||
			ret = m5mols_start_monitor(info);
 | 
								ret = m5mols_start_monitor(info);
 | 
				
			||||||
		if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
 | 
							if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
 | 
				
			||||||
			ret = m5mols_start_capture(info);
 | 
								ret = m5mols_start_capture(info);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
		return ret;
 | 
								ret = -EINVAL;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ret = m5mols_set_mode(info, REG_PARAMETER);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return m5mols_set_mode(info, REG_PARAMETER);
 | 
						mutex_unlock(&info->lock);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct v4l2_subdev_video_ops m5mols_video_ops = {
 | 
					static const struct v4l2_subdev_video_ops m5mols_video_ops = {
 | 
				
			||||||
| 
						 | 
					@ -773,6 +785,20 @@ static int m5mols_fw_start(struct v4l2_subdev *sd)
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Execute the lens soft-landing algorithm */
 | 
				
			||||||
 | 
					static int m5mols_auto_focus_stop(struct m5mols_info *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
 | 
				
			||||||
 | 
						if (!ret)
 | 
				
			||||||
 | 
							ret = m5mols_write(&info->sd, AF_MODE, REG_AF_POWEROFF);
 | 
				
			||||||
 | 
						if (!ret)
 | 
				
			||||||
 | 
							ret = m5mols_busy_wait(&info->sd, SYSTEM_STATUS, REG_AF_IDLE,
 | 
				
			||||||
 | 
									       0xff, -1);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * m5mols_s_power - Main sensor power control function
 | 
					 * m5mols_s_power - Main sensor power control function
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -785,29 +811,26 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
 | 
				
			||||||
	struct m5mols_info *info = to_m5mols(sd);
 | 
						struct m5mols_info *info = to_m5mols(sd);
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&info->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (on) {
 | 
						if (on) {
 | 
				
			||||||
		ret = m5mols_sensor_power(info, true);
 | 
							ret = m5mols_sensor_power(info, true);
 | 
				
			||||||
		if (!ret)
 | 
							if (!ret)
 | 
				
			||||||
			ret = m5mols_fw_start(sd);
 | 
								ret = m5mols_fw_start(sd);
 | 
				
			||||||
		return ret;
 | 
						} else {
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
 | 
							if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
 | 
				
			||||||
			ret = m5mols_set_mode(info, REG_MONITOR);
 | 
								ret = m5mols_set_mode(info, REG_MONITOR);
 | 
				
			||||||
			if (!ret)
 | 
								if (!ret)
 | 
				
			||||||
			ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
 | 
									ret = m5mols_auto_focus_stop(info);
 | 
				
			||||||
		if (!ret)
 | 
					 | 
				
			||||||
			ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
 | 
					 | 
				
			||||||
		if (!ret)
 | 
					 | 
				
			||||||
			ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE,
 | 
					 | 
				
			||||||
					       0xff, -1);
 | 
					 | 
				
			||||||
			if (ret < 0)
 | 
								if (ret < 0)
 | 
				
			||||||
				v4l2_warn(sd, "Soft landing lens failed\n");
 | 
									v4l2_warn(sd, "Soft landing lens failed\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		ret = m5mols_sensor_power(info, false);
 | 
							ret = m5mols_sensor_power(info, false);
 | 
				
			||||||
	info->ctrl_sync = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							info->ctrl_sync = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&info->lock);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -912,6 +935,8 @@ static int __devinit m5mols_probe(struct i2c_client *client,
 | 
				
			||||||
	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
 | 
						sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	init_waitqueue_head(&info->irq_waitq);
 | 
						init_waitqueue_head(&info->irq_waitq);
 | 
				
			||||||
 | 
						mutex_init(&info->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = request_irq(client->irq, m5mols_irq_handler,
 | 
						ret = request_irq(client->irq, m5mols_irq_handler,
 | 
				
			||||||
			  IRQF_TRIGGER_RISING, MODULE_NAME, sd);
 | 
								  IRQF_TRIGGER_RISING, MODULE_NAME, sd);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue