Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: core: centralize ioctl() calls to the main chardev

The aim of this is to improve a bit the organization of ioctl() calls in
IIO core. Currently the chardev is split across IIO core sub-modules/files.
The main chardev has to be able to handle ioctl() calls, and if we need to
add buffer ioctl() calls, this would complicate things.

The 'industrialio-core.c' file will provide a 'iio_device_ioctl()' which
will iterate over a list of ioctls registered with the IIO device. These
can be event ioctl() or buffer ioctl() calls, or something else.

Each ioctl() handler will have to return a IIO_IOCTL_UNHANDLED code (which
is positive 1), if the ioctl() did not handle the call in any. This
eliminates any potential ambiguities about negative error codes, which
should fail the call altogether.

If any ioctl() returns 0, it was considered that it was serviced
successfully and the loop will exit.

This change also moves the handling of the IIO_GET_EVENT_FD_IOCTL command
inside 'industrialio-event.c', where this is better suited.

This patch is a combination of 2 other patches from an older series:
Patch 1: iio: core: add simple centralized mechanism for ioctl() handlers
Link: https://lore.kernel.org/linux-iio/20200427131100.50845-6-alexandru.ardelean@analog.com/
Patch 2: iio: core: use new common ioctl() mechanism
Link: https://lore.kernel.org/linux-iio/20200427131100.50845-7-alexandru.ardelean@analog.com/

Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
Link: https://lore.kernel.org/r/20200924084155.99406-1-alexandru.ardelean@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Alexandru Ardelean and committed by
Jonathan Cameron
8dedcc3e 1f487721

