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

Commit 984fb244 authored by Narcisa Ana Maria Vasile's avatar Narcisa Ana Maria Vasile Committed by Jonathan Cameron
Browse files

staging: iio: ad5933: Protect DIRECT mode using claim/release helpers



This device operates in DIRECT_MODE and BUFFER_HARDWARE mode.
Replace usages of iio_dev->mlock with iio_device_{claim|release}_direct_mode()
helper functions to guarantee DIRECT mode and consequently protect
BUFFER mode too.

Add and use a device private lock to protect against conflicting access of the
state data.
This helps with IIO subsystem redefining iio_dev->mlock to be used by
the IIO core only for protecting device operating mode changes.
ie. Changes between INDIO_DIRECT_MODE, INDIO_BUFFER_* modes.

Protect changing of attributes inside ad5933_store(). Attributes
can no longer be changed while in buffered mode.

Remove lock from ad5933_work() because buffer mode should be enabled
when we reach this, and claiming DIRECT mode in all the other places
should protect it.

Signed-off-by: default avatarNarcisa Ana Maria Vasile <narcisaanamaria12@gmail.com>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent a9e9c715
Loading
Loading
Loading
Loading
+28 −22
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ struct ad5933_state {
	struct i2c_client		*client;
	struct regulator		*reg;
	struct delayed_work		work;
	struct mutex			lock; /* Protect sensor state */
	unsigned long			mclk_hz;
	unsigned char			ctrl_hb;
	unsigned char			ctrl_lb;
@@ -306,9 +307,11 @@ static ssize_t ad5933_show_frequency(struct device *dev,
		u8 d8[4];
	} dat;

	mutex_lock(&indio_dev->mlock);
	ret = iio_device_claim_direct_mode(indio_dev);
	if (ret)
		return ret;
	ret = ad5933_i2c_read(st->client, this_attr->address, 3, &dat.d8[1]);
	mutex_unlock(&indio_dev->mlock);
	iio_device_release_direct_mode(indio_dev);
	if (ret < 0)
		return ret;

@@ -338,9 +341,11 @@ static ssize_t ad5933_store_frequency(struct device *dev,
	if (val > AD5933_MAX_OUTPUT_FREQ_Hz)
		return -EINVAL;

	mutex_lock(&indio_dev->mlock);
	ret = iio_device_claim_direct_mode(indio_dev);
	if (ret)
		return ret;
	ret = ad5933_set_freq(st, this_attr->address, val);
	mutex_unlock(&indio_dev->mlock);
	iio_device_release_direct_mode(indio_dev);

	return ret ? ret : len;
}
@@ -364,7 +369,7 @@ static ssize_t ad5933_show(struct device *dev,
	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
	int ret = 0, len = 0;

	mutex_lock(&indio_dev->mlock);
	mutex_lock(&st->lock);
	switch ((u32)this_attr->address) {
	case AD5933_OUT_RANGE:
		len = sprintf(buf, "%u\n",
@@ -393,7 +398,7 @@ static ssize_t ad5933_show(struct device *dev,
		ret = -EINVAL;
	}

	mutex_unlock(&indio_dev->mlock);
	mutex_unlock(&st->lock);
	return ret ? ret : len;
}

@@ -415,7 +420,10 @@ static ssize_t ad5933_store(struct device *dev,
			return ret;
	}

	mutex_lock(&indio_dev->mlock);
	ret = iio_device_claim_direct_mode(indio_dev);
	if (ret)
		return ret;
	mutex_lock(&st->lock);
	switch ((u32)this_attr->address) {
	case AD5933_OUT_RANGE:
		ret = -EINVAL;
@@ -465,7 +473,8 @@ static ssize_t ad5933_store(struct device *dev,
		ret = -EINVAL;
	}

	mutex_unlock(&indio_dev->mlock);
	mutex_unlock(&st->lock);
	iio_device_release_direct_mode(indio_dev);
	return ret ? ret : len;
}

@@ -532,11 +541,9 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,

	switch (m) {
	case IIO_CHAN_INFO_RAW:
		mutex_lock(&indio_dev->mlock);
		if (iio_buffer_enabled(indio_dev)) {
			ret = -EBUSY;
			goto out;
		}
		ret = iio_device_claim_direct_mode(indio_dev);
		if (ret)
			return ret;
		ret = ad5933_cmd(st, AD5933_CTRL_MEASURE_TEMP);
		if (ret < 0)
			goto out;
@@ -549,7 +556,7 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
				      2, (u8 *)&dat);
		if (ret < 0)
			goto out;
		mutex_unlock(&indio_dev->mlock);
		iio_device_release_direct_mode(indio_dev);
		*val = sign_extend32(be16_to_cpu(dat), 13);

		return IIO_VAL_INT;
@@ -561,7 +568,7 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,

	return -EINVAL;
out:
	mutex_unlock(&indio_dev->mlock);
	iio_device_release_direct_mode(indio_dev);
	return ret;
}

@@ -657,18 +664,17 @@ static void ad5933_work(struct work_struct *work)
	unsigned char status;
	int ret;

	mutex_lock(&indio_dev->mlock);
	if (st->state == AD5933_CTRL_INIT_START_FREQ) {
		/* start sweep */
		ad5933_cmd(st, AD5933_CTRL_START_SWEEP);
		st->state = AD5933_CTRL_START_SWEEP;
		schedule_delayed_work(&st->work, st->poll_time_jiffies);
		goto out;
		return;
	}

	ret = ad5933_i2c_read(st->client, AD5933_REG_STATUS, 1, &status);
	if (ret)
		goto out;
		return;

	if (status & AD5933_STAT_DATA_VALID) {
		int scan_count = bitmap_weight(indio_dev->active_scan_mask,
@@ -678,7 +684,7 @@ static void ad5933_work(struct work_struct *work)
				AD5933_REG_REAL_DATA : AD5933_REG_IMAG_DATA,
				scan_count * 2, (u8 *)buf);
		if (ret)
			goto out;
			return;

		if (scan_count == 2) {
			val[0] = be16_to_cpu(buf[0]);
@@ -690,7 +696,7 @@ static void ad5933_work(struct work_struct *work)
	} else {
		/* no data available - try again later */
		schedule_delayed_work(&st->work, st->poll_time_jiffies);
		goto out;
		return;
	}

	if (status & AD5933_STAT_SWEEP_DONE) {
@@ -703,8 +709,6 @@ static void ad5933_work(struct work_struct *work)
		ad5933_cmd(st, AD5933_CTRL_INC_FREQ);
		schedule_delayed_work(&st->work, st->poll_time_jiffies);
	}
out:
	mutex_unlock(&indio_dev->mlock);
}

static int ad5933_probe(struct i2c_client *client,
@@ -723,6 +727,8 @@ static int ad5933_probe(struct i2c_client *client,
	i2c_set_clientdata(client, indio_dev);
	st->client = client;

	mutex_init(&st->lock);

	if (!pdata)
		pdata = &ad5933_default_pdata;