Skip to content

Commit

Permalink
[media] m5mols: Protect driver data with a mutex
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sylwester Nawrocki authored and Mauro Carvalho Chehab committed Oct 1, 2012
1 parent 05fb4da commit 5565a2a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 33 deletions.
18 changes: 11 additions & 7 deletions drivers/media/i2c/m5mols/m5mols.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,6 @@ struct m5mols_version {
* @pdata: platform data
* @sd: v4l-subdev instance
* @pad: media pad
* @ffmt: current fmt according to resolution type
* @res_type: current resolution type
* @irq_waitq: waitqueue for the capture
* @irq_done: set to 1 in the interrupt handler
* @handle: control handler
Expand All @@ -174,21 +172,22 @@ struct m5mols_version {
* @wdr: wide dynamic range control
* @stabilization: image stabilization 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
* @cap: the capture mode attributes
* @isp_ready: 1 when the ISP controller has completed booting
* @power: current sensor's power status
* @ctrl_sync: 1 when the control handler state is restored in H/W
* @resolution: register value for current resolution
* @mode: register value for current operation mode
* @set_power: optional power callback to the board code
*/
struct m5mols_info {
const struct m5mols_platform_data *pdata;
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
int res_type;

wait_queue_head_t irq_waitq;
atomic_t irq_done;
Expand Down Expand Up @@ -216,6 +215,13 @@ struct m5mols_info {
struct v4l2_ctrl *stabilization;
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_capture cap;

Expand All @@ -225,8 +231,6 @@ struct m5mols_info {

u8 resolution;
u8 mode;

int (*set_power)(struct device *dev, int on);
};

#define is_available_af(__info) (__info->ver.af)
Expand Down
77 changes: 51 additions & 26 deletions drivers/media/i2c/m5mols/m5mols_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 v4l2_mbus_framefmt *format;
int ret = 0;

mutex_lock(&info->lock);

format = __find_format(info, fh, fmt->which, info->res_type);
if (!format)
return -EINVAL;
fmt->format = *format;
else
ret = -EINVAL;

fmt->format = *format;
return 0;
mutex_unlock(&info->lock);
return ret;
}

static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
Expand All @@ -578,6 +583,7 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
if (!sfmt)
return 0;

mutex_lock(&info->lock);

format->code = m5mols_default_ffmt[type].code;
format->colorspace = V4L2_COLORSPACE_JPEG;
Expand All @@ -589,7 +595,8 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
info->res_type = type;
}

return 0;
mutex_unlock(&info->lock);
return ret;
}

static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
Expand Down Expand Up @@ -661,20 +668,25 @@ static int m5mols_start_monitor(struct m5mols_info *info)
static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
{
struct m5mols_info *info = to_m5mols(sd);
u32 code = info->ffmt[info->res_type].code;
u32 code;
int ret;

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

if (enable) {
if (is_code(code, M5MOLS_RESTYPE_MONITOR))
ret = m5mols_start_monitor(info);
if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
ret = m5mols_start_capture(info);

return ret;
else
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 = {
Expand Down Expand Up @@ -773,6 +785,20 @@ static int m5mols_fw_start(struct v4l2_subdev *sd)
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
*
Expand All @@ -785,29 +811,26 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
struct m5mols_info *info = to_m5mols(sd);
int ret;

mutex_lock(&info->lock);

if (on) {
ret = m5mols_sensor_power(info, true);
if (!ret)
ret = m5mols_fw_start(sd);
return ret;
}
} else {
if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
ret = m5mols_set_mode(info, REG_MONITOR);
if (!ret)
ret = m5mols_auto_focus_stop(info);
if (ret < 0)
v4l2_warn(sd, "Soft landing lens failed\n");
}
ret = m5mols_sensor_power(info, false);

if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
ret = m5mols_set_mode(info, REG_MONITOR);
if (!ret)
ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
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)
v4l2_warn(sd, "Soft landing lens failed\n");
info->ctrl_sync = 0;
}

ret = m5mols_sensor_power(info, false);
info->ctrl_sync = 0;

mutex_unlock(&info->lock);
return ret;
}

Expand Down Expand Up @@ -912,6 +935,8 @@ static int __devinit m5mols_probe(struct i2c_client *client,
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;

init_waitqueue_head(&info->irq_waitq);
mutex_init(&info->lock);

ret = request_irq(client->irq, m5mols_irq_handler,
IRQF_TRIGGER_RISING, MODULE_NAME, sd);
if (ret) {
Expand Down

0 comments on commit 5565a2a

Please sign in to comment.