18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* The industrial I/O core 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008 Jonathan Cameron 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Handling of buffer allocation / resizing. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Things to look at here. 98c2ecf20Sopenharmony_ci * - Better memory allocation techniques? 108c2ecf20Sopenharmony_ci * - Alternative access techniques? 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/export.h> 148c2ecf20Sopenharmony_ci#include <linux/device.h> 158c2ecf20Sopenharmony_ci#include <linux/fs.h> 168c2ecf20Sopenharmony_ci#include <linux/cdev.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/poll.h> 198c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 228c2ecf20Sopenharmony_ci#include <linux/iio/iio-opaque.h> 238c2ecf20Sopenharmony_ci#include "iio_core.h" 248c2ecf20Sopenharmony_ci#include "iio_core_trigger.h" 258c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 268c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h> 278c2ecf20Sopenharmony_ci#include <linux/iio/buffer_impl.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic const char * const iio_endian_prefix[] = { 308c2ecf20Sopenharmony_ci [IIO_BE] = "be", 318c2ecf20Sopenharmony_ci [IIO_LE] = "le", 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic bool iio_buffer_is_active(struct iio_buffer *buf) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci return !list_empty(&buf->buffer_list); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic size_t iio_buffer_data_available(struct iio_buffer *buf) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci return buf->access->data_available(buf); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int iio_buffer_flush_hwfifo(struct iio_dev *indio_dev, 458c2ecf20Sopenharmony_ci struct iio_buffer *buf, size_t required) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci if (!indio_dev->info->hwfifo_flush_to_buffer) 488c2ecf20Sopenharmony_ci return -ENODEV; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return indio_dev->info->hwfifo_flush_to_buffer(indio_dev, required); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, 548c2ecf20Sopenharmony_ci size_t to_wait, int to_flush) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci size_t avail; 578c2ecf20Sopenharmony_ci int flushed = 0; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* wakeup if the device was unregistered */ 608c2ecf20Sopenharmony_ci if (!indio_dev->info) 618c2ecf20Sopenharmony_ci return true; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* drain the buffer if it was disabled */ 648c2ecf20Sopenharmony_ci if (!iio_buffer_is_active(buf)) { 658c2ecf20Sopenharmony_ci to_wait = min_t(size_t, to_wait, 1); 668c2ecf20Sopenharmony_ci to_flush = 0; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci avail = iio_buffer_data_available(buf); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (avail >= to_wait) { 728c2ecf20Sopenharmony_ci /* force a flush for non-blocking reads */ 738c2ecf20Sopenharmony_ci if (!to_wait && avail < to_flush) 748c2ecf20Sopenharmony_ci iio_buffer_flush_hwfifo(indio_dev, buf, 758c2ecf20Sopenharmony_ci to_flush - avail); 768c2ecf20Sopenharmony_ci return true; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (to_flush) 808c2ecf20Sopenharmony_ci flushed = iio_buffer_flush_hwfifo(indio_dev, buf, 818c2ecf20Sopenharmony_ci to_wait - avail); 828c2ecf20Sopenharmony_ci if (flushed <= 0) 838c2ecf20Sopenharmony_ci return false; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (avail + flushed >= to_wait) 868c2ecf20Sopenharmony_ci return true; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return false; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/** 928c2ecf20Sopenharmony_ci * iio_buffer_read_outer() - chrdev read for buffer access 938c2ecf20Sopenharmony_ci * @filp: File structure pointer for the char device 948c2ecf20Sopenharmony_ci * @buf: Destination buffer for iio buffer read 958c2ecf20Sopenharmony_ci * @n: First n bytes to read 968c2ecf20Sopenharmony_ci * @f_ps: Long offset provided by the user as a seek position 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * This function relies on all buffer implementations having an 998c2ecf20Sopenharmony_ci * iio_buffer as their first element. 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * Return: negative values corresponding to error codes or ret != 0 1028c2ecf20Sopenharmony_ci * for ending the reading activity 1038c2ecf20Sopenharmony_ci **/ 1048c2ecf20Sopenharmony_cissize_t iio_buffer_read_outer(struct file *filp, char __user *buf, 1058c2ecf20Sopenharmony_ci size_t n, loff_t *f_ps) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = filp->private_data; 1088c2ecf20Sopenharmony_ci struct iio_buffer *rb = indio_dev->buffer; 1098c2ecf20Sopenharmony_ci DEFINE_WAIT_FUNC(wait, woken_wake_function); 1108c2ecf20Sopenharmony_ci size_t datum_size; 1118c2ecf20Sopenharmony_ci size_t to_wait; 1128c2ecf20Sopenharmony_ci int ret = 0; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (!indio_dev->info) 1158c2ecf20Sopenharmony_ci return -ENODEV; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (!rb || !rb->access->read) 1188c2ecf20Sopenharmony_ci return -EINVAL; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci datum_size = rb->bytes_per_datum; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * If datum_size is 0 there will never be anything to read from the 1248c2ecf20Sopenharmony_ci * buffer, so signal end of file now. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci if (!datum_size) 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (filp->f_flags & O_NONBLOCK) 1308c2ecf20Sopenharmony_ci to_wait = 0; 1318c2ecf20Sopenharmony_ci else 1328c2ecf20Sopenharmony_ci to_wait = min_t(size_t, n / datum_size, rb->watermark); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci add_wait_queue(&rb->pollq, &wait); 1358c2ecf20Sopenharmony_ci do { 1368c2ecf20Sopenharmony_ci if (!indio_dev->info) { 1378c2ecf20Sopenharmony_ci ret = -ENODEV; 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (!iio_buffer_ready(indio_dev, rb, to_wait, n / datum_size)) { 1428c2ecf20Sopenharmony_ci if (signal_pending(current)) { 1438c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci wait_woken(&wait, TASK_INTERRUPTIBLE, 1488c2ecf20Sopenharmony_ci MAX_SCHEDULE_TIMEOUT); 1498c2ecf20Sopenharmony_ci continue; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci ret = rb->access->read(rb, n, buf); 1538c2ecf20Sopenharmony_ci if (ret == 0 && (filp->f_flags & O_NONBLOCK)) 1548c2ecf20Sopenharmony_ci ret = -EAGAIN; 1558c2ecf20Sopenharmony_ci } while (ret == 0); 1568c2ecf20Sopenharmony_ci remove_wait_queue(&rb->pollq, &wait); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return ret; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/** 1628c2ecf20Sopenharmony_ci * iio_buffer_poll() - poll the buffer to find out if it has data 1638c2ecf20Sopenharmony_ci * @filp: File structure pointer for device access 1648c2ecf20Sopenharmony_ci * @wait: Poll table structure pointer for which the driver adds 1658c2ecf20Sopenharmony_ci * a wait queue 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * Return: (EPOLLIN | EPOLLRDNORM) if data is available for reading 1688c2ecf20Sopenharmony_ci * or 0 for other cases 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci__poll_t iio_buffer_poll(struct file *filp, 1718c2ecf20Sopenharmony_ci struct poll_table_struct *wait) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = filp->private_data; 1748c2ecf20Sopenharmony_ci struct iio_buffer *rb = indio_dev->buffer; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (!indio_dev->info || rb == NULL) 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci poll_wait(filp, &rb->pollq, wait); 1808c2ecf20Sopenharmony_ci if (iio_buffer_ready(indio_dev, rb, rb->watermark, 0)) 1818c2ecf20Sopenharmony_ci return EPOLLIN | EPOLLRDNORM; 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/** 1868c2ecf20Sopenharmony_ci * iio_buffer_wakeup_poll - Wakes up the buffer waitqueue 1878c2ecf20Sopenharmony_ci * @indio_dev: The IIO device 1888c2ecf20Sopenharmony_ci * 1898c2ecf20Sopenharmony_ci * Wakes up the event waitqueue used for poll(). Should usually 1908c2ecf20Sopenharmony_ci * be called when the device is unregistered. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_civoid iio_buffer_wakeup_poll(struct iio_dev *indio_dev) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (!buffer) 1978c2ecf20Sopenharmony_ci return; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci wake_up(&buffer->pollq); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_civoid iio_buffer_init(struct iio_buffer *buffer) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&buffer->demux_list); 2058c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&buffer->buffer_list); 2068c2ecf20Sopenharmony_ci init_waitqueue_head(&buffer->pollq); 2078c2ecf20Sopenharmony_ci kref_init(&buffer->ref); 2088c2ecf20Sopenharmony_ci if (!buffer->watermark) 2098c2ecf20Sopenharmony_ci buffer->watermark = 1; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iio_buffer_init); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/** 2148c2ecf20Sopenharmony_ci * iio_buffer_set_attrs - Set buffer specific attributes 2158c2ecf20Sopenharmony_ci * @buffer: The buffer for which we are setting attributes 2168c2ecf20Sopenharmony_ci * @attrs: Pointer to a null terminated list of pointers to attributes 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_civoid iio_buffer_set_attrs(struct iio_buffer *buffer, 2198c2ecf20Sopenharmony_ci const struct attribute **attrs) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci buffer->attrs = attrs; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_buffer_set_attrs); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic ssize_t iio_show_scan_index(struct device *dev, 2268c2ecf20Sopenharmony_ci struct device_attribute *attr, 2278c2ecf20Sopenharmony_ci char *buf) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", to_iio_dev_attr(attr)->c->scan_index); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic ssize_t iio_show_fixed_type(struct device *dev, 2338c2ecf20Sopenharmony_ci struct device_attribute *attr, 2348c2ecf20Sopenharmony_ci char *buf) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); 2378c2ecf20Sopenharmony_ci u8 type = this_attr->c->scan_type.endianness; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (type == IIO_CPU) { 2408c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN 2418c2ecf20Sopenharmony_ci type = IIO_LE; 2428c2ecf20Sopenharmony_ci#else 2438c2ecf20Sopenharmony_ci type = IIO_BE; 2448c2ecf20Sopenharmony_ci#endif 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci if (this_attr->c->scan_type.repeat > 1) 2478c2ecf20Sopenharmony_ci return sprintf(buf, "%s:%c%d/%dX%d>>%u\n", 2488c2ecf20Sopenharmony_ci iio_endian_prefix[type], 2498c2ecf20Sopenharmony_ci this_attr->c->scan_type.sign, 2508c2ecf20Sopenharmony_ci this_attr->c->scan_type.realbits, 2518c2ecf20Sopenharmony_ci this_attr->c->scan_type.storagebits, 2528c2ecf20Sopenharmony_ci this_attr->c->scan_type.repeat, 2538c2ecf20Sopenharmony_ci this_attr->c->scan_type.shift); 2548c2ecf20Sopenharmony_ci else 2558c2ecf20Sopenharmony_ci return sprintf(buf, "%s:%c%d/%d>>%u\n", 2568c2ecf20Sopenharmony_ci iio_endian_prefix[type], 2578c2ecf20Sopenharmony_ci this_attr->c->scan_type.sign, 2588c2ecf20Sopenharmony_ci this_attr->c->scan_type.realbits, 2598c2ecf20Sopenharmony_ci this_attr->c->scan_type.storagebits, 2608c2ecf20Sopenharmony_ci this_attr->c->scan_type.shift); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic ssize_t iio_scan_el_show(struct device *dev, 2648c2ecf20Sopenharmony_ci struct device_attribute *attr, 2658c2ecf20Sopenharmony_ci char *buf) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci int ret; 2688c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 2698c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Ensure ret is 0 or 1. */ 2728c2ecf20Sopenharmony_ci ret = !!test_bit(to_iio_dev_attr(attr)->address, 2738c2ecf20Sopenharmony_ci buffer->scan_mask); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", ret); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/* Note NULL used as error indicator as it doesn't make sense. */ 2798c2ecf20Sopenharmony_cistatic const unsigned long *iio_scan_mask_match(const unsigned long *av_masks, 2808c2ecf20Sopenharmony_ci unsigned int masklength, 2818c2ecf20Sopenharmony_ci const unsigned long *mask, 2828c2ecf20Sopenharmony_ci bool strict) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci if (bitmap_empty(mask, masklength)) 2858c2ecf20Sopenharmony_ci return NULL; 2868c2ecf20Sopenharmony_ci while (*av_masks) { 2878c2ecf20Sopenharmony_ci if (strict) { 2888c2ecf20Sopenharmony_ci if (bitmap_equal(mask, av_masks, masklength)) 2898c2ecf20Sopenharmony_ci return av_masks; 2908c2ecf20Sopenharmony_ci } else { 2918c2ecf20Sopenharmony_ci if (bitmap_subset(mask, av_masks, masklength)) 2928c2ecf20Sopenharmony_ci return av_masks; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci av_masks += BITS_TO_LONGS(masklength); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci return NULL; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic bool iio_validate_scan_mask(struct iio_dev *indio_dev, 3008c2ecf20Sopenharmony_ci const unsigned long *mask) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci if (!indio_dev->setup_ops->validate_scan_mask) 3038c2ecf20Sopenharmony_ci return true; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return indio_dev->setup_ops->validate_scan_mask(indio_dev, mask); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci/** 3098c2ecf20Sopenharmony_ci * iio_scan_mask_set() - set particular bit in the scan mask 3108c2ecf20Sopenharmony_ci * @indio_dev: the iio device 3118c2ecf20Sopenharmony_ci * @buffer: the buffer whose scan mask we are interested in 3128c2ecf20Sopenharmony_ci * @bit: the bit to be set. 3138c2ecf20Sopenharmony_ci * 3148c2ecf20Sopenharmony_ci * Note that at this point we have no way of knowing what other 3158c2ecf20Sopenharmony_ci * buffers might request, hence this code only verifies that the 3168c2ecf20Sopenharmony_ci * individual buffers request is plausible. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_cistatic int iio_scan_mask_set(struct iio_dev *indio_dev, 3198c2ecf20Sopenharmony_ci struct iio_buffer *buffer, int bit) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci const unsigned long *mask; 3228c2ecf20Sopenharmony_ci unsigned long *trialmask; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci trialmask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL); 3258c2ecf20Sopenharmony_ci if (trialmask == NULL) 3268c2ecf20Sopenharmony_ci return -ENOMEM; 3278c2ecf20Sopenharmony_ci if (!indio_dev->masklength) { 3288c2ecf20Sopenharmony_ci WARN(1, "Trying to set scanmask prior to registering buffer\n"); 3298c2ecf20Sopenharmony_ci goto err_invalid_mask; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength); 3328c2ecf20Sopenharmony_ci set_bit(bit, trialmask); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!iio_validate_scan_mask(indio_dev, trialmask)) 3358c2ecf20Sopenharmony_ci goto err_invalid_mask; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (indio_dev->available_scan_masks) { 3388c2ecf20Sopenharmony_ci mask = iio_scan_mask_match(indio_dev->available_scan_masks, 3398c2ecf20Sopenharmony_ci indio_dev->masklength, 3408c2ecf20Sopenharmony_ci trialmask, false); 3418c2ecf20Sopenharmony_ci if (!mask) 3428c2ecf20Sopenharmony_ci goto err_invalid_mask; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci bitmap_free(trialmask); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cierr_invalid_mask: 3518c2ecf20Sopenharmony_ci bitmap_free(trialmask); 3528c2ecf20Sopenharmony_ci return -EINVAL; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int iio_scan_mask_clear(struct iio_buffer *buffer, int bit) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci clear_bit(bit, buffer->scan_mask); 3588c2ecf20Sopenharmony_ci return 0; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int iio_scan_mask_query(struct iio_dev *indio_dev, 3628c2ecf20Sopenharmony_ci struct iio_buffer *buffer, int bit) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci if (bit > indio_dev->masklength) 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (!buffer->scan_mask) 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Ensure return value is 0 or 1. */ 3718c2ecf20Sopenharmony_ci return !!test_bit(bit, buffer->scan_mask); 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic ssize_t iio_scan_el_store(struct device *dev, 3758c2ecf20Sopenharmony_ci struct device_attribute *attr, 3768c2ecf20Sopenharmony_ci const char *buf, 3778c2ecf20Sopenharmony_ci size_t len) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci int ret; 3808c2ecf20Sopenharmony_ci bool state; 3818c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 3828c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 3838c2ecf20Sopenharmony_ci struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci ret = strtobool(buf, &state); 3868c2ecf20Sopenharmony_ci if (ret < 0) 3878c2ecf20Sopenharmony_ci return ret; 3888c2ecf20Sopenharmony_ci mutex_lock(&indio_dev->mlock); 3898c2ecf20Sopenharmony_ci if (iio_buffer_is_active(buffer)) { 3908c2ecf20Sopenharmony_ci ret = -EBUSY; 3918c2ecf20Sopenharmony_ci goto error_ret; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci ret = iio_scan_mask_query(indio_dev, buffer, this_attr->address); 3948c2ecf20Sopenharmony_ci if (ret < 0) 3958c2ecf20Sopenharmony_ci goto error_ret; 3968c2ecf20Sopenharmony_ci if (!state && ret) { 3978c2ecf20Sopenharmony_ci ret = iio_scan_mask_clear(buffer, this_attr->address); 3988c2ecf20Sopenharmony_ci if (ret) 3998c2ecf20Sopenharmony_ci goto error_ret; 4008c2ecf20Sopenharmony_ci } else if (state && !ret) { 4018c2ecf20Sopenharmony_ci ret = iio_scan_mask_set(indio_dev, buffer, this_attr->address); 4028c2ecf20Sopenharmony_ci if (ret) 4038c2ecf20Sopenharmony_ci goto error_ret; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cierror_ret: 4078c2ecf20Sopenharmony_ci mutex_unlock(&indio_dev->mlock); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return ret < 0 ? ret : len; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic ssize_t iio_scan_el_ts_show(struct device *dev, 4148c2ecf20Sopenharmony_ci struct device_attribute *attr, 4158c2ecf20Sopenharmony_ci char *buf) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 4188c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", buffer->scan_timestamp); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic ssize_t iio_scan_el_ts_store(struct device *dev, 4248c2ecf20Sopenharmony_ci struct device_attribute *attr, 4258c2ecf20Sopenharmony_ci const char *buf, 4268c2ecf20Sopenharmony_ci size_t len) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci int ret; 4298c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 4308c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 4318c2ecf20Sopenharmony_ci bool state; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci ret = strtobool(buf, &state); 4348c2ecf20Sopenharmony_ci if (ret < 0) 4358c2ecf20Sopenharmony_ci return ret; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci mutex_lock(&indio_dev->mlock); 4388c2ecf20Sopenharmony_ci if (iio_buffer_is_active(buffer)) { 4398c2ecf20Sopenharmony_ci ret = -EBUSY; 4408c2ecf20Sopenharmony_ci goto error_ret; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci buffer->scan_timestamp = state; 4438c2ecf20Sopenharmony_cierror_ret: 4448c2ecf20Sopenharmony_ci mutex_unlock(&indio_dev->mlock); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci return ret ? ret : len; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev, 4508c2ecf20Sopenharmony_ci struct iio_buffer *buffer, 4518c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci int ret, attrcount = 0; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci ret = __iio_add_chan_devattr("index", 4568c2ecf20Sopenharmony_ci chan, 4578c2ecf20Sopenharmony_ci &iio_show_scan_index, 4588c2ecf20Sopenharmony_ci NULL, 4598c2ecf20Sopenharmony_ci 0, 4608c2ecf20Sopenharmony_ci IIO_SEPARATE, 4618c2ecf20Sopenharmony_ci &indio_dev->dev, 4628c2ecf20Sopenharmony_ci &buffer->scan_el_dev_attr_list); 4638c2ecf20Sopenharmony_ci if (ret) 4648c2ecf20Sopenharmony_ci return ret; 4658c2ecf20Sopenharmony_ci attrcount++; 4668c2ecf20Sopenharmony_ci ret = __iio_add_chan_devattr("type", 4678c2ecf20Sopenharmony_ci chan, 4688c2ecf20Sopenharmony_ci &iio_show_fixed_type, 4698c2ecf20Sopenharmony_ci NULL, 4708c2ecf20Sopenharmony_ci 0, 4718c2ecf20Sopenharmony_ci 0, 4728c2ecf20Sopenharmony_ci &indio_dev->dev, 4738c2ecf20Sopenharmony_ci &buffer->scan_el_dev_attr_list); 4748c2ecf20Sopenharmony_ci if (ret) 4758c2ecf20Sopenharmony_ci return ret; 4768c2ecf20Sopenharmony_ci attrcount++; 4778c2ecf20Sopenharmony_ci if (chan->type != IIO_TIMESTAMP) 4788c2ecf20Sopenharmony_ci ret = __iio_add_chan_devattr("en", 4798c2ecf20Sopenharmony_ci chan, 4808c2ecf20Sopenharmony_ci &iio_scan_el_show, 4818c2ecf20Sopenharmony_ci &iio_scan_el_store, 4828c2ecf20Sopenharmony_ci chan->scan_index, 4838c2ecf20Sopenharmony_ci 0, 4848c2ecf20Sopenharmony_ci &indio_dev->dev, 4858c2ecf20Sopenharmony_ci &buffer->scan_el_dev_attr_list); 4868c2ecf20Sopenharmony_ci else 4878c2ecf20Sopenharmony_ci ret = __iio_add_chan_devattr("en", 4888c2ecf20Sopenharmony_ci chan, 4898c2ecf20Sopenharmony_ci &iio_scan_el_ts_show, 4908c2ecf20Sopenharmony_ci &iio_scan_el_ts_store, 4918c2ecf20Sopenharmony_ci chan->scan_index, 4928c2ecf20Sopenharmony_ci 0, 4938c2ecf20Sopenharmony_ci &indio_dev->dev, 4948c2ecf20Sopenharmony_ci &buffer->scan_el_dev_attr_list); 4958c2ecf20Sopenharmony_ci if (ret) 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci attrcount++; 4988c2ecf20Sopenharmony_ci ret = attrcount; 4998c2ecf20Sopenharmony_ci return ret; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic ssize_t iio_buffer_read_length(struct device *dev, 5038c2ecf20Sopenharmony_ci struct device_attribute *attr, 5048c2ecf20Sopenharmony_ci char *buf) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 5078c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", buffer->length); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic ssize_t iio_buffer_write_length(struct device *dev, 5138c2ecf20Sopenharmony_ci struct device_attribute *attr, 5148c2ecf20Sopenharmony_ci const char *buf, size_t len) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 5178c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 5188c2ecf20Sopenharmony_ci unsigned int val; 5198c2ecf20Sopenharmony_ci int ret; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci ret = kstrtouint(buf, 10, &val); 5228c2ecf20Sopenharmony_ci if (ret) 5238c2ecf20Sopenharmony_ci return ret; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (val == buffer->length) 5268c2ecf20Sopenharmony_ci return len; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci mutex_lock(&indio_dev->mlock); 5298c2ecf20Sopenharmony_ci if (iio_buffer_is_active(buffer)) { 5308c2ecf20Sopenharmony_ci ret = -EBUSY; 5318c2ecf20Sopenharmony_ci } else { 5328c2ecf20Sopenharmony_ci buffer->access->set_length(buffer, val); 5338c2ecf20Sopenharmony_ci ret = 0; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci if (ret) 5368c2ecf20Sopenharmony_ci goto out; 5378c2ecf20Sopenharmony_ci if (buffer->length && buffer->length < buffer->watermark) 5388c2ecf20Sopenharmony_ci buffer->watermark = buffer->length; 5398c2ecf20Sopenharmony_ciout: 5408c2ecf20Sopenharmony_ci mutex_unlock(&indio_dev->mlock); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return ret ? ret : len; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic ssize_t iio_buffer_show_enable(struct device *dev, 5468c2ecf20Sopenharmony_ci struct device_attribute *attr, 5478c2ecf20Sopenharmony_ci char *buf) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 5508c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", iio_buffer_is_active(buffer)); 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic unsigned int iio_storage_bytes_for_si(struct iio_dev *indio_dev, 5568c2ecf20Sopenharmony_ci unsigned int scan_index) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci const struct iio_chan_spec *ch; 5598c2ecf20Sopenharmony_ci unsigned int bytes; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci ch = iio_find_channel_from_si(indio_dev, scan_index); 5628c2ecf20Sopenharmony_ci bytes = ch->scan_type.storagebits / 8; 5638c2ecf20Sopenharmony_ci if (ch->scan_type.repeat > 1) 5648c2ecf20Sopenharmony_ci bytes *= ch->scan_type.repeat; 5658c2ecf20Sopenharmony_ci return bytes; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic unsigned int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci return iio_storage_bytes_for_si(indio_dev, 5718c2ecf20Sopenharmony_ci indio_dev->scan_index_timestamp); 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int iio_compute_scan_bytes(struct iio_dev *indio_dev, 5758c2ecf20Sopenharmony_ci const unsigned long *mask, bool timestamp) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci unsigned bytes = 0; 5788c2ecf20Sopenharmony_ci int length, i, largest = 0; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* How much space will the demuxed element take? */ 5818c2ecf20Sopenharmony_ci for_each_set_bit(i, mask, 5828c2ecf20Sopenharmony_ci indio_dev->masklength) { 5838c2ecf20Sopenharmony_ci length = iio_storage_bytes_for_si(indio_dev, i); 5848c2ecf20Sopenharmony_ci bytes = ALIGN(bytes, length); 5858c2ecf20Sopenharmony_ci bytes += length; 5868c2ecf20Sopenharmony_ci largest = max(largest, length); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (timestamp) { 5908c2ecf20Sopenharmony_ci length = iio_storage_bytes_for_timestamp(indio_dev); 5918c2ecf20Sopenharmony_ci bytes = ALIGN(bytes, length); 5928c2ecf20Sopenharmony_ci bytes += length; 5938c2ecf20Sopenharmony_ci largest = max(largest, length); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci bytes = ALIGN(bytes, largest); 5978c2ecf20Sopenharmony_ci return bytes; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic void iio_buffer_activate(struct iio_dev *indio_dev, 6018c2ecf20Sopenharmony_ci struct iio_buffer *buffer) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci iio_buffer_get(buffer); 6068c2ecf20Sopenharmony_ci list_add(&buffer->buffer_list, &iio_dev_opaque->buffer_list); 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic void iio_buffer_deactivate(struct iio_buffer *buffer) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci list_del_init(&buffer->buffer_list); 6128c2ecf20Sopenharmony_ci wake_up_interruptible(&buffer->pollq); 6138c2ecf20Sopenharmony_ci iio_buffer_put(buffer); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic void iio_buffer_deactivate_all(struct iio_dev *indio_dev) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 6198c2ecf20Sopenharmony_ci struct iio_buffer *buffer, *_buffer; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci list_for_each_entry_safe(buffer, _buffer, 6228c2ecf20Sopenharmony_ci &iio_dev_opaque->buffer_list, buffer_list) 6238c2ecf20Sopenharmony_ci iio_buffer_deactivate(buffer); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic int iio_buffer_enable(struct iio_buffer *buffer, 6278c2ecf20Sopenharmony_ci struct iio_dev *indio_dev) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci if (!buffer->access->enable) 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci return buffer->access->enable(buffer, indio_dev); 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int iio_buffer_disable(struct iio_buffer *buffer, 6358c2ecf20Sopenharmony_ci struct iio_dev *indio_dev) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci if (!buffer->access->disable) 6388c2ecf20Sopenharmony_ci return 0; 6398c2ecf20Sopenharmony_ci return buffer->access->disable(buffer, indio_dev); 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev, 6438c2ecf20Sopenharmony_ci struct iio_buffer *buffer) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci unsigned int bytes; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (!buffer->access->set_bytes_per_datum) 6488c2ecf20Sopenharmony_ci return; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci bytes = iio_compute_scan_bytes(indio_dev, buffer->scan_mask, 6518c2ecf20Sopenharmony_ci buffer->scan_timestamp); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci buffer->access->set_bytes_per_datum(buffer, bytes); 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int iio_buffer_request_update(struct iio_dev *indio_dev, 6578c2ecf20Sopenharmony_ci struct iio_buffer *buffer) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci int ret; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci iio_buffer_update_bytes_per_datum(indio_dev, buffer); 6628c2ecf20Sopenharmony_ci if (buffer->access->request_update) { 6638c2ecf20Sopenharmony_ci ret = buffer->access->request_update(buffer); 6648c2ecf20Sopenharmony_ci if (ret) { 6658c2ecf20Sopenharmony_ci dev_dbg(&indio_dev->dev, 6668c2ecf20Sopenharmony_ci "Buffer not started: buffer parameter update failed (%d)\n", 6678c2ecf20Sopenharmony_ci ret); 6688c2ecf20Sopenharmony_ci return ret; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic void iio_free_scan_mask(struct iio_dev *indio_dev, 6768c2ecf20Sopenharmony_ci const unsigned long *mask) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci /* If the mask is dynamically allocated free it, otherwise do nothing */ 6798c2ecf20Sopenharmony_ci if (!indio_dev->available_scan_masks) 6808c2ecf20Sopenharmony_ci bitmap_free(mask); 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistruct iio_device_config { 6848c2ecf20Sopenharmony_ci unsigned int mode; 6858c2ecf20Sopenharmony_ci unsigned int watermark; 6868c2ecf20Sopenharmony_ci const unsigned long *scan_mask; 6878c2ecf20Sopenharmony_ci unsigned int scan_bytes; 6888c2ecf20Sopenharmony_ci bool scan_timestamp; 6898c2ecf20Sopenharmony_ci}; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int iio_verify_update(struct iio_dev *indio_dev, 6928c2ecf20Sopenharmony_ci struct iio_buffer *insert_buffer, struct iio_buffer *remove_buffer, 6938c2ecf20Sopenharmony_ci struct iio_device_config *config) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 6968c2ecf20Sopenharmony_ci unsigned long *compound_mask; 6978c2ecf20Sopenharmony_ci const unsigned long *scan_mask; 6988c2ecf20Sopenharmony_ci bool strict_scanmask = false; 6998c2ecf20Sopenharmony_ci struct iio_buffer *buffer; 7008c2ecf20Sopenharmony_ci bool scan_timestamp; 7018c2ecf20Sopenharmony_ci unsigned int modes; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (insert_buffer && 7048c2ecf20Sopenharmony_ci bitmap_empty(insert_buffer->scan_mask, indio_dev->masklength)) { 7058c2ecf20Sopenharmony_ci dev_dbg(&indio_dev->dev, 7068c2ecf20Sopenharmony_ci "At least one scan element must be enabled first\n"); 7078c2ecf20Sopenharmony_ci return -EINVAL; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci memset(config, 0, sizeof(*config)); 7118c2ecf20Sopenharmony_ci config->watermark = ~0; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* 7148c2ecf20Sopenharmony_ci * If there is just one buffer and we are removing it there is nothing 7158c2ecf20Sopenharmony_ci * to verify. 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_ci if (remove_buffer && !insert_buffer && 7188c2ecf20Sopenharmony_ci list_is_singular(&iio_dev_opaque->buffer_list)) 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci modes = indio_dev->modes; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci list_for_each_entry(buffer, &iio_dev_opaque->buffer_list, buffer_list) { 7248c2ecf20Sopenharmony_ci if (buffer == remove_buffer) 7258c2ecf20Sopenharmony_ci continue; 7268c2ecf20Sopenharmony_ci modes &= buffer->access->modes; 7278c2ecf20Sopenharmony_ci config->watermark = min(config->watermark, buffer->watermark); 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (insert_buffer) { 7318c2ecf20Sopenharmony_ci modes &= insert_buffer->access->modes; 7328c2ecf20Sopenharmony_ci config->watermark = min(config->watermark, 7338c2ecf20Sopenharmony_ci insert_buffer->watermark); 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* Definitely possible for devices to support both of these. */ 7378c2ecf20Sopenharmony_ci if ((modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) { 7388c2ecf20Sopenharmony_ci config->mode = INDIO_BUFFER_TRIGGERED; 7398c2ecf20Sopenharmony_ci } else if (modes & INDIO_BUFFER_HARDWARE) { 7408c2ecf20Sopenharmony_ci /* 7418c2ecf20Sopenharmony_ci * Keep things simple for now and only allow a single buffer to 7428c2ecf20Sopenharmony_ci * be connected in hardware mode. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci if (insert_buffer && !list_empty(&iio_dev_opaque->buffer_list)) 7458c2ecf20Sopenharmony_ci return -EINVAL; 7468c2ecf20Sopenharmony_ci config->mode = INDIO_BUFFER_HARDWARE; 7478c2ecf20Sopenharmony_ci strict_scanmask = true; 7488c2ecf20Sopenharmony_ci } else if (modes & INDIO_BUFFER_SOFTWARE) { 7498c2ecf20Sopenharmony_ci config->mode = INDIO_BUFFER_SOFTWARE; 7508c2ecf20Sopenharmony_ci } else { 7518c2ecf20Sopenharmony_ci /* Can only occur on first buffer */ 7528c2ecf20Sopenharmony_ci if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) 7538c2ecf20Sopenharmony_ci dev_dbg(&indio_dev->dev, "Buffer not started: no trigger\n"); 7548c2ecf20Sopenharmony_ci return -EINVAL; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* What scan mask do we actually have? */ 7588c2ecf20Sopenharmony_ci compound_mask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL); 7598c2ecf20Sopenharmony_ci if (compound_mask == NULL) 7608c2ecf20Sopenharmony_ci return -ENOMEM; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci scan_timestamp = false; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci list_for_each_entry(buffer, &iio_dev_opaque->buffer_list, buffer_list) { 7658c2ecf20Sopenharmony_ci if (buffer == remove_buffer) 7668c2ecf20Sopenharmony_ci continue; 7678c2ecf20Sopenharmony_ci bitmap_or(compound_mask, compound_mask, buffer->scan_mask, 7688c2ecf20Sopenharmony_ci indio_dev->masklength); 7698c2ecf20Sopenharmony_ci scan_timestamp |= buffer->scan_timestamp; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (insert_buffer) { 7738c2ecf20Sopenharmony_ci bitmap_or(compound_mask, compound_mask, 7748c2ecf20Sopenharmony_ci insert_buffer->scan_mask, indio_dev->masklength); 7758c2ecf20Sopenharmony_ci scan_timestamp |= insert_buffer->scan_timestamp; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (indio_dev->available_scan_masks) { 7798c2ecf20Sopenharmony_ci scan_mask = iio_scan_mask_match(indio_dev->available_scan_masks, 7808c2ecf20Sopenharmony_ci indio_dev->masklength, 7818c2ecf20Sopenharmony_ci compound_mask, 7828c2ecf20Sopenharmony_ci strict_scanmask); 7838c2ecf20Sopenharmony_ci bitmap_free(compound_mask); 7848c2ecf20Sopenharmony_ci if (scan_mask == NULL) 7858c2ecf20Sopenharmony_ci return -EINVAL; 7868c2ecf20Sopenharmony_ci } else { 7878c2ecf20Sopenharmony_ci scan_mask = compound_mask; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci config->scan_bytes = iio_compute_scan_bytes(indio_dev, 7918c2ecf20Sopenharmony_ci scan_mask, scan_timestamp); 7928c2ecf20Sopenharmony_ci config->scan_mask = scan_mask; 7938c2ecf20Sopenharmony_ci config->scan_timestamp = scan_timestamp; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return 0; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/** 7998c2ecf20Sopenharmony_ci * struct iio_demux_table - table describing demux memcpy ops 8008c2ecf20Sopenharmony_ci * @from: index to copy from 8018c2ecf20Sopenharmony_ci * @to: index to copy to 8028c2ecf20Sopenharmony_ci * @length: how many bytes to copy 8038c2ecf20Sopenharmony_ci * @l: list head used for management 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_cistruct iio_demux_table { 8068c2ecf20Sopenharmony_ci unsigned from; 8078c2ecf20Sopenharmony_ci unsigned to; 8088c2ecf20Sopenharmony_ci unsigned length; 8098c2ecf20Sopenharmony_ci struct list_head l; 8108c2ecf20Sopenharmony_ci}; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic void iio_buffer_demux_free(struct iio_buffer *buffer) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci struct iio_demux_table *p, *q; 8158c2ecf20Sopenharmony_ci list_for_each_entry_safe(p, q, &buffer->demux_list, l) { 8168c2ecf20Sopenharmony_ci list_del(&p->l); 8178c2ecf20Sopenharmony_ci kfree(p); 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int iio_buffer_add_demux(struct iio_buffer *buffer, 8228c2ecf20Sopenharmony_ci struct iio_demux_table **p, unsigned int in_loc, unsigned int out_loc, 8238c2ecf20Sopenharmony_ci unsigned int length) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (*p && (*p)->from + (*p)->length == in_loc && 8278c2ecf20Sopenharmony_ci (*p)->to + (*p)->length == out_loc) { 8288c2ecf20Sopenharmony_ci (*p)->length += length; 8298c2ecf20Sopenharmony_ci } else { 8308c2ecf20Sopenharmony_ci *p = kmalloc(sizeof(**p), GFP_KERNEL); 8318c2ecf20Sopenharmony_ci if (*p == NULL) 8328c2ecf20Sopenharmony_ci return -ENOMEM; 8338c2ecf20Sopenharmony_ci (*p)->from = in_loc; 8348c2ecf20Sopenharmony_ci (*p)->to = out_loc; 8358c2ecf20Sopenharmony_ci (*p)->length = length; 8368c2ecf20Sopenharmony_ci list_add_tail(&(*p)->l, &buffer->demux_list); 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic int iio_buffer_update_demux(struct iio_dev *indio_dev, 8438c2ecf20Sopenharmony_ci struct iio_buffer *buffer) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci int ret, in_ind = -1, out_ind, length; 8468c2ecf20Sopenharmony_ci unsigned in_loc = 0, out_loc = 0; 8478c2ecf20Sopenharmony_ci struct iio_demux_table *p = NULL; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci /* Clear out any old demux */ 8508c2ecf20Sopenharmony_ci iio_buffer_demux_free(buffer); 8518c2ecf20Sopenharmony_ci kfree(buffer->demux_bounce); 8528c2ecf20Sopenharmony_ci buffer->demux_bounce = NULL; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* First work out which scan mode we will actually have */ 8558c2ecf20Sopenharmony_ci if (bitmap_equal(indio_dev->active_scan_mask, 8568c2ecf20Sopenharmony_ci buffer->scan_mask, 8578c2ecf20Sopenharmony_ci indio_dev->masklength)) 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* Now we have the two masks, work from least sig and build up sizes */ 8618c2ecf20Sopenharmony_ci for_each_set_bit(out_ind, 8628c2ecf20Sopenharmony_ci buffer->scan_mask, 8638c2ecf20Sopenharmony_ci indio_dev->masklength) { 8648c2ecf20Sopenharmony_ci in_ind = find_next_bit(indio_dev->active_scan_mask, 8658c2ecf20Sopenharmony_ci indio_dev->masklength, 8668c2ecf20Sopenharmony_ci in_ind + 1); 8678c2ecf20Sopenharmony_ci while (in_ind != out_ind) { 8688c2ecf20Sopenharmony_ci length = iio_storage_bytes_for_si(indio_dev, in_ind); 8698c2ecf20Sopenharmony_ci /* Make sure we are aligned */ 8708c2ecf20Sopenharmony_ci in_loc = roundup(in_loc, length) + length; 8718c2ecf20Sopenharmony_ci in_ind = find_next_bit(indio_dev->active_scan_mask, 8728c2ecf20Sopenharmony_ci indio_dev->masklength, 8738c2ecf20Sopenharmony_ci in_ind + 1); 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci length = iio_storage_bytes_for_si(indio_dev, in_ind); 8768c2ecf20Sopenharmony_ci out_loc = roundup(out_loc, length); 8778c2ecf20Sopenharmony_ci in_loc = roundup(in_loc, length); 8788c2ecf20Sopenharmony_ci ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); 8798c2ecf20Sopenharmony_ci if (ret) 8808c2ecf20Sopenharmony_ci goto error_clear_mux_table; 8818c2ecf20Sopenharmony_ci out_loc += length; 8828c2ecf20Sopenharmony_ci in_loc += length; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci /* Relies on scan_timestamp being last */ 8858c2ecf20Sopenharmony_ci if (buffer->scan_timestamp) { 8868c2ecf20Sopenharmony_ci length = iio_storage_bytes_for_timestamp(indio_dev); 8878c2ecf20Sopenharmony_ci out_loc = roundup(out_loc, length); 8888c2ecf20Sopenharmony_ci in_loc = roundup(in_loc, length); 8898c2ecf20Sopenharmony_ci ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); 8908c2ecf20Sopenharmony_ci if (ret) 8918c2ecf20Sopenharmony_ci goto error_clear_mux_table; 8928c2ecf20Sopenharmony_ci out_loc += length; 8938c2ecf20Sopenharmony_ci in_loc += length; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL); 8968c2ecf20Sopenharmony_ci if (buffer->demux_bounce == NULL) { 8978c2ecf20Sopenharmony_ci ret = -ENOMEM; 8988c2ecf20Sopenharmony_ci goto error_clear_mux_table; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci return 0; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cierror_clear_mux_table: 9038c2ecf20Sopenharmony_ci iio_buffer_demux_free(buffer); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci return ret; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic int iio_update_demux(struct iio_dev *indio_dev) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 9118c2ecf20Sopenharmony_ci struct iio_buffer *buffer; 9128c2ecf20Sopenharmony_ci int ret; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci list_for_each_entry(buffer, &iio_dev_opaque->buffer_list, buffer_list) { 9158c2ecf20Sopenharmony_ci ret = iio_buffer_update_demux(indio_dev, buffer); 9168c2ecf20Sopenharmony_ci if (ret < 0) 9178c2ecf20Sopenharmony_ci goto error_clear_mux_table; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci return 0; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cierror_clear_mux_table: 9228c2ecf20Sopenharmony_ci list_for_each_entry(buffer, &iio_dev_opaque->buffer_list, buffer_list) 9238c2ecf20Sopenharmony_ci iio_buffer_demux_free(buffer); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return ret; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic int iio_enable_buffers(struct iio_dev *indio_dev, 9298c2ecf20Sopenharmony_ci struct iio_device_config *config) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 9328c2ecf20Sopenharmony_ci struct iio_buffer *buffer; 9338c2ecf20Sopenharmony_ci int ret; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci indio_dev->active_scan_mask = config->scan_mask; 9368c2ecf20Sopenharmony_ci indio_dev->scan_timestamp = config->scan_timestamp; 9378c2ecf20Sopenharmony_ci indio_dev->scan_bytes = config->scan_bytes; 9388c2ecf20Sopenharmony_ci indio_dev->currentmode = config->mode; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci iio_update_demux(indio_dev); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* Wind up again */ 9438c2ecf20Sopenharmony_ci if (indio_dev->setup_ops->preenable) { 9448c2ecf20Sopenharmony_ci ret = indio_dev->setup_ops->preenable(indio_dev); 9458c2ecf20Sopenharmony_ci if (ret) { 9468c2ecf20Sopenharmony_ci dev_dbg(&indio_dev->dev, 9478c2ecf20Sopenharmony_ci "Buffer not started: buffer preenable failed (%d)\n", ret); 9488c2ecf20Sopenharmony_ci goto err_undo_config; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (indio_dev->info->update_scan_mode) { 9538c2ecf20Sopenharmony_ci ret = indio_dev->info 9548c2ecf20Sopenharmony_ci ->update_scan_mode(indio_dev, 9558c2ecf20Sopenharmony_ci indio_dev->active_scan_mask); 9568c2ecf20Sopenharmony_ci if (ret < 0) { 9578c2ecf20Sopenharmony_ci dev_dbg(&indio_dev->dev, 9588c2ecf20Sopenharmony_ci "Buffer not started: update scan mode failed (%d)\n", 9598c2ecf20Sopenharmony_ci ret); 9608c2ecf20Sopenharmony_ci goto err_run_postdisable; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (indio_dev->info->hwfifo_set_watermark) 9658c2ecf20Sopenharmony_ci indio_dev->info->hwfifo_set_watermark(indio_dev, 9668c2ecf20Sopenharmony_ci config->watermark); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci list_for_each_entry(buffer, &iio_dev_opaque->buffer_list, buffer_list) { 9698c2ecf20Sopenharmony_ci ret = iio_buffer_enable(buffer, indio_dev); 9708c2ecf20Sopenharmony_ci if (ret) 9718c2ecf20Sopenharmony_ci goto err_disable_buffers; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { 9758c2ecf20Sopenharmony_ci ret = iio_trigger_attach_poll_func(indio_dev->trig, 9768c2ecf20Sopenharmony_ci indio_dev->pollfunc); 9778c2ecf20Sopenharmony_ci if (ret) 9788c2ecf20Sopenharmony_ci goto err_disable_buffers; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (indio_dev->setup_ops->postenable) { 9828c2ecf20Sopenharmony_ci ret = indio_dev->setup_ops->postenable(indio_dev); 9838c2ecf20Sopenharmony_ci if (ret) { 9848c2ecf20Sopenharmony_ci dev_dbg(&indio_dev->dev, 9858c2ecf20Sopenharmony_ci "Buffer not started: postenable failed (%d)\n", ret); 9868c2ecf20Sopenharmony_ci goto err_detach_pollfunc; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return 0; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cierr_detach_pollfunc: 9938c2ecf20Sopenharmony_ci if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { 9948c2ecf20Sopenharmony_ci iio_trigger_detach_poll_func(indio_dev->trig, 9958c2ecf20Sopenharmony_ci indio_dev->pollfunc); 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_cierr_disable_buffers: 9988c2ecf20Sopenharmony_ci list_for_each_entry_continue_reverse(buffer, &iio_dev_opaque->buffer_list, 9998c2ecf20Sopenharmony_ci buffer_list) 10008c2ecf20Sopenharmony_ci iio_buffer_disable(buffer, indio_dev); 10018c2ecf20Sopenharmony_cierr_run_postdisable: 10028c2ecf20Sopenharmony_ci if (indio_dev->setup_ops->postdisable) 10038c2ecf20Sopenharmony_ci indio_dev->setup_ops->postdisable(indio_dev); 10048c2ecf20Sopenharmony_cierr_undo_config: 10058c2ecf20Sopenharmony_ci indio_dev->currentmode = INDIO_DIRECT_MODE; 10068c2ecf20Sopenharmony_ci indio_dev->active_scan_mask = NULL; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci return ret; 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic int iio_disable_buffers(struct iio_dev *indio_dev) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 10148c2ecf20Sopenharmony_ci struct iio_buffer *buffer; 10158c2ecf20Sopenharmony_ci int ret = 0; 10168c2ecf20Sopenharmony_ci int ret2; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci /* Wind down existing buffers - iff there are any */ 10198c2ecf20Sopenharmony_ci if (list_empty(&iio_dev_opaque->buffer_list)) 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci /* 10238c2ecf20Sopenharmony_ci * If things go wrong at some step in disable we still need to continue 10248c2ecf20Sopenharmony_ci * to perform the other steps, otherwise we leave the device in a 10258c2ecf20Sopenharmony_ci * inconsistent state. We return the error code for the first error we 10268c2ecf20Sopenharmony_ci * encountered. 10278c2ecf20Sopenharmony_ci */ 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (indio_dev->setup_ops->predisable) { 10308c2ecf20Sopenharmony_ci ret2 = indio_dev->setup_ops->predisable(indio_dev); 10318c2ecf20Sopenharmony_ci if (ret2 && !ret) 10328c2ecf20Sopenharmony_ci ret = ret2; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { 10368c2ecf20Sopenharmony_ci iio_trigger_detach_poll_func(indio_dev->trig, 10378c2ecf20Sopenharmony_ci indio_dev->pollfunc); 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci list_for_each_entry(buffer, &iio_dev_opaque->buffer_list, buffer_list) { 10418c2ecf20Sopenharmony_ci ret2 = iio_buffer_disable(buffer, indio_dev); 10428c2ecf20Sopenharmony_ci if (ret2 && !ret) 10438c2ecf20Sopenharmony_ci ret = ret2; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (indio_dev->setup_ops->postdisable) { 10478c2ecf20Sopenharmony_ci ret2 = indio_dev->setup_ops->postdisable(indio_dev); 10488c2ecf20Sopenharmony_ci if (ret2 && !ret) 10498c2ecf20Sopenharmony_ci ret = ret2; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci iio_free_scan_mask(indio_dev, indio_dev->active_scan_mask); 10538c2ecf20Sopenharmony_ci indio_dev->active_scan_mask = NULL; 10548c2ecf20Sopenharmony_ci indio_dev->currentmode = INDIO_DIRECT_MODE; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci return ret; 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic int __iio_update_buffers(struct iio_dev *indio_dev, 10608c2ecf20Sopenharmony_ci struct iio_buffer *insert_buffer, 10618c2ecf20Sopenharmony_ci struct iio_buffer *remove_buffer) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 10648c2ecf20Sopenharmony_ci struct iio_device_config new_config; 10658c2ecf20Sopenharmony_ci int ret; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci ret = iio_verify_update(indio_dev, insert_buffer, remove_buffer, 10688c2ecf20Sopenharmony_ci &new_config); 10698c2ecf20Sopenharmony_ci if (ret) 10708c2ecf20Sopenharmony_ci return ret; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (insert_buffer) { 10738c2ecf20Sopenharmony_ci ret = iio_buffer_request_update(indio_dev, insert_buffer); 10748c2ecf20Sopenharmony_ci if (ret) 10758c2ecf20Sopenharmony_ci goto err_free_config; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci ret = iio_disable_buffers(indio_dev); 10798c2ecf20Sopenharmony_ci if (ret) 10808c2ecf20Sopenharmony_ci goto err_deactivate_all; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (remove_buffer) 10838c2ecf20Sopenharmony_ci iio_buffer_deactivate(remove_buffer); 10848c2ecf20Sopenharmony_ci if (insert_buffer) 10858c2ecf20Sopenharmony_ci iio_buffer_activate(indio_dev, insert_buffer); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* If no buffers in list, we are done */ 10888c2ecf20Sopenharmony_ci if (list_empty(&iio_dev_opaque->buffer_list)) 10898c2ecf20Sopenharmony_ci return 0; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci ret = iio_enable_buffers(indio_dev, &new_config); 10928c2ecf20Sopenharmony_ci if (ret) 10938c2ecf20Sopenharmony_ci goto err_deactivate_all; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cierr_deactivate_all: 10988c2ecf20Sopenharmony_ci /* 10998c2ecf20Sopenharmony_ci * We've already verified that the config is valid earlier. If things go 11008c2ecf20Sopenharmony_ci * wrong in either enable or disable the most likely reason is an IO 11018c2ecf20Sopenharmony_ci * error from the device. In this case there is no good recovery 11028c2ecf20Sopenharmony_ci * strategy. Just make sure to disable everything and leave the device 11038c2ecf20Sopenharmony_ci * in a sane state. With a bit of luck the device might come back to 11048c2ecf20Sopenharmony_ci * life again later and userspace can try again. 11058c2ecf20Sopenharmony_ci */ 11068c2ecf20Sopenharmony_ci iio_buffer_deactivate_all(indio_dev); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cierr_free_config: 11098c2ecf20Sopenharmony_ci iio_free_scan_mask(indio_dev, new_config.scan_mask); 11108c2ecf20Sopenharmony_ci return ret; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ciint iio_update_buffers(struct iio_dev *indio_dev, 11148c2ecf20Sopenharmony_ci struct iio_buffer *insert_buffer, 11158c2ecf20Sopenharmony_ci struct iio_buffer *remove_buffer) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci int ret; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (insert_buffer == remove_buffer) 11208c2ecf20Sopenharmony_ci return 0; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci mutex_lock(&indio_dev->info_exist_lock); 11238c2ecf20Sopenharmony_ci mutex_lock(&indio_dev->mlock); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (insert_buffer && iio_buffer_is_active(insert_buffer)) 11268c2ecf20Sopenharmony_ci insert_buffer = NULL; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (remove_buffer && !iio_buffer_is_active(remove_buffer)) 11298c2ecf20Sopenharmony_ci remove_buffer = NULL; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (!insert_buffer && !remove_buffer) { 11328c2ecf20Sopenharmony_ci ret = 0; 11338c2ecf20Sopenharmony_ci goto out_unlock; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (indio_dev->info == NULL) { 11378c2ecf20Sopenharmony_ci ret = -ENODEV; 11388c2ecf20Sopenharmony_ci goto out_unlock; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci ret = __iio_update_buffers(indio_dev, insert_buffer, remove_buffer); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ciout_unlock: 11448c2ecf20Sopenharmony_ci mutex_unlock(&indio_dev->mlock); 11458c2ecf20Sopenharmony_ci mutex_unlock(&indio_dev->info_exist_lock); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci return ret; 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_update_buffers); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_civoid iio_disable_all_buffers(struct iio_dev *indio_dev) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci iio_disable_buffers(indio_dev); 11548c2ecf20Sopenharmony_ci iio_buffer_deactivate_all(indio_dev); 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cistatic ssize_t iio_buffer_store_enable(struct device *dev, 11588c2ecf20Sopenharmony_ci struct device_attribute *attr, 11598c2ecf20Sopenharmony_ci const char *buf, 11608c2ecf20Sopenharmony_ci size_t len) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci int ret; 11638c2ecf20Sopenharmony_ci bool requested_state; 11648c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 11658c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 11668c2ecf20Sopenharmony_ci bool inlist; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci ret = strtobool(buf, &requested_state); 11698c2ecf20Sopenharmony_ci if (ret < 0) 11708c2ecf20Sopenharmony_ci return ret; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci mutex_lock(&indio_dev->mlock); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci /* Find out if it is in the list */ 11758c2ecf20Sopenharmony_ci inlist = iio_buffer_is_active(buffer); 11768c2ecf20Sopenharmony_ci /* Already in desired state */ 11778c2ecf20Sopenharmony_ci if (inlist == requested_state) 11788c2ecf20Sopenharmony_ci goto done; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci if (requested_state) 11818c2ecf20Sopenharmony_ci ret = __iio_update_buffers(indio_dev, buffer, NULL); 11828c2ecf20Sopenharmony_ci else 11838c2ecf20Sopenharmony_ci ret = __iio_update_buffers(indio_dev, NULL, buffer); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_cidone: 11868c2ecf20Sopenharmony_ci mutex_unlock(&indio_dev->mlock); 11878c2ecf20Sopenharmony_ci return (ret < 0) ? ret : len; 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic const char * const iio_scan_elements_group_name = "scan_elements"; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic ssize_t iio_buffer_show_watermark(struct device *dev, 11938c2ecf20Sopenharmony_ci struct device_attribute *attr, 11948c2ecf20Sopenharmony_ci char *buf) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 11978c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", buffer->watermark); 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic ssize_t iio_buffer_store_watermark(struct device *dev, 12038c2ecf20Sopenharmony_ci struct device_attribute *attr, 12048c2ecf20Sopenharmony_ci const char *buf, 12058c2ecf20Sopenharmony_ci size_t len) 12068c2ecf20Sopenharmony_ci{ 12078c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 12088c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 12098c2ecf20Sopenharmony_ci unsigned int val; 12108c2ecf20Sopenharmony_ci int ret; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci ret = kstrtouint(buf, 10, &val); 12138c2ecf20Sopenharmony_ci if (ret) 12148c2ecf20Sopenharmony_ci return ret; 12158c2ecf20Sopenharmony_ci if (!val) 12168c2ecf20Sopenharmony_ci return -EINVAL; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci mutex_lock(&indio_dev->mlock); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (val > buffer->length) { 12218c2ecf20Sopenharmony_ci ret = -EINVAL; 12228c2ecf20Sopenharmony_ci goto out; 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci if (iio_buffer_is_active(buffer)) { 12268c2ecf20Sopenharmony_ci ret = -EBUSY; 12278c2ecf20Sopenharmony_ci goto out; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci buffer->watermark = val; 12318c2ecf20Sopenharmony_ciout: 12328c2ecf20Sopenharmony_ci mutex_unlock(&indio_dev->mlock); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci return ret ? ret : len; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic ssize_t iio_dma_show_data_available(struct device *dev, 12388c2ecf20Sopenharmony_ci struct device_attribute *attr, 12398c2ecf20Sopenharmony_ci char *buf) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 12428c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci return sprintf(buf, "%zu\n", iio_buffer_data_available(buffer)); 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length, 12488c2ecf20Sopenharmony_ci iio_buffer_write_length); 12498c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_length_ro = __ATTR(length, 12508c2ecf20Sopenharmony_ci S_IRUGO, iio_buffer_read_length, NULL); 12518c2ecf20Sopenharmony_cistatic DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, 12528c2ecf20Sopenharmony_ci iio_buffer_show_enable, iio_buffer_store_enable); 12538c2ecf20Sopenharmony_cistatic DEVICE_ATTR(watermark, S_IRUGO | S_IWUSR, 12548c2ecf20Sopenharmony_ci iio_buffer_show_watermark, iio_buffer_store_watermark); 12558c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_watermark_ro = __ATTR(watermark, 12568c2ecf20Sopenharmony_ci S_IRUGO, iio_buffer_show_watermark, NULL); 12578c2ecf20Sopenharmony_cistatic DEVICE_ATTR(data_available, S_IRUGO, 12588c2ecf20Sopenharmony_ci iio_dma_show_data_available, NULL); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic struct attribute *iio_buffer_attrs[] = { 12618c2ecf20Sopenharmony_ci &dev_attr_length.attr, 12628c2ecf20Sopenharmony_ci &dev_attr_enable.attr, 12638c2ecf20Sopenharmony_ci &dev_attr_watermark.attr, 12648c2ecf20Sopenharmony_ci &dev_attr_data_available.attr, 12658c2ecf20Sopenharmony_ci}; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_cistatic int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer, 12688c2ecf20Sopenharmony_ci struct iio_dev *indio_dev) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci struct iio_dev_attr *p; 12718c2ecf20Sopenharmony_ci struct attribute **attr; 12728c2ecf20Sopenharmony_ci int ret, i, attrn, attrcount; 12738c2ecf20Sopenharmony_ci const struct iio_chan_spec *channels; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci attrcount = 0; 12768c2ecf20Sopenharmony_ci if (buffer->attrs) { 12778c2ecf20Sopenharmony_ci while (buffer->attrs[attrcount] != NULL) 12788c2ecf20Sopenharmony_ci attrcount++; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci attr = kcalloc(attrcount + ARRAY_SIZE(iio_buffer_attrs) + 1, 12828c2ecf20Sopenharmony_ci sizeof(struct attribute *), GFP_KERNEL); 12838c2ecf20Sopenharmony_ci if (!attr) 12848c2ecf20Sopenharmony_ci return -ENOMEM; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs)); 12878c2ecf20Sopenharmony_ci if (!buffer->access->set_length) 12888c2ecf20Sopenharmony_ci attr[0] = &dev_attr_length_ro.attr; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (buffer->access->flags & INDIO_BUFFER_FLAG_FIXED_WATERMARK) 12918c2ecf20Sopenharmony_ci attr[2] = &dev_attr_watermark_ro.attr; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (buffer->attrs) 12948c2ecf20Sopenharmony_ci memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs, 12958c2ecf20Sopenharmony_ci sizeof(struct attribute *) * attrcount); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci attr[attrcount + ARRAY_SIZE(iio_buffer_attrs)] = NULL; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci buffer->buffer_group.name = "buffer"; 13008c2ecf20Sopenharmony_ci buffer->buffer_group.attrs = attr; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci attrcount = 0; 13058c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list); 13068c2ecf20Sopenharmony_ci channels = indio_dev->channels; 13078c2ecf20Sopenharmony_ci if (channels) { 13088c2ecf20Sopenharmony_ci /* new magic */ 13098c2ecf20Sopenharmony_ci for (i = 0; i < indio_dev->num_channels; i++) { 13108c2ecf20Sopenharmony_ci if (channels[i].scan_index < 0) 13118c2ecf20Sopenharmony_ci continue; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci ret = iio_buffer_add_channel_sysfs(indio_dev, buffer, 13148c2ecf20Sopenharmony_ci &channels[i]); 13158c2ecf20Sopenharmony_ci if (ret < 0) 13168c2ecf20Sopenharmony_ci goto error_cleanup_dynamic; 13178c2ecf20Sopenharmony_ci attrcount += ret; 13188c2ecf20Sopenharmony_ci if (channels[i].type == IIO_TIMESTAMP) 13198c2ecf20Sopenharmony_ci indio_dev->scan_index_timestamp = 13208c2ecf20Sopenharmony_ci channels[i].scan_index; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci if (indio_dev->masklength && buffer->scan_mask == NULL) { 13238c2ecf20Sopenharmony_ci buffer->scan_mask = bitmap_zalloc(indio_dev->masklength, 13248c2ecf20Sopenharmony_ci GFP_KERNEL); 13258c2ecf20Sopenharmony_ci if (buffer->scan_mask == NULL) { 13268c2ecf20Sopenharmony_ci ret = -ENOMEM; 13278c2ecf20Sopenharmony_ci goto error_cleanup_dynamic; 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci buffer->scan_el_group.name = iio_scan_elements_group_name; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci buffer->scan_el_group.attrs = kcalloc(attrcount + 1, 13358c2ecf20Sopenharmony_ci sizeof(buffer->scan_el_group.attrs[0]), 13368c2ecf20Sopenharmony_ci GFP_KERNEL); 13378c2ecf20Sopenharmony_ci if (buffer->scan_el_group.attrs == NULL) { 13388c2ecf20Sopenharmony_ci ret = -ENOMEM; 13398c2ecf20Sopenharmony_ci goto error_free_scan_mask; 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ci attrn = 0; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l) 13448c2ecf20Sopenharmony_ci buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr; 13458c2ecf20Sopenharmony_ci indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci return 0; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cierror_free_scan_mask: 13508c2ecf20Sopenharmony_ci bitmap_free(buffer->scan_mask); 13518c2ecf20Sopenharmony_cierror_cleanup_dynamic: 13528c2ecf20Sopenharmony_ci iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); 13538c2ecf20Sopenharmony_ci kfree(buffer->buffer_group.attrs); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci return ret; 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ciint iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 13618c2ecf20Sopenharmony_ci const struct iio_chan_spec *channels; 13628c2ecf20Sopenharmony_ci int i; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci channels = indio_dev->channels; 13658c2ecf20Sopenharmony_ci if (channels) { 13668c2ecf20Sopenharmony_ci int ml = indio_dev->masklength; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci for (i = 0; i < indio_dev->num_channels; i++) 13698c2ecf20Sopenharmony_ci ml = max(ml, channels[i].scan_index + 1); 13708c2ecf20Sopenharmony_ci indio_dev->masklength = ml; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci if (!buffer) 13748c2ecf20Sopenharmony_ci return 0; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci return __iio_buffer_alloc_sysfs_and_mask(buffer, indio_dev); 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_cistatic void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci bitmap_free(buffer->scan_mask); 13828c2ecf20Sopenharmony_ci kfree(buffer->buffer_group.attrs); 13838c2ecf20Sopenharmony_ci kfree(buffer->scan_el_group.attrs); 13848c2ecf20Sopenharmony_ci iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list); 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_civoid iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct iio_buffer *buffer = indio_dev->buffer; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (!buffer) 13928c2ecf20Sopenharmony_ci return; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci __iio_buffer_free_sysfs_and_mask(buffer); 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci/** 13988c2ecf20Sopenharmony_ci * iio_validate_scan_mask_onehot() - Validates that exactly one channel is selected 13998c2ecf20Sopenharmony_ci * @indio_dev: the iio device 14008c2ecf20Sopenharmony_ci * @mask: scan mask to be checked 14018c2ecf20Sopenharmony_ci * 14028c2ecf20Sopenharmony_ci * Return true if exactly one bit is set in the scan mask, false otherwise. It 14038c2ecf20Sopenharmony_ci * can be used for devices where only one channel can be active for sampling at 14048c2ecf20Sopenharmony_ci * a time. 14058c2ecf20Sopenharmony_ci */ 14068c2ecf20Sopenharmony_cibool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, 14078c2ecf20Sopenharmony_ci const unsigned long *mask) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci return bitmap_weight(mask, indio_dev->masklength) == 1; 14108c2ecf20Sopenharmony_ci} 14118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_validate_scan_mask_onehot); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_cistatic const void *iio_demux(struct iio_buffer *buffer, 14148c2ecf20Sopenharmony_ci const void *datain) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci struct iio_demux_table *t; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci if (list_empty(&buffer->demux_list)) 14198c2ecf20Sopenharmony_ci return datain; 14208c2ecf20Sopenharmony_ci list_for_each_entry(t, &buffer->demux_list, l) 14218c2ecf20Sopenharmony_ci memcpy(buffer->demux_bounce + t->to, 14228c2ecf20Sopenharmony_ci datain + t->from, t->length); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci return buffer->demux_bounce; 14258c2ecf20Sopenharmony_ci} 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_cistatic int iio_push_to_buffer(struct iio_buffer *buffer, const void *data) 14288c2ecf20Sopenharmony_ci{ 14298c2ecf20Sopenharmony_ci const void *dataout = iio_demux(buffer, data); 14308c2ecf20Sopenharmony_ci int ret; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci ret = buffer->access->store_to(buffer, dataout); 14338c2ecf20Sopenharmony_ci if (ret) 14348c2ecf20Sopenharmony_ci return ret; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci /* 14378c2ecf20Sopenharmony_ci * We can't just test for watermark to decide if we wake the poll queue 14388c2ecf20Sopenharmony_ci * because read may request less samples than the watermark. 14398c2ecf20Sopenharmony_ci */ 14408c2ecf20Sopenharmony_ci wake_up_interruptible_poll(&buffer->pollq, EPOLLIN | EPOLLRDNORM); 14418c2ecf20Sopenharmony_ci return 0; 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci/** 14458c2ecf20Sopenharmony_ci * iio_push_to_buffers() - push to a registered buffer. 14468c2ecf20Sopenharmony_ci * @indio_dev: iio_dev structure for device. 14478c2ecf20Sopenharmony_ci * @data: Full scan. 14488c2ecf20Sopenharmony_ci */ 14498c2ecf20Sopenharmony_ciint iio_push_to_buffers(struct iio_dev *indio_dev, const void *data) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 14528c2ecf20Sopenharmony_ci int ret; 14538c2ecf20Sopenharmony_ci struct iio_buffer *buf; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci list_for_each_entry(buf, &iio_dev_opaque->buffer_list, buffer_list) { 14568c2ecf20Sopenharmony_ci ret = iio_push_to_buffer(buf, data); 14578c2ecf20Sopenharmony_ci if (ret < 0) 14588c2ecf20Sopenharmony_ci return ret; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci return 0; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_push_to_buffers); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci/** 14668c2ecf20Sopenharmony_ci * iio_buffer_release() - Free a buffer's resources 14678c2ecf20Sopenharmony_ci * @ref: Pointer to the kref embedded in the iio_buffer struct 14688c2ecf20Sopenharmony_ci * 14698c2ecf20Sopenharmony_ci * This function is called when the last reference to the buffer has been 14708c2ecf20Sopenharmony_ci * dropped. It will typically free all resources allocated by the buffer. Do not 14718c2ecf20Sopenharmony_ci * call this function manually, always use iio_buffer_put() when done using a 14728c2ecf20Sopenharmony_ci * buffer. 14738c2ecf20Sopenharmony_ci */ 14748c2ecf20Sopenharmony_cistatic void iio_buffer_release(struct kref *ref) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci struct iio_buffer *buffer = container_of(ref, struct iio_buffer, ref); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci buffer->access->release(buffer); 14798c2ecf20Sopenharmony_ci} 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci/** 14828c2ecf20Sopenharmony_ci * iio_buffer_get() - Grab a reference to the buffer 14838c2ecf20Sopenharmony_ci * @buffer: The buffer to grab a reference for, may be NULL 14848c2ecf20Sopenharmony_ci * 14858c2ecf20Sopenharmony_ci * Returns the pointer to the buffer that was passed into the function. 14868c2ecf20Sopenharmony_ci */ 14878c2ecf20Sopenharmony_cistruct iio_buffer *iio_buffer_get(struct iio_buffer *buffer) 14888c2ecf20Sopenharmony_ci{ 14898c2ecf20Sopenharmony_ci if (buffer) 14908c2ecf20Sopenharmony_ci kref_get(&buffer->ref); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci return buffer; 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_buffer_get); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci/** 14978c2ecf20Sopenharmony_ci * iio_buffer_put() - Release the reference to the buffer 14988c2ecf20Sopenharmony_ci * @buffer: The buffer to release the reference for, may be NULL 14998c2ecf20Sopenharmony_ci */ 15008c2ecf20Sopenharmony_civoid iio_buffer_put(struct iio_buffer *buffer) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci if (buffer) 15038c2ecf20Sopenharmony_ci kref_put(&buffer->ref, iio_buffer_release); 15048c2ecf20Sopenharmony_ci} 15058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_buffer_put); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci/** 15088c2ecf20Sopenharmony_ci * iio_device_attach_buffer - Attach a buffer to a IIO device 15098c2ecf20Sopenharmony_ci * @indio_dev: The device the buffer should be attached to 15108c2ecf20Sopenharmony_ci * @buffer: The buffer to attach to the device 15118c2ecf20Sopenharmony_ci * 15128c2ecf20Sopenharmony_ci * This function attaches a buffer to a IIO device. The buffer stays attached to 15138c2ecf20Sopenharmony_ci * the device until the device is freed. The function should only be called at 15148c2ecf20Sopenharmony_ci * most once per device. 15158c2ecf20Sopenharmony_ci */ 15168c2ecf20Sopenharmony_civoid iio_device_attach_buffer(struct iio_dev *indio_dev, 15178c2ecf20Sopenharmony_ci struct iio_buffer *buffer) 15188c2ecf20Sopenharmony_ci{ 15198c2ecf20Sopenharmony_ci indio_dev->buffer = iio_buffer_get(buffer); 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(iio_device_attach_buffer); 1522