1a980e046SJonathan Cameron /* Industrial I/O event handling
2a980e046SJonathan Cameron  *
3a980e046SJonathan Cameron  * Copyright (c) 2008 Jonathan Cameron
4a980e046SJonathan Cameron  *
5a980e046SJonathan Cameron  * This program is free software; you can redistribute it and/or modify it
6a980e046SJonathan Cameron  * under the terms of the GNU General Public License version 2 as published by
7a980e046SJonathan Cameron  * the Free Software Foundation.
8a980e046SJonathan Cameron  *
9a980e046SJonathan Cameron  * Based on elements of hwmon and input subsystems.
10a980e046SJonathan Cameron  */
11a980e046SJonathan Cameron 
12a980e046SJonathan Cameron #include <linux/anon_inodes.h>
13a980e046SJonathan Cameron #include <linux/device.h>
14a980e046SJonathan Cameron #include <linux/fs.h>
15a980e046SJonathan Cameron #include <linux/kernel.h>
16a980e046SJonathan Cameron #include <linux/kfifo.h>
17a980e046SJonathan Cameron #include <linux/module.h>
18a980e046SJonathan Cameron #include <linux/poll.h>
19a980e046SJonathan Cameron #include <linux/sched.h>
20a980e046SJonathan Cameron #include <linux/slab.h>
21a980e046SJonathan Cameron #include <linux/uaccess.h>
22a980e046SJonathan Cameron #include <linux/wait.h>
23a980e046SJonathan Cameron #include <linux/iio/iio.h>
24a980e046SJonathan Cameron #include "iio_core.h"
25a980e046SJonathan Cameron #include <linux/iio/sysfs.h>
26a980e046SJonathan Cameron #include <linux/iio/events.h>
27a980e046SJonathan Cameron 
28a980e046SJonathan Cameron /**
29a980e046SJonathan Cameron  * struct iio_event_interface - chrdev interface for an event line
30a980e046SJonathan Cameron  * @wait:		wait queue to allow blocking reads of events
31a980e046SJonathan Cameron  * @det_events:		list of detected events
32a980e046SJonathan Cameron  * @dev_attr_list:	list of event interface sysfs attribute
33a980e046SJonathan Cameron  * @flags:		file operations related flags including busy flag.
34a980e046SJonathan Cameron  * @group:		event interface sysfs attribute group
35a980e046SJonathan Cameron  */
36a980e046SJonathan Cameron struct iio_event_interface {
37a980e046SJonathan Cameron 	wait_queue_head_t	wait;
38a980e046SJonathan Cameron 	DECLARE_KFIFO(det_events, struct iio_event_data, 16);
39a980e046SJonathan Cameron 
40a980e046SJonathan Cameron 	struct list_head	dev_attr_list;
41a980e046SJonathan Cameron 	unsigned long		flags;
42a980e046SJonathan Cameron 	struct attribute_group	group;
43b91accafSLars-Peter Clausen 	struct mutex		read_lock;
44a980e046SJonathan Cameron };
45a980e046SJonathan Cameron 
46a7e57dceSSachin Kamat /**
47a7e57dceSSachin Kamat  * iio_push_event() - try to add event to the list for userspace reading
48a7e57dceSSachin Kamat  * @indio_dev:		IIO device structure
49a7e57dceSSachin Kamat  * @ev_code:		What event
50a7e57dceSSachin Kamat  * @timestamp:		When the event occurred
51b91accafSLars-Peter Clausen  *
52b91accafSLars-Peter Clausen  * Note: The caller must make sure that this function is not running
53b91accafSLars-Peter Clausen  * concurrently for the same indio_dev more than once.
54a7e57dceSSachin Kamat  **/
55a980e046SJonathan Cameron int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
56a980e046SJonathan Cameron {
57a980e046SJonathan Cameron 	struct iio_event_interface *ev_int = indio_dev->event_interface;
58a980e046SJonathan Cameron 	struct iio_event_data ev;
59a980e046SJonathan Cameron 	int copied;
60a980e046SJonathan Cameron 
61a980e046SJonathan Cameron 	/* Does anyone care? */
62a980e046SJonathan Cameron 	if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
63a980e046SJonathan Cameron 
64a980e046SJonathan Cameron 		ev.id = ev_code;
65a980e046SJonathan Cameron 		ev.timestamp = timestamp;
66a980e046SJonathan Cameron 
67498d319bSStefani Seibold 		copied = kfifo_put(&ev_int->det_events, ev);
68a980e046SJonathan Cameron 		if (copied != 0)
69b91accafSLars-Peter Clausen 			wake_up_poll(&ev_int->wait, POLLIN);
70a980e046SJonathan Cameron 	}
71a980e046SJonathan Cameron 
72a980e046SJonathan Cameron 	return 0;
73a980e046SJonathan Cameron }
74a980e046SJonathan Cameron EXPORT_SYMBOL(iio_push_event);
75a980e046SJonathan Cameron 
76a980e046SJonathan Cameron /**
77a980e046SJonathan Cameron  * iio_event_poll() - poll the event queue to find out if it has data
78a980e046SJonathan Cameron  */
79a980e046SJonathan Cameron static unsigned int iio_event_poll(struct file *filep,
80a980e046SJonathan Cameron 			     struct poll_table_struct *wait)
81a980e046SJonathan Cameron {
82cadc2125SLars-Peter Clausen 	struct iio_dev *indio_dev = filep->private_data;
83cadc2125SLars-Peter Clausen 	struct iio_event_interface *ev_int = indio_dev->event_interface;
84a980e046SJonathan Cameron 	unsigned int events = 0;
85a980e046SJonathan Cameron 
86f18e7a06SLars-Peter Clausen 	if (!indio_dev->info)
87f18e7a06SLars-Peter Clausen 		return -ENODEV;
88f18e7a06SLars-Peter Clausen 
89a980e046SJonathan Cameron 	poll_wait(filep, &ev_int->wait, wait);
90a980e046SJonathan Cameron 
91a980e046SJonathan Cameron 	if (!kfifo_is_empty(&ev_int->det_events))
92a980e046SJonathan Cameron 		events = POLLIN | POLLRDNORM;
93a980e046SJonathan Cameron 
94a980e046SJonathan Cameron 	return events;
95a980e046SJonathan Cameron }
96a980e046SJonathan Cameron 
97a980e046SJonathan Cameron static ssize_t iio_event_chrdev_read(struct file *filep,
98a980e046SJonathan Cameron 				     char __user *buf,
99a980e046SJonathan Cameron 				     size_t count,
100a980e046SJonathan Cameron 				     loff_t *f_ps)
101a980e046SJonathan Cameron {
102cadc2125SLars-Peter Clausen 	struct iio_dev *indio_dev = filep->private_data;
103cadc2125SLars-Peter Clausen 	struct iio_event_interface *ev_int = indio_dev->event_interface;
104a980e046SJonathan Cameron 	unsigned int copied;
105a980e046SJonathan Cameron 	int ret;
106a980e046SJonathan Cameron 
107f18e7a06SLars-Peter Clausen 	if (!indio_dev->info)
108f18e7a06SLars-Peter Clausen 		return -ENODEV;
109f18e7a06SLars-Peter Clausen 
110a980e046SJonathan Cameron 	if (count < sizeof(struct iio_event_data))
111a980e046SJonathan Cameron 		return -EINVAL;
112a980e046SJonathan Cameron 
113b91accafSLars-Peter Clausen 	do {
114a980e046SJonathan Cameron 		if (kfifo_is_empty(&ev_int->det_events)) {
115b91accafSLars-Peter Clausen 			if (filep->f_flags & O_NONBLOCK)
116b91accafSLars-Peter Clausen 				return -EAGAIN;
117b91accafSLars-Peter Clausen 
118b91accafSLars-Peter Clausen 			ret = wait_event_interruptible(ev_int->wait,
119d2f0a48fSLars-Peter Clausen 					!kfifo_is_empty(&ev_int->det_events) ||
120d2f0a48fSLars-Peter Clausen 					indio_dev->info == NULL);
121a980e046SJonathan Cameron 			if (ret)
122b91accafSLars-Peter Clausen 				return ret;
123b91accafSLars-Peter Clausen 			if (indio_dev->info == NULL)
124b91accafSLars-Peter Clausen 				return -ENODEV;
125a980e046SJonathan Cameron 		}
126a980e046SJonathan Cameron 
127b91accafSLars-Peter Clausen 		if (mutex_lock_interruptible(&ev_int->read_lock))
128b91accafSLars-Peter Clausen 			return -ERESTARTSYS;
129a980e046SJonathan Cameron 		ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
130b91accafSLars-Peter Clausen 		mutex_unlock(&ev_int->read_lock);
131a980e046SJonathan Cameron 
132b91accafSLars-Peter Clausen 		if (ret)
133b91accafSLars-Peter Clausen 			return ret;
134a980e046SJonathan Cameron 
135b91accafSLars-Peter Clausen 		/*
136b91accafSLars-Peter Clausen 		 * If we couldn't read anything from the fifo (a different
137b91accafSLars-Peter Clausen 		 * thread might have been faster) we either return -EAGAIN if
138b91accafSLars-Peter Clausen 		 * the file descriptor is non-blocking, otherwise we go back to
139b91accafSLars-Peter Clausen 		 * sleep and wait for more data to arrive.
140b91accafSLars-Peter Clausen 		 */
141b91accafSLars-Peter Clausen 		if (copied == 0 && (filep->f_flags & O_NONBLOCK))
142b91accafSLars-Peter Clausen 			return -EAGAIN;
143b91accafSLars-Peter Clausen 
144b91accafSLars-Peter Clausen 	} while (copied == 0);
145b91accafSLars-Peter Clausen 
146b91accafSLars-Peter Clausen 	return copied;
147a980e046SJonathan Cameron }
148a980e046SJonathan Cameron 
149a980e046SJonathan Cameron static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
150a980e046SJonathan Cameron {
151cadc2125SLars-Peter Clausen 	struct iio_dev *indio_dev = filep->private_data;
152cadc2125SLars-Peter Clausen 	struct iio_event_interface *ev_int = indio_dev->event_interface;
153a980e046SJonathan Cameron 
154b91accafSLars-Peter Clausen 	clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
155a980e046SJonathan Cameron 
156cadc2125SLars-Peter Clausen 	iio_device_put(indio_dev);
157cadc2125SLars-Peter Clausen 
158a980e046SJonathan Cameron 	return 0;
159a980e046SJonathan Cameron }
160a980e046SJonathan Cameron 
161a980e046SJonathan Cameron static const struct file_operations iio_event_chrdev_fileops = {
162a980e046SJonathan Cameron 	.read =  iio_event_chrdev_read,
163a980e046SJonathan Cameron 	.poll =  iio_event_poll,
164a980e046SJonathan Cameron 	.release = iio_event_chrdev_release,
165a980e046SJonathan Cameron 	.owner = THIS_MODULE,
166a980e046SJonathan Cameron 	.llseek = noop_llseek,
167a980e046SJonathan Cameron };
168a980e046SJonathan Cameron 
169a980e046SJonathan Cameron int iio_event_getfd(struct iio_dev *indio_dev)
170a980e046SJonathan Cameron {
171a980e046SJonathan Cameron 	struct iio_event_interface *ev_int = indio_dev->event_interface;
172a980e046SJonathan Cameron 	int fd;
173a980e046SJonathan Cameron 
174a980e046SJonathan Cameron 	if (ev_int == NULL)
175a980e046SJonathan Cameron 		return -ENODEV;
176a980e046SJonathan Cameron 
177b91accafSLars-Peter Clausen 	if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags))
178a980e046SJonathan Cameron 		return -EBUSY;
179b91accafSLars-Peter Clausen 
180cadc2125SLars-Peter Clausen 	iio_device_get(indio_dev);
181cadc2125SLars-Peter Clausen 
182cadc2125SLars-Peter Clausen 	fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops,
183e2aad1d5SGreg Kroah-Hartman 				indio_dev, O_RDONLY | O_CLOEXEC);
184a980e046SJonathan Cameron 	if (fd < 0) {
185b91accafSLars-Peter Clausen 		clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
186cadc2125SLars-Peter Clausen 		iio_device_put(indio_dev);
187b91accafSLars-Peter Clausen 	} else {
188b91accafSLars-Peter Clausen 		kfifo_reset_out(&ev_int->det_events);
189a980e046SJonathan Cameron 	}
190b91accafSLars-Peter Clausen 
191a980e046SJonathan Cameron 	return fd;
192a980e046SJonathan Cameron }
193a980e046SJonathan Cameron 
194a980e046SJonathan Cameron static const char * const iio_ev_type_text[] = {
195a980e046SJonathan Cameron 	[IIO_EV_TYPE_THRESH] = "thresh",
196a980e046SJonathan Cameron 	[IIO_EV_TYPE_MAG] = "mag",
197a980e046SJonathan Cameron 	[IIO_EV_TYPE_ROC] = "roc",
198a980e046SJonathan Cameron 	[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
199a980e046SJonathan Cameron 	[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
200a980e046SJonathan Cameron };
201a980e046SJonathan Cameron 
202a980e046SJonathan Cameron static const char * const iio_ev_dir_text[] = {
203a980e046SJonathan Cameron 	[IIO_EV_DIR_EITHER] = "either",
204a980e046SJonathan Cameron 	[IIO_EV_DIR_RISING] = "rising",
205a980e046SJonathan Cameron 	[IIO_EV_DIR_FALLING] = "falling"
206a980e046SJonathan Cameron };
207a980e046SJonathan Cameron 
208b4e3ac0aSLars-Peter Clausen static const char * const iio_ev_info_text[] = {
209b4e3ac0aSLars-Peter Clausen 	[IIO_EV_INFO_ENABLE] = "en",
210b4e3ac0aSLars-Peter Clausen 	[IIO_EV_INFO_VALUE] = "value",
211ec6670aeSLars-Peter Clausen 	[IIO_EV_INFO_HYSTERESIS] = "hysteresis",
212b4e3ac0aSLars-Peter Clausen };
213b4e3ac0aSLars-Peter Clausen 
214b4e3ac0aSLars-Peter Clausen static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr)
215b4e3ac0aSLars-Peter Clausen {
216b4e3ac0aSLars-Peter Clausen 	return attr->c->event_spec[attr->address & 0xffff].dir;
217b4e3ac0aSLars-Peter Clausen }
218b4e3ac0aSLars-Peter Clausen 
219b4e3ac0aSLars-Peter Clausen static enum iio_event_type iio_ev_attr_type(struct iio_dev_attr *attr)
220b4e3ac0aSLars-Peter Clausen {
221b4e3ac0aSLars-Peter Clausen 	return attr->c->event_spec[attr->address & 0xffff].type;
222b4e3ac0aSLars-Peter Clausen }
223b4e3ac0aSLars-Peter Clausen 
224b4e3ac0aSLars-Peter Clausen static enum iio_event_info iio_ev_attr_info(struct iio_dev_attr *attr)
225b4e3ac0aSLars-Peter Clausen {
226b4e3ac0aSLars-Peter Clausen 	return (attr->address >> 16) & 0xffff;
227b4e3ac0aSLars-Peter Clausen }
228b4e3ac0aSLars-Peter Clausen 
229a980e046SJonathan Cameron static ssize_t iio_ev_state_store(struct device *dev,
230a980e046SJonathan Cameron 				  struct device_attribute *attr,
231a980e046SJonathan Cameron 				  const char *buf,
232a980e046SJonathan Cameron 				  size_t len)
233a980e046SJonathan Cameron {
234e53f5ac5SLars-Peter Clausen 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
235a980e046SJonathan Cameron 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
236a980e046SJonathan Cameron 	int ret;
237a980e046SJonathan Cameron 	bool val;
238a980e046SJonathan Cameron 
239a980e046SJonathan Cameron 	ret = strtobool(buf, &val);
240a980e046SJonathan Cameron 	if (ret < 0)
241a980e046SJonathan Cameron 		return ret;
242a980e046SJonathan Cameron 
243a980e046SJonathan Cameron 	ret = indio_dev->info->write_event_config(indio_dev,
244b4e3ac0aSLars-Peter Clausen 		this_attr->c, iio_ev_attr_type(this_attr),
245b4e3ac0aSLars-Peter Clausen 		iio_ev_attr_dir(this_attr), val);
246b4e3ac0aSLars-Peter Clausen 
247a980e046SJonathan Cameron 	return (ret < 0) ? ret : len;
248a980e046SJonathan Cameron }
249a980e046SJonathan Cameron 
250a980e046SJonathan Cameron static ssize_t iio_ev_state_show(struct device *dev,
251a980e046SJonathan Cameron 				 struct device_attribute *attr,
252a980e046SJonathan Cameron 				 char *buf)
253a980e046SJonathan Cameron {
254e53f5ac5SLars-Peter Clausen 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
255a980e046SJonathan Cameron 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
256b4e3ac0aSLars-Peter Clausen 	int val;
257a980e046SJonathan Cameron 
258b4e3ac0aSLars-Peter Clausen 	val = indio_dev->info->read_event_config(indio_dev,
259b4e3ac0aSLars-Peter Clausen 		this_attr->c, iio_ev_attr_type(this_attr),
260b4e3ac0aSLars-Peter Clausen 		iio_ev_attr_dir(this_attr));
261a980e046SJonathan Cameron 	if (val < 0)
262a980e046SJonathan Cameron 		return val;
263a980e046SJonathan Cameron 	else
264a980e046SJonathan Cameron 		return sprintf(buf, "%d\n", val);
265a980e046SJonathan Cameron }
266a980e046SJonathan Cameron 
267a980e046SJonathan Cameron static ssize_t iio_ev_value_show(struct device *dev,
268a980e046SJonathan Cameron 				 struct device_attribute *attr,
269a980e046SJonathan Cameron 				 char *buf)
270a980e046SJonathan Cameron {
271e53f5ac5SLars-Peter Clausen 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
272a980e046SJonathan Cameron 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
2739fbfb4b3SSrinivas Pandruvada 	int val, val2, val_arr[2];
274b4e3ac0aSLars-Peter Clausen 	int ret;
275a980e046SJonathan Cameron 
276a980e046SJonathan Cameron 	ret = indio_dev->info->read_event_value(indio_dev,
277b4e3ac0aSLars-Peter Clausen 		this_attr->c, iio_ev_attr_type(this_attr),
278b4e3ac0aSLars-Peter Clausen 		iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr),
279b4e3ac0aSLars-Peter Clausen 		&val, &val2);
280b4e3ac0aSLars-Peter Clausen 	if (ret < 0)
281b4e3ac0aSLars-Peter Clausen 		return ret;
2829fbfb4b3SSrinivas Pandruvada 	val_arr[0] = val;
2839fbfb4b3SSrinivas Pandruvada 	val_arr[1] = val2;
2849fbfb4b3SSrinivas Pandruvada 	return iio_format_value(buf, ret, 2, val_arr);
285b4e3ac0aSLars-Peter Clausen }
286a980e046SJonathan Cameron 
287a980e046SJonathan Cameron static ssize_t iio_ev_value_store(struct device *dev,
288a980e046SJonathan Cameron 				  struct device_attribute *attr,
289a980e046SJonathan Cameron 				  const char *buf,
290a980e046SJonathan Cameron 				  size_t len)
291a980e046SJonathan Cameron {
292e53f5ac5SLars-Peter Clausen 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
293a980e046SJonathan Cameron 	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
294b4e3ac0aSLars-Peter Clausen 	int val, val2;
295a980e046SJonathan Cameron 	int ret;
296a980e046SJonathan Cameron 
297cb955852SLars-Peter Clausen 	if (!indio_dev->info->write_event_value)
298a980e046SJonathan Cameron 		return -EINVAL;
299a980e046SJonathan Cameron 
300b4e3ac0aSLars-Peter Clausen 	ret = iio_str_to_fixpoint(buf, 100000, &val, &val2);
301b4e3ac0aSLars-Peter Clausen 	if (ret)
302b4e3ac0aSLars-Peter Clausen 		return ret;
303cb955852SLars-Peter Clausen 	ret = indio_dev->info->write_event_value(indio_dev,
304b4e3ac0aSLars-Peter Clausen 		this_attr->c, iio_ev_attr_type(this_attr),
305b4e3ac0aSLars-Peter Clausen 		iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr),
306b4e3ac0aSLars-Peter Clausen 		val, val2);
307a980e046SJonathan Cameron 	if (ret < 0)
308a980e046SJonathan Cameron 		return ret;
309a980e046SJonathan Cameron 
310a980e046SJonathan Cameron 	return len;
311a980e046SJonathan Cameron }
312a980e046SJonathan Cameron 
313b4e3ac0aSLars-Peter Clausen static int iio_device_add_event(struct iio_dev *indio_dev,
314b4e3ac0aSLars-Peter Clausen 	const struct iio_chan_spec *chan, unsigned int spec_index,
315b4e3ac0aSLars-Peter Clausen 	enum iio_event_type type, enum iio_event_direction dir,
316b4e3ac0aSLars-Peter Clausen 	enum iio_shared_by shared_by, const unsigned long *mask)
317b4e3ac0aSLars-Peter Clausen {
318b4e3ac0aSLars-Peter Clausen 	ssize_t (*show)(struct device *, struct device_attribute *, char *);
319b4e3ac0aSLars-Peter Clausen 	ssize_t (*store)(struct device *, struct device_attribute *,
320b4e3ac0aSLars-Peter Clausen 		const char *, size_t);
321b4e3ac0aSLars-Peter Clausen 	unsigned int attrcount = 0;
322b4e3ac0aSLars-Peter Clausen 	unsigned int i;
323b4e3ac0aSLars-Peter Clausen 	char *postfix;
324b4e3ac0aSLars-Peter Clausen 	int ret;
325b4e3ac0aSLars-Peter Clausen 
326ef4b4856SJonathan Cameron 	for_each_set_bit(i, mask, sizeof(*mask)*8) {
327ef4b4856SJonathan Cameron 		if (i >= ARRAY_SIZE(iio_ev_info_text))
328ef4b4856SJonathan Cameron 			return -EINVAL;
329b4e3ac0aSLars-Peter Clausen 		postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
330b4e3ac0aSLars-Peter Clausen 				iio_ev_type_text[type], iio_ev_dir_text[dir],
331b4e3ac0aSLars-Peter Clausen 				iio_ev_info_text[i]);
332b4e3ac0aSLars-Peter Clausen 		if (postfix == NULL)
333b4e3ac0aSLars-Peter Clausen 			return -ENOMEM;
334b4e3ac0aSLars-Peter Clausen 
335b4e3ac0aSLars-Peter Clausen 		if (i == IIO_EV_INFO_ENABLE) {
336b4e3ac0aSLars-Peter Clausen 			show = iio_ev_state_show;
337b4e3ac0aSLars-Peter Clausen 			store = iio_ev_state_store;
338b4e3ac0aSLars-Peter Clausen 		} else {
339b4e3ac0aSLars-Peter Clausen 			show = iio_ev_value_show;
340b4e3ac0aSLars-Peter Clausen 			store = iio_ev_value_store;
341b4e3ac0aSLars-Peter Clausen 		}
342b4e3ac0aSLars-Peter Clausen 
343b4e3ac0aSLars-Peter Clausen 		ret = __iio_add_chan_devattr(postfix, chan, show, store,
344b4e3ac0aSLars-Peter Clausen 			 (i << 16) | spec_index, shared_by, &indio_dev->dev,
345b4e3ac0aSLars-Peter Clausen 			&indio_dev->event_interface->dev_attr_list);
346b4e3ac0aSLars-Peter Clausen 		kfree(postfix);
347b4e3ac0aSLars-Peter Clausen 
348b4e3ac0aSLars-Peter Clausen 		if (ret)
349b4e3ac0aSLars-Peter Clausen 			return ret;
350b4e3ac0aSLars-Peter Clausen 
351b4e3ac0aSLars-Peter Clausen 		attrcount++;
352b4e3ac0aSLars-Peter Clausen 	}
353b4e3ac0aSLars-Peter Clausen 
354b4e3ac0aSLars-Peter Clausen 	return attrcount;
355b4e3ac0aSLars-Peter Clausen }
356b4e3ac0aSLars-Peter Clausen 
357cb955852SLars-Peter Clausen static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
358b4e3ac0aSLars-Peter Clausen 	struct iio_chan_spec const *chan)
359b4e3ac0aSLars-Peter Clausen {
360b4e3ac0aSLars-Peter Clausen 	int ret = 0, i, attrcount = 0;
361b4e3ac0aSLars-Peter Clausen 	enum iio_event_direction dir;
362b4e3ac0aSLars-Peter Clausen 	enum iio_event_type type;
363b4e3ac0aSLars-Peter Clausen 
364b4e3ac0aSLars-Peter Clausen 	for (i = 0; i < chan->num_event_specs; i++) {
365b4e3ac0aSLars-Peter Clausen 		type = chan->event_spec[i].type;
366b4e3ac0aSLars-Peter Clausen 		dir = chan->event_spec[i].dir;
367b4e3ac0aSLars-Peter Clausen 
368b4e3ac0aSLars-Peter Clausen 		ret = iio_device_add_event(indio_dev, chan, i, type, dir,
369b4e3ac0aSLars-Peter Clausen 			IIO_SEPARATE, &chan->event_spec[i].mask_separate);
370b4e3ac0aSLars-Peter Clausen 		if (ret < 0)
37192825ff9SHartmut Knaack 			return ret;
372b4e3ac0aSLars-Peter Clausen 		attrcount += ret;
373b4e3ac0aSLars-Peter Clausen 
374b4e3ac0aSLars-Peter Clausen 		ret = iio_device_add_event(indio_dev, chan, i, type, dir,
375b4e3ac0aSLars-Peter Clausen 			IIO_SHARED_BY_TYPE,
376b4e3ac0aSLars-Peter Clausen 			&chan->event_spec[i].mask_shared_by_type);
377b4e3ac0aSLars-Peter Clausen 		if (ret < 0)
37892825ff9SHartmut Knaack 			return ret;
379b4e3ac0aSLars-Peter Clausen 		attrcount += ret;
380b4e3ac0aSLars-Peter Clausen 
381b4e3ac0aSLars-Peter Clausen 		ret = iio_device_add_event(indio_dev, chan, i, type, dir,
382b4e3ac0aSLars-Peter Clausen 			IIO_SHARED_BY_DIR,
383b4e3ac0aSLars-Peter Clausen 			&chan->event_spec[i].mask_shared_by_dir);
384b4e3ac0aSLars-Peter Clausen 		if (ret < 0)
38592825ff9SHartmut Knaack 			return ret;
386b4e3ac0aSLars-Peter Clausen 		attrcount += ret;
387b4e3ac0aSLars-Peter Clausen 
388b4e3ac0aSLars-Peter Clausen 		ret = iio_device_add_event(indio_dev, chan, i, type, dir,
389b4e3ac0aSLars-Peter Clausen 			IIO_SHARED_BY_ALL,
390b4e3ac0aSLars-Peter Clausen 			&chan->event_spec[i].mask_shared_by_all);
391b4e3ac0aSLars-Peter Clausen 		if (ret < 0)
39292825ff9SHartmut Knaack 			return ret;
393b4e3ac0aSLars-Peter Clausen 		attrcount += ret;
394b4e3ac0aSLars-Peter Clausen 	}
395b4e3ac0aSLars-Peter Clausen 	ret = attrcount;
396b4e3ac0aSLars-Peter Clausen 	return ret;
397b4e3ac0aSLars-Peter Clausen }
398b4e3ac0aSLars-Peter Clausen 
399a980e046SJonathan Cameron static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
400a980e046SJonathan Cameron {
401a980e046SJonathan Cameron 	int j, ret, attrcount = 0;
402a980e046SJonathan Cameron 
403a980e046SJonathan Cameron 	/* Dynically created from the channels array */
404a980e046SJonathan Cameron 	for (j = 0; j < indio_dev->num_channels; j++) {
405a980e046SJonathan Cameron 		ret = iio_device_add_event_sysfs(indio_dev,
406a980e046SJonathan Cameron 						 &indio_dev->channels[j]);
407a980e046SJonathan Cameron 		if (ret < 0)
408e3db9ef6SJulia Lawall 			return ret;
409a980e046SJonathan Cameron 		attrcount += ret;
410a980e046SJonathan Cameron 	}
411a980e046SJonathan Cameron 	return attrcount;
412a980e046SJonathan Cameron }
413a980e046SJonathan Cameron 
414a980e046SJonathan Cameron static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
415a980e046SJonathan Cameron {
416a980e046SJonathan Cameron 	int j;
417a980e046SJonathan Cameron 
418b4e3ac0aSLars-Peter Clausen 	for (j = 0; j < indio_dev->num_channels; j++) {
419b4e3ac0aSLars-Peter Clausen 		if (indio_dev->channels[j].num_event_specs != 0)
420b4e3ac0aSLars-Peter Clausen 			return true;
421b4e3ac0aSLars-Peter Clausen 	}
422a980e046SJonathan Cameron 	return false;
423a980e046SJonathan Cameron }
424a980e046SJonathan Cameron 
425a980e046SJonathan Cameron static void iio_setup_ev_int(struct iio_event_interface *ev_int)
426a980e046SJonathan Cameron {
427a980e046SJonathan Cameron 	INIT_KFIFO(ev_int->det_events);
428a980e046SJonathan Cameron 	init_waitqueue_head(&ev_int->wait);
429b91accafSLars-Peter Clausen 	mutex_init(&ev_int->read_lock);
430a980e046SJonathan Cameron }
431a980e046SJonathan Cameron 
432a980e046SJonathan Cameron static const char *iio_event_group_name = "events";
433a980e046SJonathan Cameron int iio_device_register_eventset(struct iio_dev *indio_dev)
434a980e046SJonathan Cameron {
435a980e046SJonathan Cameron 	struct iio_dev_attr *p;
436a980e046SJonathan Cameron 	int ret = 0, attrcount_orig = 0, attrcount, attrn;
437a980e046SJonathan Cameron 	struct attribute **attr;
438a980e046SJonathan Cameron 
439a980e046SJonathan Cameron 	if (!(indio_dev->info->event_attrs ||
440a980e046SJonathan Cameron 	      iio_check_for_dynamic_events(indio_dev)))
441a980e046SJonathan Cameron 		return 0;
442a980e046SJonathan Cameron 
443a980e046SJonathan Cameron 	indio_dev->event_interface =
444a980e046SJonathan Cameron 		kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
44592825ff9SHartmut Knaack 	if (indio_dev->event_interface == NULL)
44692825ff9SHartmut Knaack 		return -ENOMEM;
447a980e046SJonathan Cameron 
44846b24311SSascha Hauer 	INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
44946b24311SSascha Hauer 
450a980e046SJonathan Cameron 	iio_setup_ev_int(indio_dev->event_interface);
451a980e046SJonathan Cameron 	if (indio_dev->info->event_attrs != NULL) {
452a980e046SJonathan Cameron 		attr = indio_dev->info->event_attrs->attrs;
453a980e046SJonathan Cameron 		while (*attr++ != NULL)
454a980e046SJonathan Cameron 			attrcount_orig++;
455a980e046SJonathan Cameron 	}
456a980e046SJonathan Cameron 	attrcount = attrcount_orig;
457a980e046SJonathan Cameron 	if (indio_dev->channels) {
458a980e046SJonathan Cameron 		ret = __iio_add_event_config_attrs(indio_dev);
459a980e046SJonathan Cameron 		if (ret < 0)
460a980e046SJonathan Cameron 			goto error_free_setup_event_lines;
461a980e046SJonathan Cameron 		attrcount += ret;
462a980e046SJonathan Cameron 	}
463a980e046SJonathan Cameron 
464a980e046SJonathan Cameron 	indio_dev->event_interface->group.name = iio_event_group_name;
465a980e046SJonathan Cameron 	indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1,
466a980e046SJonathan Cameron 							  sizeof(indio_dev->event_interface->group.attrs[0]),
467a980e046SJonathan Cameron 							  GFP_KERNEL);
468a980e046SJonathan Cameron 	if (indio_dev->event_interface->group.attrs == NULL) {
469a980e046SJonathan Cameron 		ret = -ENOMEM;
470a980e046SJonathan Cameron 		goto error_free_setup_event_lines;
471a980e046SJonathan Cameron 	}
472a980e046SJonathan Cameron 	if (indio_dev->info->event_attrs)
473a980e046SJonathan Cameron 		memcpy(indio_dev->event_interface->group.attrs,
474a980e046SJonathan Cameron 		       indio_dev->info->event_attrs->attrs,
475a980e046SJonathan Cameron 		       sizeof(indio_dev->event_interface->group.attrs[0])
476a980e046SJonathan Cameron 		       *attrcount_orig);
477a980e046SJonathan Cameron 	attrn = attrcount_orig;
478a980e046SJonathan Cameron 	/* Add all elements from the list. */
479a980e046SJonathan Cameron 	list_for_each_entry(p,
480a980e046SJonathan Cameron 			    &indio_dev->event_interface->dev_attr_list,
481a980e046SJonathan Cameron 			    l)
482a980e046SJonathan Cameron 		indio_dev->event_interface->group.attrs[attrn++] =
483a980e046SJonathan Cameron 			&p->dev_attr.attr;
484a980e046SJonathan Cameron 	indio_dev->groups[indio_dev->groupcounter++] =
485a980e046SJonathan Cameron 		&indio_dev->event_interface->group;
486a980e046SJonathan Cameron 
487a980e046SJonathan Cameron 	return 0;
488a980e046SJonathan Cameron 
489a980e046SJonathan Cameron error_free_setup_event_lines:
49084088ebdSLars-Peter Clausen 	iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
491a980e046SJonathan Cameron 	kfree(indio_dev->event_interface);
492a980e046SJonathan Cameron 	return ret;
493a980e046SJonathan Cameron }
494a980e046SJonathan Cameron 
495d2f0a48fSLars-Peter Clausen /**
496d2f0a48fSLars-Peter Clausen  * iio_device_wakeup_eventset - Wakes up the event waitqueue
497d2f0a48fSLars-Peter Clausen  * @indio_dev: The IIO device
498d2f0a48fSLars-Peter Clausen  *
499d2f0a48fSLars-Peter Clausen  * Wakes up the event waitqueue used for poll() and blocking read().
500d2f0a48fSLars-Peter Clausen  * Should usually be called when the device is unregistered.
501d2f0a48fSLars-Peter Clausen  */
502d2f0a48fSLars-Peter Clausen void iio_device_wakeup_eventset(struct iio_dev *indio_dev)
503d2f0a48fSLars-Peter Clausen {
504d2f0a48fSLars-Peter Clausen 	if (indio_dev->event_interface == NULL)
505d2f0a48fSLars-Peter Clausen 		return;
506d2f0a48fSLars-Peter Clausen 	wake_up(&indio_dev->event_interface->wait);
507d2f0a48fSLars-Peter Clausen }
508d2f0a48fSLars-Peter Clausen 
509a980e046SJonathan Cameron void iio_device_unregister_eventset(struct iio_dev *indio_dev)
510a980e046SJonathan Cameron {
511a980e046SJonathan Cameron 	if (indio_dev->event_interface == NULL)
512a980e046SJonathan Cameron 		return;
51384088ebdSLars-Peter Clausen 	iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
514a980e046SJonathan Cameron 	kfree(indio_dev->event_interface->group.attrs);
515a980e046SJonathan Cameron 	kfree(indio_dev->event_interface);
516a980e046SJonathan Cameron }
517