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

Commit 5565a2ad authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 05fb4da4
Loading
Loading
Loading
Loading
+11 −7
Original line number Original line Diff line number Diff line
@@ -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)
+51 −26
Original line number Original line Diff line number Diff line
@@ -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;


	if (enable) {
	mutex_lock(&info->lock);
		int ret = -EINVAL;
	code = info->ffmt[info->res_type].code;


	if (enable) {
		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) {