Commit b46413367961c2e8bd827e067a231be982aaeee2
1 parent
c332c10c01
Exists in
master
and in
6 other branches
iio: fix a leak due to improper use of anon_inode_getfd()
it can fail and in that case ->release() will *not* be called... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 1 changed file with 9 additions and 1 deletions Inline Diff
drivers/staging/iio/industrialio-core.c
1 | /* The industrial I/O core | 1 | /* The industrial I/O core |
2 | * | 2 | * |
3 | * Copyright (c) 2008 Jonathan Cameron | 3 | * Copyright (c) 2008 Jonathan Cameron |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 as published by | 6 | * under the terms of the GNU General Public License version 2 as published by |
7 | * the Free Software Foundation. | 7 | * the Free Software Foundation. |
8 | * | 8 | * |
9 | * Based on elements of hwmon and input subsystems. | 9 | * Based on elements of hwmon and input subsystems. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/idr.h> | 14 | #include <linux/idr.h> |
15 | #include <linux/kdev_t.h> | 15 | #include <linux/kdev_t.h> |
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/poll.h> | 19 | #include <linux/poll.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/wait.h> | 21 | #include <linux/wait.h> |
22 | #include <linux/cdev.h> | 22 | #include <linux/cdev.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/anon_inodes.h> | 24 | #include <linux/anon_inodes.h> |
25 | #include "iio.h" | 25 | #include "iio.h" |
26 | #include "iio_core.h" | 26 | #include "iio_core.h" |
27 | #include "iio_core_trigger.h" | 27 | #include "iio_core_trigger.h" |
28 | #include "chrdev.h" | 28 | #include "chrdev.h" |
29 | #include "sysfs.h" | 29 | #include "sysfs.h" |
30 | 30 | ||
31 | /* IDA to assign each registered device a unique id*/ | 31 | /* IDA to assign each registered device a unique id*/ |
32 | static DEFINE_IDA(iio_ida); | 32 | static DEFINE_IDA(iio_ida); |
33 | 33 | ||
34 | static dev_t iio_devt; | 34 | static dev_t iio_devt; |
35 | 35 | ||
36 | #define IIO_DEV_MAX 256 | 36 | #define IIO_DEV_MAX 256 |
37 | struct bus_type iio_bus_type = { | 37 | struct bus_type iio_bus_type = { |
38 | .name = "iio", | 38 | .name = "iio", |
39 | }; | 39 | }; |
40 | EXPORT_SYMBOL(iio_bus_type); | 40 | EXPORT_SYMBOL(iio_bus_type); |
41 | 41 | ||
42 | static const char * const iio_data_type_name[] = { | 42 | static const char * const iio_data_type_name[] = { |
43 | [IIO_RAW] = "raw", | 43 | [IIO_RAW] = "raw", |
44 | [IIO_PROCESSED] = "input", | 44 | [IIO_PROCESSED] = "input", |
45 | }; | 45 | }; |
46 | 46 | ||
47 | static const char * const iio_direction[] = { | 47 | static const char * const iio_direction[] = { |
48 | [0] = "in", | 48 | [0] = "in", |
49 | [1] = "out", | 49 | [1] = "out", |
50 | }; | 50 | }; |
51 | 51 | ||
52 | static const char * const iio_chan_type_name_spec[] = { | 52 | static const char * const iio_chan_type_name_spec[] = { |
53 | [IIO_VOLTAGE] = "voltage", | 53 | [IIO_VOLTAGE] = "voltage", |
54 | [IIO_CURRENT] = "current", | 54 | [IIO_CURRENT] = "current", |
55 | [IIO_POWER] = "power", | 55 | [IIO_POWER] = "power", |
56 | [IIO_ACCEL] = "accel", | 56 | [IIO_ACCEL] = "accel", |
57 | [IIO_ANGL_VEL] = "anglvel", | 57 | [IIO_ANGL_VEL] = "anglvel", |
58 | [IIO_MAGN] = "magn", | 58 | [IIO_MAGN] = "magn", |
59 | [IIO_LIGHT] = "illuminance", | 59 | [IIO_LIGHT] = "illuminance", |
60 | [IIO_INTENSITY] = "intensity", | 60 | [IIO_INTENSITY] = "intensity", |
61 | [IIO_PROXIMITY] = "proximity", | 61 | [IIO_PROXIMITY] = "proximity", |
62 | [IIO_TEMP] = "temp", | 62 | [IIO_TEMP] = "temp", |
63 | [IIO_INCLI] = "incli", | 63 | [IIO_INCLI] = "incli", |
64 | [IIO_ROT] = "rot", | 64 | [IIO_ROT] = "rot", |
65 | [IIO_ANGL] = "angl", | 65 | [IIO_ANGL] = "angl", |
66 | [IIO_TIMESTAMP] = "timestamp", | 66 | [IIO_TIMESTAMP] = "timestamp", |
67 | [IIO_CAPACITANCE] = "capacitance", | 67 | [IIO_CAPACITANCE] = "capacitance", |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static const char * const iio_modifier_names[] = { | 70 | static const char * const iio_modifier_names[] = { |
71 | [IIO_MOD_X] = "x", | 71 | [IIO_MOD_X] = "x", |
72 | [IIO_MOD_Y] = "y", | 72 | [IIO_MOD_Y] = "y", |
73 | [IIO_MOD_Z] = "z", | 73 | [IIO_MOD_Z] = "z", |
74 | [IIO_MOD_LIGHT_BOTH] = "both", | 74 | [IIO_MOD_LIGHT_BOTH] = "both", |
75 | [IIO_MOD_LIGHT_IR] = "ir", | 75 | [IIO_MOD_LIGHT_IR] = "ir", |
76 | }; | 76 | }; |
77 | 77 | ||
78 | /* relies on pairs of these shared then separate */ | 78 | /* relies on pairs of these shared then separate */ |
79 | static const char * const iio_chan_info_postfix[] = { | 79 | static const char * const iio_chan_info_postfix[] = { |
80 | [IIO_CHAN_INFO_SCALE_SHARED/2] = "scale", | 80 | [IIO_CHAN_INFO_SCALE_SHARED/2] = "scale", |
81 | [IIO_CHAN_INFO_OFFSET_SHARED/2] = "offset", | 81 | [IIO_CHAN_INFO_OFFSET_SHARED/2] = "offset", |
82 | [IIO_CHAN_INFO_CALIBSCALE_SHARED/2] = "calibscale", | 82 | [IIO_CHAN_INFO_CALIBSCALE_SHARED/2] = "calibscale", |
83 | [IIO_CHAN_INFO_CALIBBIAS_SHARED/2] = "calibbias", | 83 | [IIO_CHAN_INFO_CALIBBIAS_SHARED/2] = "calibbias", |
84 | [IIO_CHAN_INFO_PEAK_SHARED/2] = "peak_raw", | 84 | [IIO_CHAN_INFO_PEAK_SHARED/2] = "peak_raw", |
85 | [IIO_CHAN_INFO_PEAK_SCALE_SHARED/2] = "peak_scale", | 85 | [IIO_CHAN_INFO_PEAK_SCALE_SHARED/2] = "peak_scale", |
86 | [IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED/2] | 86 | [IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED/2] |
87 | = "quadrature_correction_raw", | 87 | = "quadrature_correction_raw", |
88 | [IIO_CHAN_INFO_AVERAGE_RAW_SHARED/2] = "mean_raw", | 88 | [IIO_CHAN_INFO_AVERAGE_RAW_SHARED/2] = "mean_raw", |
89 | }; | 89 | }; |
90 | 90 | ||
91 | /** | 91 | /** |
92 | * struct iio_detected_event_list - list element for events that have occurred | 92 | * struct iio_detected_event_list - list element for events that have occurred |
93 | * @list: linked list header | 93 | * @list: linked list header |
94 | * @ev: the event itself | 94 | * @ev: the event itself |
95 | */ | 95 | */ |
96 | struct iio_detected_event_list { | 96 | struct iio_detected_event_list { |
97 | struct list_head list; | 97 | struct list_head list; |
98 | struct iio_event_data ev; | 98 | struct iio_event_data ev; |
99 | }; | 99 | }; |
100 | 100 | ||
101 | /** | 101 | /** |
102 | * struct iio_event_interface - chrdev interface for an event line | 102 | * struct iio_event_interface - chrdev interface for an event line |
103 | * @dev: device assocated with event interface | 103 | * @dev: device assocated with event interface |
104 | * @wait: wait queue to allow blocking reads of events | 104 | * @wait: wait queue to allow blocking reads of events |
105 | * @event_list_lock: mutex to protect the list of detected events | 105 | * @event_list_lock: mutex to protect the list of detected events |
106 | * @det_events: list of detected events | 106 | * @det_events: list of detected events |
107 | * @max_events: maximum number of events before new ones are dropped | 107 | * @max_events: maximum number of events before new ones are dropped |
108 | * @current_events: number of events in detected list | 108 | * @current_events: number of events in detected list |
109 | * @flags: file operations related flags including busy flag. | 109 | * @flags: file operations related flags including busy flag. |
110 | */ | 110 | */ |
111 | struct iio_event_interface { | 111 | struct iio_event_interface { |
112 | wait_queue_head_t wait; | 112 | wait_queue_head_t wait; |
113 | struct mutex event_list_lock; | 113 | struct mutex event_list_lock; |
114 | struct list_head det_events; | 114 | struct list_head det_events; |
115 | int max_events; | 115 | int max_events; |
116 | int current_events; | 116 | int current_events; |
117 | struct list_head dev_attr_list; | 117 | struct list_head dev_attr_list; |
118 | unsigned long flags; | 118 | unsigned long flags; |
119 | struct attribute_group group; | 119 | struct attribute_group group; |
120 | }; | 120 | }; |
121 | 121 | ||
122 | int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) | 122 | int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) |
123 | { | 123 | { |
124 | struct iio_event_interface *ev_int = indio_dev->event_interface; | 124 | struct iio_event_interface *ev_int = indio_dev->event_interface; |
125 | struct iio_detected_event_list *ev; | 125 | struct iio_detected_event_list *ev; |
126 | int ret = 0; | 126 | int ret = 0; |
127 | 127 | ||
128 | /* Does anyone care? */ | 128 | /* Does anyone care? */ |
129 | mutex_lock(&ev_int->event_list_lock); | 129 | mutex_lock(&ev_int->event_list_lock); |
130 | if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { | 130 | if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { |
131 | if (ev_int->current_events == ev_int->max_events) { | 131 | if (ev_int->current_events == ev_int->max_events) { |
132 | mutex_unlock(&ev_int->event_list_lock); | 132 | mutex_unlock(&ev_int->event_list_lock); |
133 | return 0; | 133 | return 0; |
134 | } | 134 | } |
135 | ev = kmalloc(sizeof(*ev), GFP_KERNEL); | 135 | ev = kmalloc(sizeof(*ev), GFP_KERNEL); |
136 | if (ev == NULL) { | 136 | if (ev == NULL) { |
137 | ret = -ENOMEM; | 137 | ret = -ENOMEM; |
138 | mutex_unlock(&ev_int->event_list_lock); | 138 | mutex_unlock(&ev_int->event_list_lock); |
139 | goto error_ret; | 139 | goto error_ret; |
140 | } | 140 | } |
141 | ev->ev.id = ev_code; | 141 | ev->ev.id = ev_code; |
142 | ev->ev.timestamp = timestamp; | 142 | ev->ev.timestamp = timestamp; |
143 | 143 | ||
144 | list_add_tail(&ev->list, &ev_int->det_events); | 144 | list_add_tail(&ev->list, &ev_int->det_events); |
145 | ev_int->current_events++; | 145 | ev_int->current_events++; |
146 | mutex_unlock(&ev_int->event_list_lock); | 146 | mutex_unlock(&ev_int->event_list_lock); |
147 | wake_up_interruptible(&ev_int->wait); | 147 | wake_up_interruptible(&ev_int->wait); |
148 | } else | 148 | } else |
149 | mutex_unlock(&ev_int->event_list_lock); | 149 | mutex_unlock(&ev_int->event_list_lock); |
150 | 150 | ||
151 | error_ret: | 151 | error_ret: |
152 | return ret; | 152 | return ret; |
153 | } | 153 | } |
154 | EXPORT_SYMBOL(iio_push_event); | 154 | EXPORT_SYMBOL(iio_push_event); |
155 | 155 | ||
156 | /* This turns up an awful lot */ | 156 | /* This turns up an awful lot */ |
157 | ssize_t iio_read_const_attr(struct device *dev, | 157 | ssize_t iio_read_const_attr(struct device *dev, |
158 | struct device_attribute *attr, | 158 | struct device_attribute *attr, |
159 | char *buf) | 159 | char *buf) |
160 | { | 160 | { |
161 | return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string); | 161 | return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string); |
162 | } | 162 | } |
163 | EXPORT_SYMBOL(iio_read_const_attr); | 163 | EXPORT_SYMBOL(iio_read_const_attr); |
164 | 164 | ||
165 | static ssize_t iio_event_chrdev_read(struct file *filep, | 165 | static ssize_t iio_event_chrdev_read(struct file *filep, |
166 | char __user *buf, | 166 | char __user *buf, |
167 | size_t count, | 167 | size_t count, |
168 | loff_t *f_ps) | 168 | loff_t *f_ps) |
169 | { | 169 | { |
170 | struct iio_event_interface *ev_int = filep->private_data; | 170 | struct iio_event_interface *ev_int = filep->private_data; |
171 | struct iio_detected_event_list *el; | 171 | struct iio_detected_event_list *el; |
172 | int ret; | 172 | int ret; |
173 | size_t len; | 173 | size_t len; |
174 | 174 | ||
175 | mutex_lock(&ev_int->event_list_lock); | 175 | mutex_lock(&ev_int->event_list_lock); |
176 | if (list_empty(&ev_int->det_events)) { | 176 | if (list_empty(&ev_int->det_events)) { |
177 | if (filep->f_flags & O_NONBLOCK) { | 177 | if (filep->f_flags & O_NONBLOCK) { |
178 | ret = -EAGAIN; | 178 | ret = -EAGAIN; |
179 | goto error_mutex_unlock; | 179 | goto error_mutex_unlock; |
180 | } | 180 | } |
181 | mutex_unlock(&ev_int->event_list_lock); | 181 | mutex_unlock(&ev_int->event_list_lock); |
182 | /* Blocking on device; waiting for something to be there */ | 182 | /* Blocking on device; waiting for something to be there */ |
183 | ret = wait_event_interruptible(ev_int->wait, | 183 | ret = wait_event_interruptible(ev_int->wait, |
184 | !list_empty(&ev_int | 184 | !list_empty(&ev_int |
185 | ->det_events)); | 185 | ->det_events)); |
186 | if (ret) | 186 | if (ret) |
187 | goto error_ret; | 187 | goto error_ret; |
188 | /* Single access device so no one else can get the data */ | 188 | /* Single access device so no one else can get the data */ |
189 | mutex_lock(&ev_int->event_list_lock); | 189 | mutex_lock(&ev_int->event_list_lock); |
190 | } | 190 | } |
191 | 191 | ||
192 | el = list_first_entry(&ev_int->det_events, | 192 | el = list_first_entry(&ev_int->det_events, |
193 | struct iio_detected_event_list, | 193 | struct iio_detected_event_list, |
194 | list); | 194 | list); |
195 | len = sizeof el->ev; | 195 | len = sizeof el->ev; |
196 | if (copy_to_user(buf, &(el->ev), len)) { | 196 | if (copy_to_user(buf, &(el->ev), len)) { |
197 | ret = -EFAULT; | 197 | ret = -EFAULT; |
198 | goto error_mutex_unlock; | 198 | goto error_mutex_unlock; |
199 | } | 199 | } |
200 | list_del(&el->list); | 200 | list_del(&el->list); |
201 | ev_int->current_events--; | 201 | ev_int->current_events--; |
202 | mutex_unlock(&ev_int->event_list_lock); | 202 | mutex_unlock(&ev_int->event_list_lock); |
203 | kfree(el); | 203 | kfree(el); |
204 | 204 | ||
205 | return len; | 205 | return len; |
206 | 206 | ||
207 | error_mutex_unlock: | 207 | error_mutex_unlock: |
208 | mutex_unlock(&ev_int->event_list_lock); | 208 | mutex_unlock(&ev_int->event_list_lock); |
209 | error_ret: | 209 | error_ret: |
210 | 210 | ||
211 | return ret; | 211 | return ret; |
212 | } | 212 | } |
213 | 213 | ||
214 | static int iio_event_chrdev_release(struct inode *inode, struct file *filep) | 214 | static int iio_event_chrdev_release(struct inode *inode, struct file *filep) |
215 | { | 215 | { |
216 | struct iio_event_interface *ev_int = filep->private_data; | 216 | struct iio_event_interface *ev_int = filep->private_data; |
217 | struct iio_detected_event_list *el, *t; | 217 | struct iio_detected_event_list *el, *t; |
218 | 218 | ||
219 | mutex_lock(&ev_int->event_list_lock); | 219 | mutex_lock(&ev_int->event_list_lock); |
220 | clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); | 220 | clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); |
221 | /* | 221 | /* |
222 | * In order to maintain a clean state for reopening, | 222 | * In order to maintain a clean state for reopening, |
223 | * clear out any awaiting events. The mask will prevent | 223 | * clear out any awaiting events. The mask will prevent |
224 | * any new __iio_push_event calls running. | 224 | * any new __iio_push_event calls running. |
225 | */ | 225 | */ |
226 | list_for_each_entry_safe(el, t, &ev_int->det_events, list) { | 226 | list_for_each_entry_safe(el, t, &ev_int->det_events, list) { |
227 | list_del(&el->list); | 227 | list_del(&el->list); |
228 | kfree(el); | 228 | kfree(el); |
229 | } | 229 | } |
230 | ev_int->current_events = 0; | 230 | ev_int->current_events = 0; |
231 | mutex_unlock(&ev_int->event_list_lock); | 231 | mutex_unlock(&ev_int->event_list_lock); |
232 | 232 | ||
233 | return 0; | 233 | return 0; |
234 | } | 234 | } |
235 | 235 | ||
236 | static const struct file_operations iio_event_chrdev_fileops = { | 236 | static const struct file_operations iio_event_chrdev_fileops = { |
237 | .read = iio_event_chrdev_read, | 237 | .read = iio_event_chrdev_read, |
238 | .release = iio_event_chrdev_release, | 238 | .release = iio_event_chrdev_release, |
239 | .owner = THIS_MODULE, | 239 | .owner = THIS_MODULE, |
240 | .llseek = noop_llseek, | 240 | .llseek = noop_llseek, |
241 | }; | 241 | }; |
242 | 242 | ||
243 | static int iio_event_getfd(struct iio_dev *indio_dev) | 243 | static int iio_event_getfd(struct iio_dev *indio_dev) |
244 | { | 244 | { |
245 | int fd; | ||
246 | |||
245 | if (indio_dev->event_interface == NULL) | 247 | if (indio_dev->event_interface == NULL) |
246 | return -ENODEV; | 248 | return -ENODEV; |
247 | 249 | ||
248 | mutex_lock(&indio_dev->event_interface->event_list_lock); | 250 | mutex_lock(&indio_dev->event_interface->event_list_lock); |
249 | if (test_and_set_bit(IIO_BUSY_BIT_POS, | 251 | if (test_and_set_bit(IIO_BUSY_BIT_POS, |
250 | &indio_dev->event_interface->flags)) { | 252 | &indio_dev->event_interface->flags)) { |
251 | mutex_unlock(&indio_dev->event_interface->event_list_lock); | 253 | mutex_unlock(&indio_dev->event_interface->event_list_lock); |
252 | return -EBUSY; | 254 | return -EBUSY; |
253 | } | 255 | } |
254 | mutex_unlock(&indio_dev->event_interface->event_list_lock); | 256 | mutex_unlock(&indio_dev->event_interface->event_list_lock); |
255 | return anon_inode_getfd("iio:event", | 257 | fd = anon_inode_getfd("iio:event", |
256 | &iio_event_chrdev_fileops, | 258 | &iio_event_chrdev_fileops, |
257 | indio_dev->event_interface, O_RDONLY); | 259 | indio_dev->event_interface, O_RDONLY); |
260 | if (fd < 0) { | ||
261 | mutex_lock(&indio_dev->event_interface->event_list_lock); | ||
262 | clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); | ||
263 | mutex_unlock(&indio_dev->event_interface->event_list_lock); | ||
264 | } | ||
265 | return fd; | ||
258 | } | 266 | } |
259 | 267 | ||
260 | static int __init iio_init(void) | 268 | static int __init iio_init(void) |
261 | { | 269 | { |
262 | int ret; | 270 | int ret; |
263 | 271 | ||
264 | /* Register sysfs bus */ | 272 | /* Register sysfs bus */ |
265 | ret = bus_register(&iio_bus_type); | 273 | ret = bus_register(&iio_bus_type); |
266 | if (ret < 0) { | 274 | if (ret < 0) { |
267 | printk(KERN_ERR | 275 | printk(KERN_ERR |
268 | "%s could not register bus type\n", | 276 | "%s could not register bus type\n", |
269 | __FILE__); | 277 | __FILE__); |
270 | goto error_nothing; | 278 | goto error_nothing; |
271 | } | 279 | } |
272 | 280 | ||
273 | ret = alloc_chrdev_region(&iio_devt, 0, IIO_DEV_MAX, "iio"); | 281 | ret = alloc_chrdev_region(&iio_devt, 0, IIO_DEV_MAX, "iio"); |
274 | if (ret < 0) { | 282 | if (ret < 0) { |
275 | printk(KERN_ERR "%s: failed to allocate char dev region\n", | 283 | printk(KERN_ERR "%s: failed to allocate char dev region\n", |
276 | __FILE__); | 284 | __FILE__); |
277 | goto error_unregister_bus_type; | 285 | goto error_unregister_bus_type; |
278 | } | 286 | } |
279 | 287 | ||
280 | return 0; | 288 | return 0; |
281 | 289 | ||
282 | error_unregister_bus_type: | 290 | error_unregister_bus_type: |
283 | bus_unregister(&iio_bus_type); | 291 | bus_unregister(&iio_bus_type); |
284 | error_nothing: | 292 | error_nothing: |
285 | return ret; | 293 | return ret; |
286 | } | 294 | } |
287 | 295 | ||
288 | static void __exit iio_exit(void) | 296 | static void __exit iio_exit(void) |
289 | { | 297 | { |
290 | if (iio_devt) | 298 | if (iio_devt) |
291 | unregister_chrdev_region(iio_devt, IIO_DEV_MAX); | 299 | unregister_chrdev_region(iio_devt, IIO_DEV_MAX); |
292 | bus_unregister(&iio_bus_type); | 300 | bus_unregister(&iio_bus_type); |
293 | } | 301 | } |
294 | 302 | ||
295 | static ssize_t iio_read_channel_info(struct device *dev, | 303 | static ssize_t iio_read_channel_info(struct device *dev, |
296 | struct device_attribute *attr, | 304 | struct device_attribute *attr, |
297 | char *buf) | 305 | char *buf) |
298 | { | 306 | { |
299 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 307 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
300 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | 308 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); |
301 | int val, val2; | 309 | int val, val2; |
302 | int ret = indio_dev->info->read_raw(indio_dev, this_attr->c, | 310 | int ret = indio_dev->info->read_raw(indio_dev, this_attr->c, |
303 | &val, &val2, this_attr->address); | 311 | &val, &val2, this_attr->address); |
304 | 312 | ||
305 | if (ret < 0) | 313 | if (ret < 0) |
306 | return ret; | 314 | return ret; |
307 | 315 | ||
308 | if (ret == IIO_VAL_INT) | 316 | if (ret == IIO_VAL_INT) |
309 | return sprintf(buf, "%d\n", val); | 317 | return sprintf(buf, "%d\n", val); |
310 | else if (ret == IIO_VAL_INT_PLUS_MICRO) { | 318 | else if (ret == IIO_VAL_INT_PLUS_MICRO) { |
311 | if (val2 < 0) | 319 | if (val2 < 0) |
312 | return sprintf(buf, "-%d.%06u\n", val, -val2); | 320 | return sprintf(buf, "-%d.%06u\n", val, -val2); |
313 | else | 321 | else |
314 | return sprintf(buf, "%d.%06u\n", val, val2); | 322 | return sprintf(buf, "%d.%06u\n", val, val2); |
315 | } else if (ret == IIO_VAL_INT_PLUS_NANO) { | 323 | } else if (ret == IIO_VAL_INT_PLUS_NANO) { |
316 | if (val2 < 0) | 324 | if (val2 < 0) |
317 | return sprintf(buf, "-%d.%09u\n", val, -val2); | 325 | return sprintf(buf, "-%d.%09u\n", val, -val2); |
318 | else | 326 | else |
319 | return sprintf(buf, "%d.%09u\n", val, val2); | 327 | return sprintf(buf, "%d.%09u\n", val, val2); |
320 | } else | 328 | } else |
321 | return 0; | 329 | return 0; |
322 | } | 330 | } |
323 | 331 | ||
324 | static ssize_t iio_write_channel_info(struct device *dev, | 332 | static ssize_t iio_write_channel_info(struct device *dev, |
325 | struct device_attribute *attr, | 333 | struct device_attribute *attr, |
326 | const char *buf, | 334 | const char *buf, |
327 | size_t len) | 335 | size_t len) |
328 | { | 336 | { |
329 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 337 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
330 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | 338 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); |
331 | int ret, integer = 0, fract = 0, fract_mult = 100000; | 339 | int ret, integer = 0, fract = 0, fract_mult = 100000; |
332 | bool integer_part = true, negative = false; | 340 | bool integer_part = true, negative = false; |
333 | 341 | ||
334 | /* Assumes decimal - precision based on number of digits */ | 342 | /* Assumes decimal - precision based on number of digits */ |
335 | if (!indio_dev->info->write_raw) | 343 | if (!indio_dev->info->write_raw) |
336 | return -EINVAL; | 344 | return -EINVAL; |
337 | 345 | ||
338 | if (indio_dev->info->write_raw_get_fmt) | 346 | if (indio_dev->info->write_raw_get_fmt) |
339 | switch (indio_dev->info->write_raw_get_fmt(indio_dev, | 347 | switch (indio_dev->info->write_raw_get_fmt(indio_dev, |
340 | this_attr->c, this_attr->address)) { | 348 | this_attr->c, this_attr->address)) { |
341 | case IIO_VAL_INT_PLUS_MICRO: | 349 | case IIO_VAL_INT_PLUS_MICRO: |
342 | fract_mult = 100000; | 350 | fract_mult = 100000; |
343 | break; | 351 | break; |
344 | case IIO_VAL_INT_PLUS_NANO: | 352 | case IIO_VAL_INT_PLUS_NANO: |
345 | fract_mult = 100000000; | 353 | fract_mult = 100000000; |
346 | break; | 354 | break; |
347 | default: | 355 | default: |
348 | return -EINVAL; | 356 | return -EINVAL; |
349 | } | 357 | } |
350 | 358 | ||
351 | if (buf[0] == '-') { | 359 | if (buf[0] == '-') { |
352 | negative = true; | 360 | negative = true; |
353 | buf++; | 361 | buf++; |
354 | } | 362 | } |
355 | 363 | ||
356 | while (*buf) { | 364 | while (*buf) { |
357 | if ('0' <= *buf && *buf <= '9') { | 365 | if ('0' <= *buf && *buf <= '9') { |
358 | if (integer_part) | 366 | if (integer_part) |
359 | integer = integer*10 + *buf - '0'; | 367 | integer = integer*10 + *buf - '0'; |
360 | else { | 368 | else { |
361 | fract += fract_mult*(*buf - '0'); | 369 | fract += fract_mult*(*buf - '0'); |
362 | if (fract_mult == 1) | 370 | if (fract_mult == 1) |
363 | break; | 371 | break; |
364 | fract_mult /= 10; | 372 | fract_mult /= 10; |
365 | } | 373 | } |
366 | } else if (*buf == '\n') { | 374 | } else if (*buf == '\n') { |
367 | if (*(buf + 1) == '\0') | 375 | if (*(buf + 1) == '\0') |
368 | break; | 376 | break; |
369 | else | 377 | else |
370 | return -EINVAL; | 378 | return -EINVAL; |
371 | } else if (*buf == '.') { | 379 | } else if (*buf == '.') { |
372 | integer_part = false; | 380 | integer_part = false; |
373 | } else { | 381 | } else { |
374 | return -EINVAL; | 382 | return -EINVAL; |
375 | } | 383 | } |
376 | buf++; | 384 | buf++; |
377 | } | 385 | } |
378 | if (negative) { | 386 | if (negative) { |
379 | if (integer) | 387 | if (integer) |
380 | integer = -integer; | 388 | integer = -integer; |
381 | else | 389 | else |
382 | fract = -fract; | 390 | fract = -fract; |
383 | } | 391 | } |
384 | 392 | ||
385 | ret = indio_dev->info->write_raw(indio_dev, this_attr->c, | 393 | ret = indio_dev->info->write_raw(indio_dev, this_attr->c, |
386 | integer, fract, this_attr->address); | 394 | integer, fract, this_attr->address); |
387 | if (ret) | 395 | if (ret) |
388 | return ret; | 396 | return ret; |
389 | 397 | ||
390 | return len; | 398 | return len; |
391 | } | 399 | } |
392 | 400 | ||
393 | static | 401 | static |
394 | int __iio_device_attr_init(struct device_attribute *dev_attr, | 402 | int __iio_device_attr_init(struct device_attribute *dev_attr, |
395 | const char *postfix, | 403 | const char *postfix, |
396 | struct iio_chan_spec const *chan, | 404 | struct iio_chan_spec const *chan, |
397 | ssize_t (*readfunc)(struct device *dev, | 405 | ssize_t (*readfunc)(struct device *dev, |
398 | struct device_attribute *attr, | 406 | struct device_attribute *attr, |
399 | char *buf), | 407 | char *buf), |
400 | ssize_t (*writefunc)(struct device *dev, | 408 | ssize_t (*writefunc)(struct device *dev, |
401 | struct device_attribute *attr, | 409 | struct device_attribute *attr, |
402 | const char *buf, | 410 | const char *buf, |
403 | size_t len), | 411 | size_t len), |
404 | bool generic) | 412 | bool generic) |
405 | { | 413 | { |
406 | int ret; | 414 | int ret; |
407 | char *name_format, *full_postfix; | 415 | char *name_format, *full_postfix; |
408 | sysfs_attr_init(&dev_attr->attr); | 416 | sysfs_attr_init(&dev_attr->attr); |
409 | 417 | ||
410 | /* Build up postfix of <extend_name>_<modifier>_postfix */ | 418 | /* Build up postfix of <extend_name>_<modifier>_postfix */ |
411 | if (chan->modified) { | 419 | if (chan->modified) { |
412 | if (chan->extend_name) | 420 | if (chan->extend_name) |
413 | full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s", | 421 | full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s", |
414 | iio_modifier_names[chan | 422 | iio_modifier_names[chan |
415 | ->channel2], | 423 | ->channel2], |
416 | chan->extend_name, | 424 | chan->extend_name, |
417 | postfix); | 425 | postfix); |
418 | else | 426 | else |
419 | full_postfix = kasprintf(GFP_KERNEL, "%s_%s", | 427 | full_postfix = kasprintf(GFP_KERNEL, "%s_%s", |
420 | iio_modifier_names[chan | 428 | iio_modifier_names[chan |
421 | ->channel2], | 429 | ->channel2], |
422 | postfix); | 430 | postfix); |
423 | } else { | 431 | } else { |
424 | if (chan->extend_name == NULL) | 432 | if (chan->extend_name == NULL) |
425 | full_postfix = kstrdup(postfix, GFP_KERNEL); | 433 | full_postfix = kstrdup(postfix, GFP_KERNEL); |
426 | else | 434 | else |
427 | full_postfix = kasprintf(GFP_KERNEL, | 435 | full_postfix = kasprintf(GFP_KERNEL, |
428 | "%s_%s", | 436 | "%s_%s", |
429 | chan->extend_name, | 437 | chan->extend_name, |
430 | postfix); | 438 | postfix); |
431 | } | 439 | } |
432 | if (full_postfix == NULL) { | 440 | if (full_postfix == NULL) { |
433 | ret = -ENOMEM; | 441 | ret = -ENOMEM; |
434 | goto error_ret; | 442 | goto error_ret; |
435 | } | 443 | } |
436 | 444 | ||
437 | if (chan->differential) { /* Differential can not have modifier */ | 445 | if (chan->differential) { /* Differential can not have modifier */ |
438 | if (generic) | 446 | if (generic) |
439 | name_format | 447 | name_format |
440 | = kasprintf(GFP_KERNEL, "%s_%s-%s_%s", | 448 | = kasprintf(GFP_KERNEL, "%s_%s-%s_%s", |
441 | iio_direction[chan->output], | 449 | iio_direction[chan->output], |
442 | iio_chan_type_name_spec[chan->type], | 450 | iio_chan_type_name_spec[chan->type], |
443 | iio_chan_type_name_spec[chan->type], | 451 | iio_chan_type_name_spec[chan->type], |
444 | full_postfix); | 452 | full_postfix); |
445 | else if (chan->indexed) | 453 | else if (chan->indexed) |
446 | name_format | 454 | name_format |
447 | = kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s", | 455 | = kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s", |
448 | iio_direction[chan->output], | 456 | iio_direction[chan->output], |
449 | iio_chan_type_name_spec[chan->type], | 457 | iio_chan_type_name_spec[chan->type], |
450 | chan->channel, | 458 | chan->channel, |
451 | iio_chan_type_name_spec[chan->type], | 459 | iio_chan_type_name_spec[chan->type], |
452 | chan->channel2, | 460 | chan->channel2, |
453 | full_postfix); | 461 | full_postfix); |
454 | else { | 462 | else { |
455 | WARN_ON("Differential channels must be indexed\n"); | 463 | WARN_ON("Differential channels must be indexed\n"); |
456 | ret = -EINVAL; | 464 | ret = -EINVAL; |
457 | goto error_free_full_postfix; | 465 | goto error_free_full_postfix; |
458 | } | 466 | } |
459 | } else { /* Single ended */ | 467 | } else { /* Single ended */ |
460 | if (generic) | 468 | if (generic) |
461 | name_format | 469 | name_format |
462 | = kasprintf(GFP_KERNEL, "%s_%s_%s", | 470 | = kasprintf(GFP_KERNEL, "%s_%s_%s", |
463 | iio_direction[chan->output], | 471 | iio_direction[chan->output], |
464 | iio_chan_type_name_spec[chan->type], | 472 | iio_chan_type_name_spec[chan->type], |
465 | full_postfix); | 473 | full_postfix); |
466 | else if (chan->indexed) | 474 | else if (chan->indexed) |
467 | name_format | 475 | name_format |
468 | = kasprintf(GFP_KERNEL, "%s_%s%d_%s", | 476 | = kasprintf(GFP_KERNEL, "%s_%s%d_%s", |
469 | iio_direction[chan->output], | 477 | iio_direction[chan->output], |
470 | iio_chan_type_name_spec[chan->type], | 478 | iio_chan_type_name_spec[chan->type], |
471 | chan->channel, | 479 | chan->channel, |
472 | full_postfix); | 480 | full_postfix); |
473 | else | 481 | else |
474 | name_format | 482 | name_format |
475 | = kasprintf(GFP_KERNEL, "%s_%s_%s", | 483 | = kasprintf(GFP_KERNEL, "%s_%s_%s", |
476 | iio_direction[chan->output], | 484 | iio_direction[chan->output], |
477 | iio_chan_type_name_spec[chan->type], | 485 | iio_chan_type_name_spec[chan->type], |
478 | full_postfix); | 486 | full_postfix); |
479 | } | 487 | } |
480 | if (name_format == NULL) { | 488 | if (name_format == NULL) { |
481 | ret = -ENOMEM; | 489 | ret = -ENOMEM; |
482 | goto error_free_full_postfix; | 490 | goto error_free_full_postfix; |
483 | } | 491 | } |
484 | dev_attr->attr.name = kasprintf(GFP_KERNEL, | 492 | dev_attr->attr.name = kasprintf(GFP_KERNEL, |
485 | name_format, | 493 | name_format, |
486 | chan->channel, | 494 | chan->channel, |
487 | chan->channel2); | 495 | chan->channel2); |
488 | if (dev_attr->attr.name == NULL) { | 496 | if (dev_attr->attr.name == NULL) { |
489 | ret = -ENOMEM; | 497 | ret = -ENOMEM; |
490 | goto error_free_name_format; | 498 | goto error_free_name_format; |
491 | } | 499 | } |
492 | 500 | ||
493 | if (readfunc) { | 501 | if (readfunc) { |
494 | dev_attr->attr.mode |= S_IRUGO; | 502 | dev_attr->attr.mode |= S_IRUGO; |
495 | dev_attr->show = readfunc; | 503 | dev_attr->show = readfunc; |
496 | } | 504 | } |
497 | 505 | ||
498 | if (writefunc) { | 506 | if (writefunc) { |
499 | dev_attr->attr.mode |= S_IWUSR; | 507 | dev_attr->attr.mode |= S_IWUSR; |
500 | dev_attr->store = writefunc; | 508 | dev_attr->store = writefunc; |
501 | } | 509 | } |
502 | kfree(name_format); | 510 | kfree(name_format); |
503 | kfree(full_postfix); | 511 | kfree(full_postfix); |
504 | 512 | ||
505 | return 0; | 513 | return 0; |
506 | 514 | ||
507 | error_free_name_format: | 515 | error_free_name_format: |
508 | kfree(name_format); | 516 | kfree(name_format); |
509 | error_free_full_postfix: | 517 | error_free_full_postfix: |
510 | kfree(full_postfix); | 518 | kfree(full_postfix); |
511 | error_ret: | 519 | error_ret: |
512 | return ret; | 520 | return ret; |
513 | } | 521 | } |
514 | 522 | ||
515 | static void __iio_device_attr_deinit(struct device_attribute *dev_attr) | 523 | static void __iio_device_attr_deinit(struct device_attribute *dev_attr) |
516 | { | 524 | { |
517 | kfree(dev_attr->attr.name); | 525 | kfree(dev_attr->attr.name); |
518 | } | 526 | } |
519 | 527 | ||
520 | int __iio_add_chan_devattr(const char *postfix, | 528 | int __iio_add_chan_devattr(const char *postfix, |
521 | struct iio_chan_spec const *chan, | 529 | struct iio_chan_spec const *chan, |
522 | ssize_t (*readfunc)(struct device *dev, | 530 | ssize_t (*readfunc)(struct device *dev, |
523 | struct device_attribute *attr, | 531 | struct device_attribute *attr, |
524 | char *buf), | 532 | char *buf), |
525 | ssize_t (*writefunc)(struct device *dev, | 533 | ssize_t (*writefunc)(struct device *dev, |
526 | struct device_attribute *attr, | 534 | struct device_attribute *attr, |
527 | const char *buf, | 535 | const char *buf, |
528 | size_t len), | 536 | size_t len), |
529 | u64 mask, | 537 | u64 mask, |
530 | bool generic, | 538 | bool generic, |
531 | struct device *dev, | 539 | struct device *dev, |
532 | struct list_head *attr_list) | 540 | struct list_head *attr_list) |
533 | { | 541 | { |
534 | int ret; | 542 | int ret; |
535 | struct iio_dev_attr *iio_attr, *t; | 543 | struct iio_dev_attr *iio_attr, *t; |
536 | 544 | ||
537 | iio_attr = kzalloc(sizeof *iio_attr, GFP_KERNEL); | 545 | iio_attr = kzalloc(sizeof *iio_attr, GFP_KERNEL); |
538 | if (iio_attr == NULL) { | 546 | if (iio_attr == NULL) { |
539 | ret = -ENOMEM; | 547 | ret = -ENOMEM; |
540 | goto error_ret; | 548 | goto error_ret; |
541 | } | 549 | } |
542 | ret = __iio_device_attr_init(&iio_attr->dev_attr, | 550 | ret = __iio_device_attr_init(&iio_attr->dev_attr, |
543 | postfix, chan, | 551 | postfix, chan, |
544 | readfunc, writefunc, generic); | 552 | readfunc, writefunc, generic); |
545 | if (ret) | 553 | if (ret) |
546 | goto error_iio_dev_attr_free; | 554 | goto error_iio_dev_attr_free; |
547 | iio_attr->c = chan; | 555 | iio_attr->c = chan; |
548 | iio_attr->address = mask; | 556 | iio_attr->address = mask; |
549 | list_for_each_entry(t, attr_list, l) | 557 | list_for_each_entry(t, attr_list, l) |
550 | if (strcmp(t->dev_attr.attr.name, | 558 | if (strcmp(t->dev_attr.attr.name, |
551 | iio_attr->dev_attr.attr.name) == 0) { | 559 | iio_attr->dev_attr.attr.name) == 0) { |
552 | if (!generic) | 560 | if (!generic) |
553 | dev_err(dev, "tried to double register : %s\n", | 561 | dev_err(dev, "tried to double register : %s\n", |
554 | t->dev_attr.attr.name); | 562 | t->dev_attr.attr.name); |
555 | ret = -EBUSY; | 563 | ret = -EBUSY; |
556 | goto error_device_attr_deinit; | 564 | goto error_device_attr_deinit; |
557 | } | 565 | } |
558 | list_add(&iio_attr->l, attr_list); | 566 | list_add(&iio_attr->l, attr_list); |
559 | 567 | ||
560 | return 0; | 568 | return 0; |
561 | 569 | ||
562 | error_device_attr_deinit: | 570 | error_device_attr_deinit: |
563 | __iio_device_attr_deinit(&iio_attr->dev_attr); | 571 | __iio_device_attr_deinit(&iio_attr->dev_attr); |
564 | error_iio_dev_attr_free: | 572 | error_iio_dev_attr_free: |
565 | kfree(iio_attr); | 573 | kfree(iio_attr); |
566 | error_ret: | 574 | error_ret: |
567 | return ret; | 575 | return ret; |
568 | } | 576 | } |
569 | 577 | ||
570 | static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, | 578 | static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, |
571 | struct iio_chan_spec const *chan) | 579 | struct iio_chan_spec const *chan) |
572 | { | 580 | { |
573 | int ret, i, attrcount = 0; | 581 | int ret, i, attrcount = 0; |
574 | 582 | ||
575 | if (chan->channel < 0) | 583 | if (chan->channel < 0) |
576 | return 0; | 584 | return 0; |
577 | 585 | ||
578 | ret = __iio_add_chan_devattr(iio_data_type_name[chan->processed_val], | 586 | ret = __iio_add_chan_devattr(iio_data_type_name[chan->processed_val], |
579 | chan, | 587 | chan, |
580 | &iio_read_channel_info, | 588 | &iio_read_channel_info, |
581 | (chan->output ? | 589 | (chan->output ? |
582 | &iio_write_channel_info : NULL), | 590 | &iio_write_channel_info : NULL), |
583 | 0, | 591 | 0, |
584 | 0, | 592 | 0, |
585 | &indio_dev->dev, | 593 | &indio_dev->dev, |
586 | &indio_dev->channel_attr_list); | 594 | &indio_dev->channel_attr_list); |
587 | if (ret) | 595 | if (ret) |
588 | goto error_ret; | 596 | goto error_ret; |
589 | attrcount++; | 597 | attrcount++; |
590 | 598 | ||
591 | for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) { | 599 | for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) { |
592 | ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2], | 600 | ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2], |
593 | chan, | 601 | chan, |
594 | &iio_read_channel_info, | 602 | &iio_read_channel_info, |
595 | &iio_write_channel_info, | 603 | &iio_write_channel_info, |
596 | (1 << i), | 604 | (1 << i), |
597 | !(i%2), | 605 | !(i%2), |
598 | &indio_dev->dev, | 606 | &indio_dev->dev, |
599 | &indio_dev->channel_attr_list); | 607 | &indio_dev->channel_attr_list); |
600 | if (ret == -EBUSY && (i%2 == 0)) { | 608 | if (ret == -EBUSY && (i%2 == 0)) { |
601 | ret = 0; | 609 | ret = 0; |
602 | continue; | 610 | continue; |
603 | } | 611 | } |
604 | if (ret < 0) | 612 | if (ret < 0) |
605 | goto error_ret; | 613 | goto error_ret; |
606 | attrcount++; | 614 | attrcount++; |
607 | } | 615 | } |
608 | ret = attrcount; | 616 | ret = attrcount; |
609 | error_ret: | 617 | error_ret: |
610 | return ret; | 618 | return ret; |
611 | } | 619 | } |
612 | 620 | ||
613 | static void iio_device_remove_and_free_read_attr(struct iio_dev *indio_dev, | 621 | static void iio_device_remove_and_free_read_attr(struct iio_dev *indio_dev, |
614 | struct iio_dev_attr *p) | 622 | struct iio_dev_attr *p) |
615 | { | 623 | { |
616 | kfree(p->dev_attr.attr.name); | 624 | kfree(p->dev_attr.attr.name); |
617 | kfree(p); | 625 | kfree(p); |
618 | } | 626 | } |
619 | 627 | ||
620 | static ssize_t iio_show_dev_name(struct device *dev, | 628 | static ssize_t iio_show_dev_name(struct device *dev, |
621 | struct device_attribute *attr, | 629 | struct device_attribute *attr, |
622 | char *buf) | 630 | char *buf) |
623 | { | 631 | { |
624 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 632 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
625 | return sprintf(buf, "%s\n", indio_dev->name); | 633 | return sprintf(buf, "%s\n", indio_dev->name); |
626 | } | 634 | } |
627 | 635 | ||
628 | static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); | 636 | static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); |
629 | 637 | ||
630 | static int iio_device_register_sysfs(struct iio_dev *indio_dev) | 638 | static int iio_device_register_sysfs(struct iio_dev *indio_dev) |
631 | { | 639 | { |
632 | int i, ret = 0, attrcount, attrn, attrcount_orig = 0; | 640 | int i, ret = 0, attrcount, attrn, attrcount_orig = 0; |
633 | struct iio_dev_attr *p, *n; | 641 | struct iio_dev_attr *p, *n; |
634 | struct attribute **attr; | 642 | struct attribute **attr; |
635 | 643 | ||
636 | /* First count elements in any existing group */ | 644 | /* First count elements in any existing group */ |
637 | if (indio_dev->info->attrs) { | 645 | if (indio_dev->info->attrs) { |
638 | attr = indio_dev->info->attrs->attrs; | 646 | attr = indio_dev->info->attrs->attrs; |
639 | while (*attr++ != NULL) | 647 | while (*attr++ != NULL) |
640 | attrcount_orig++; | 648 | attrcount_orig++; |
641 | } | 649 | } |
642 | attrcount = attrcount_orig; | 650 | attrcount = attrcount_orig; |
643 | /* | 651 | /* |
644 | * New channel registration method - relies on the fact a group does | 652 | * New channel registration method - relies on the fact a group does |
645 | * not need to be initialized if it is name is NULL. | 653 | * not need to be initialized if it is name is NULL. |
646 | */ | 654 | */ |
647 | INIT_LIST_HEAD(&indio_dev->channel_attr_list); | 655 | INIT_LIST_HEAD(&indio_dev->channel_attr_list); |
648 | if (indio_dev->channels) | 656 | if (indio_dev->channels) |
649 | for (i = 0; i < indio_dev->num_channels; i++) { | 657 | for (i = 0; i < indio_dev->num_channels; i++) { |
650 | ret = iio_device_add_channel_sysfs(indio_dev, | 658 | ret = iio_device_add_channel_sysfs(indio_dev, |
651 | &indio_dev | 659 | &indio_dev |
652 | ->channels[i]); | 660 | ->channels[i]); |
653 | if (ret < 0) | 661 | if (ret < 0) |
654 | goto error_clear_attrs; | 662 | goto error_clear_attrs; |
655 | attrcount += ret; | 663 | attrcount += ret; |
656 | } | 664 | } |
657 | 665 | ||
658 | if (indio_dev->name) | 666 | if (indio_dev->name) |
659 | attrcount++; | 667 | attrcount++; |
660 | 668 | ||
661 | indio_dev->chan_attr_group.attrs | 669 | indio_dev->chan_attr_group.attrs |
662 | = kzalloc(sizeof(indio_dev->chan_attr_group.attrs[0])* | 670 | = kzalloc(sizeof(indio_dev->chan_attr_group.attrs[0])* |
663 | (attrcount + 1), | 671 | (attrcount + 1), |
664 | GFP_KERNEL); | 672 | GFP_KERNEL); |
665 | if (indio_dev->chan_attr_group.attrs == NULL) { | 673 | if (indio_dev->chan_attr_group.attrs == NULL) { |
666 | ret = -ENOMEM; | 674 | ret = -ENOMEM; |
667 | goto error_clear_attrs; | 675 | goto error_clear_attrs; |
668 | } | 676 | } |
669 | /* Copy across original attributes */ | 677 | /* Copy across original attributes */ |
670 | if (indio_dev->info->attrs) | 678 | if (indio_dev->info->attrs) |
671 | memcpy(indio_dev->chan_attr_group.attrs, | 679 | memcpy(indio_dev->chan_attr_group.attrs, |
672 | indio_dev->info->attrs->attrs, | 680 | indio_dev->info->attrs->attrs, |
673 | sizeof(indio_dev->chan_attr_group.attrs[0]) | 681 | sizeof(indio_dev->chan_attr_group.attrs[0]) |
674 | *attrcount_orig); | 682 | *attrcount_orig); |
675 | attrn = attrcount_orig; | 683 | attrn = attrcount_orig; |
676 | /* Add all elements from the list. */ | 684 | /* Add all elements from the list. */ |
677 | list_for_each_entry(p, &indio_dev->channel_attr_list, l) | 685 | list_for_each_entry(p, &indio_dev->channel_attr_list, l) |
678 | indio_dev->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr; | 686 | indio_dev->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr; |
679 | if (indio_dev->name) | 687 | if (indio_dev->name) |
680 | indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr; | 688 | indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr; |
681 | 689 | ||
682 | indio_dev->groups[indio_dev->groupcounter++] = | 690 | indio_dev->groups[indio_dev->groupcounter++] = |
683 | &indio_dev->chan_attr_group; | 691 | &indio_dev->chan_attr_group; |
684 | 692 | ||
685 | return 0; | 693 | return 0; |
686 | 694 | ||
687 | error_clear_attrs: | 695 | error_clear_attrs: |
688 | list_for_each_entry_safe(p, n, | 696 | list_for_each_entry_safe(p, n, |
689 | &indio_dev->channel_attr_list, l) { | 697 | &indio_dev->channel_attr_list, l) { |
690 | list_del(&p->l); | 698 | list_del(&p->l); |
691 | iio_device_remove_and_free_read_attr(indio_dev, p); | 699 | iio_device_remove_and_free_read_attr(indio_dev, p); |
692 | } | 700 | } |
693 | 701 | ||
694 | return ret; | 702 | return ret; |
695 | } | 703 | } |
696 | 704 | ||
697 | static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) | 705 | static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) |
698 | { | 706 | { |
699 | 707 | ||
700 | struct iio_dev_attr *p, *n; | 708 | struct iio_dev_attr *p, *n; |
701 | 709 | ||
702 | list_for_each_entry_safe(p, n, &indio_dev->channel_attr_list, l) { | 710 | list_for_each_entry_safe(p, n, &indio_dev->channel_attr_list, l) { |
703 | list_del(&p->l); | 711 | list_del(&p->l); |
704 | iio_device_remove_and_free_read_attr(indio_dev, p); | 712 | iio_device_remove_and_free_read_attr(indio_dev, p); |
705 | } | 713 | } |
706 | kfree(indio_dev->chan_attr_group.attrs); | 714 | kfree(indio_dev->chan_attr_group.attrs); |
707 | } | 715 | } |
708 | 716 | ||
709 | static const char * const iio_ev_type_text[] = { | 717 | static const char * const iio_ev_type_text[] = { |
710 | [IIO_EV_TYPE_THRESH] = "thresh", | 718 | [IIO_EV_TYPE_THRESH] = "thresh", |
711 | [IIO_EV_TYPE_MAG] = "mag", | 719 | [IIO_EV_TYPE_MAG] = "mag", |
712 | [IIO_EV_TYPE_ROC] = "roc", | 720 | [IIO_EV_TYPE_ROC] = "roc", |
713 | [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", | 721 | [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", |
714 | [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", | 722 | [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", |
715 | }; | 723 | }; |
716 | 724 | ||
717 | static const char * const iio_ev_dir_text[] = { | 725 | static const char * const iio_ev_dir_text[] = { |
718 | [IIO_EV_DIR_EITHER] = "either", | 726 | [IIO_EV_DIR_EITHER] = "either", |
719 | [IIO_EV_DIR_RISING] = "rising", | 727 | [IIO_EV_DIR_RISING] = "rising", |
720 | [IIO_EV_DIR_FALLING] = "falling" | 728 | [IIO_EV_DIR_FALLING] = "falling" |
721 | }; | 729 | }; |
722 | 730 | ||
723 | static ssize_t iio_ev_state_store(struct device *dev, | 731 | static ssize_t iio_ev_state_store(struct device *dev, |
724 | struct device_attribute *attr, | 732 | struct device_attribute *attr, |
725 | const char *buf, | 733 | const char *buf, |
726 | size_t len) | 734 | size_t len) |
727 | { | 735 | { |
728 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 736 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
729 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | 737 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); |
730 | int ret; | 738 | int ret; |
731 | bool val; | 739 | bool val; |
732 | 740 | ||
733 | ret = strtobool(buf, &val); | 741 | ret = strtobool(buf, &val); |
734 | if (ret < 0) | 742 | if (ret < 0) |
735 | return ret; | 743 | return ret; |
736 | 744 | ||
737 | ret = indio_dev->info->write_event_config(indio_dev, | 745 | ret = indio_dev->info->write_event_config(indio_dev, |
738 | this_attr->address, | 746 | this_attr->address, |
739 | val); | 747 | val); |
740 | return (ret < 0) ? ret : len; | 748 | return (ret < 0) ? ret : len; |
741 | } | 749 | } |
742 | 750 | ||
743 | static ssize_t iio_ev_state_show(struct device *dev, | 751 | static ssize_t iio_ev_state_show(struct device *dev, |
744 | struct device_attribute *attr, | 752 | struct device_attribute *attr, |
745 | char *buf) | 753 | char *buf) |
746 | { | 754 | { |
747 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 755 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
748 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | 756 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); |
749 | int val = indio_dev->info->read_event_config(indio_dev, | 757 | int val = indio_dev->info->read_event_config(indio_dev, |
750 | this_attr->address); | 758 | this_attr->address); |
751 | 759 | ||
752 | if (val < 0) | 760 | if (val < 0) |
753 | return val; | 761 | return val; |
754 | else | 762 | else |
755 | return sprintf(buf, "%d\n", val); | 763 | return sprintf(buf, "%d\n", val); |
756 | } | 764 | } |
757 | 765 | ||
758 | static ssize_t iio_ev_value_show(struct device *dev, | 766 | static ssize_t iio_ev_value_show(struct device *dev, |
759 | struct device_attribute *attr, | 767 | struct device_attribute *attr, |
760 | char *buf) | 768 | char *buf) |
761 | { | 769 | { |
762 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 770 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
763 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | 771 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); |
764 | int val, ret; | 772 | int val, ret; |
765 | 773 | ||
766 | ret = indio_dev->info->read_event_value(indio_dev, | 774 | ret = indio_dev->info->read_event_value(indio_dev, |
767 | this_attr->address, &val); | 775 | this_attr->address, &val); |
768 | if (ret < 0) | 776 | if (ret < 0) |
769 | return ret; | 777 | return ret; |
770 | 778 | ||
771 | return sprintf(buf, "%d\n", val); | 779 | return sprintf(buf, "%d\n", val); |
772 | } | 780 | } |
773 | 781 | ||
774 | static ssize_t iio_ev_value_store(struct device *dev, | 782 | static ssize_t iio_ev_value_store(struct device *dev, |
775 | struct device_attribute *attr, | 783 | struct device_attribute *attr, |
776 | const char *buf, | 784 | const char *buf, |
777 | size_t len) | 785 | size_t len) |
778 | { | 786 | { |
779 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 787 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
780 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | 788 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); |
781 | unsigned long val; | 789 | unsigned long val; |
782 | int ret; | 790 | int ret; |
783 | 791 | ||
784 | ret = strict_strtoul(buf, 10, &val); | 792 | ret = strict_strtoul(buf, 10, &val); |
785 | if (ret) | 793 | if (ret) |
786 | return ret; | 794 | return ret; |
787 | 795 | ||
788 | ret = indio_dev->info->write_event_value(indio_dev, this_attr->address, | 796 | ret = indio_dev->info->write_event_value(indio_dev, this_attr->address, |
789 | val); | 797 | val); |
790 | if (ret < 0) | 798 | if (ret < 0) |
791 | return ret; | 799 | return ret; |
792 | 800 | ||
793 | return len; | 801 | return len; |
794 | } | 802 | } |
795 | 803 | ||
796 | static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, | 804 | static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, |
797 | struct iio_chan_spec const *chan) | 805 | struct iio_chan_spec const *chan) |
798 | { | 806 | { |
799 | int ret = 0, i, attrcount = 0; | 807 | int ret = 0, i, attrcount = 0; |
800 | u64 mask = 0; | 808 | u64 mask = 0; |
801 | char *postfix; | 809 | char *postfix; |
802 | if (!chan->event_mask) | 810 | if (!chan->event_mask) |
803 | return 0; | 811 | return 0; |
804 | 812 | ||
805 | for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) { | 813 | for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) { |
806 | postfix = kasprintf(GFP_KERNEL, "%s_%s_en", | 814 | postfix = kasprintf(GFP_KERNEL, "%s_%s_en", |
807 | iio_ev_type_text[i/IIO_EV_DIR_MAX], | 815 | iio_ev_type_text[i/IIO_EV_DIR_MAX], |
808 | iio_ev_dir_text[i%IIO_EV_DIR_MAX]); | 816 | iio_ev_dir_text[i%IIO_EV_DIR_MAX]); |
809 | if (postfix == NULL) { | 817 | if (postfix == NULL) { |
810 | ret = -ENOMEM; | 818 | ret = -ENOMEM; |
811 | goto error_ret; | 819 | goto error_ret; |
812 | } | 820 | } |
813 | if (chan->modified) | 821 | if (chan->modified) |
814 | mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel, | 822 | mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel, |
815 | i/IIO_EV_DIR_MAX, | 823 | i/IIO_EV_DIR_MAX, |
816 | i%IIO_EV_DIR_MAX); | 824 | i%IIO_EV_DIR_MAX); |
817 | else if (chan->differential) | 825 | else if (chan->differential) |
818 | mask = IIO_EVENT_CODE(chan->type, | 826 | mask = IIO_EVENT_CODE(chan->type, |
819 | 0, 0, | 827 | 0, 0, |
820 | i%IIO_EV_DIR_MAX, | 828 | i%IIO_EV_DIR_MAX, |
821 | i/IIO_EV_DIR_MAX, | 829 | i/IIO_EV_DIR_MAX, |
822 | 0, | 830 | 0, |
823 | chan->channel, | 831 | chan->channel, |
824 | chan->channel2); | 832 | chan->channel2); |
825 | else | 833 | else |
826 | mask = IIO_UNMOD_EVENT_CODE(chan->type, | 834 | mask = IIO_UNMOD_EVENT_CODE(chan->type, |
827 | chan->channel, | 835 | chan->channel, |
828 | i/IIO_EV_DIR_MAX, | 836 | i/IIO_EV_DIR_MAX, |
829 | i%IIO_EV_DIR_MAX); | 837 | i%IIO_EV_DIR_MAX); |
830 | 838 | ||
831 | ret = __iio_add_chan_devattr(postfix, | 839 | ret = __iio_add_chan_devattr(postfix, |
832 | chan, | 840 | chan, |
833 | &iio_ev_state_show, | 841 | &iio_ev_state_show, |
834 | iio_ev_state_store, | 842 | iio_ev_state_store, |
835 | mask, | 843 | mask, |
836 | 0, | 844 | 0, |
837 | &indio_dev->dev, | 845 | &indio_dev->dev, |
838 | &indio_dev->event_interface-> | 846 | &indio_dev->event_interface-> |
839 | dev_attr_list); | 847 | dev_attr_list); |
840 | kfree(postfix); | 848 | kfree(postfix); |
841 | if (ret) | 849 | if (ret) |
842 | goto error_ret; | 850 | goto error_ret; |
843 | attrcount++; | 851 | attrcount++; |
844 | postfix = kasprintf(GFP_KERNEL, "%s_%s_value", | 852 | postfix = kasprintf(GFP_KERNEL, "%s_%s_value", |
845 | iio_ev_type_text[i/IIO_EV_DIR_MAX], | 853 | iio_ev_type_text[i/IIO_EV_DIR_MAX], |
846 | iio_ev_dir_text[i%IIO_EV_DIR_MAX]); | 854 | iio_ev_dir_text[i%IIO_EV_DIR_MAX]); |
847 | if (postfix == NULL) { | 855 | if (postfix == NULL) { |
848 | ret = -ENOMEM; | 856 | ret = -ENOMEM; |
849 | goto error_ret; | 857 | goto error_ret; |
850 | } | 858 | } |
851 | ret = __iio_add_chan_devattr(postfix, chan, | 859 | ret = __iio_add_chan_devattr(postfix, chan, |
852 | iio_ev_value_show, | 860 | iio_ev_value_show, |
853 | iio_ev_value_store, | 861 | iio_ev_value_store, |
854 | mask, | 862 | mask, |
855 | 0, | 863 | 0, |
856 | &indio_dev->dev, | 864 | &indio_dev->dev, |
857 | &indio_dev->event_interface-> | 865 | &indio_dev->event_interface-> |
858 | dev_attr_list); | 866 | dev_attr_list); |
859 | kfree(postfix); | 867 | kfree(postfix); |
860 | if (ret) | 868 | if (ret) |
861 | goto error_ret; | 869 | goto error_ret; |
862 | attrcount++; | 870 | attrcount++; |
863 | } | 871 | } |
864 | ret = attrcount; | 872 | ret = attrcount; |
865 | error_ret: | 873 | error_ret: |
866 | return ret; | 874 | return ret; |
867 | } | 875 | } |
868 | 876 | ||
869 | static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev) | 877 | static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev) |
870 | { | 878 | { |
871 | struct iio_dev_attr *p, *n; | 879 | struct iio_dev_attr *p, *n; |
872 | list_for_each_entry_safe(p, n, | 880 | list_for_each_entry_safe(p, n, |
873 | &indio_dev->event_interface-> | 881 | &indio_dev->event_interface-> |
874 | dev_attr_list, l) { | 882 | dev_attr_list, l) { |
875 | kfree(p->dev_attr.attr.name); | 883 | kfree(p->dev_attr.attr.name); |
876 | kfree(p); | 884 | kfree(p); |
877 | } | 885 | } |
878 | } | 886 | } |
879 | 887 | ||
880 | static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev) | 888 | static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev) |
881 | { | 889 | { |
882 | int j, ret, attrcount = 0; | 890 | int j, ret, attrcount = 0; |
883 | 891 | ||
884 | INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list); | 892 | INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list); |
885 | /* Dynically created from the channels array */ | 893 | /* Dynically created from the channels array */ |
886 | for (j = 0; j < indio_dev->num_channels; j++) { | 894 | for (j = 0; j < indio_dev->num_channels; j++) { |
887 | ret = iio_device_add_event_sysfs(indio_dev, | 895 | ret = iio_device_add_event_sysfs(indio_dev, |
888 | &indio_dev->channels[j]); | 896 | &indio_dev->channels[j]); |
889 | if (ret < 0) | 897 | if (ret < 0) |
890 | goto error_clear_attrs; | 898 | goto error_clear_attrs; |
891 | attrcount += ret; | 899 | attrcount += ret; |
892 | } | 900 | } |
893 | return attrcount; | 901 | return attrcount; |
894 | 902 | ||
895 | error_clear_attrs: | 903 | error_clear_attrs: |
896 | __iio_remove_event_config_attrs(indio_dev); | 904 | __iio_remove_event_config_attrs(indio_dev); |
897 | 905 | ||
898 | return ret; | 906 | return ret; |
899 | } | 907 | } |
900 | 908 | ||
901 | static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev) | 909 | static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev) |
902 | { | 910 | { |
903 | int j; | 911 | int j; |
904 | 912 | ||
905 | for (j = 0; j < indio_dev->num_channels; j++) | 913 | for (j = 0; j < indio_dev->num_channels; j++) |
906 | if (indio_dev->channels[j].event_mask != 0) | 914 | if (indio_dev->channels[j].event_mask != 0) |
907 | return true; | 915 | return true; |
908 | return false; | 916 | return false; |
909 | } | 917 | } |
910 | 918 | ||
911 | static void iio_setup_ev_int(struct iio_event_interface *ev_int) | 919 | static void iio_setup_ev_int(struct iio_event_interface *ev_int) |
912 | { | 920 | { |
913 | mutex_init(&ev_int->event_list_lock); | 921 | mutex_init(&ev_int->event_list_lock); |
914 | /* discussion point - make this variable? */ | 922 | /* discussion point - make this variable? */ |
915 | ev_int->max_events = 10; | 923 | ev_int->max_events = 10; |
916 | ev_int->current_events = 0; | 924 | ev_int->current_events = 0; |
917 | INIT_LIST_HEAD(&ev_int->det_events); | 925 | INIT_LIST_HEAD(&ev_int->det_events); |
918 | init_waitqueue_head(&ev_int->wait); | 926 | init_waitqueue_head(&ev_int->wait); |
919 | } | 927 | } |
920 | 928 | ||
921 | static const char *iio_event_group_name = "events"; | 929 | static const char *iio_event_group_name = "events"; |
922 | static int iio_device_register_eventset(struct iio_dev *indio_dev) | 930 | static int iio_device_register_eventset(struct iio_dev *indio_dev) |
923 | { | 931 | { |
924 | struct iio_dev_attr *p; | 932 | struct iio_dev_attr *p; |
925 | int ret = 0, attrcount_orig = 0, attrcount, attrn; | 933 | int ret = 0, attrcount_orig = 0, attrcount, attrn; |
926 | struct attribute **attr; | 934 | struct attribute **attr; |
927 | 935 | ||
928 | if (!(indio_dev->info->event_attrs || | 936 | if (!(indio_dev->info->event_attrs || |
929 | iio_check_for_dynamic_events(indio_dev))) | 937 | iio_check_for_dynamic_events(indio_dev))) |
930 | return 0; | 938 | return 0; |
931 | 939 | ||
932 | indio_dev->event_interface = | 940 | indio_dev->event_interface = |
933 | kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL); | 941 | kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL); |
934 | if (indio_dev->event_interface == NULL) { | 942 | if (indio_dev->event_interface == NULL) { |
935 | ret = -ENOMEM; | 943 | ret = -ENOMEM; |
936 | goto error_ret; | 944 | goto error_ret; |
937 | } | 945 | } |
938 | 946 | ||
939 | iio_setup_ev_int(indio_dev->event_interface); | 947 | iio_setup_ev_int(indio_dev->event_interface); |
940 | if (indio_dev->info->event_attrs != NULL) { | 948 | if (indio_dev->info->event_attrs != NULL) { |
941 | attr = indio_dev->info->event_attrs->attrs; | 949 | attr = indio_dev->info->event_attrs->attrs; |
942 | while (*attr++ != NULL) | 950 | while (*attr++ != NULL) |
943 | attrcount_orig++; | 951 | attrcount_orig++; |
944 | } | 952 | } |
945 | attrcount = attrcount_orig; | 953 | attrcount = attrcount_orig; |
946 | if (indio_dev->channels) { | 954 | if (indio_dev->channels) { |
947 | ret = __iio_add_event_config_attrs(indio_dev); | 955 | ret = __iio_add_event_config_attrs(indio_dev); |
948 | if (ret < 0) | 956 | if (ret < 0) |
949 | goto error_free_setup_event_lines; | 957 | goto error_free_setup_event_lines; |
950 | attrcount += ret; | 958 | attrcount += ret; |
951 | } | 959 | } |
952 | 960 | ||
953 | indio_dev->event_interface->group.name = iio_event_group_name; | 961 | indio_dev->event_interface->group.name = iio_event_group_name; |
954 | indio_dev->event_interface->group.attrs = | 962 | indio_dev->event_interface->group.attrs = |
955 | kzalloc(sizeof(indio_dev->event_interface->group.attrs[0]) | 963 | kzalloc(sizeof(indio_dev->event_interface->group.attrs[0]) |
956 | *(attrcount + 1), | 964 | *(attrcount + 1), |
957 | GFP_KERNEL); | 965 | GFP_KERNEL); |
958 | if (indio_dev->event_interface->group.attrs == NULL) { | 966 | if (indio_dev->event_interface->group.attrs == NULL) { |
959 | ret = -ENOMEM; | 967 | ret = -ENOMEM; |
960 | goto error_free_setup_event_lines; | 968 | goto error_free_setup_event_lines; |
961 | } | 969 | } |
962 | if (indio_dev->info->event_attrs) | 970 | if (indio_dev->info->event_attrs) |
963 | memcpy(indio_dev->event_interface->group.attrs, | 971 | memcpy(indio_dev->event_interface->group.attrs, |
964 | indio_dev->info->event_attrs->attrs, | 972 | indio_dev->info->event_attrs->attrs, |
965 | sizeof(indio_dev->event_interface->group.attrs[0]) | 973 | sizeof(indio_dev->event_interface->group.attrs[0]) |
966 | *attrcount_orig); | 974 | *attrcount_orig); |
967 | attrn = attrcount_orig; | 975 | attrn = attrcount_orig; |
968 | /* Add all elements from the list. */ | 976 | /* Add all elements from the list. */ |
969 | list_for_each_entry(p, | 977 | list_for_each_entry(p, |
970 | &indio_dev->event_interface->dev_attr_list, | 978 | &indio_dev->event_interface->dev_attr_list, |
971 | l) | 979 | l) |
972 | indio_dev->event_interface->group.attrs[attrn++] = | 980 | indio_dev->event_interface->group.attrs[attrn++] = |
973 | &p->dev_attr.attr; | 981 | &p->dev_attr.attr; |
974 | indio_dev->groups[indio_dev->groupcounter++] = | 982 | indio_dev->groups[indio_dev->groupcounter++] = |
975 | &indio_dev->event_interface->group; | 983 | &indio_dev->event_interface->group; |
976 | 984 | ||
977 | return 0; | 985 | return 0; |
978 | 986 | ||
979 | error_free_setup_event_lines: | 987 | error_free_setup_event_lines: |
980 | __iio_remove_event_config_attrs(indio_dev); | 988 | __iio_remove_event_config_attrs(indio_dev); |
981 | kfree(indio_dev->event_interface); | 989 | kfree(indio_dev->event_interface); |
982 | error_ret: | 990 | error_ret: |
983 | 991 | ||
984 | return ret; | 992 | return ret; |
985 | } | 993 | } |
986 | 994 | ||
987 | static void iio_device_unregister_eventset(struct iio_dev *indio_dev) | 995 | static void iio_device_unregister_eventset(struct iio_dev *indio_dev) |
988 | { | 996 | { |
989 | if (indio_dev->event_interface == NULL) | 997 | if (indio_dev->event_interface == NULL) |
990 | return; | 998 | return; |
991 | __iio_remove_event_config_attrs(indio_dev); | 999 | __iio_remove_event_config_attrs(indio_dev); |
992 | kfree(indio_dev->event_interface->group.attrs); | 1000 | kfree(indio_dev->event_interface->group.attrs); |
993 | kfree(indio_dev->event_interface); | 1001 | kfree(indio_dev->event_interface); |
994 | } | 1002 | } |
995 | 1003 | ||
996 | static void iio_dev_release(struct device *device) | 1004 | static void iio_dev_release(struct device *device) |
997 | { | 1005 | { |
998 | struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev); | 1006 | struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev); |
999 | cdev_del(&indio_dev->chrdev); | 1007 | cdev_del(&indio_dev->chrdev); |
1000 | if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) | 1008 | if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) |
1001 | iio_device_unregister_trigger_consumer(indio_dev); | 1009 | iio_device_unregister_trigger_consumer(indio_dev); |
1002 | iio_device_unregister_eventset(indio_dev); | 1010 | iio_device_unregister_eventset(indio_dev); |
1003 | iio_device_unregister_sysfs(indio_dev); | 1011 | iio_device_unregister_sysfs(indio_dev); |
1004 | } | 1012 | } |
1005 | 1013 | ||
1006 | static struct device_type iio_dev_type = { | 1014 | static struct device_type iio_dev_type = { |
1007 | .name = "iio_device", | 1015 | .name = "iio_device", |
1008 | .release = iio_dev_release, | 1016 | .release = iio_dev_release, |
1009 | }; | 1017 | }; |
1010 | 1018 | ||
1011 | struct iio_dev *iio_allocate_device(int sizeof_priv) | 1019 | struct iio_dev *iio_allocate_device(int sizeof_priv) |
1012 | { | 1020 | { |
1013 | struct iio_dev *dev; | 1021 | struct iio_dev *dev; |
1014 | size_t alloc_size; | 1022 | size_t alloc_size; |
1015 | 1023 | ||
1016 | alloc_size = sizeof(struct iio_dev); | 1024 | alloc_size = sizeof(struct iio_dev); |
1017 | if (sizeof_priv) { | 1025 | if (sizeof_priv) { |
1018 | alloc_size = ALIGN(alloc_size, IIO_ALIGN); | 1026 | alloc_size = ALIGN(alloc_size, IIO_ALIGN); |
1019 | alloc_size += sizeof_priv; | 1027 | alloc_size += sizeof_priv; |
1020 | } | 1028 | } |
1021 | /* ensure 32-byte alignment of whole construct ? */ | 1029 | /* ensure 32-byte alignment of whole construct ? */ |
1022 | alloc_size += IIO_ALIGN - 1; | 1030 | alloc_size += IIO_ALIGN - 1; |
1023 | 1031 | ||
1024 | dev = kzalloc(alloc_size, GFP_KERNEL); | 1032 | dev = kzalloc(alloc_size, GFP_KERNEL); |
1025 | 1033 | ||
1026 | if (dev) { | 1034 | if (dev) { |
1027 | dev->dev.groups = dev->groups; | 1035 | dev->dev.groups = dev->groups; |
1028 | dev->dev.type = &iio_dev_type; | 1036 | dev->dev.type = &iio_dev_type; |
1029 | dev->dev.bus = &iio_bus_type; | 1037 | dev->dev.bus = &iio_bus_type; |
1030 | device_initialize(&dev->dev); | 1038 | device_initialize(&dev->dev); |
1031 | dev_set_drvdata(&dev->dev, (void *)dev); | 1039 | dev_set_drvdata(&dev->dev, (void *)dev); |
1032 | mutex_init(&dev->mlock); | 1040 | mutex_init(&dev->mlock); |
1033 | 1041 | ||
1034 | dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL); | 1042 | dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL); |
1035 | if (dev->id < 0) { | 1043 | if (dev->id < 0) { |
1036 | /* cannot use a dev_err as the name isn't available */ | 1044 | /* cannot use a dev_err as the name isn't available */ |
1037 | printk(KERN_ERR "Failed to get id\n"); | 1045 | printk(KERN_ERR "Failed to get id\n"); |
1038 | kfree(dev); | 1046 | kfree(dev); |
1039 | return NULL; | 1047 | return NULL; |
1040 | } | 1048 | } |
1041 | dev_set_name(&dev->dev, "iio:device%d", dev->id); | 1049 | dev_set_name(&dev->dev, "iio:device%d", dev->id); |
1042 | } | 1050 | } |
1043 | 1051 | ||
1044 | return dev; | 1052 | return dev; |
1045 | } | 1053 | } |
1046 | EXPORT_SYMBOL(iio_allocate_device); | 1054 | EXPORT_SYMBOL(iio_allocate_device); |
1047 | 1055 | ||
1048 | void iio_free_device(struct iio_dev *dev) | 1056 | void iio_free_device(struct iio_dev *dev) |
1049 | { | 1057 | { |
1050 | if (dev) { | 1058 | if (dev) { |
1051 | ida_simple_remove(&iio_ida, dev->id); | 1059 | ida_simple_remove(&iio_ida, dev->id); |
1052 | kfree(dev); | 1060 | kfree(dev); |
1053 | } | 1061 | } |
1054 | } | 1062 | } |
1055 | EXPORT_SYMBOL(iio_free_device); | 1063 | EXPORT_SYMBOL(iio_free_device); |
1056 | 1064 | ||
1057 | /** | 1065 | /** |
1058 | * iio_chrdev_open() - chrdev file open for buffer access and ioctls | 1066 | * iio_chrdev_open() - chrdev file open for buffer access and ioctls |
1059 | **/ | 1067 | **/ |
1060 | static int iio_chrdev_open(struct inode *inode, struct file *filp) | 1068 | static int iio_chrdev_open(struct inode *inode, struct file *filp) |
1061 | { | 1069 | { |
1062 | struct iio_dev *indio_dev = container_of(inode->i_cdev, | 1070 | struct iio_dev *indio_dev = container_of(inode->i_cdev, |
1063 | struct iio_dev, chrdev); | 1071 | struct iio_dev, chrdev); |
1064 | filp->private_data = indio_dev; | 1072 | filp->private_data = indio_dev; |
1065 | 1073 | ||
1066 | return iio_chrdev_buffer_open(indio_dev); | 1074 | return iio_chrdev_buffer_open(indio_dev); |
1067 | } | 1075 | } |
1068 | 1076 | ||
1069 | /** | 1077 | /** |
1070 | * iio_chrdev_release() - chrdev file close buffer access and ioctls | 1078 | * iio_chrdev_release() - chrdev file close buffer access and ioctls |
1071 | **/ | 1079 | **/ |
1072 | static int iio_chrdev_release(struct inode *inode, struct file *filp) | 1080 | static int iio_chrdev_release(struct inode *inode, struct file *filp) |
1073 | { | 1081 | { |
1074 | iio_chrdev_buffer_release(container_of(inode->i_cdev, | 1082 | iio_chrdev_buffer_release(container_of(inode->i_cdev, |
1075 | struct iio_dev, chrdev)); | 1083 | struct iio_dev, chrdev)); |
1076 | return 0; | 1084 | return 0; |
1077 | } | 1085 | } |
1078 | 1086 | ||
1079 | /* Somewhat of a cross file organization violation - ioctls here are actually | 1087 | /* Somewhat of a cross file organization violation - ioctls here are actually |
1080 | * event related */ | 1088 | * event related */ |
1081 | static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 1089 | static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
1082 | { | 1090 | { |
1083 | struct iio_dev *indio_dev = filp->private_data; | 1091 | struct iio_dev *indio_dev = filp->private_data; |
1084 | int __user *ip = (int __user *)arg; | 1092 | int __user *ip = (int __user *)arg; |
1085 | int fd; | 1093 | int fd; |
1086 | 1094 | ||
1087 | if (cmd == IIO_GET_EVENT_FD_IOCTL) { | 1095 | if (cmd == IIO_GET_EVENT_FD_IOCTL) { |
1088 | fd = iio_event_getfd(indio_dev); | 1096 | fd = iio_event_getfd(indio_dev); |
1089 | if (copy_to_user(ip, &fd, sizeof(fd))) | 1097 | if (copy_to_user(ip, &fd, sizeof(fd))) |
1090 | return -EFAULT; | 1098 | return -EFAULT; |
1091 | return 0; | 1099 | return 0; |
1092 | } | 1100 | } |
1093 | return -EINVAL; | 1101 | return -EINVAL; |
1094 | } | 1102 | } |
1095 | 1103 | ||
1096 | static const struct file_operations iio_buffer_fileops = { | 1104 | static const struct file_operations iio_buffer_fileops = { |
1097 | .read = iio_buffer_read_first_n_outer_addr, | 1105 | .read = iio_buffer_read_first_n_outer_addr, |
1098 | .release = iio_chrdev_release, | 1106 | .release = iio_chrdev_release, |
1099 | .open = iio_chrdev_open, | 1107 | .open = iio_chrdev_open, |
1100 | .poll = iio_buffer_poll_addr, | 1108 | .poll = iio_buffer_poll_addr, |
1101 | .owner = THIS_MODULE, | 1109 | .owner = THIS_MODULE, |
1102 | .llseek = noop_llseek, | 1110 | .llseek = noop_llseek, |
1103 | .unlocked_ioctl = iio_ioctl, | 1111 | .unlocked_ioctl = iio_ioctl, |
1104 | .compat_ioctl = iio_ioctl, | 1112 | .compat_ioctl = iio_ioctl, |
1105 | }; | 1113 | }; |
1106 | 1114 | ||
1107 | int iio_device_register(struct iio_dev *indio_dev) | 1115 | int iio_device_register(struct iio_dev *indio_dev) |
1108 | { | 1116 | { |
1109 | int ret; | 1117 | int ret; |
1110 | 1118 | ||
1111 | /* configure elements for the chrdev */ | 1119 | /* configure elements for the chrdev */ |
1112 | indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); | 1120 | indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); |
1113 | 1121 | ||
1114 | ret = iio_device_register_sysfs(indio_dev); | 1122 | ret = iio_device_register_sysfs(indio_dev); |
1115 | if (ret) { | 1123 | if (ret) { |
1116 | dev_err(indio_dev->dev.parent, | 1124 | dev_err(indio_dev->dev.parent, |
1117 | "Failed to register sysfs interfaces\n"); | 1125 | "Failed to register sysfs interfaces\n"); |
1118 | goto error_ret; | 1126 | goto error_ret; |
1119 | } | 1127 | } |
1120 | ret = iio_device_register_eventset(indio_dev); | 1128 | ret = iio_device_register_eventset(indio_dev); |
1121 | if (ret) { | 1129 | if (ret) { |
1122 | dev_err(indio_dev->dev.parent, | 1130 | dev_err(indio_dev->dev.parent, |
1123 | "Failed to register event set\n"); | 1131 | "Failed to register event set\n"); |
1124 | goto error_free_sysfs; | 1132 | goto error_free_sysfs; |
1125 | } | 1133 | } |
1126 | if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) | 1134 | if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) |
1127 | iio_device_register_trigger_consumer(indio_dev); | 1135 | iio_device_register_trigger_consumer(indio_dev); |
1128 | 1136 | ||
1129 | ret = device_add(&indio_dev->dev); | 1137 | ret = device_add(&indio_dev->dev); |
1130 | if (ret < 0) | 1138 | if (ret < 0) |
1131 | goto error_unreg_eventset; | 1139 | goto error_unreg_eventset; |
1132 | cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); | 1140 | cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); |
1133 | indio_dev->chrdev.owner = indio_dev->info->driver_module; | 1141 | indio_dev->chrdev.owner = indio_dev->info->driver_module; |
1134 | ret = cdev_add(&indio_dev->chrdev, indio_dev->dev.devt, 1); | 1142 | ret = cdev_add(&indio_dev->chrdev, indio_dev->dev.devt, 1); |
1135 | if (ret < 0) | 1143 | if (ret < 0) |
1136 | goto error_del_device; | 1144 | goto error_del_device; |
1137 | return 0; | 1145 | return 0; |
1138 | 1146 | ||
1139 | error_del_device: | 1147 | error_del_device: |
1140 | device_del(&indio_dev->dev); | 1148 | device_del(&indio_dev->dev); |
1141 | error_unreg_eventset: | 1149 | error_unreg_eventset: |
1142 | iio_device_unregister_eventset(indio_dev); | 1150 | iio_device_unregister_eventset(indio_dev); |
1143 | error_free_sysfs: | 1151 | error_free_sysfs: |
1144 | iio_device_unregister_sysfs(indio_dev); | 1152 | iio_device_unregister_sysfs(indio_dev); |
1145 | error_ret: | 1153 | error_ret: |
1146 | return ret; | 1154 | return ret; |
1147 | } | 1155 | } |
1148 | EXPORT_SYMBOL(iio_device_register); | 1156 | EXPORT_SYMBOL(iio_device_register); |
1149 | 1157 | ||
1150 | void iio_device_unregister(struct iio_dev *indio_dev) | 1158 | void iio_device_unregister(struct iio_dev *indio_dev) |
1151 | { | 1159 | { |
1152 | device_unregister(&indio_dev->dev); | 1160 | device_unregister(&indio_dev->dev); |
1153 | } | 1161 | } |
1154 | EXPORT_SYMBOL(iio_device_unregister); | 1162 | EXPORT_SYMBOL(iio_device_unregister); |
1155 | subsys_initcall(iio_init); | 1163 | subsys_initcall(iio_init); |
1156 | module_exit(iio_exit); | 1164 | module_exit(iio_exit); |
1157 | 1165 | ||
1158 | MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); | 1166 | MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); |
1159 | MODULE_DESCRIPTION("Industrial I/O core"); | 1167 | MODULE_DESCRIPTION("Industrial I/O core"); |
1160 | MODULE_LICENSE("GPL"); | 1168 | MODULE_LICENSE("GPL"); |
1161 | 1169 |