Merge git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6] / arch / um / kernel / irq_user.c
1 /* 
2  * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <string.h>
11 #include <sys/poll.h>
12 #include <sys/types.h>
13 #include <sys/time.h>
14 #include "user_util.h"
15 #include "kern_util.h"
16 #include "user.h"
17 #include "process.h"
18 #include "signal_user.h"
19 #include "sigio.h"
20 #include "irq_user.h"
21 #include "os.h"
22
23 struct irq_fd {
24         struct irq_fd *next;
25         void *id;
26         int fd;
27         int type;
28         int irq;
29         int pid;
30         int events;
31         int current_events;
32 };
33
34 static struct irq_fd *active_fds = NULL;
35 static struct irq_fd **last_irq_ptr = &active_fds;
36
37 static struct pollfd *pollfds = NULL;
38 static int pollfds_num = 0;
39 static int pollfds_size = 0;
40
41 extern int io_count, intr_count;
42
43 extern void free_irqs(void);
44
45 void sigio_handler(int sig, union uml_pt_regs *regs)
46 {
47         struct irq_fd *irq_fd;
48         int i, n;
49
50         if(smp_sigio_handler()) return;
51         while(1){
52                 n = poll(pollfds, pollfds_num, 0);
53                 if(n < 0){
54                         if(errno == EINTR) continue;
55                         printk("sigio_handler : poll returned %d, "
56                                "errno = %d\n", n, errno);
57                         break;
58                 }
59                 if(n == 0) break;
60
61                 irq_fd = active_fds;
62                 for(i = 0; i < pollfds_num; i++){
63                         if(pollfds[i].revents != 0){
64                                 irq_fd->current_events = pollfds[i].revents;
65                                 pollfds[i].fd = -1;
66                         }
67                         irq_fd = irq_fd->next;
68                 }
69
70                 for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
71                         if(irq_fd->current_events != 0){
72                                 irq_fd->current_events = 0;
73                                 do_IRQ(irq_fd->irq, regs);
74                         }
75                 }
76         }
77
78         free_irqs();
79 }
80
81 int activate_ipi(int fd, int pid)
82 {
83         return(os_set_fd_async(fd, pid));
84 }
85
86 static void maybe_sigio_broken(int fd, int type)
87 {
88         if(isatty(fd)){
89                 if((type == IRQ_WRITE) && !pty_output_sigio){
90                         write_sigio_workaround();
91                         add_sigio_fd(fd, 0);
92                 }
93                 else if((type == IRQ_READ) && !pty_close_sigio){
94                         write_sigio_workaround();
95                         add_sigio_fd(fd, 1);                    
96                 }
97         }
98 }
99
100 int activate_fd(int irq, int fd, int type, void *dev_id)
101 {
102         struct pollfd *tmp_pfd;
103         struct irq_fd *new_fd, *irq_fd;
104         unsigned long flags;
105         int pid, events, err, n, size;
106
107         pid = os_getpid();
108         err = os_set_fd_async(fd, pid);
109         if(err < 0)
110                 goto out;
111
112         new_fd = um_kmalloc(sizeof(*new_fd));
113         err = -ENOMEM;
114         if(new_fd == NULL)
115                 goto out;
116
117         if(type == IRQ_READ) events = POLLIN | POLLPRI;
118         else events = POLLOUT;
119         *new_fd = ((struct irq_fd) { .next              = NULL,
120                                      .id                = dev_id,
121                                      .fd                = fd,
122                                      .type              = type,
123                                      .irq               = irq,
124                                      .pid               = pid,
125                                      .events            = events,
126                                      .current_events    = 0 } );
127
128         /* Critical section - locked by a spinlock because this stuff can
129          * be changed from interrupt handlers.  The stuff above is done 
130          * outside the lock because it allocates memory.
131          */
132
133         /* Actually, it only looks like it can be called from interrupt
134          * context.  The culprit is reactivate_fd, which calls 
135          * maybe_sigio_broken, which calls write_sigio_workaround,
136          * which calls activate_fd.  However, write_sigio_workaround should
137          * only be called once, at boot time.  That would make it clear that
138          * this is called only from process context, and can be locked with
139          * a semaphore.
140          */
141         flags = irq_lock();
142         for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
143                 if((irq_fd->fd == fd) && (irq_fd->type == type)){
144                         printk("Registering fd %d twice\n", fd);
145                         printk("Irqs : %d, %d\n", irq_fd->irq, irq);
146                         printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id);
147                         goto out_unlock;
148                 }
149         }
150
151         n = pollfds_num;
152         if(n == pollfds_size){
153                 while(1){
154                         /* Here we have to drop the lock in order to call 
155                          * kmalloc, which might sleep.  If something else
156                          * came in and changed the pollfds array, we free
157                          * the buffer and try again.
158                          */
159                         irq_unlock(flags);
160                         size = (pollfds_num + 1) * sizeof(pollfds[0]);
161                         tmp_pfd = um_kmalloc(size);
162                         flags = irq_lock();
163                         if(tmp_pfd == NULL)
164                                 goto out_unlock;
165                         if(n == pollfds_size)
166                                 break;
167                         kfree(tmp_pfd);
168                 }
169                 if(pollfds != NULL){
170                         memcpy(tmp_pfd, pollfds,
171                                sizeof(pollfds[0]) * pollfds_size);
172                         kfree(pollfds);
173                 }
174                 pollfds = tmp_pfd;
175                 pollfds_size++;
176         }
177
178         if(type == IRQ_WRITE) 
179                 fd = -1;
180
181         pollfds[pollfds_num] = ((struct pollfd) { .fd   = fd,
182                                                   .events       = events,
183                                                   .revents      = 0 });
184         pollfds_num++;
185
186         *last_irq_ptr = new_fd;
187         last_irq_ptr = &new_fd->next;
188
189         irq_unlock(flags);
190
191         /* This calls activate_fd, so it has to be outside the critical
192          * section.
193          */
194         maybe_sigio_broken(fd, type);
195
196         return(0);
197
198  out_unlock:
199         irq_unlock(flags);
200         kfree(new_fd);
201  out:
202         return(err);
203 }
204
205 static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
206 {
207         struct irq_fd **prev;
208         unsigned long flags;
209         int i = 0;
210
211         flags = irq_lock();
212         prev = &active_fds;
213         while(*prev != NULL){
214                 if((*test)(*prev, arg)){
215                         struct irq_fd *old_fd = *prev;
216                         if((pollfds[i].fd != -1) && 
217                            (pollfds[i].fd != (*prev)->fd)){
218                                 printk("free_irq_by_cb - mismatch between "
219                                        "active_fds and pollfds, fd %d vs %d\n",
220                                        (*prev)->fd, pollfds[i].fd);
221                                 goto out;
222                         }
223
224                         pollfds_num--;
225
226                         /* This moves the *whole* array after pollfds[i] (though
227                          * it doesn't spot as such)! */
228
229                         memmove(&pollfds[i], &pollfds[i + 1],
230                                (pollfds_num - i) * sizeof(pollfds[0]));
231
232                         if(last_irq_ptr == &old_fd->next) 
233                                 last_irq_ptr = prev;
234                         *prev = (*prev)->next;
235                         if(old_fd->type == IRQ_WRITE) 
236                                 ignore_sigio_fd(old_fd->fd);
237                         kfree(old_fd);
238                         continue;
239                 }
240                 prev = &(*prev)->next;
241                 i++;
242         }
243  out:
244         irq_unlock(flags);
245 }
246
247 struct irq_and_dev {
248         int irq;
249         void *dev;
250 };
251
252 static int same_irq_and_dev(struct irq_fd *irq, void *d)
253 {
254         struct irq_and_dev *data = d;
255
256         return((irq->irq == data->irq) && (irq->id == data->dev));
257 }
258
259 void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
260 {
261         struct irq_and_dev data = ((struct irq_and_dev) { .irq  = irq,
262                                                           .dev  = dev });
263
264         free_irq_by_cb(same_irq_and_dev, &data);
265 }
266
267 static int same_fd(struct irq_fd *irq, void *fd)
268 {
269         return(irq->fd == *((int *) fd));
270 }
271
272 void free_irq_by_fd(int fd)
273 {
274         free_irq_by_cb(same_fd, &fd);
275 }
276
277 static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
278 {
279         struct irq_fd *irq;
280         int i = 0;
281
282         for(irq=active_fds; irq != NULL; irq = irq->next){
283                 if((irq->fd == fd) && (irq->irq == irqnum)) break;
284                 i++;
285         }
286         if(irq == NULL){
287                 printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
288                 goto out;
289         }
290         if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){
291                 printk("find_irq_by_fd - mismatch between active_fds and "
292                        "pollfds, fd %d vs %d, need %d\n", irq->fd, 
293                        pollfds[i].fd, fd);
294                 irq = NULL;
295                 goto out;
296         }
297         *index_out = i;
298  out:
299         return(irq);
300 }
301
302 void reactivate_fd(int fd, int irqnum)
303 {
304         struct irq_fd *irq;
305         unsigned long flags;
306         int i;
307
308         flags = irq_lock();
309         irq = find_irq_by_fd(fd, irqnum, &i);
310         if(irq == NULL){
311                 irq_unlock(flags);
312                 return;
313         }
314
315         pollfds[i].fd = irq->fd;
316
317         irq_unlock(flags);
318
319         /* This calls activate_fd, so it has to be outside the critical
320          * section.
321          */
322         maybe_sigio_broken(fd, irq->type);
323 }
324
325 void deactivate_fd(int fd, int irqnum)
326 {
327         struct irq_fd *irq;
328         unsigned long flags;
329         int i;
330
331         flags = irq_lock();
332         irq = find_irq_by_fd(fd, irqnum, &i);
333         if(irq == NULL)
334                 goto out;
335         pollfds[i].fd = -1;
336  out:
337         irq_unlock(flags);
338 }
339
340 int deactivate_all_fds(void)
341 {
342         struct irq_fd *irq;
343         int err;
344
345         for(irq=active_fds;irq != NULL;irq = irq->next){
346                 err = os_clear_fd_async(irq->fd);
347                 if(err)
348                         return(err);
349         }
350         /* If there is a signal already queued, after unblocking ignore it */
351         set_handler(SIGIO, SIG_IGN, 0, -1);
352
353         return(0);
354 }
355
356 void forward_ipi(int fd, int pid)
357 {
358         int err;
359
360         err = os_set_owner(fd, pid);
361         if(err < 0)
362                 printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
363                        "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
364 }
365
366 void forward_interrupts(int pid)
367 {
368         struct irq_fd *irq;
369         unsigned long flags;
370         int err;
371
372         flags = irq_lock();
373         for(irq=active_fds;irq != NULL;irq = irq->next){
374                 err = os_set_owner(irq->fd, pid);
375                 if(err < 0){
376                         /* XXX Just remove the irq rather than
377                          * print out an infinite stream of these
378                          */
379                         printk("Failed to forward %d to pid %d, err = %d\n",
380                                irq->fd, pid, -err);
381                 }
382
383                 irq->pid = pid;
384         }
385         irq_unlock(flags);
386 }
387
388 void init_irq_signals(int on_sigstack)
389 {
390         __sighandler_t h;
391         int flags;
392
393         flags = on_sigstack ? SA_ONSTACK : 0;
394         if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
395         else h = boot_timer_handler;
396
397         set_handler(SIGVTALRM, h, flags | SA_RESTART, 
398                     SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
399         set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
400                     SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
401         signal(SIGWINCH, SIG_IGN);
402 }
403
404 /*
405  * Overrides for Emacs so that we follow Linus's tabbing style.
406  * Emacs will notice this stuff at the end of the file and automatically
407  * adjust the settings for this buffer only.  This must remain at the end
408  * of the file.
409  * ---------------------------------------------------------------------------
410  * Local variables:
411  * c-file-style: "linux"
412  * End:
413  */