summaryrefslogtreecommitdiff
path: root/drivers/iio/industrialio-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/industrialio-core.c')
-rw-r--r--drivers/iio/industrialio-core.c132
1 files changed, 88 insertions, 44 deletions
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 173dc00762a1..a2117ad1337d 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -11,6 +11,7 @@
#include <linux/anon_inodes.h>
#include <linux/cdev.h>
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -42,7 +43,7 @@ static DEFINE_IDA(iio_ida);
static dev_t iio_devt;
#define IIO_DEV_MAX 256
-struct bus_type iio_bus_type = {
+const struct bus_type iio_bus_type = {
.name = "iio",
};
EXPORT_SYMBOL(iio_bus_type);
@@ -94,6 +95,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_DELTA_VELOCITY] = "deltavelocity",
[IIO_COLORTEMP] = "colortemp",
[IIO_CHROMATICITY] = "chromaticity",
+ [IIO_ATTENTION] = "attention",
};
static const char * const iio_modifier_names[] = {
@@ -213,9 +215,7 @@ bool iio_buffer_enabled(struct iio_dev *indio_dev)
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
- return iio_dev_opaque->currentmode &
- (INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE |
- INDIO_BUFFER_TRIGGERED);
+ return iio_dev_opaque->currentmode & INDIO_ALL_BUFFER_MODES;
}
EXPORT_SYMBOL_GPL(iio_buffer_enabled);
@@ -668,7 +668,6 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type,
vals[1]);
case IIO_VAL_FRACTIONAL:
tmp2 = div_s64((s64)vals[0] * 1000000000LL, vals[1]);
- tmp1 = vals[1];
tmp0 = (int)div_s64_rem(tmp2, 1000000000, &tmp1);
if ((tmp2 < 0) && (tmp0 == 0))
return sysfs_emit_at(buf, offset, "-0.%09u", abs(tmp1));
@@ -728,22 +727,27 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
}
EXPORT_SYMBOL_GPL(iio_format_value);
-static ssize_t iio_read_channel_label(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ssize_t do_iio_read_channel_label(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *c,
+ char *buf)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-
if (indio_dev->info->read_label)
- return indio_dev->info->read_label(indio_dev, this_attr->c, buf);
+ return indio_dev->info->read_label(indio_dev, c, buf);
- if (this_attr->c->extend_name)
- return sysfs_emit(buf, "%s\n", this_attr->c->extend_name);
+ if (c->extend_name)
+ return sysfs_emit(buf, "%s\n", c->extend_name);
return -EINVAL;
}
+static ssize_t iio_read_channel_label(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return do_iio_read_channel_label(dev_to_iio_dev(dev),
+ to_iio_dev_attr(attr)->c, buf);
+}
+
static ssize_t iio_read_channel_info(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -759,9 +763,11 @@ static ssize_t iio_read_channel_info(struct device *dev,
INDIO_MAX_RAW_ELEMENTS,
vals, &val_len,
this_attr->address);
- else
+ else if (indio_dev->info->read_raw)
ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
&vals[0], &vals[1], this_attr->address);
+ else
+ return -EINVAL;
if (ret < 0)
return ret;
@@ -843,6 +849,9 @@ static ssize_t iio_read_channel_info_avail(struct device *dev,
int length;
int type;
+ if (!indio_dev->info->read_avail)
+ return -EINVAL;
+
ret = indio_dev->info->read_avail(indio_dev, this_attr->c,
&vals, &type, &length,
this_attr->address);
@@ -1645,19 +1654,20 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
struct iio_dev *indio_dev;
size_t alloc_size;
- alloc_size = sizeof(struct iio_dev_opaque);
- if (sizeof_priv) {
- alloc_size = ALIGN(alloc_size, IIO_DMA_MINALIGN);
- alloc_size += sizeof_priv;
- }
+ if (sizeof_priv)
+ alloc_size = ALIGN(sizeof(*iio_dev_opaque), IIO_DMA_MINALIGN) + sizeof_priv;
+ else
+ alloc_size = sizeof(*iio_dev_opaque);
iio_dev_opaque = kzalloc(alloc_size, GFP_KERNEL);
if (!iio_dev_opaque)
return NULL;
indio_dev = &iio_dev_opaque->indio_dev;
- indio_dev->priv = (char *)iio_dev_opaque +
- ALIGN(sizeof(struct iio_dev_opaque), IIO_DMA_MINALIGN);
+
+ if (sizeof_priv)
+ ACCESS_PRIVATE(indio_dev, priv) = (char *)iio_dev_opaque +
+ ALIGN(sizeof(*iio_dev_opaque), IIO_DMA_MINALIGN);
indio_dev->dev.parent = parent;
indio_dev->dev.type = &iio_device_type;
@@ -1811,31 +1821,24 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
struct iio_dev *indio_dev = ib->indio_dev;
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_ioctl_handler *h;
- int ret = -ENODEV;
-
- mutex_lock(&iio_dev_opaque->info_exist_lock);
+ int ret;
+ guard(mutex)(&iio_dev_opaque->info_exist_lock);
/*
* The NULL check here is required to prevent crashing when a device
* is being removed while userspace would still have open file handles
* to try to access this device.
*/
if (!indio_dev->info)
- goto out_unlock;
+ return -ENODEV;
list_for_each_entry(h, &iio_dev_opaque->ioctl_handlers, entry) {
ret = h->ioctl(indio_dev, filp, cmd, arg);
if (ret != IIO_IOCTL_UNHANDLED)
- break;
+ return ret;
}
- if (ret == IIO_IOCTL_UNHANDLED)
- ret = -ENODEV;
-
-out_unlock:
- mutex_unlock(&iio_dev_opaque->info_exist_lock);
-
- return ret;
+ return -ENODEV;
}
static const struct file_operations iio_buffer_fileops = {
@@ -1909,7 +1912,7 @@ static void iio_sanity_check_avail_scan_masks(struct iio_dev *indio_dev)
int i;
av_masks = indio_dev->available_scan_masks;
- masklength = indio_dev->masklength;
+ masklength = iio_get_masklength(indio_dev);
longs_per_mask = BITS_TO_LONGS(masklength);
/*
@@ -1962,6 +1965,49 @@ static void iio_sanity_check_avail_scan_masks(struct iio_dev *indio_dev)
}
}
+/**
+ * iio_active_scan_mask_index - Get index of the active scan mask inside the
+ * available scan masks array
+ * @indio_dev: the IIO device containing the active and available scan masks
+ *
+ * Returns: the index or -EINVAL if active_scan_mask is not set
+ */
+int iio_active_scan_mask_index(struct iio_dev *indio_dev)
+
+{
+ const unsigned long *av_masks;
+ unsigned int masklength = iio_get_masklength(indio_dev);
+ int i = 0;
+
+ if (!indio_dev->active_scan_mask)
+ return -EINVAL;
+
+ /*
+ * As in iio_scan_mask_match and iio_sanity_check_avail_scan_masks,
+ * the condition here do not handle multi-long masks correctly.
+ * It only checks the first long to be zero, and will use such mask
+ * as a terminator even if there was bits set after the first long.
+ *
+ * This should be fine since the available_scan_mask has already been
+ * sanity tested using iio_sanity_check_avail_scan_masks.
+ *
+ * See iio_scan_mask_match and iio_sanity_check_avail_scan_masks for
+ * more details
+ */
+ av_masks = indio_dev->available_scan_masks;
+ while (*av_masks) {
+ if (indio_dev->active_scan_mask == av_masks)
+ return i;
+ av_masks += BITS_TO_LONGS(masklength);
+ i++;
+ }
+
+ dev_warn(indio_dev->dev.parent,
+ "active scan mask is not part of the available scan masks\n");
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(iio_active_scan_mask_index);
+
int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
@@ -2063,18 +2109,16 @@ void iio_device_unregister(struct iio_dev *indio_dev)
cdev_device_del(&iio_dev_opaque->chrdev, &indio_dev->dev);
- mutex_lock(&iio_dev_opaque->info_exist_lock);
-
- iio_device_unregister_debugfs(indio_dev);
-
- iio_disable_all_buffers(indio_dev);
+ scoped_guard(mutex, &iio_dev_opaque->info_exist_lock) {
+ iio_device_unregister_debugfs(indio_dev);
- indio_dev->info = NULL;
+ iio_disable_all_buffers(indio_dev);
- iio_device_wakeup_eventset(indio_dev);
- iio_buffer_wakeup_poll(indio_dev);
+ indio_dev->info = NULL;
- mutex_unlock(&iio_dev_opaque->info_exist_lock);
+ iio_device_wakeup_eventset(indio_dev);
+ iio_buffer_wakeup_poll(indio_dev);
+ }
iio_buffers_free_sysfs_and_mask(indio_dev);
}