1/* 2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Licensed under the GPL 4 */ 5 6#include <stdlib.h> 7#include <errno.h> 8#include <poll.h> 9#include <signal.h> 10#include <string.h> 11#include <irq_user.h> 12#include <os.h> 13#include <um_malloc.h> 14 15/* 16 * Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd 17 * and os_free_irq_by_cb, which are called under irq_lock. 18 */ 19static struct pollfd *pollfds = NULL; 20static int pollfds_num = 0; 21static int pollfds_size = 0; 22 23int os_waiting_for_events(struct irq_fd *active_fds) 24{ 25 struct irq_fd *irq_fd; 26 int i, n, err; 27 28 n = poll(pollfds, pollfds_num, 0); 29 if (n < 0) { 30 err = -errno; 31 if (errno != EINTR) 32 printk(UM_KERN_ERR "os_waiting_for_events:" 33 " poll returned %d, errno = %d\n", n, errno); 34 return err; 35 } 36 37 if (n == 0) 38 return 0; 39 40 irq_fd = active_fds; 41 42 for (i = 0; i < pollfds_num; i++) { 43 if (pollfds[i].revents != 0) { 44 irq_fd->current_events = pollfds[i].revents; 45 pollfds[i].fd = -1; 46 } 47 irq_fd = irq_fd->next; 48 } 49 return n; 50} 51 52int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds) 53{ 54 if (pollfds_num == pollfds_size) { 55 if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) { 56 /* return min size needed for new pollfds area */ 57 return (pollfds_size + 1) * sizeof(pollfds[0]); 58 } 59 60 if (pollfds != NULL) { 61 memcpy(tmp_pfd, pollfds, 62 sizeof(pollfds[0]) * pollfds_size); 63 /* remove old pollfds */ 64 kfree(pollfds); 65 } 66 pollfds = tmp_pfd; 67 pollfds_size++; 68 } else 69 kfree(tmp_pfd); /* remove not used tmp_pfd */ 70 71 pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, 72 .events = events, 73 .revents = 0 }); 74 pollfds_num++; 75 76 return 0; 77} 78 79void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, 80 struct irq_fd *active_fds, struct irq_fd ***last_irq_ptr2) 81{ 82 struct irq_fd **prev; 83 int i = 0; 84 85 prev = &active_fds; 86 while (*prev != NULL) { 87 if ((*test)(*prev, arg)) { 88 struct irq_fd *old_fd = *prev; 89 if ((pollfds[i].fd != -1) && 90 (pollfds[i].fd != (*prev)->fd)) { 91 printk(UM_KERN_ERR "os_free_irq_by_cb - " 92 "mismatch between active_fds and " 93 "pollfds, fd %d vs %d\n", 94 (*prev)->fd, pollfds[i].fd); 95 goto out; 96 } 97 98 pollfds_num--; 99 100 /* 101 * This moves the *whole* array after pollfds[i] 102 * (though it doesn't spot as such)! 103 */ 104 memmove(&pollfds[i], &pollfds[i + 1], 105 (pollfds_num - i) * sizeof(pollfds[0])); 106 if (*last_irq_ptr2 == &old_fd->next) 107 *last_irq_ptr2 = prev; 108 109 *prev = (*prev)->next; 110 if (old_fd->type == IRQ_WRITE) 111 ignore_sigio_fd(old_fd->fd); 112 kfree(old_fd); 113 continue; 114 } 115 prev = &(*prev)->next; 116 i++; 117 } 118 out: 119 return; 120} 121 122int os_get_pollfd(int i) 123{ 124 return pollfds[i].fd; 125} 126 127void os_set_pollfd(int i, int fd) 128{ 129 pollfds[i].fd = fd; 130} 131 132void os_set_ioignore(void) 133{ 134 signal(SIGIO, SIG_IGN); 135} 136