#include <linux/wait.h>
#include <linux/cdev.h>
#include <linux/slab.h>
+#include <linux/anon_inodes.h>
#include "iio.h"
#include "iio_core.h"
#include "iio_core_trigger.h"
struct iio_event_data ev;
};
+
/**
* struct iio_event_interface - chrdev interface for an event line
* @dev: device assocated with event interface
* @current_events: number of events in detected list
*/
struct iio_event_interface {
- struct device dev;
struct iio_handler handler;
wait_queue_head_t wait;
struct mutex event_list_lock;
}
EXPORT_SYMBOL(iio_push_event);
-
/* This turns up an awful lot */
ssize_t iio_read_const_attr(struct device *dev,
struct device_attribute *attr,
struct iio_detected_event_list *el;
int ret;
size_t len;
-
mutex_lock(&ev_int->event_list_lock);
if (list_empty(&ev_int->det_events)) {
if (filep->f_flags & O_NONBLOCK) {
static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
{
- struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev);
- struct iio_event_interface *ev_int = hand->private;
+ struct iio_event_interface *ev_int = filep->private_data;
struct iio_detected_event_list *el, *t;
-
mutex_lock(&ev_int->event_list_lock);
clear_bit(IIO_BUSY_BIT_POS, &ev_int->handler.flags);
/*
list_del(&el->list);
kfree(el);
}
- mutex_unlock(&ev_int->event_list_lock);
-
- return 0;
-}
-
-static int iio_event_chrdev_open(struct inode *inode, struct file *filep)
-{
- struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev);
- struct iio_event_interface *ev_int = hand->private;
-
- mutex_lock(&ev_int->event_list_lock);
- if (test_and_set_bit(IIO_BUSY_BIT_POS, &hand->flags)) {
- fops_put(filep->f_op);
- mutex_unlock(&ev_int->event_list_lock);
- return -EBUSY;
- }
- filep->private_data = hand->private;
+ ev_int->current_events = 0;
mutex_unlock(&ev_int->event_list_lock);
return 0;
static const struct file_operations iio_event_chrdev_fileops = {
.read = iio_event_chrdev_read,
.release = iio_event_chrdev_release,
- .open = iio_event_chrdev_open,
.owner = THIS_MODULE,
.llseek = noop_llseek,
};
-static void iio_event_dev_release(struct device *dev)
-{
- struct iio_event_interface *ev_int
- = container_of(dev, struct iio_event_interface, dev);
- cdev_del(&ev_int->handler.chrdev);
- iio_device_free_chrdev_minor(MINOR(dev->devt));
-};
-
-static struct device_type iio_event_type = {
- .release = iio_event_dev_release,
-};
-
int iio_device_get_chrdev_minor(void)
{
int ret;
iio_free_ida_val(&iio_chrdev_ida, val);
}
-static int iio_setup_ev_int(struct iio_event_interface *ev_int,
+int iio_event_getfd(struct iio_dev *indio_dev)
+{
+ if (indio_dev->event_interfaces == NULL)
+ return -ENODEV;
+
+ mutex_lock(&indio_dev->event_interfaces->event_list_lock);
+ if (test_and_set_bit(IIO_BUSY_BIT_POS,
+ &indio_dev->event_interfaces->handler.flags)) {
+ mutex_unlock(&indio_dev->event_interfaces->event_list_lock);
+ return -EBUSY;
+ }
+ mutex_unlock(&indio_dev->event_interfaces->event_list_lock);
+ return anon_inode_getfd("iio:event",
+ &iio_event_chrdev_fileops,
+ &indio_dev->event_interfaces[0], O_RDONLY);
+}
+
+static void iio_setup_ev_int(struct iio_event_interface *ev_int,
const char *dev_name,
int index,
struct module *owner,
struct device *dev)
{
- int ret, minor;
-
- ev_int->dev.bus = &iio_bus_type;
- ev_int->dev.parent = dev;
- ev_int->dev.type = &iio_event_type;
- device_initialize(&ev_int->dev);
-
- minor = iio_device_get_chrdev_minor();
- if (minor < 0) {
- ret = minor;
- goto error_device_put;
- }
- ev_int->dev.devt = MKDEV(MAJOR(iio_devt), minor);
- dev_set_name(&ev_int->dev, "%s:event%d", dev_name, index);
-
- ret = device_add(&ev_int->dev);
- if (ret)
- goto error_free_minor;
-
- cdev_init(&ev_int->handler.chrdev, &iio_event_chrdev_fileops);
- ev_int->handler.chrdev.owner = owner;
-
mutex_init(&ev_int->event_list_lock);
/* discussion point - make this variable? */
ev_int->max_events = 10;
init_waitqueue_head(&ev_int->wait);
ev_int->handler.private = ev_int;
ev_int->handler.flags = 0;
-
- ret = cdev_add(&ev_int->handler.chrdev, ev_int->dev.devt, 1);
- if (ret)
- goto error_unreg_device;
-
- return 0;
-
-error_unreg_device:
- device_unregister(&ev_int->dev);
-error_free_minor:
- iio_device_free_chrdev_minor(minor);
-error_device_put:
- put_device(&ev_int->dev);
-
- return ret;
-}
-
-static void iio_free_ev_int(struct iio_event_interface *ev_int)
-{
- device_unregister(&ev_int->dev);
- put_device(&ev_int->dev);
}
static int __init iio_init(void)
continue;
}
ret = __iio_add_chan_devattr(postfix,
- NULL,
+ "events",
chan,
&iio_ev_state_show,
iio_ev_state_store,
extending the bitmask - but
how far*/
0,
- &dev_info->event_interfaces[0].dev,
+ &dev_info->dev,
&dev_info->event_interfaces[0].
dev_attr_list);
kfree(postfix);
ret = -ENOMEM;
goto error_ret;
}
- ret = __iio_add_chan_devattr(postfix, NULL, chan,
+ ret = __iio_add_chan_devattr(postfix, "events", chan,
iio_ev_value_show,
iio_ev_value_store,
mask,
0,
- &dev_info->event_interfaces[0]
- .dev,
+ &dev_info->dev,
&dev_info->event_interfaces[0]
.dev_attr_list);
kfree(postfix);
list_for_each_entry_safe(p, n,
&dev_info->event_interfaces[i].
dev_attr_list, l) {
- sysfs_remove_file_from_group(&dev_info
- ->event_interfaces[i].dev.kobj,
+ sysfs_remove_file_from_group(&dev_info->dev.kobj,
&p->dev_attr.attr,
NULL);
kfree(p->dev_attr.attr.name);
return ret;
}
+static struct attribute *iio_events_dummy_attrs[] = {
+ NULL
+};
+
+static struct attribute_group iio_events_dummy_group = {
+ .name = "events",
+ .attrs = iio_events_dummy_attrs
+};
+
static int iio_device_register_eventset(struct iio_dev *dev_info)
{
int ret = 0, i, j;
}
for (i = 0; i < dev_info->info->num_interrupt_lines; i++) {
- ret = iio_setup_ev_int(&dev_info->event_interfaces[i],
- dev_name(&dev_info->dev),
- i,
- dev_info->info->driver_module,
- &dev_info->dev);
- if (ret) {
- dev_err(&dev_info->dev,
- "Could not get chrdev interface\n");
- goto error_free_setup_event_lines;
- }
-
- dev_set_drvdata(&dev_info->event_interfaces[i].dev,
- (void *)dev_info);
+ iio_setup_ev_int(&dev_info->event_interfaces[i],
+ dev_name(&dev_info->dev),
+ i,
+ dev_info->info->driver_module,
+ &dev_info->dev);
if (dev_info->info->event_attrs != NULL)
- ret = sysfs_create_group(&dev_info
- ->event_interfaces[i]
- .dev.kobj,
+ ret = sysfs_create_group(&dev_info->dev.kobj,
&dev_info->info
->event_attrs[i]);
-
+ else
+ ret = sysfs_create_group(&dev_info->dev.kobj,
+ &iio_events_dummy_group);
if (ret) {
dev_err(&dev_info->dev,
"Failed to register sysfs for event attrs");
- iio_free_ev_int(&dev_info->event_interfaces[i]);
goto error_free_setup_event_lines;
}
ret = __iio_add_event_config_attrs(dev_info, i);
if (ret) {
if (dev_info->info->event_attrs != NULL)
- sysfs_remove_group(&dev_info
- ->event_interfaces[i]
- .dev.kobj,
+ sysfs_remove_group(&dev_info->dev.kobj,
&dev_info->info
->event_attrs[i]);
- iio_free_ev_int(&dev_info->event_interfaces[i]);
+ else
+ sysfs_remove_group(&dev_info->dev.kobj,
+ &iio_events_dummy_group);
goto error_free_setup_event_lines;
}
}
error_free_setup_event_lines:
for (j = 0; j < i; j++) {
__iio_remove_event_config_attrs(dev_info, j);
- if (dev_info->info->event_attrs != NULL)
- sysfs_remove_group(&dev_info
- ->event_interfaces[j].dev.kobj,
+ if (dev_info->info->event_attrs != NULL) {
+ sysfs_remove_group(&dev_info->dev.kobj,
&dev_info->info->event_attrs[j]);
- iio_free_ev_int(&dev_info->event_interfaces[j]);
+ sysfs_remove_group(&dev_info->dev.kobj,
+ &iio_events_dummy_group);
+ }
}
kfree(dev_info->event_interfaces);
error_ret:
for (i = 0; i < dev_info->info->num_interrupt_lines; i++) {
__iio_remove_event_config_attrs(dev_info, i);
if (dev_info->info->event_attrs != NULL)
- sysfs_remove_group(&dev_info
- ->event_interfaces[i].dev.kobj,
+ sysfs_remove_group(&dev_info->dev.kobj,
&dev_info->info->event_attrs[i]);
- iio_free_ev_int(&dev_info->event_interfaces[i]);
+ else
+ sysfs_remove_group(&dev_info->dev.kobj,
+ &iio_events_dummy_group);
}
kfree(dev_info->event_interfaces);
}