| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* Industrial I/O event handling |
|---|
| 2 | 3 | * |
|---|
| 3 | 4 | * 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 | 5 | * |
|---|
| 9 | 6 | * Based on elements of hwmon and input subsystems. |
|---|
| 10 | 7 | */ |
|---|
| .. | .. |
|---|
| 21 | 18 | #include <linux/uaccess.h> |
|---|
| 22 | 19 | #include <linux/wait.h> |
|---|
| 23 | 20 | #include <linux/iio/iio.h> |
|---|
| 21 | +#include <linux/iio/iio-opaque.h> |
|---|
| 24 | 22 | #include "iio_core.h" |
|---|
| 25 | 23 | #include <linux/iio/sysfs.h> |
|---|
| 26 | 24 | #include <linux/iio/events.h> |
|---|
| .. | .. |
|---|
| 65 | 63 | **/ |
|---|
| 66 | 64 | int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) |
|---|
| 67 | 65 | { |
|---|
| 68 | | - struct iio_event_interface *ev_int = indio_dev->event_interface; |
|---|
| 66 | + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
|---|
| 67 | + struct iio_event_interface *ev_int = iio_dev_opaque->event_interface; |
|---|
| 69 | 68 | struct iio_event_data ev; |
|---|
| 70 | 69 | int copied; |
|---|
| 71 | 70 | |
|---|
| .. | .. |
|---|
| 99 | 98 | struct poll_table_struct *wait) |
|---|
| 100 | 99 | { |
|---|
| 101 | 100 | struct iio_dev *indio_dev = filep->private_data; |
|---|
| 102 | | - struct iio_event_interface *ev_int = indio_dev->event_interface; |
|---|
| 101 | + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
|---|
| 102 | + struct iio_event_interface *ev_int = iio_dev_opaque->event_interface; |
|---|
| 103 | 103 | __poll_t events = 0; |
|---|
| 104 | 104 | |
|---|
| 105 | 105 | if (!indio_dev->info) |
|---|
| .. | .. |
|---|
| 119 | 119 | loff_t *f_ps) |
|---|
| 120 | 120 | { |
|---|
| 121 | 121 | struct iio_dev *indio_dev = filep->private_data; |
|---|
| 122 | | - struct iio_event_interface *ev_int = indio_dev->event_interface; |
|---|
| 122 | + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
|---|
| 123 | + struct iio_event_interface *ev_int = iio_dev_opaque->event_interface; |
|---|
| 123 | 124 | unsigned int copied; |
|---|
| 124 | 125 | int ret; |
|---|
| 125 | 126 | |
|---|
| .. | .. |
|---|
| 168 | 169 | static int iio_event_chrdev_release(struct inode *inode, struct file *filep) |
|---|
| 169 | 170 | { |
|---|
| 170 | 171 | struct iio_dev *indio_dev = filep->private_data; |
|---|
| 171 | | - struct iio_event_interface *ev_int = indio_dev->event_interface; |
|---|
| 172 | + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
|---|
| 173 | + struct iio_event_interface *ev_int = iio_dev_opaque->event_interface; |
|---|
| 172 | 174 | |
|---|
| 173 | 175 | clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); |
|---|
| 174 | 176 | |
|---|
| .. | .. |
|---|
| 187 | 189 | |
|---|
| 188 | 190 | int iio_event_getfd(struct iio_dev *indio_dev) |
|---|
| 189 | 191 | { |
|---|
| 190 | | - struct iio_event_interface *ev_int = indio_dev->event_interface; |
|---|
| 192 | + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
|---|
| 193 | + struct iio_event_interface *ev_int = iio_dev_opaque->event_interface; |
|---|
| 191 | 194 | int fd; |
|---|
| 192 | 195 | |
|---|
| 193 | 196 | if (ev_int == NULL) |
|---|
| .. | .. |
|---|
| 225 | 228 | [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", |
|---|
| 226 | 229 | [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", |
|---|
| 227 | 230 | [IIO_EV_TYPE_CHANGE] = "change", |
|---|
| 231 | +#ifdef CONFIG_NO_GKI |
|---|
| 232 | + [IIO_EV_TYPE_FIFO_FLUSH] = "fifo_flush", |
|---|
| 233 | +#endif |
|---|
| 228 | 234 | }; |
|---|
| 229 | 235 | |
|---|
| 230 | 236 | static const char * const iio_ev_dir_text[] = { |
|---|
| 231 | 237 | [IIO_EV_DIR_EITHER] = "either", |
|---|
| 232 | 238 | [IIO_EV_DIR_RISING] = "rising", |
|---|
| 233 | | - [IIO_EV_DIR_FALLING] = "falling" |
|---|
| 239 | + [IIO_EV_DIR_FALLING] = "falling", |
|---|
| 240 | +#ifdef CONFIG_NO_GKI |
|---|
| 241 | + [IIO_EV_DIR_FIFO_EMPTY] = "empty", |
|---|
| 242 | + [IIO_EV_DIR_FIFO_DATA] = "data", |
|---|
| 243 | +#endif |
|---|
| 234 | 244 | }; |
|---|
| 235 | 245 | |
|---|
| 236 | 246 | static const char * const iio_ev_info_text[] = { |
|---|
| .. | .. |
|---|
| 346 | 356 | enum iio_event_type type, enum iio_event_direction dir, |
|---|
| 347 | 357 | enum iio_shared_by shared_by, const unsigned long *mask) |
|---|
| 348 | 358 | { |
|---|
| 359 | + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
|---|
| 349 | 360 | ssize_t (*show)(struct device *, struct device_attribute *, char *); |
|---|
| 350 | 361 | ssize_t (*store)(struct device *, struct device_attribute *, |
|---|
| 351 | 362 | const char *, size_t); |
|---|
| .. | .. |
|---|
| 379 | 390 | |
|---|
| 380 | 391 | ret = __iio_add_chan_devattr(postfix, chan, show, store, |
|---|
| 381 | 392 | (i << 16) | spec_index, shared_by, &indio_dev->dev, |
|---|
| 382 | | - &indio_dev->event_interface->dev_attr_list); |
|---|
| 393 | + &iio_dev_opaque->event_interface->dev_attr_list); |
|---|
| 383 | 394 | kfree(postfix); |
|---|
| 384 | 395 | |
|---|
| 385 | 396 | if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE)) |
|---|
| .. | .. |
|---|
| 472 | 483 | static const char *iio_event_group_name = "events"; |
|---|
| 473 | 484 | int iio_device_register_eventset(struct iio_dev *indio_dev) |
|---|
| 474 | 485 | { |
|---|
| 486 | + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
|---|
| 487 | + struct iio_event_interface *ev_int; |
|---|
| 475 | 488 | struct iio_dev_attr *p; |
|---|
| 476 | 489 | int ret = 0, attrcount_orig = 0, attrcount, attrn; |
|---|
| 477 | 490 | struct attribute **attr; |
|---|
| .. | .. |
|---|
| 480 | 493 | iio_check_for_dynamic_events(indio_dev))) |
|---|
| 481 | 494 | return 0; |
|---|
| 482 | 495 | |
|---|
| 483 | | - indio_dev->event_interface = |
|---|
| 484 | | - kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL); |
|---|
| 485 | | - if (indio_dev->event_interface == NULL) |
|---|
| 496 | + ev_int = kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL); |
|---|
| 497 | + if (ev_int == NULL) |
|---|
| 486 | 498 | return -ENOMEM; |
|---|
| 487 | 499 | |
|---|
| 488 | | - INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list); |
|---|
| 500 | + iio_dev_opaque->event_interface = ev_int; |
|---|
| 489 | 501 | |
|---|
| 490 | | - iio_setup_ev_int(indio_dev->event_interface); |
|---|
| 502 | + INIT_LIST_HEAD(&ev_int->dev_attr_list); |
|---|
| 503 | + |
|---|
| 504 | + iio_setup_ev_int(ev_int); |
|---|
| 491 | 505 | if (indio_dev->info->event_attrs != NULL) { |
|---|
| 492 | 506 | attr = indio_dev->info->event_attrs->attrs; |
|---|
| 493 | 507 | while (*attr++ != NULL) |
|---|
| .. | .. |
|---|
| 501 | 515 | attrcount += ret; |
|---|
| 502 | 516 | } |
|---|
| 503 | 517 | |
|---|
| 504 | | - indio_dev->event_interface->group.name = iio_event_group_name; |
|---|
| 505 | | - indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1, |
|---|
| 506 | | - sizeof(indio_dev->event_interface->group.attrs[0]), |
|---|
| 507 | | - GFP_KERNEL); |
|---|
| 508 | | - if (indio_dev->event_interface->group.attrs == NULL) { |
|---|
| 518 | + ev_int->group.name = iio_event_group_name; |
|---|
| 519 | + ev_int->group.attrs = kcalloc(attrcount + 1, |
|---|
| 520 | + sizeof(ev_int->group.attrs[0]), |
|---|
| 521 | + GFP_KERNEL); |
|---|
| 522 | + if (ev_int->group.attrs == NULL) { |
|---|
| 509 | 523 | ret = -ENOMEM; |
|---|
| 510 | 524 | goto error_free_setup_event_lines; |
|---|
| 511 | 525 | } |
|---|
| 512 | 526 | if (indio_dev->info->event_attrs) |
|---|
| 513 | | - memcpy(indio_dev->event_interface->group.attrs, |
|---|
| 527 | + memcpy(ev_int->group.attrs, |
|---|
| 514 | 528 | indio_dev->info->event_attrs->attrs, |
|---|
| 515 | | - sizeof(indio_dev->event_interface->group.attrs[0]) |
|---|
| 516 | | - *attrcount_orig); |
|---|
| 529 | + sizeof(ev_int->group.attrs[0]) * attrcount_orig); |
|---|
| 517 | 530 | attrn = attrcount_orig; |
|---|
| 518 | 531 | /* Add all elements from the list. */ |
|---|
| 519 | | - list_for_each_entry(p, |
|---|
| 520 | | - &indio_dev->event_interface->dev_attr_list, |
|---|
| 521 | | - l) |
|---|
| 522 | | - indio_dev->event_interface->group.attrs[attrn++] = |
|---|
| 523 | | - &p->dev_attr.attr; |
|---|
| 524 | | - indio_dev->groups[indio_dev->groupcounter++] = |
|---|
| 525 | | - &indio_dev->event_interface->group; |
|---|
| 532 | + list_for_each_entry(p, &ev_int->dev_attr_list, l) |
|---|
| 533 | + ev_int->group.attrs[attrn++] = &p->dev_attr.attr; |
|---|
| 534 | + indio_dev->groups[indio_dev->groupcounter++] = &ev_int->group; |
|---|
| 526 | 535 | |
|---|
| 527 | 536 | return 0; |
|---|
| 528 | 537 | |
|---|
| 529 | 538 | error_free_setup_event_lines: |
|---|
| 530 | | - iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list); |
|---|
| 531 | | - kfree(indio_dev->event_interface); |
|---|
| 532 | | - indio_dev->event_interface = NULL; |
|---|
| 539 | + iio_free_chan_devattr_list(&ev_int->dev_attr_list); |
|---|
| 540 | + kfree(ev_int); |
|---|
| 541 | + iio_dev_opaque->event_interface = NULL; |
|---|
| 533 | 542 | return ret; |
|---|
| 534 | 543 | } |
|---|
| 535 | 544 | |
|---|
| .. | .. |
|---|
| 542 | 551 | */ |
|---|
| 543 | 552 | void iio_device_wakeup_eventset(struct iio_dev *indio_dev) |
|---|
| 544 | 553 | { |
|---|
| 545 | | - if (indio_dev->event_interface == NULL) |
|---|
| 554 | + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
|---|
| 555 | + |
|---|
| 556 | + if (iio_dev_opaque->event_interface == NULL) |
|---|
| 546 | 557 | return; |
|---|
| 547 | | - wake_up(&indio_dev->event_interface->wait); |
|---|
| 558 | + wake_up(&iio_dev_opaque->event_interface->wait); |
|---|
| 548 | 559 | } |
|---|
| 549 | 560 | |
|---|
| 550 | 561 | void iio_device_unregister_eventset(struct iio_dev *indio_dev) |
|---|
| 551 | 562 | { |
|---|
| 552 | | - if (indio_dev->event_interface == NULL) |
|---|
| 563 | + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); |
|---|
| 564 | + struct iio_event_interface *ev_int = iio_dev_opaque->event_interface; |
|---|
| 565 | + |
|---|
| 566 | + if (ev_int == NULL) |
|---|
| 553 | 567 | return; |
|---|
| 554 | | - iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list); |
|---|
| 555 | | - kfree(indio_dev->event_interface->group.attrs); |
|---|
| 556 | | - kfree(indio_dev->event_interface); |
|---|
| 568 | + iio_free_chan_devattr_list(&ev_int->dev_attr_list); |
|---|
| 569 | + kfree(ev_int->group.attrs); |
|---|
| 570 | + kfree(ev_int); |
|---|
| 571 | + iio_dev_opaque->event_interface = NULL; |
|---|
| 557 | 572 | } |
|---|