+84 -15
+14 -1
drivers/iio/iio_core.h
··· 17 17 18 18 extern struct device_type iio_device_type; 19 19 20 + #define IIO_IOCTL_UNHANDLED 1 21 + struct iio_ioctl_handler { 22 + struct list_head entry; 23 + long (*ioctl)(struct iio_dev *indio_dev, struct file *filp, 24 + unsigned int cmd, unsigned long arg); 25 + }; 26 + 27 + long iio_device_ioctl(struct iio_dev *indio_dev, struct file *filp, 28 + unsigned int cmd, unsigned long arg); 29 + 30 + void iio_device_ioctl_handler_register(struct iio_dev *indio_dev, 31 + struct iio_ioctl_handler *h); 32 + void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h); 33 + 20 34 int __iio_add_chan_devattr(const char *postfix, 21 35 struct iio_chan_spec const *chan, 22 36 ssize_t (*func)(struct device *dev, ··· 88 74 int iio_device_register_eventset(struct iio_dev *indio_dev); 89 75 void iio_device_unregister_eventset(struct iio_dev *indio_dev); 90 76 void iio_device_wakeup_eventset(struct iio_dev *indio_dev); 91 - int iio_event_getfd(struct iio_dev *indio_dev); 92 77 93 78 struct iio_event_interface; 94 79 bool iio_event_enabled(const struct iio_event_interface *ev_int);
+41 -13
drivers/iio/industrialio-core.c
··· 1612 1612 } 1613 1613 dev_set_name(&dev->dev, "iio:device%d", dev->id); 1614 1614 INIT_LIST_HEAD(&iio_dev_opaque->buffer_list); 1615 + INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers); 1615 1616 1616 1617 return dev; 1617 1618 } ··· 1706 1705 return 0; 1707 1706 } 1708 1707 1709 - /* Somewhat of a cross file organization violation - ioctls here are actually 1710 - * event related */ 1708 + void iio_device_ioctl_handler_register(struct iio_dev *indio_dev, 1709 + struct iio_ioctl_handler *h) 1710 + { 1711 + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 1712 + 1713 + list_add_tail(&h->entry, &iio_dev_opaque->ioctl_handlers); 1714 + } 1715 + 1716 + void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h) 1717 + { 1718 + list_del(&h->entry); 1719 + } 1720 + 1711 1721 static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 1712 1722 { 1713 1723 struct iio_dev *indio_dev = filp->private_data; 1714 - int __user *ip = (int __user *)arg; 1715 - int fd; 1724 + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 1725 + struct iio_ioctl_handler *h; 1726 + int ret = -ENODEV; 1716 1727 1728 + mutex_lock(&indio_dev->info_exist_lock); 1729 + 1730 + /** 1731 + * The NULL check here is required to prevent crashing when a device 1732 + * is being removed while userspace would still have open file handles 1733 + * to try to access this device. 1734 + */ 1717 1735 if (!indio_dev->info) 1718 - return -ENODEV; 1736 + goto out_unlock; 1719 1737 1720 - if (cmd == IIO_GET_EVENT_FD_IOCTL) { 1721 - fd = iio_event_getfd(indio_dev); 1722 - if (fd < 0) 1723 - return fd; 1724 - if (copy_to_user(ip, &fd, sizeof(fd))) 1725 - return -EFAULT; 1726 - return 0; 1738 + ret = -EINVAL; 1739 + list_for_each_entry(h, &iio_dev_opaque->ioctl_handlers, entry) { 1740 + ret = h->ioctl(indio_dev, filp, cmd, arg); 1741 + if (ret != IIO_IOCTL_UNHANDLED) 1742 + break; 1727 1743 } 1728 - return -EINVAL; 1744 + 1745 + out_unlock: 1746 + mutex_unlock(&indio_dev->info_exist_lock); 1747 + 1748 + return ret; 1729 1749 } 1730 1750 1731 1751 static const struct file_operations iio_buffer_fileops = { ··· 1863 1841 **/ 1864 1842 void iio_device_unregister(struct iio_dev *indio_dev) 1865 1843 { 1844 + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 1845 + struct iio_ioctl_handler *h, *t; 1846 + 1866 1847 cdev_device_del(&indio_dev->chrdev, &indio_dev->dev); 1867 1848 1868 1849 mutex_lock(&indio_dev->info_exist_lock); ··· 1875 1850 iio_disable_all_buffers(indio_dev); 1876 1851 1877 1852 indio_dev->info = NULL; 1853 + 1854 + list_for_each_entry_safe(h, t, &iio_dev_opaque->ioctl_handlers, entry) 1855 + list_del(&h->entry); 1878 1856 1879 1857 iio_device_wakeup_eventset(indio_dev); 1880 1858 iio_buffer_wakeup_poll(indio_dev);
+27 -1
drivers/iio/industrialio-event.c
··· 31 31 * @flags: file operations related flags including busy flag. 32 32 * @group: event interface sysfs attribute group 33 33 * @read_lock: lock to protect kfifo read operations 34 + * @ioctl_handler: handler for event ioctl() calls 34 35 */ 35 36 struct iio_event_interface { 36 37 wait_queue_head_t wait; ··· 41 40 unsigned long flags; 42 41 struct attribute_group group; 43 42 struct mutex read_lock; 43 + struct iio_ioctl_handler ioctl_handler; 44 44 }; 45 45 46 46 bool iio_event_enabled(const struct iio_event_interface *ev_int) ··· 189 187 .llseek = noop_llseek, 190 188 }; 191 189 192 - int iio_event_getfd(struct iio_dev *indio_dev) 190 + static int iio_event_getfd(struct iio_dev *indio_dev) 193 191 { 194 192 struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); 195 193 struct iio_event_interface *ev_int = iio_dev_opaque->event_interface; ··· 475 473 mutex_init(&ev_int->read_lock); 476 474 } 477 475 476 + static long iio_event_ioctl(struct iio_dev *indio_dev, struct file *filp, 477 + unsigned int cmd, unsigned long arg) 478 + { 479 + int __user *ip = (int __user *)arg; 480 + int fd; 481 + 482 + if (cmd == IIO_GET_EVENT_FD_IOCTL) { 483 + fd = iio_event_getfd(indio_dev); 484 + if (fd < 0) 485 + return fd; 486 + if (copy_to_user(ip, &fd, sizeof(fd))) 487 + return -EFAULT; 488 + return 0; 489 + } 490 + 491 + return IIO_IOCTL_UNHANDLED; 492 + } 493 + 478 494 static const char *iio_event_group_name = "events"; 479 495 int iio_device_register_eventset(struct iio_dev *indio_dev) 480 496 { ··· 546 526 ev_int->group.attrs[attrn++] = &p->dev_attr.attr; 547 527 indio_dev->groups[indio_dev->groupcounter++] = &ev_int->group; 548 528 529 + ev_int->ioctl_handler.ioctl = iio_event_ioctl; 530 + iio_device_ioctl_handler_register(&iio_dev_opaque->indio_dev, 531 + &ev_int->ioctl_handler); 532 + 549 533 return 0; 550 534 551 535 error_free_setup_event_lines: ··· 582 558 583 559 if (ev_int == NULL) 584 560 return; 561 + 562 + iio_device_ioctl_handler_unregister(&ev_int->ioctl_handler); 585 563 iio_free_chan_devattr_list(&ev_int->dev_attr_list); 586 564 kfree(ev_int->group.attrs); 587 565 kfree(ev_int);
+2
include/linux/iio/iio-opaque.h
··· 11 11 * @channel_attr_list: keep track of automatically created channel 12 12 * attributes 13 13 * @chan_attr_group: group for all attrs in base directory 14 + * @ioctl_handlers: ioctl handlers registered with the core handler 14 15 * @debugfs_dentry: device specific debugfs dentry 15 16 * @cached_reg_addr: cached register address for debugfs reads 16 17 * @read_buf: read buffer to be used for the initial reg read ··· 23 22 struct list_head buffer_list; 24 23 struct list_head channel_attr_list; 25 24 struct attribute_group chan_attr_group; 25 + struct list_head ioctl_handlers; 26 26 #if defined(CONFIG_DEBUG_FS) 27 27 struct dentry *debugfs_dentry; 28 28 unsigned cached_reg_addr;