summaryrefslogtreecommitdiffstats
path: root/kernel/arch/um/os-Linux/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/arch/um/os-Linux/irq.c')
-rw-r--r--kernel/arch/um/os-Linux/irq.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/kernel/arch/um/os-Linux/irq.c b/kernel/arch/um/os-Linux/irq.c
new file mode 100644
index 000000000..b9afb74b7
--- /dev/null
+++ b/kernel/arch/um/os-Linux/irq.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <poll.h>
+#include <signal.h>
+#include <string.h>
+#include <irq_user.h>
+#include <os.h>
+#include <um_malloc.h>
+
+/*
+ * Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd
+ * and os_free_irq_by_cb, which are called under irq_lock.
+ */
+static struct pollfd *pollfds = NULL;
+static int pollfds_num = 0;
+static int pollfds_size = 0;
+
+int os_waiting_for_events(struct irq_fd *active_fds)
+{
+ struct irq_fd *irq_fd;
+ int i, n, err;
+
+ n = poll(pollfds, pollfds_num, 0);
+ if (n < 0) {
+ err = -errno;
+ if (errno != EINTR)
+ printk(UM_KERN_ERR "os_waiting_for_events:"
+ " poll returned %d, errno = %d\n", n, errno);
+ return err;
+ }
+
+ if (n == 0)
+ return 0;
+
+ irq_fd = active_fds;
+
+ for (i = 0; i < pollfds_num; i++) {
+ if (pollfds[i].revents != 0) {
+ irq_fd->current_events = pollfds[i].revents;
+ pollfds[i].fd = -1;
+ }
+ irq_fd = irq_fd->next;
+ }
+ return n;
+}
+
+int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds)
+{
+ if (pollfds_num == pollfds_size) {
+ if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) {
+ /* return min size needed for new pollfds area */
+ return (pollfds_size + 1) * sizeof(pollfds[0]);
+ }
+
+ if (pollfds != NULL) {
+ memcpy(tmp_pfd, pollfds,
+ sizeof(pollfds[0]) * pollfds_size);
+ /* remove old pollfds */
+ kfree(pollfds);
+ }
+ pollfds = tmp_pfd;
+ pollfds_size++;
+ } else
+ kfree(tmp_pfd); /* remove not used tmp_pfd */
+
+ pollfds[pollfds_num] = ((struct pollfd) { .fd = fd,
+ .events = events,
+ .revents = 0 });
+ pollfds_num++;
+
+ return 0;
+}
+
+void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg,
+ struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2)
+{
+ struct irq_fd **prev;
+ int i = 0;
+
+ prev = &active_fds;
+ while (*prev != NULL) {
+ if ((*test)(*prev, arg)) {
+ struct irq_fd *old_fd = *prev;
+ if ((pollfds[i].fd != -1) &&
+ (pollfds[i].fd != (*prev)->fd)) {
+ printk(UM_KERN_ERR "os_free_irq_by_cb - "
+ "mismatch between active_fds and "
+ "pollfds, fd %d vs %d\n",
+ (*prev)->fd, pollfds[i].fd);
+ goto out;
+ }
+
+ pollfds_num--;
+
+ /*
+ * This moves the *whole* array after pollfds[i]
+ * (though it doesn't spot as such)!
+ */
+ memmove(&pollfds[i], &pollfds[i + 1],
+ (pollfds_num - i) * sizeof(pollfds[0]));
+ if (*last_irq_ptr2 == &old_fd->next)
+ *last_irq_ptr2 = prev;
+
+ *prev = (*prev)->next;
+ if (old_fd->type == IRQ_WRITE)
+ ignore_sigio_fd(old_fd->fd);
+ kfree(old_fd);
+ continue;
+ }
+ prev = &(*prev)->next;
+ i++;
+ }
+ out:
+ return;
+}
+
+int os_get_pollfd(int i)
+{
+ return pollfds[i].fd;
+}
+
+void os_set_pollfd(int i, int fd)
+{
+ pollfds[i].fd = fd;
+}
+
+void os_set_ioignore(void)
+{
+ signal(SIGIO, SIG_IGN);
+}