// SPDX-License-Identifier: GPL-2.0-only /* * The industrial I/O core * * Copyright (c) 2008 Jonathan Cameron * * Based on elements of hwmon and input subsystems.
*/
/** * 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);
#ifdefined(CONFIG_DEBUG_FS) /* * There's also a CONFIG_DEBUG_FS guard in include/linux/iio/iio.h for * iio_get_debugfs_dentry() to make it inline if CONFIG_DEBUG_FS is undefined
*/ struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
{ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
/** * 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.
*/ conststruct iio_chan_spec
*iio_find_channel_from_si(struct iio_dev *indio_dev, int si)
{ int i;
for (i = 0; i < indio_dev->num_channels; i++) if (indio_dev->channels[i].scan_index == si) return &indio_dev->channels[i]; return NULL;
}
/* This turns up an awful lot */
ssize_t iio_read_const_attr(struct device *dev, struct device_attribute *attr, char *buf)
{ return sysfs_emit(buf, "%s\n", to_iio_const_attr(attr)->string);
}
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. * * Returns: 0 on success, or a negative error code.
*/ int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
{ int ret; struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); conststruct iio_event_interface *ev_int = iio_dev_opaque->event_interface;
ret = mutex_lock_interruptible(&iio_dev_opaque->mlock); if (ret) return ret; if ((ev_int && iio_event_enabled(ev_int)) ||
iio_buffer_enabled(indio_dev)) {
mutex_unlock(&iio_dev_opaque->mlock); return -EBUSY;
}
iio_dev_opaque->clock_id = clock_id;
mutex_unlock(&iio_dev_opaque->mlock);
return 0;
}
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(conststruct iio_dev *indio_dev)
{ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
/** * 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(conststruct iio_dev *indio_dev)
{ struct timespec64 tp;
switch (iio_device_get_clock(indio_dev)) { case CLOCK_REALTIME: return ktime_get_real_ns(); case CLOCK_MONOTONIC: return ktime_get_ns(); case CLOCK_MONOTONIC_RAW: return ktime_get_raw_ns(); case CLOCK_REALTIME_COARSE: return ktime_to_ns(ktime_get_coarse_real()); case CLOCK_MONOTONIC_COARSE:
ktime_get_coarse_ts64(&tp); return timespec64_to_ns(&tp); case CLOCK_BOOTTIME: return ktime_get_boottime_ns(); case CLOCK_TAI: return ktime_get_clocktai_ns(); default:
BUG();
}
}
EXPORT_SYMBOL(iio_get_time_ns);
staticint __init iio_init(void)
{ int ret;
/* Register sysfs bus */
ret = bus_register(&iio_bus_type); if (ret < 0) {
pr_err("could not register bus type\n"); goto error_nothing;
}
ret = alloc_chrdev_region(&iio_devt, 0, IIO_DEV_MAX, "iio"); if (ret < 0) {
pr_err("failed to allocate char dev region\n"); goto error_unregister_bus_type;
}
/** * iio_read_mount_matrix() - retrieve iio device mounting matrix from * device "mount-matrix" property * @dev: device the mounting matrix property is assigned to * @matrix: where to store retrieved matrix * * If device is assigned no mounting matrix property, a default 3x3 identity * matrix will be filled in. * * Returns: 0 if success, or a negative error code on failure.
*/ int iio_read_mount_matrix(struct device *dev, struct iio_mount_matrix *matrix)
{
size_t len = ARRAY_SIZE(iio_mount_idmatrix.rotation); int err;
for (i = 0; i < size; ++i)
l += sysfs_emit_at(buf, offset + l, "%d ", vals[i]); return l;
} case IIO_VAL_CHAR: return sysfs_emit_at(buf, offset, "%c", (char)vals[0]); case IIO_VAL_INT_64:
tmp2 = (s64)((((u64)vals[1]) << 32) | (u32)vals[0]); return sysfs_emit_at(buf, offset, "%lld", tmp2); default: return 0;
}
}
/** * iio_format_value() - Formats a IIO value into its string representation * @buf: The buffer to which the formatted value gets written * which is assumed to be big enough (i.e. PAGE_SIZE). * @type: One of the IIO_VAL_* constants. This decides how the val * and val2 parameters are formatted. * @size: Number of IIO value entries contained in vals * @vals: Pointer to the values, exact meaning depends on the * type parameter. * * 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, unsignedint type, int size, int *vals)
{
ssize_t len;
len = __iio_format_value(buf, 0, type, size, vals); if (len >= PAGE_SIZE - 1) return -EFBIG;
return len + sysfs_emit_at(buf, len, "\n");
}
EXPORT_SYMBOL_GPL(iio_format_value);
static ssize_t iio_format_avail_range(char *buf, constint *vals, int type)
{ int length;
/* * length refers to the array size , not the number of elements. * The purpose is to print the range [min , step ,max] so length should * be 3 in case of int, and 6 for other types.
*/ switch (type) { case IIO_VAL_INT:
length = 3; break; default:
length = 6; break;
}
static ssize_t iio_read_channel_info_avail(struct device *dev, struct device_attribute *attr, char *buf)
{ struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); constint *vals; int ret; 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);
if (ret < 0) return ret; switch (ret) { case IIO_AVAIL_LIST: return iio_format_avail_list(buf, vals, type, length); case IIO_AVAIL_RANGE: return iio_format_avail_range(buf, vals, type); default: return -EINVAL;
}
}
/** * __iio_str_to_fixpoint() - Parse a fixed-point number from a string * @str: The string to parse * @fract_mult: Multiplier for the first decimal place, should be a power of 10 * @integer: The integer part of the number * @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.
*/ staticint __iio_str_to_fixpoint(constchar *str, int fract_mult, int *integer, int *fract, bool scale_db)
{ int i = 0, f = 0; bool integer_part = true, negative = false;
/** * iio_str_to_fixpoint() - Parse a fixed-point number from a string * @str: The string to parse * @fract_mult: Multiplier for the first decimal place, should be a power of 10 * @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.
*/ int iio_str_to_fixpoint(constchar *str, int fract_mult, int *integer, int *fract)
{ return __iio_str_to_fixpoint(str, fract_mult, integer, fract, false);
}
EXPORT_SYMBOL_GPL(iio_str_to_fixpoint);
/* Build up postfix of <extend_name>_<modifier>_postfix */ if (chan->modified && (shared_by == IIO_SEPARATE)) { if (chan->extend_name)
full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_modifier_names[chan->channel2],
chan->extend_name,
postfix); else
full_postfix = kasprintf(GFP_KERNEL, "%s_%s",
iio_modifier_names[chan->channel2],
postfix);
} else { if (chan->extend_name == NULL || shared_by != IIO_SEPARATE)
full_postfix = kstrdup(postfix, GFP_KERNEL); else
full_postfix = kasprintf(GFP_KERNEL, "%s_%s",
chan->extend_name,
postfix);
} if (full_postfix == NULL) return -ENOMEM;
if (chan->differential) { /* Differential can not have modifier */ switch (shared_by) { case IIO_SHARED_BY_ALL:
name = kasprintf(GFP_KERNEL, "%s", full_postfix); break; case IIO_SHARED_BY_DIR:
name = kasprintf(GFP_KERNEL, "%s_%s",
iio_direction[chan->output],
full_postfix); break; case IIO_SHARED_BY_TYPE:
name = kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
iio_chan_type_name_spec[chan->type],
full_postfix); break; case IIO_SEPARATE: if (!chan->indexed) {
WARN(1, "Differential channels must be indexed\n");
ret = -EINVAL; goto error_free_full_postfix;
}
name = kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
chan->channel,
iio_chan_type_name_spec[chan->type],
chan->channel2,
full_postfix); break;
}
} else { /* Single ended */ switch (shared_by) { case IIO_SHARED_BY_ALL:
name = kasprintf(GFP_KERNEL, "%s", full_postfix); break; case IIO_SHARED_BY_DIR:
name = kasprintf(GFP_KERNEL, "%s_%s",
iio_direction[chan->output],
full_postfix); break; case IIO_SHARED_BY_TYPE:
name = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
full_postfix); break;
case IIO_SEPARATE: if (chan->indexed)
name = kasprintf(GFP_KERNEL, "%s_%s%d_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
chan->channel,
full_postfix); else
name = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_direction[chan->output],
iio_chan_type_name_spec[chan->type],
full_postfix); break;
}
} if (name == NULL) {
ret = -ENOMEM; goto error_free_full_postfix;
}
dev_attr->attr.name = name;
if (readfunc) {
dev_attr->attr.mode |= 0444;
dev_attr->show = readfunc;
}
if (writefunc) {
dev_attr->attr.mode |= 0200;
dev_attr->store = writefunc;
}
if (chan->channel < 0) return 0;
ret = iio_device_add_info_mask_type(indio_dev, chan,
IIO_SEPARATE,
&chan->info_mask_separate); if (ret < 0) return ret;
attrcount += ret;
ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
IIO_SEPARATE,
&chan->info_mask_separate_available); if (ret < 0) return ret;
attrcount += ret;
ret = iio_device_add_info_mask_type(indio_dev, chan,
IIO_SHARED_BY_TYPE,
&chan->info_mask_shared_by_type); if (ret < 0) return ret;
attrcount += ret;
ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
IIO_SHARED_BY_TYPE,
&chan->info_mask_shared_by_type_available); if (ret < 0) return ret;
attrcount += ret;
ret = iio_device_add_info_mask_type(indio_dev, chan,
IIO_SHARED_BY_DIR,
&chan->info_mask_shared_by_dir); if (ret < 0) return ret;
attrcount += ret;
ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
IIO_SHARED_BY_DIR,
&chan->info_mask_shared_by_dir_available); if (ret < 0) return ret;
attrcount += ret;
ret = iio_device_add_info_mask_type(indio_dev, chan,
IIO_SHARED_BY_ALL,
&chan->info_mask_shared_by_all); if (ret < 0) return ret;
attrcount += ret;
ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
IIO_SHARED_BY_ALL,
&chan->info_mask_shared_by_all_available); if (ret < 0) return ret;
attrcount += ret;
ret = iio_device_add_channel_label(indio_dev, chan); if (ret < 0) return ret;
attrcount += ret;
if (chan->ext_info) { unsignedint i = 0;
for (ext_info = chan->ext_info; ext_info->name; ext_info++) {
ret = __iio_add_chan_devattr(ext_info->name,
chan,
ext_info->read ?
&iio_read_channel_ext_info : NULL,
ext_info->write ?
&iio_write_channel_ext_info : NULL,
i,
ext_info->shared,
&indio_dev->dev,
NULL,
&iio_dev_opaque->channel_attr_list);
i++; if (ret == -EBUSY && ext_info->shared) continue;
if (ret) return ret;
attrcount++;
}
}
return attrcount;
}
/** * iio_free_chan_devattr_list() - Free a list of IIO device attributes * @attr_list: List of IIO device attributes * * This function frees the memory allocated for each of the IIO device * attributes in the list.
*/ void iio_free_chan_devattr_list(struct list_head *attr_list)
{ struct iio_dev_attr *p, *n;
list_for_each_entry_safe(p, n, attr_list, l) {
kfree_const(p->dev_attr.attr.name);
list_del(&p->l);
kfree(p);
}
}
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:
BUG();
}
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) return ret;
staticint iio_device_register_sysfs(struct iio_dev *indio_dev)
{ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); int i, ret = 0, attrcount, attrn, attrcount_orig = 0; struct iio_dev_attr *p; struct attribute **attr, *clk = NULL;
/* First count elements in any existing group */ if (indio_dev->info->attrs) {
attr = indio_dev->info->attrs->attrs; while (*attr++ != NULL)
attrcount_orig++;
}
attrcount = attrcount_orig; /* * New channel registration method - relies on the fact a group does * not need to be initialized if its name is NULL.
*/ if (indio_dev->channels) for (i = 0; i < indio_dev->num_channels; i++) { conststruct iio_chan_spec *chan =
&indio_dev->channels[i];
if (chan->type == IIO_TIMESTAMP)
clk = &dev_attr_current_timestamp_clock.attr;
ret = iio_device_add_channel_sysfs(indio_dev, chan); if (ret < 0) goto error_clear_attrs;
attrcount += ret;
}
if (iio_dev_opaque->event_interface)
clk = &dev_attr_current_timestamp_clock.attr;
if (indio_dev->name)
attrcount++; if (indio_dev->label)
attrcount++; if (clk)
attrcount++;
iio_dev_opaque->chan_attr_group.attrs =
kcalloc(attrcount + 1, sizeof(iio_dev_opaque->chan_attr_group.attrs[0]),
GFP_KERNEL); if (iio_dev_opaque->chan_attr_group.attrs == NULL) {
ret = -ENOMEM; goto error_clear_attrs;
} /* Copy across original attributes, and point to original binary attributes */ if (indio_dev->info->attrs) {
memcpy(iio_dev_opaque->chan_attr_group.attrs,
indio_dev->info->attrs->attrs, sizeof(iio_dev_opaque->chan_attr_group.attrs[0])
*attrcount_orig);
iio_dev_opaque->chan_attr_group.is_visible =
indio_dev->info->attrs->is_visible;
iio_dev_opaque->chan_attr_group.bin_attrs =
indio_dev->info->attrs->bin_attrs;
}
attrn = attrcount_orig; /* Add all elements from the list. */
list_for_each_entry(p, &iio_dev_opaque->channel_attr_list, l)
iio_dev_opaque->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr; if (indio_dev->name)
iio_dev_opaque->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr; if (indio_dev->label)
iio_dev_opaque->chan_attr_group.attrs[attrn++] = &dev_attr_label.attr; if (clk)
iio_dev_opaque->chan_attr_group.attrs[attrn++] = clk;
ret = iio_device_register_sysfs_group(indio_dev,
&iio_dev_opaque->chan_attr_group); if (ret) goto error_free_chan_attrs;
iio_dev_opaque->id = ida_alloc(&iio_ida, GFP_KERNEL); if (iio_dev_opaque->id < 0) { /* cannot use a dev_err as the name isn't available */
pr_err("failed to get device id\n");
kfree(iio_dev_opaque); return NULL;
}
/** * 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)
put_device(&dev->dev);
}
EXPORT_SYMBOL(iio_device_free);
/** * devm_iio_device_alloc - Resource-managed iio_device_alloc() * @parent: Device to allocate iio_dev for, and parent for this IIO device * @sizeof_priv: Space to allocate for private structure. * * Managed iio_device_alloc. iio_dev allocated with this function is * automatically freed on driver detach. * * Returns: * Pointer to allocated iio_dev on success, NULL on failure.
*/ struct iio_dev *devm_iio_device_alloc(struct device *parent, int sizeof_priv)
{ struct iio_dev *iio_dev; int ret;
iio_dev = iio_device_alloc(parent, sizeof_priv); if (!iio_dev) return NULL;
ret = devm_add_action_or_reset(parent, devm_iio_device_release,
iio_dev); if (ret) return NULL;
/** * iio_chrdev_open() - chrdev file open for buffer access and ioctls * @inode: Inode structure for identifying the device in the file system * @filp: File structure for iio device used to keep and later access * private data * * Returns: 0 on success or -EBUSY if the device is already opened
*/ staticint iio_chrdev_open(struct inode *inode, struct file *filp)
{ struct iio_dev_opaque *iio_dev_opaque =
container_of(inode->i_cdev, struct iio_dev_opaque, chrdev); struct iio_dev *indio_dev = &iio_dev_opaque->indio_dev; struct iio_dev_buffer_pair *ib;
if (test_and_set_bit(IIO_BUSY_BIT_POS, &iio_dev_opaque->flags)) return -EBUSY;
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) 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) return ret;
}
for (i = 0; i < indio_dev->num_channels; i++) { if (indio_dev->channels[i].extend_name) {
dev_err(&indio_dev->dev, "Cannot use labels and extend_name at the same time\n"); return -EINVAL;
}
}
/* * 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++) { constunsignedlong *mask1; int j;
mask1 = av_masks + i * longs_per_mask; for (j = i + 1; j < num_masks; j++) { constunsignedlong *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)
{ constunsignedlong *av_masks; unsignedint 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 = NULL; int ret;
if (!indio_dev->info) return -EINVAL;
iio_dev_opaque->driver_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); /* The default dummy IIO device has no parent */ elseif (indio_dev->dev.parent)
fwnode = dev_fwnode(indio_dev->dev.parent);
device_set_node(&indio_dev->dev, fwnode);
ret = iio_check_unique_scan_index(indio_dev); if (ret < 0) return ret;
ret = iio_check_extended_name(indio_dev); if (ret < 0) return ret;
iio_device_register_debugfs(indio_dev);
ret = iio_buffers_alloc_sysfs_and_mask(indio_dev); if (ret) {
dev_err(indio_dev->dev.parent, "Failed to create buffer sysfs interfaces\n"); 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, "Failed to register sysfs interfaces\n"); goto error_buffer_free_sysfs;
}
ret = iio_device_register_eventset(indio_dev); if (ret) {
dev_err(indio_dev->dev.parent, "Failed to register event set\n"); goto error_free_sysfs;
} if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES)
iio_device_register_trigger_consumer(indio_dev);
/** * __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() is called. * * Use with __iio_device_release_direct(). * * Drivers should only call iio_device_claim_direct(). * * Returns: true on success, false on failure.
*/ bool __iio_device_claim_direct(struct iio_dev *indio_dev)
{ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
mutex_lock(&iio_dev_opaque->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&iio_dev_opaque->mlock); returnfalse;
} returntrue;
}
EXPORT_SYMBOL_GPL(__iio_device_claim_direct);
/** * __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. * * Drivers should only call iio_device_release_direct(). * * Use with __iio_device_claim_direct()
*/ 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);
/** * iio_device_claim_buffer_mode - Keep device in buffer mode * @indio_dev: the iio_dev associated with the device * * If the device is in buffer mode it is guaranteed to stay * that way until iio_device_release_buffer_mode() is called. * * Use with iio_device_release_buffer_mode(). * * Returns: 0 on success, -EBUSY on failure.
*/ int iio_device_claim_buffer_mode(struct iio_dev *indio_dev)
{ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
/** * iio_device_release_buffer_mode - releases claim on buffer mode * @indio_dev: the iio_dev associated with the device * * Release the claim. Device is no longer guaranteed to stay * in buffer mode. * * Use with iio_device_claim_buffer_mode().
*/ void iio_device_release_buffer_mode(struct iio_dev *indio_dev)
{
mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock);
}
EXPORT_SYMBOL_GPL(iio_device_release_buffer_mode);
/** * iio_device_get_current_mode() - helper function providing read-only access to * the opaque @currentmode variable * @indio_dev: IIO device structure for device
*/ int iio_device_get_current_mode(struct iio_dev *indio_dev)
{ struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.