diff options
Diffstat (limited to 'drivers/iio/industrialio-core.c')
| -rw-r--r-- | drivers/iio/industrialio-core.c | 508 |
1 files changed, 319 insertions, 189 deletions
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 52e690f031cb..f69deefcfb6f 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -/* The industrial I/O core +/* + * The industrial I/O core * * Copyright (c) 2008 Jonathan Cameron * @@ -8,30 +9,34 @@ #define pr_fmt(fmt) "iio-core: " fmt -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/idr.h> -#include <linux/kdev_t.h> -#include <linux/err.h> +#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> #include <linux/fs.h> +#include <linux/idr.h> +#include <linux/kdev_t.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> #include <linux/poll.h> #include <linux/property.h> #include <linux/sched.h> -#include <linux/wait.h> -#include <linux/cdev.h> #include <linux/slab.h> -#include <linux/anon_inodes.h> -#include <linux/debugfs.h> -#include <linux/mutex.h> -#include <linux/iio/iio.h> +#include <linux/wait.h> +#include <linux/wordpart.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/buffer_impl.h> +#include <linux/iio/events.h> #include <linux/iio/iio-opaque.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + #include "iio_core.h" #include "iio_core_trigger.h" -#include <linux/iio/sysfs.h> -#include <linux/iio/events.h> -#include <linux/iio/buffer.h> -#include <linux/iio/buffer_impl.h> /* IDA to assign each registered device a unique id */ static DEFINE_IDA(iio_ida); @@ -39,7 +44,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); @@ -87,6 +92,12 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_POSITIONRELATIVE] = "positionrelative", [IIO_PHASE] = "phase", [IIO_MASSCONCENTRATION] = "massconcentration", + [IIO_DELTA_ANGL] = "deltaangl", + [IIO_DELTA_VELOCITY] = "deltavelocity", + [IIO_COLORTEMP] = "colortemp", + [IIO_CHROMATICITY] = "chromaticity", + [IIO_ATTENTION] = "attention", + [IIO_ALTCURRENT] = "altcurrent", }; static const char * const iio_modifier_names[] = { @@ -110,6 +121,8 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_LIGHT_GREEN] = "green", [IIO_MOD_LIGHT_BLUE] = "blue", [IIO_MOD_LIGHT_UV] = "uv", + [IIO_MOD_LIGHT_UVA] = "uva", + [IIO_MOD_LIGHT_UVB] = "uvb", [IIO_MOD_LIGHT_DUV] = "duv", [IIO_MOD_QUATERNION] = "quaternion", [IIO_MOD_TEMP_AMBIENT] = "ambient", @@ -140,6 +153,10 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_PITCH] = "pitch", [IIO_MOD_YAW] = "yaw", [IIO_MOD_ROLL] = "roll", + [IIO_MOD_RMS] = "rms", + [IIO_MOD_ACTIVE] = "active", + [IIO_MOD_REACTIVE] = "reactive", + [IIO_MOD_APPARENT] = "apparent", }; /* relies on pairs of these shared then separate */ @@ -175,13 +192,18 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_THERMOCOUPLE_TYPE] = "thermocouple_type", [IIO_CHAN_INFO_CALIBAMBIENT] = "calibambient", [IIO_CHAN_INFO_ZEROPOINT] = "zeropoint", + [IIO_CHAN_INFO_TROUGH] = "trough_raw", + [IIO_CHAN_INFO_CONVDELAY] = "convdelay", + [IIO_CHAN_INFO_POWERFACTOR] = "powerfactor", }; /** * iio_device_id() - query the unique ID for the device * @indio_dev: Device structure whose ID is being queried * * The IIO device ID is a unique index used for example for the naming - * of the character device /dev/iio\:device[ID] + * of the character device /dev/iio\:device[ID]. + * + * Returns: Unique ID for the device. */ int iio_device_id(struct iio_dev *indio_dev) { @@ -194,47 +216,17 @@ EXPORT_SYMBOL_GPL(iio_device_id); /** * iio_buffer_enabled() - helper function to test if the buffer is enabled * @indio_dev: IIO device structure for device + * + * Returns: True, if the buffer is enabled. */ 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_TRIGGERED | INDIO_BUFFER_HARDWARE | - INDIO_BUFFER_SOFTWARE); + return iio_dev_opaque->currentmode & INDIO_ALL_BUFFER_MODES; } EXPORT_SYMBOL_GPL(iio_buffer_enabled); -/** - * iio_sysfs_match_string_with_gaps - matches given string in an array with gaps - * @array: array of strings - * @n: number of strings in the array - * @str: string to match with - * - * Returns index of @str in the @array or -EINVAL, similar to match_string(). - * Uses sysfs_streq instead of strcmp for matching. - * - * This routine will look for a string in an array of strings. - * The search will continue until the element is found or the n-th element - * is reached, regardless of any NULL elements in the array. - */ -static int iio_sysfs_match_string_with_gaps(const char * const *array, size_t n, - const char *str) -{ - const char *item; - int index; - - for (index = 0; index < n; index++) { - item = array[index]; - if (!item) - continue; - if (sysfs_streq(item, str)) - return index; - } - - return -EINVAL; -} - #if defined(CONFIG_DEBUG_FS) /* * There's also a CONFIG_DEBUG_FS guard in include/linux/iio/iio.h for @@ -253,6 +245,9 @@ EXPORT_SYMBOL_GPL(iio_get_debugfs_dentry); * iio_find_channel_from_si() - get channel from its scan index * @indio_dev: device * @si: scan index to match + * + * Returns: + * Constant pointer to iio_chan_spec, if scan index matches, NULL on failure. */ const struct iio_chan_spec *iio_find_channel_from_si(struct iio_dev *indio_dev, int si) @@ -277,7 +272,9 @@ EXPORT_SYMBOL(iio_read_const_attr); /** * iio_device_set_clock() - Set current timestamping clock for the device * @indio_dev: IIO device structure containing the device - * @clock_id: timestamping clock posix identifier to set. + * @clock_id: timestamping clock POSIX identifier to set. + * + * Returns: 0 on success, or a negative error code. */ int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id) { @@ -303,6 +300,8 @@ EXPORT_SYMBOL(iio_device_set_clock); /** * iio_device_get_clock() - Retrieve current timestamping clock for the device * @indio_dev: IIO device structure containing the device + * + * Returns: Clock ID of the current timestamping clock for the device. */ clockid_t iio_device_get_clock(const struct iio_dev *indio_dev) { @@ -315,6 +314,8 @@ EXPORT_SYMBOL(iio_device_get_clock); /** * iio_get_time_ns() - utility function to get a time stamp for events etc * @indio_dev: device + * + * Returns: Timestamp of the event in nanoseconds. */ s64 iio_get_time_ns(const struct iio_dev *indio_dev) { @@ -400,8 +401,8 @@ static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf, } iio_dev_opaque->read_buf_len = snprintf(iio_dev_opaque->read_buf, - sizeof(iio_dev_opaque->read_buf), - "0x%X\n", val); + sizeof(iio_dev_opaque->read_buf), + "0x%X\n", val); return simple_read_from_buffer(userbuf, count, ppos, iio_dev_opaque->read_buf, @@ -417,11 +418,15 @@ static ssize_t iio_debugfs_write_reg(struct file *file, char buf[80]; int ret; - count = min_t(size_t, count, (sizeof(buf)-1)); - if (copy_from_user(buf, userbuf, count)) - return -EFAULT; + if (count >= sizeof(buf)) + return -EINVAL; + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf, + count); + if (ret < 0) + return ret; - buf[count] = 0; + buf[ret] = '\0'; ret = sscanf(buf, "%i %i", ®, &val); @@ -504,8 +509,7 @@ static ssize_t iio_read_channel_ext_info(struct device *dev, static ssize_t iio_write_channel_ext_info(struct device *dev, struct device_attribute *attr, - const char *buf, - size_t len) + const char *buf, size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); @@ -552,7 +556,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev, i = e->get(indio_dev, chan); if (i < 0) return i; - else if (i >= e->num_items || !e->items[i]) + if (i >= e->num_items || !e->items[i]) return -EINVAL; return sysfs_emit(buf, "%s\n", e->items[i]); @@ -569,7 +573,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, if (!e->set) return -EINVAL; - ret = iio_sysfs_match_string_with_gaps(e->items, e->num_items, buf); + ret = __sysfs_match_string(e->items, e->num_items, buf); if (ret < 0) return ret; @@ -597,9 +601,9 @@ static int iio_setup_mount_idmatrix(const struct device *dev, ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv, const struct iio_chan_spec *chan, char *buf) { - const struct iio_mount_matrix *mtx = ((iio_get_mount_matrix_t *) - priv)(indio_dev, chan); + const struct iio_mount_matrix *mtx; + mtx = ((iio_get_mount_matrix_t *)priv)(indio_dev, chan); if (IS_ERR(mtx)) return PTR_ERR(mtx); @@ -622,7 +626,7 @@ EXPORT_SYMBOL_GPL(iio_show_mount_matrix); * If device is assigned no mounting matrix property, a default 3x3 identity * matrix will be filled in. * - * Return: 0 if success, or a negative error code on failure. + * Returns: 0 if success, or a negative error code on failure. */ int iio_read_mount_matrix(struct device *dev, struct iio_mount_matrix *matrix) { @@ -676,7 +680,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)); @@ -720,9 +723,9 @@ static ssize_t __iio_format_value(char *buf, size_t offset, unsigned int type, * @vals: Pointer to the values, exact meaning depends on the * type parameter. * - * Return: 0 by default, a negative number on failure or the - * total number of characters written for a type that belongs - * to the IIO_VAL_* constant. + * Returns: + * 0 by default, a negative number on failure or the total number of characters + * written for a type that belongs to the IIO_VAL_* constant. */ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) { @@ -736,22 +739,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) @@ -767,9 +775,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; @@ -786,6 +796,7 @@ static ssize_t iio_format_list(char *buf, const int *vals, int type, int length, switch (type) { case IIO_VAL_INT: + case IIO_VAL_CHAR: stride = 1; break; default: @@ -851,6 +862,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); @@ -875,8 +889,8 @@ static ssize_t iio_read_channel_info_avail(struct device *dev, * @fract: The fractional part of the number * @scale_db: True if this should parse as dB * - * Returns 0 on success, or a negative error code if the string could not be - * parsed. + * Returns: + * 0 on success, or a negative error code if the string could not be parsed. */ static int __iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, int *fract, bool scale_db) @@ -945,8 +959,8 @@ static int __iio_str_to_fixpoint(const char *str, int fract_mult, * @integer: The integer part of the number * @fract: The fractional part of the number * - * Returns 0 on success, or a negative error code if the string could not be - * parsed. + * Returns: + * 0 on success, or a negative error code if the string could not be parsed. */ int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer, int *fract) @@ -964,8 +978,10 @@ static ssize_t iio_write_channel_info(struct device *dev, struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret, fract_mult = 100000; int integer, fract = 0; + long long integer64; bool is_char = false; bool scale_db = false; + bool is_64bit = false; /* Assumes decimal - precision based on number of digits */ if (!indio_dev->info->write_raw) @@ -989,6 +1005,9 @@ static ssize_t iio_write_channel_info(struct device *dev, case IIO_VAL_CHAR: is_char = true; break; + case IIO_VAL_INT_64: + is_64bit = true; + break; default: return -EINVAL; } @@ -999,6 +1018,13 @@ static ssize_t iio_write_channel_info(struct device *dev, if (sscanf(buf, "%c", &ch) != 1) return -EINVAL; integer = ch; + } else if (is_64bit) { + ret = kstrtoll(buf, 0, &integer64); + if (ret) + return ret; + + fract = upper_32_bits(integer64); + integer = lower_32_bits(integer64); } else { ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract, scale_db); @@ -1037,14 +1063,12 @@ int __iio_device_attr_init(struct device_attribute *dev_attr, if (chan->modified && (shared_by == IIO_SEPARATE)) { if (chan->extend_name) full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s", - iio_modifier_names[chan - ->channel2], + iio_modifier_names[chan->channel2], chan->extend_name, postfix); else full_postfix = kasprintf(GFP_KERNEL, "%s_%s", - iio_modifier_names[chan - ->channel2], + iio_modifier_names[chan->channel2], postfix); } else { if (chan->extend_name == NULL || shared_by != IIO_SEPARATE) @@ -1226,7 +1250,7 @@ static int iio_device_add_channel_label(struct iio_dev *indio_dev, static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, enum iio_shared_by shared_by, - const long *infomask) + const unsigned long *infomask) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); int i, ret, attrcount = 0; @@ -1245,7 +1269,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, &iio_dev_opaque->channel_attr_list); if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) continue; - else if (ret < 0) + if (ret < 0) return ret; attrcount++; } @@ -1256,7 +1280,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, enum iio_shared_by shared_by, - const long *infomask) + const unsigned long *infomask) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); int i, ret, attrcount = 0; @@ -1283,7 +1307,7 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev, kfree(avail_postfix); if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) continue; - else if (ret < 0) + if (ret < 0) return ret; attrcount++; } @@ -1428,50 +1452,42 @@ static ssize_t label_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(label); +static const char * const clock_names[] = { + [CLOCK_REALTIME] = "realtime", + [CLOCK_MONOTONIC] = "monotonic", + [CLOCK_PROCESS_CPUTIME_ID] = "process_cputime_id", + [CLOCK_THREAD_CPUTIME_ID] = "thread_cputime_id", + [CLOCK_MONOTONIC_RAW] = "monotonic_raw", + [CLOCK_REALTIME_COARSE] = "realtime_coarse", + [CLOCK_MONOTONIC_COARSE] = "monotonic_coarse", + [CLOCK_BOOTTIME] = "boottime", + [CLOCK_REALTIME_ALARM] = "realtime_alarm", + [CLOCK_BOOTTIME_ALARM] = "boottime_alarm", + [CLOCK_SGI_CYCLE] = "sgi_cycle", + [CLOCK_TAI] = "tai", +}; + static ssize_t current_timestamp_clock_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct iio_dev *indio_dev = dev_to_iio_dev(dev); const clockid_t clk = iio_device_get_clock(indio_dev); - const char *name; - ssize_t sz; switch (clk) { case CLOCK_REALTIME: - name = "realtime\n"; - sz = sizeof("realtime\n"); - break; case CLOCK_MONOTONIC: - name = "monotonic\n"; - sz = sizeof("monotonic\n"); - break; case CLOCK_MONOTONIC_RAW: - name = "monotonic_raw\n"; - sz = sizeof("monotonic_raw\n"); - break; case CLOCK_REALTIME_COARSE: - name = "realtime_coarse\n"; - sz = sizeof("realtime_coarse\n"); - break; case CLOCK_MONOTONIC_COARSE: - name = "monotonic_coarse\n"; - sz = sizeof("monotonic_coarse\n"); - break; case CLOCK_BOOTTIME: - name = "boottime\n"; - sz = sizeof("boottime\n"); - break; case CLOCK_TAI: - name = "tai\n"; - sz = sizeof("tai\n"); break; default: BUG(); } - memcpy(buf, name, sz); - return sz; + return sysfs_emit(buf, "%s\n", clock_names[clk]); } static ssize_t current_timestamp_clock_store(struct device *dev, @@ -1481,22 +1497,23 @@ static ssize_t current_timestamp_clock_store(struct device *dev, clockid_t clk; int ret; - if (sysfs_streq(buf, "realtime")) - clk = CLOCK_REALTIME; - else if (sysfs_streq(buf, "monotonic")) - clk = CLOCK_MONOTONIC; - else if (sysfs_streq(buf, "monotonic_raw")) - clk = CLOCK_MONOTONIC_RAW; - else if (sysfs_streq(buf, "realtime_coarse")) - clk = CLOCK_REALTIME_COARSE; - else if (sysfs_streq(buf, "monotonic_coarse")) - clk = CLOCK_MONOTONIC_COARSE; - else if (sysfs_streq(buf, "boottime")) - clk = CLOCK_BOOTTIME; - else if (sysfs_streq(buf, "tai")) - clk = CLOCK_TAI; - else + ret = sysfs_match_string(clock_names, buf); + if (ret < 0) + return ret; + clk = ret; + + switch (clk) { + case CLOCK_REALTIME: + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_RAW: + case CLOCK_REALTIME_COARSE: + case CLOCK_MONOTONIC_COARSE: + case CLOCK_BOOTTIME: + case CLOCK_TAI: + break; + default: return -EINVAL; + } ret = iio_device_set_clock(dev_to_iio_dev(dev), clk); if (ret) @@ -1512,7 +1529,7 @@ int iio_device_register_sysfs_group(struct iio_dev *indio_dev, const struct attribute_group **new, **old = iio_dev_opaque->groups; unsigned int cnt = iio_dev_opaque->groupcounter; - new = krealloc(old, sizeof(*new) * (cnt + 2), GFP_KERNEL); + new = krealloc_array(old, cnt + 2, sizeof(*new), GFP_KERNEL); if (!new) return -ENOMEM; @@ -1601,10 +1618,13 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) ret = iio_device_register_sysfs_group(indio_dev, &iio_dev_opaque->chan_attr_group); if (ret) - goto error_clear_attrs; + goto error_free_chan_attrs; return 0; +error_free_chan_attrs: + kfree(iio_dev_opaque->chan_attr_group.attrs); + iio_dev_opaque->chan_attr_group.attrs = NULL; error_clear_attrs: iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list); @@ -1634,6 +1654,9 @@ static void iio_dev_release(struct device *device) iio_device_detach_buffers(indio_dev); + mutex_destroy(&iio_dev_opaque->info_exist_lock); + mutex_destroy(&iio_dev_opaque->mlock); + lockdep_unregister_key(&iio_dev_opaque->mlock_key); ida_free(&iio_ida, iio_dev_opaque->id); @@ -1649,33 +1672,31 @@ const struct device_type iio_device_type = { * iio_device_alloc() - allocate an iio_dev from a driver * @parent: Parent device. * @sizeof_priv: Space to allocate for private structure. - **/ + * + * Returns: + * Pointer to allocated iio_dev on success, NULL on failure. + */ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) { struct iio_dev_opaque *iio_dev_opaque; 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); - indio_dev->dev.parent = parent; - indio_dev->dev.type = &iio_device_type; - indio_dev->dev.bus = &iio_bus_type; - device_initialize(&indio_dev->dev); - mutex_init(&iio_dev_opaque->mlock); - mutex_init(&iio_dev_opaque->info_exist_lock); + if (sizeof_priv) + ACCESS_PRIVATE(indio_dev, priv) = (char *)iio_dev_opaque + + ALIGN(sizeof(*iio_dev_opaque), IIO_DMA_MINALIGN); + INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list); iio_dev_opaque->id = ida_alloc(&iio_ida, GFP_KERNEL); @@ -1696,7 +1717,14 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers); lockdep_register_key(&iio_dev_opaque->mlock_key); - lockdep_set_class(&iio_dev_opaque->mlock, &iio_dev_opaque->mlock_key); + + mutex_init_with_key(&iio_dev_opaque->mlock, &iio_dev_opaque->mlock_key); + mutex_init(&iio_dev_opaque->info_exist_lock); + + indio_dev->dev.parent = parent; + indio_dev->dev.type = &iio_device_type; + indio_dev->dev.bus = &iio_bus_type; + device_initialize(&indio_dev->dev); return indio_dev; } @@ -1705,7 +1733,7 @@ EXPORT_SYMBOL(iio_device_alloc); /** * iio_device_free() - free an iio_dev from a driver * @dev: the iio_dev associated with the device - **/ + */ void iio_device_free(struct iio_dev *dev) { if (dev) @@ -1726,7 +1754,7 @@ static void devm_iio_device_release(void *iio_dev) * Managed iio_device_alloc. iio_dev allocated with this function is * automatically freed on driver detach. * - * RETURNS: + * Returns: * Pointer to allocated iio_dev on success, NULL on failure. */ struct iio_dev *devm_iio_device_alloc(struct device *parent, int sizeof_priv) @@ -1753,8 +1781,8 @@ EXPORT_SYMBOL_GPL(devm_iio_device_alloc); * @filp: File structure for iio device used to keep and later access * private data * - * Return: 0 on success or -EBUSY if the device is already opened - **/ + * Returns: 0 on success or -EBUSY if the device is already opened + */ static int iio_chrdev_open(struct inode *inode, struct file *filp) { struct iio_dev_opaque *iio_dev_opaque = @@ -1787,7 +1815,7 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) * @inode: Inode structure pointer for the char device * @filp: File structure pointer for the char device * - * Return: 0 for successful release + * Returns: 0 for successful release. */ static int iio_chrdev_release(struct inode *inode, struct file *filp) { @@ -1822,31 +1850,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 = { @@ -1913,10 +1934,113 @@ static int iio_check_extended_name(const struct iio_dev *indio_dev) static const struct iio_buffer_setup_ops noop_ring_setup_ops; +static void iio_sanity_check_avail_scan_masks(struct iio_dev *indio_dev) +{ + unsigned int num_masks, masklength, longs_per_mask; + const unsigned long *av_masks; + int i; + + av_masks = indio_dev->available_scan_masks; + masklength = iio_get_masklength(indio_dev); + longs_per_mask = BITS_TO_LONGS(masklength); + + /* + * The code determining how many available_scan_masks is in the array + * will be assuming the end of masks when first long with all bits + * zeroed is encountered. This is incorrect for masks where mask + * consists of more than one long, and where some of the available masks + * has long worth of bits zeroed (but has subsequent bit(s) set). This + * is a safety measure against bug where array of masks is terminated by + * a single zero while mask width is greater than width of a long. + */ + if (longs_per_mask > 1) + dev_warn(indio_dev->dev.parent, + "multi long available scan masks not fully supported\n"); + + if (bitmap_empty(av_masks, masklength)) + dev_warn(indio_dev->dev.parent, "empty scan mask\n"); + + for (num_masks = 0; *av_masks; num_masks++) + av_masks += longs_per_mask; + + if (num_masks < 2) + return; + + av_masks = indio_dev->available_scan_masks; + + /* + * Go through all the masks from first to one before the last, and see + * that no mask found later from the available_scan_masks array is a + * subset of mask found earlier. If this happens, then the mask found + * later will never get used because scanning the array is stopped when + * the first suitable mask is found. Drivers should order the array of + * available masks in the order of preference (presumably the least + * costy to access masks first). + */ + for (i = 0; i < num_masks - 1; i++) { + const unsigned long *mask1; + int j; + + mask1 = av_masks + i * longs_per_mask; + for (j = i + 1; j < num_masks; j++) { + const unsigned long *mask2; + + mask2 = av_masks + j * longs_per_mask; + if (bitmap_subset(mask2, mask1, masklength)) + dev_warn(indio_dev->dev.parent, + "available_scan_mask %d subset of %d. Never used\n", + j, i); + } + } +} + +/** + * 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); - struct fwnode_handle *fwnode; + struct fwnode_handle *fwnode = NULL; int ret; if (!indio_dev->info) @@ -1927,7 +2051,8 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) /* If the calling driver did not initialize firmware node, do it here */ if (dev_fwnode(&indio_dev->dev)) fwnode = dev_fwnode(&indio_dev->dev); - else + /* The default dummy IIO device has no parent */ + else if (indio_dev->dev.parent) fwnode = dev_fwnode(indio_dev->dev.parent); device_set_node(&indio_dev->dev, fwnode); @@ -1950,6 +2075,9 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) goto error_unreg_debugfs; } + if (indio_dev->available_scan_masks) + iio_sanity_check_avail_scan_masks(indio_dev); + ret = iio_device_register_sysfs(indio_dev); if (ret) { dev_err(indio_dev->dev.parent, @@ -2003,25 +2131,23 @@ EXPORT_SYMBOL(__iio_device_register); /** * iio_device_unregister() - unregister a device from the IIO subsystem * @indio_dev: Device structure representing the device. - **/ + */ void iio_device_unregister(struct iio_dev *indio_dev) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(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); } @@ -2046,17 +2172,19 @@ int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev, EXPORT_SYMBOL_GPL(__devm_iio_device_register); /** - * iio_device_claim_direct_mode - Keep device in direct mode + * __iio_device_claim_direct - Keep device in direct mode * @indio_dev: the iio_dev associated with the device * * If the device is in direct mode it is guaranteed to stay - * that way until iio_device_release_direct_mode() is called. + * that way until __iio_device_release_direct() is called. + * + * Use with __iio_device_release_direct(). * - * Use with iio_device_release_direct_mode() + * Drivers should only call iio_device_claim_direct(). * - * Returns: 0 on success, -EBUSY on failure + * Returns: true on success, false on failure. */ -int iio_device_claim_direct_mode(struct iio_dev *indio_dev) +bool __iio_device_claim_direct(struct iio_dev *indio_dev) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); @@ -2064,26 +2192,28 @@ int iio_device_claim_direct_mode(struct iio_dev *indio_dev) if (iio_buffer_enabled(indio_dev)) { mutex_unlock(&iio_dev_opaque->mlock); - return -EBUSY; + return false; } - return 0; + return true; } -EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode); +EXPORT_SYMBOL_GPL(__iio_device_claim_direct); /** - * iio_device_release_direct_mode - releases claim on direct mode + * __iio_device_release_direct - releases claim on direct mode * @indio_dev: the iio_dev associated with the device * * Release the claim. Device is no longer guaranteed to stay * in direct mode. * - * Use with iio_device_claim_direct_mode() + * Drivers should only call iio_device_release_direct(). + * + * Use with __iio_device_claim_direct() */ -void iio_device_release_direct_mode(struct iio_dev *indio_dev) +void __iio_device_release_direct(struct iio_dev *indio_dev) { mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock); } -EXPORT_SYMBOL_GPL(iio_device_release_direct_mode); +EXPORT_SYMBOL_GPL(__iio_device_release_direct); /** * iio_device_claim_buffer_mode - Keep device in buffer mode |
