diff options
| author | Ataberk <olgunataberk@gmail.com> | 2022-09-25 17:22:03 +0200 |
|---|---|---|
| committer | Ataberk <olgunataberk@gmail.com> | 2022-09-25 17:22:03 +0200 |
| commit | dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f (patch) | |
| tree | b47203aa281bdd959def4451c84d310cd9cf2e12 /sources/xdma_driver/xdma/cdev_events.c | |
| download | dram-bender-dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f.tar.gz | |
Initial commit
Diffstat (limited to 'sources/xdma_driver/xdma/cdev_events.c')
| -rw-r--r-- | sources/xdma_driver/xdma/cdev_events.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/sources/xdma_driver/xdma/cdev_events.c b/sources/xdma_driver/xdma/cdev_events.c new file mode 100644 index 0000000..3ada7db --- /dev/null +++ b/sources/xdma_driver/xdma/cdev_events.c @@ -0,0 +1,113 @@ +/* + * This file is part of the Xilinx DMA IP Core driver for Linux + * + * Copyright (c) 2016-present, Xilinx, Inc. + * All rights reserved. + * + * This source code is licensed under both the BSD-style license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + +#include "xdma_cdev.h" + +/* + * character device file operations for events + */ +static ssize_t char_events_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int rv; + struct xdma_user_irq *user_irq; + struct xdma_cdev *xcdev = (struct xdma_cdev *)file->private_data; + u32 events_user; + unsigned long flags; + + rv = xcdev_check(__func__, xcdev, 0); + if (rv < 0) + return rv; + user_irq = xcdev->user_irq; + if (!user_irq) { + pr_info("xcdev 0x%p, user_irq NULL.\n", xcdev); + return -EINVAL; + } + + if (count != 4) + return -EPROTO; + + if (*pos & 3) + return -EPROTO; + + /* + * sleep until any interrupt events have occurred, + * or a signal arrived + */ + rv = wait_event_interruptible(user_irq->events_wq, + user_irq->events_irq != 0); + if (rv) + dbg_sg("wait_event_interruptible=%d\n", rv); + + /* wait_event_interruptible() was interrupted by a signal */ + if (rv == -ERESTARTSYS) + return -ERESTARTSYS; + + /* atomically decide which events are passed to the user */ + spin_lock_irqsave(&user_irq->events_lock, flags); + events_user = user_irq->events_irq; + user_irq->events_irq = 0; + spin_unlock_irqrestore(&user_irq->events_lock, flags); + + rv = copy_to_user(buf, &events_user, 4); + if (rv) + dbg_sg("Copy to user failed but continuing\n"); + + return 4; +} + +static unsigned int char_events_poll(struct file *file, poll_table *wait) +{ + struct xdma_user_irq *user_irq; + struct xdma_cdev *xcdev = (struct xdma_cdev *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + int rv; + + rv = xcdev_check(__func__, xcdev, 0); + if (rv < 0) + return rv; + user_irq = xcdev->user_irq; + if (!user_irq) { + pr_info("xcdev 0x%p, user_irq NULL.\n", xcdev); + return -EINVAL; + } + + poll_wait(file, &user_irq->events_wq, wait); + + spin_lock_irqsave(&user_irq->events_lock, flags); + if (user_irq->events_irq) + mask = POLLIN | POLLRDNORM; /* readable */ + + spin_unlock_irqrestore(&user_irq->events_lock, flags); + + return mask; +} + +/* + * character device file operations for the irq events + */ +static const struct file_operations events_fops = { + .owner = THIS_MODULE, + .open = char_open, + .release = char_close, + .read = char_events_read, + .poll = char_events_poll, +}; + +void cdev_event_init(struct xdma_cdev *xcdev) +{ + xcdev->user_irq = &(xcdev->xdev->user_irq[xcdev->bar]); + cdev_init(&xcdev->cdev, &events_fops); +} |
