diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/staging/iio/industrialio-trigger.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/staging/iio/industrialio-trigger.c')
-rw-r--r-- | drivers/staging/iio/industrialio-trigger.c | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/staging/iio/industrialio-trigger.c new file mode 100644 index 00000000000..90ca2df23ea --- /dev/null +++ b/drivers/staging/iio/industrialio-trigger.c | |||
@@ -0,0 +1,525 @@ | |||
1 | /* The industrial I/O core, trigger handling functions | ||
2 | * | ||
3 | * Copyright (c) 2008 Jonathan Cameron | ||
4 | * | ||
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 | ||
7 | * the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/idr.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/list.h> | ||
17 | #include <linux/slab.h> | ||
18 | |||
19 | #include "iio.h" | ||
20 | #include "trigger.h" | ||
21 | #include "trigger_consumer.h" | ||
22 | |||
23 | /* RFC - Question of approach | ||
24 | * Make the common case (single sensor single trigger) | ||
25 | * simple by starting trigger capture from when first sensors | ||
26 | * is added. | ||
27 | * | ||
28 | * Complex simultaneous start requires use of 'hold' functionality | ||
29 | * of the trigger. (not implemented) | ||
30 | * | ||
31 | * Any other suggestions? | ||
32 | */ | ||
33 | |||
34 | static DEFINE_IDR(iio_trigger_idr); | ||
35 | static DEFINE_SPINLOCK(iio_trigger_idr_lock); | ||
36 | |||
37 | /* Single list of all available triggers */ | ||
38 | static LIST_HEAD(iio_trigger_list); | ||
39 | static DEFINE_MUTEX(iio_trigger_list_lock); | ||
40 | |||
41 | /** | ||
42 | * iio_trigger_read_name() - retrieve useful identifying name | ||
43 | **/ | ||
44 | static ssize_t iio_trigger_read_name(struct device *dev, | ||
45 | struct device_attribute *attr, | ||
46 | char *buf) | ||
47 | { | ||
48 | struct iio_trigger *trig = dev_get_drvdata(dev); | ||
49 | return sprintf(buf, "%s\n", trig->name); | ||
50 | } | ||
51 | |||
52 | static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); | ||
53 | |||
54 | /** | ||
55 | * iio_trigger_register_sysfs() - create a device for this trigger | ||
56 | * @trig_info: the trigger | ||
57 | * | ||
58 | * Also adds any control attribute registered by the trigger driver | ||
59 | **/ | ||
60 | static int iio_trigger_register_sysfs(struct iio_trigger *trig_info) | ||
61 | { | ||
62 | return sysfs_add_file_to_group(&trig_info->dev.kobj, | ||
63 | &dev_attr_name.attr, | ||
64 | NULL); | ||
65 | } | ||
66 | |||
67 | static void iio_trigger_unregister_sysfs(struct iio_trigger *trig_info) | ||
68 | { | ||
69 | sysfs_remove_file_from_group(&trig_info->dev.kobj, | ||
70 | &dev_attr_name.attr, | ||
71 | NULL); | ||
72 | } | ||
73 | |||
74 | |||
75 | /** | ||
76 | * iio_trigger_register_id() - get a unique id for this trigger | ||
77 | * @trig_info: the trigger | ||
78 | **/ | ||
79 | static int iio_trigger_register_id(struct iio_trigger *trig_info) | ||
80 | { | ||
81 | int ret = 0; | ||
82 | |||
83 | idr_again: | ||
84 | if (unlikely(idr_pre_get(&iio_trigger_idr, GFP_KERNEL) == 0)) | ||
85 | return -ENOMEM; | ||
86 | |||
87 | spin_lock(&iio_trigger_idr_lock); | ||
88 | ret = idr_get_new(&iio_trigger_idr, NULL, &trig_info->id); | ||
89 | spin_unlock(&iio_trigger_idr_lock); | ||
90 | if (unlikely(ret == -EAGAIN)) | ||
91 | goto idr_again; | ||
92 | else if (likely(!ret)) | ||
93 | trig_info->id = trig_info->id & MAX_ID_MASK; | ||
94 | |||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * iio_trigger_unregister_id() - free up unique id for use by another trigger | ||
100 | * @trig_info: the trigger | ||
101 | **/ | ||
102 | static void iio_trigger_unregister_id(struct iio_trigger *trig_info) | ||
103 | { | ||
104 | spin_lock(&iio_trigger_idr_lock); | ||
105 | idr_remove(&iio_trigger_idr, trig_info->id); | ||
106 | spin_unlock(&iio_trigger_idr_lock); | ||
107 | } | ||
108 | |||
109 | int iio_trigger_register(struct iio_trigger *trig_info) | ||
110 | { | ||
111 | int ret; | ||
112 | |||
113 | ret = iio_trigger_register_id(trig_info); | ||
114 | if (ret) | ||
115 | goto error_ret; | ||
116 | /* Set the name used for the sysfs directory etc */ | ||
117 | dev_set_name(&trig_info->dev, "trigger%ld", | ||
118 | (unsigned long) trig_info->id); | ||
119 | |||
120 | ret = device_add(&trig_info->dev); | ||
121 | if (ret) | ||
122 | goto error_unregister_id; | ||
123 | |||
124 | ret = iio_trigger_register_sysfs(trig_info); | ||
125 | if (ret) | ||
126 | goto error_device_del; | ||
127 | |||
128 | /* Add to list of available triggers held by the IIO core */ | ||
129 | mutex_lock(&iio_trigger_list_lock); | ||
130 | list_add_tail(&trig_info->list, &iio_trigger_list); | ||
131 | mutex_unlock(&iio_trigger_list_lock); | ||
132 | |||
133 | return 0; | ||
134 | |||
135 | error_device_del: | ||
136 | device_del(&trig_info->dev); | ||
137 | error_unregister_id: | ||
138 | iio_trigger_unregister_id(trig_info); | ||
139 | error_ret: | ||
140 | return ret; | ||
141 | } | ||
142 | EXPORT_SYMBOL(iio_trigger_register); | ||
143 | |||
144 | void iio_trigger_unregister(struct iio_trigger *trig_info) | ||
145 | { | ||
146 | mutex_lock(&iio_trigger_list_lock); | ||
147 | list_del(&trig_info->list); | ||
148 | mutex_unlock(&iio_trigger_list_lock); | ||
149 | |||
150 | iio_trigger_unregister_sysfs(trig_info); | ||
151 | iio_trigger_unregister_id(trig_info); | ||
152 | /* Possible issue in here */ | ||
153 | device_unregister(&trig_info->dev); | ||
154 | } | ||
155 | EXPORT_SYMBOL(iio_trigger_unregister); | ||
156 | |||
157 | static struct iio_trigger *iio_trigger_find_by_name(const char *name, | ||
158 | size_t len) | ||
159 | { | ||
160 | struct iio_trigger *trig = NULL, *iter; | ||
161 | |||
162 | mutex_lock(&iio_trigger_list_lock); | ||
163 | list_for_each_entry(iter, &iio_trigger_list, list) | ||
164 | if (sysfs_streq(iter->name, name)) { | ||
165 | trig = iter; | ||
166 | break; | ||
167 | } | ||
168 | mutex_unlock(&iio_trigger_list_lock); | ||
169 | |||
170 | return trig; | ||
171 | } | ||
172 | |||
173 | void iio_trigger_poll(struct iio_trigger *trig, s64 time) | ||
174 | { | ||
175 | int i; | ||
176 | if (!trig->use_count) { | ||
177 | for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) | ||
178 | if (trig->subirqs[i].enabled) { | ||
179 | trig->use_count++; | ||
180 | generic_handle_irq(trig->subirq_base + i); | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | EXPORT_SYMBOL(iio_trigger_poll); | ||
185 | |||
186 | irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private) | ||
187 | { | ||
188 | iio_trigger_poll(private, iio_get_time_ns()); | ||
189 | return IRQ_HANDLED; | ||
190 | } | ||
191 | EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll); | ||
192 | |||
193 | void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time) | ||
194 | { | ||
195 | int i; | ||
196 | if (!trig->use_count) { | ||
197 | for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) | ||
198 | if (trig->subirqs[i].enabled) { | ||
199 | trig->use_count++; | ||
200 | handle_nested_irq(trig->subirq_base + i); | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | EXPORT_SYMBOL(iio_trigger_poll_chained); | ||
205 | |||
206 | void iio_trigger_notify_done(struct iio_trigger *trig) | ||
207 | { | ||
208 | trig->use_count--; | ||
209 | if (trig->use_count == 0 && trig->try_reenable) | ||
210 | if (trig->try_reenable(trig)) { | ||
211 | /* Missed and interrupt so launch new poll now */ | ||
212 | iio_trigger_poll(trig, 0); | ||
213 | } | ||
214 | } | ||
215 | EXPORT_SYMBOL(iio_trigger_notify_done); | ||
216 | |||
217 | /* Trigger Consumer related functions */ | ||
218 | |||
219 | /* Complexity in here. With certain triggers (datardy) an acknowledgement | ||
220 | * may be needed if the pollfuncs do not include the data read for the | ||
221 | * triggering device. | ||
222 | * This is not currently handled. Alternative of not enabling trigger unless | ||
223 | * the relevant function is in there may be the best option. | ||
224 | */ | ||
225 | /* Worth protecting against double additions?*/ | ||
226 | int iio_trigger_attach_poll_func(struct iio_trigger *trig, | ||
227 | struct iio_poll_func *pf) | ||
228 | { | ||
229 | int ret = 0; | ||
230 | bool notinuse | ||
231 | = bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER); | ||
232 | |||
233 | pf->irq = iio_trigger_get_irq(trig); | ||
234 | ret = request_threaded_irq(pf->irq, pf->h, pf->thread, | ||
235 | pf->type, pf->name, | ||
236 | pf); | ||
237 | if (trig->set_trigger_state && notinuse) | ||
238 | ret = trig->set_trigger_state(trig, true); | ||
239 | |||
240 | return ret; | ||
241 | } | ||
242 | EXPORT_SYMBOL(iio_trigger_attach_poll_func); | ||
243 | |||
244 | int iio_trigger_dettach_poll_func(struct iio_trigger *trig, | ||
245 | struct iio_poll_func *pf) | ||
246 | { | ||
247 | int ret = 0; | ||
248 | bool no_other_users | ||
249 | = (bitmap_weight(trig->pool, | ||
250 | CONFIG_IIO_CONSUMERS_PER_TRIGGER) | ||
251 | == 1); | ||
252 | if (trig->set_trigger_state && no_other_users) { | ||
253 | ret = trig->set_trigger_state(trig, false); | ||
254 | if (ret) | ||
255 | goto error_ret; | ||
256 | } | ||
257 | iio_trigger_put_irq(trig, pf->irq); | ||
258 | free_irq(pf->irq, pf); | ||
259 | |||
260 | error_ret: | ||
261 | return ret; | ||
262 | } | ||
263 | EXPORT_SYMBOL(iio_trigger_dettach_poll_func); | ||
264 | |||
265 | irqreturn_t iio_pollfunc_store_time(int irq, void *p) | ||
266 | { | ||
267 | struct iio_poll_func *pf = p; | ||
268 | pf->timestamp = iio_get_time_ns(); | ||
269 | return IRQ_WAKE_THREAD; | ||
270 | } | ||
271 | EXPORT_SYMBOL(iio_pollfunc_store_time); | ||
272 | |||
273 | struct iio_poll_func | ||
274 | *iio_alloc_pollfunc(irqreturn_t (*h)(int irq, void *p), | ||
275 | irqreturn_t (*thread)(int irq, void *p), | ||
276 | int type, | ||
277 | void *private, | ||
278 | const char *fmt, | ||
279 | ...) | ||
280 | { | ||
281 | va_list vargs; | ||
282 | struct iio_poll_func *pf; | ||
283 | |||
284 | pf = kmalloc(sizeof *pf, GFP_KERNEL); | ||
285 | if (pf == NULL) | ||
286 | return NULL; | ||
287 | va_start(vargs, fmt); | ||
288 | pf->name = kvasprintf(GFP_KERNEL, fmt, vargs); | ||
289 | va_end(vargs); | ||
290 | if (pf->name == NULL) { | ||
291 | kfree(pf); | ||
292 | return NULL; | ||
293 | } | ||
294 | pf->h = h; | ||
295 | pf->thread = thread; | ||
296 | pf->type = type; | ||
297 | pf->private_data = private; | ||
298 | |||
299 | return pf; | ||
300 | } | ||
301 | EXPORT_SYMBOL_GPL(iio_alloc_pollfunc); | ||
302 | |||
303 | void iio_dealloc_pollfunc(struct iio_poll_func *pf) | ||
304 | { | ||
305 | kfree(pf->name); | ||
306 | kfree(pf); | ||
307 | } | ||
308 | EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc); | ||
309 | |||
310 | /** | ||
311 | * iio_trigger_read_currrent() - trigger consumer sysfs query which trigger | ||
312 | * | ||
313 | * For trigger consumers the current_trigger interface allows the trigger | ||
314 | * used by the device to be queried. | ||
315 | **/ | ||
316 | static ssize_t iio_trigger_read_current(struct device *dev, | ||
317 | struct device_attribute *attr, | ||
318 | char *buf) | ||
319 | { | ||
320 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
321 | int len = 0; | ||
322 | if (dev_info->trig) | ||
323 | len = sprintf(buf, | ||
324 | "%s\n", | ||
325 | dev_info->trig->name); | ||
326 | return len; | ||
327 | } | ||
328 | |||
329 | /** | ||
330 | * iio_trigger_write_current() trigger consumer sysfs set current trigger | ||
331 | * | ||
332 | * For trigger consumers the current_trigger interface allows the trigger | ||
333 | * used for this device to be specified at run time based on the triggers | ||
334 | * name. | ||
335 | **/ | ||
336 | static ssize_t iio_trigger_write_current(struct device *dev, | ||
337 | struct device_attribute *attr, | ||
338 | const char *buf, | ||
339 | size_t len) | ||
340 | { | ||
341 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
342 | struct iio_trigger *oldtrig = dev_info->trig; | ||
343 | struct iio_trigger *trig; | ||
344 | int ret; | ||
345 | |||
346 | mutex_lock(&dev_info->mlock); | ||
347 | if (dev_info->currentmode == INDIO_RING_TRIGGERED) { | ||
348 | mutex_unlock(&dev_info->mlock); | ||
349 | return -EBUSY; | ||
350 | } | ||
351 | mutex_unlock(&dev_info->mlock); | ||
352 | |||
353 | trig = iio_trigger_find_by_name(buf, len); | ||
354 | |||
355 | if (trig && dev_info->info->validate_trigger) { | ||
356 | ret = dev_info->info->validate_trigger(dev_info, trig); | ||
357 | if (ret) | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | if (trig && trig->validate_device) { | ||
362 | ret = trig->validate_device(trig, dev_info); | ||
363 | if (ret) | ||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | dev_info->trig = trig; | ||
368 | |||
369 | if (oldtrig && dev_info->trig != oldtrig) | ||
370 | iio_put_trigger(oldtrig); | ||
371 | if (dev_info->trig) | ||
372 | iio_get_trigger(dev_info->trig); | ||
373 | |||
374 | return len; | ||
375 | } | ||
376 | |||
377 | static DEVICE_ATTR(current_trigger, S_IRUGO | S_IWUSR, | ||
378 | iio_trigger_read_current, | ||
379 | iio_trigger_write_current); | ||
380 | |||
381 | static struct attribute *iio_trigger_consumer_attrs[] = { | ||
382 | &dev_attr_current_trigger.attr, | ||
383 | NULL, | ||
384 | }; | ||
385 | |||
386 | static const struct attribute_group iio_trigger_consumer_attr_group = { | ||
387 | .name = "trigger", | ||
388 | .attrs = iio_trigger_consumer_attrs, | ||
389 | }; | ||
390 | |||
391 | static void iio_trig_release(struct device *device) | ||
392 | { | ||
393 | struct iio_trigger *trig = to_iio_trigger(device); | ||
394 | int i; | ||
395 | |||
396 | if (trig->subirq_base) { | ||
397 | for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) { | ||
398 | irq_modify_status(trig->subirq_base + i, | ||
399 | IRQ_NOAUTOEN, | ||
400 | IRQ_NOREQUEST | IRQ_NOPROBE); | ||
401 | irq_set_chip(trig->subirq_base + i, | ||
402 | NULL); | ||
403 | irq_set_handler(trig->subirq_base + i, | ||
404 | NULL); | ||
405 | } | ||
406 | |||
407 | irq_free_descs(trig->subirq_base, | ||
408 | CONFIG_IIO_CONSUMERS_PER_TRIGGER); | ||
409 | } | ||
410 | kfree(trig->name); | ||
411 | kfree(trig); | ||
412 | iio_put(); | ||
413 | } | ||
414 | |||
415 | static struct device_type iio_trig_type = { | ||
416 | .release = iio_trig_release, | ||
417 | }; | ||
418 | |||
419 | static void iio_trig_subirqmask(struct irq_data *d) | ||
420 | { | ||
421 | struct irq_chip *chip = irq_data_get_irq_chip(d); | ||
422 | struct iio_trigger *trig | ||
423 | = container_of(chip, | ||
424 | struct iio_trigger, subirq_chip); | ||
425 | trig->subirqs[d->irq - trig->subirq_base].enabled = false; | ||
426 | } | ||
427 | |||
428 | static void iio_trig_subirqunmask(struct irq_data *d) | ||
429 | { | ||
430 | struct irq_chip *chip = irq_data_get_irq_chip(d); | ||
431 | struct iio_trigger *trig | ||
432 | = container_of(chip, | ||
433 | struct iio_trigger, subirq_chip); | ||
434 | trig->subirqs[d->irq - trig->subirq_base].enabled = true; | ||
435 | } | ||
436 | |||
437 | struct iio_trigger *iio_allocate_trigger(const char *fmt, ...) | ||
438 | { | ||
439 | va_list vargs; | ||
440 | struct iio_trigger *trig; | ||
441 | trig = kzalloc(sizeof *trig, GFP_KERNEL); | ||
442 | if (trig) { | ||
443 | int i; | ||
444 | trig->dev.type = &iio_trig_type; | ||
445 | trig->dev.bus = &iio_bus_type; | ||
446 | device_initialize(&trig->dev); | ||
447 | dev_set_drvdata(&trig->dev, (void *)trig); | ||
448 | |||
449 | mutex_init(&trig->pool_lock); | ||
450 | trig->subirq_base | ||
451 | = irq_alloc_descs(-1, 0, | ||
452 | CONFIG_IIO_CONSUMERS_PER_TRIGGER, | ||
453 | 0); | ||
454 | if (trig->subirq_base < 0) { | ||
455 | kfree(trig); | ||
456 | return NULL; | ||
457 | } | ||
458 | va_start(vargs, fmt); | ||
459 | trig->name = kvasprintf(GFP_KERNEL, fmt, vargs); | ||
460 | va_end(vargs); | ||
461 | if (trig->name == NULL) { | ||
462 | irq_free_descs(trig->subirq_base, | ||
463 | CONFIG_IIO_CONSUMERS_PER_TRIGGER); | ||
464 | kfree(trig); | ||
465 | return NULL; | ||
466 | } | ||
467 | trig->subirq_chip.name = trig->name; | ||
468 | trig->subirq_chip.irq_mask = &iio_trig_subirqmask; | ||
469 | trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask; | ||
470 | for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) { | ||
471 | irq_set_chip(trig->subirq_base + i, | ||
472 | &trig->subirq_chip); | ||
473 | irq_set_handler(trig->subirq_base + i, | ||
474 | &handle_simple_irq); | ||
475 | irq_modify_status(trig->subirq_base + i, | ||
476 | IRQ_NOREQUEST | IRQ_NOAUTOEN, | ||
477 | IRQ_NOPROBE); | ||
478 | } | ||
479 | iio_get(); | ||
480 | } | ||
481 | return trig; | ||
482 | } | ||
483 | EXPORT_SYMBOL(iio_allocate_trigger); | ||
484 | |||
485 | void iio_free_trigger(struct iio_trigger *trig) | ||
486 | { | ||
487 | if (trig) | ||
488 | put_device(&trig->dev); | ||
489 | } | ||
490 | EXPORT_SYMBOL(iio_free_trigger); | ||
491 | |||
492 | int iio_device_register_trigger_consumer(struct iio_dev *dev_info) | ||
493 | { | ||
494 | int ret; | ||
495 | ret = sysfs_create_group(&dev_info->dev.kobj, | ||
496 | &iio_trigger_consumer_attr_group); | ||
497 | return ret; | ||
498 | } | ||
499 | EXPORT_SYMBOL(iio_device_register_trigger_consumer); | ||
500 | |||
501 | int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info) | ||
502 | { | ||
503 | sysfs_remove_group(&dev_info->dev.kobj, | ||
504 | &iio_trigger_consumer_attr_group); | ||
505 | return 0; | ||
506 | } | ||
507 | EXPORT_SYMBOL(iio_device_unregister_trigger_consumer); | ||
508 | |||
509 | int iio_triggered_ring_postenable(struct iio_dev *indio_dev) | ||
510 | { | ||
511 | return indio_dev->trig | ||
512 | ? iio_trigger_attach_poll_func(indio_dev->trig, | ||
513 | indio_dev->pollfunc) | ||
514 | : 0; | ||
515 | } | ||
516 | EXPORT_SYMBOL(iio_triggered_ring_postenable); | ||
517 | |||
518 | int iio_triggered_ring_predisable(struct iio_dev *indio_dev) | ||
519 | { | ||
520 | return indio_dev->trig | ||
521 | ? iio_trigger_dettach_poll_func(indio_dev->trig, | ||
522 | indio_dev->pollfunc) | ||
523 | : 0; | ||
524 | } | ||
525 | EXPORT_SYMBOL(iio_triggered_ring_predisable); | ||