11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) 31da177e4SLinus Torvalds * Licensed under the GPL 41da177e4SLinus Torvalds * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c: 51da177e4SLinus Torvalds * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #include "linux/config.h" 91da177e4SLinus Torvalds #include "linux/kernel.h" 101da177e4SLinus Torvalds #include "linux/module.h" 111da177e4SLinus Torvalds #include "linux/smp.h" 121da177e4SLinus Torvalds #include "linux/kernel_stat.h" 131da177e4SLinus Torvalds #include "linux/interrupt.h" 141da177e4SLinus Torvalds #include "linux/random.h" 151da177e4SLinus Torvalds #include "linux/slab.h" 161da177e4SLinus Torvalds #include "linux/file.h" 171da177e4SLinus Torvalds #include "linux/proc_fs.h" 181da177e4SLinus Torvalds #include "linux/init.h" 191da177e4SLinus Torvalds #include "linux/seq_file.h" 201da177e4SLinus Torvalds #include "linux/profile.h" 211da177e4SLinus Torvalds #include "linux/hardirq.h" 221da177e4SLinus Torvalds #include "asm/irq.h" 231da177e4SLinus Torvalds #include "asm/hw_irq.h" 241da177e4SLinus Torvalds #include "asm/atomic.h" 251da177e4SLinus Torvalds #include "asm/signal.h" 261da177e4SLinus Torvalds #include "asm/system.h" 271da177e4SLinus Torvalds #include "asm/errno.h" 281da177e4SLinus Torvalds #include "asm/uaccess.h" 291da177e4SLinus Torvalds #include "user_util.h" 301da177e4SLinus Torvalds #include "kern_util.h" 311da177e4SLinus Torvalds #include "irq_user.h" 321da177e4SLinus Torvalds #include "irq_kern.h" 3375e5584cSJeff Dike #include "os.h" 34*9b4f018dSJeff Dike #include "sigio.h" 35*9b4f018dSJeff Dike #include "misc_constants.h" 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds /* 381da177e4SLinus Torvalds * Generic, controller-independent functions: 391da177e4SLinus Torvalds */ 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds int show_interrupts(struct seq_file *p, void *v) 421da177e4SLinus Torvalds { 431da177e4SLinus Torvalds int i = *(loff_t *) v, j; 441da177e4SLinus Torvalds struct irqaction * action; 451da177e4SLinus Torvalds unsigned long flags; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds if (i == 0) { 481da177e4SLinus Torvalds seq_printf(p, " "); 491da177e4SLinus Torvalds for_each_online_cpu(j) 501da177e4SLinus Torvalds seq_printf(p, "CPU%d ",j); 511da177e4SLinus Torvalds seq_putc(p, '\n'); 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds if (i < NR_IRQS) { 551da177e4SLinus Torvalds spin_lock_irqsave(&irq_desc[i].lock, flags); 561da177e4SLinus Torvalds action = irq_desc[i].action; 571da177e4SLinus Torvalds if (!action) 581da177e4SLinus Torvalds goto skip; 591da177e4SLinus Torvalds seq_printf(p, "%3d: ",i); 601da177e4SLinus Torvalds #ifndef CONFIG_SMP 611da177e4SLinus Torvalds seq_printf(p, "%10u ", kstat_irqs(i)); 621da177e4SLinus Torvalds #else 631da177e4SLinus Torvalds for_each_online_cpu(j) 641da177e4SLinus Torvalds seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); 651da177e4SLinus Torvalds #endif 661da177e4SLinus Torvalds seq_printf(p, " %14s", irq_desc[i].handler->typename); 671da177e4SLinus Torvalds seq_printf(p, " %s", action->name); 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds for (action=action->next; action; action = action->next) 701da177e4SLinus Torvalds seq_printf(p, ", %s", action->name); 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds seq_putc(p, '\n'); 731da177e4SLinus Torvalds skip: 741da177e4SLinus Torvalds spin_unlock_irqrestore(&irq_desc[i].lock, flags); 751da177e4SLinus Torvalds } else if (i == NR_IRQS) { 761da177e4SLinus Torvalds seq_putc(p, '\n'); 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds return 0; 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 82*9b4f018dSJeff Dike struct irq_fd *active_fds = NULL; 83*9b4f018dSJeff Dike static struct irq_fd **last_irq_ptr = &active_fds; 84*9b4f018dSJeff Dike 85*9b4f018dSJeff Dike extern void free_irqs(void); 86*9b4f018dSJeff Dike 87*9b4f018dSJeff Dike void sigio_handler(int sig, union uml_pt_regs *regs) 88*9b4f018dSJeff Dike { 89*9b4f018dSJeff Dike struct irq_fd *irq_fd; 90*9b4f018dSJeff Dike int n; 91*9b4f018dSJeff Dike 92*9b4f018dSJeff Dike if(smp_sigio_handler()) return; 93*9b4f018dSJeff Dike while(1){ 94*9b4f018dSJeff Dike n = os_waiting_for_events(active_fds); 95*9b4f018dSJeff Dike if (n <= 0) { 96*9b4f018dSJeff Dike if(n == -EINTR) continue; 97*9b4f018dSJeff Dike else break; 98*9b4f018dSJeff Dike } 99*9b4f018dSJeff Dike 100*9b4f018dSJeff Dike for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ 101*9b4f018dSJeff Dike if(irq_fd->current_events != 0){ 102*9b4f018dSJeff Dike irq_fd->current_events = 0; 103*9b4f018dSJeff Dike do_IRQ(irq_fd->irq, regs); 104*9b4f018dSJeff Dike } 105*9b4f018dSJeff Dike } 106*9b4f018dSJeff Dike } 107*9b4f018dSJeff Dike 108*9b4f018dSJeff Dike free_irqs(); 109*9b4f018dSJeff Dike } 110*9b4f018dSJeff Dike 111*9b4f018dSJeff Dike static void maybe_sigio_broken(int fd, int type) 112*9b4f018dSJeff Dike { 113*9b4f018dSJeff Dike if(os_isatty(fd)){ 114*9b4f018dSJeff Dike if((type == IRQ_WRITE) && !pty_output_sigio){ 115*9b4f018dSJeff Dike write_sigio_workaround(); 116*9b4f018dSJeff Dike add_sigio_fd(fd, 0); 117*9b4f018dSJeff Dike } 118*9b4f018dSJeff Dike else if((type == IRQ_READ) && !pty_close_sigio){ 119*9b4f018dSJeff Dike write_sigio_workaround(); 120*9b4f018dSJeff Dike add_sigio_fd(fd, 1); 121*9b4f018dSJeff Dike } 122*9b4f018dSJeff Dike } 123*9b4f018dSJeff Dike } 124*9b4f018dSJeff Dike 125*9b4f018dSJeff Dike 126*9b4f018dSJeff Dike int activate_fd(int irq, int fd, int type, void *dev_id) 127*9b4f018dSJeff Dike { 128*9b4f018dSJeff Dike struct pollfd *tmp_pfd; 129*9b4f018dSJeff Dike struct irq_fd *new_fd, *irq_fd; 130*9b4f018dSJeff Dike unsigned long flags; 131*9b4f018dSJeff Dike int pid, events, err, n; 132*9b4f018dSJeff Dike 133*9b4f018dSJeff Dike pid = os_getpid(); 134*9b4f018dSJeff Dike err = os_set_fd_async(fd, pid); 135*9b4f018dSJeff Dike if(err < 0) 136*9b4f018dSJeff Dike goto out; 137*9b4f018dSJeff Dike 138*9b4f018dSJeff Dike new_fd = um_kmalloc(sizeof(*new_fd)); 139*9b4f018dSJeff Dike err = -ENOMEM; 140*9b4f018dSJeff Dike if(new_fd == NULL) 141*9b4f018dSJeff Dike goto out; 142*9b4f018dSJeff Dike 143*9b4f018dSJeff Dike if(type == IRQ_READ) events = UM_POLLIN | UM_POLLPRI; 144*9b4f018dSJeff Dike else events = UM_POLLOUT; 145*9b4f018dSJeff Dike *new_fd = ((struct irq_fd) { .next = NULL, 146*9b4f018dSJeff Dike .id = dev_id, 147*9b4f018dSJeff Dike .fd = fd, 148*9b4f018dSJeff Dike .type = type, 149*9b4f018dSJeff Dike .irq = irq, 150*9b4f018dSJeff Dike .pid = pid, 151*9b4f018dSJeff Dike .events = events, 152*9b4f018dSJeff Dike .current_events = 0 } ); 153*9b4f018dSJeff Dike 154*9b4f018dSJeff Dike /* Critical section - locked by a spinlock because this stuff can 155*9b4f018dSJeff Dike * be changed from interrupt handlers. The stuff above is done 156*9b4f018dSJeff Dike * outside the lock because it allocates memory. 157*9b4f018dSJeff Dike */ 158*9b4f018dSJeff Dike 159*9b4f018dSJeff Dike /* Actually, it only looks like it can be called from interrupt 160*9b4f018dSJeff Dike * context. The culprit is reactivate_fd, which calls 161*9b4f018dSJeff Dike * maybe_sigio_broken, which calls write_sigio_workaround, 162*9b4f018dSJeff Dike * which calls activate_fd. However, write_sigio_workaround should 163*9b4f018dSJeff Dike * only be called once, at boot time. That would make it clear that 164*9b4f018dSJeff Dike * this is called only from process context, and can be locked with 165*9b4f018dSJeff Dike * a semaphore. 166*9b4f018dSJeff Dike */ 167*9b4f018dSJeff Dike flags = irq_lock(); 168*9b4f018dSJeff Dike for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ 169*9b4f018dSJeff Dike if((irq_fd->fd == fd) && (irq_fd->type == type)){ 170*9b4f018dSJeff Dike printk("Registering fd %d twice\n", fd); 171*9b4f018dSJeff Dike printk("Irqs : %d, %d\n", irq_fd->irq, irq); 172*9b4f018dSJeff Dike printk("Ids : 0x%p, 0x%p\n", irq_fd->id, dev_id); 173*9b4f018dSJeff Dike goto out_unlock; 174*9b4f018dSJeff Dike } 175*9b4f018dSJeff Dike } 176*9b4f018dSJeff Dike 177*9b4f018dSJeff Dike /*-------------*/ 178*9b4f018dSJeff Dike if(type == IRQ_WRITE) 179*9b4f018dSJeff Dike fd = -1; 180*9b4f018dSJeff Dike 181*9b4f018dSJeff Dike tmp_pfd = NULL; 182*9b4f018dSJeff Dike n = 0; 183*9b4f018dSJeff Dike 184*9b4f018dSJeff Dike while(1){ 185*9b4f018dSJeff Dike n = os_create_pollfd(fd, events, tmp_pfd, n); 186*9b4f018dSJeff Dike if (n == 0) 187*9b4f018dSJeff Dike break; 188*9b4f018dSJeff Dike 189*9b4f018dSJeff Dike /* n > 0 190*9b4f018dSJeff Dike * It means we couldn't put new pollfd to current pollfds 191*9b4f018dSJeff Dike * and tmp_fds is NULL or too small for new pollfds array. 192*9b4f018dSJeff Dike * Needed size is equal to n as minimum. 193*9b4f018dSJeff Dike * 194*9b4f018dSJeff Dike * Here we have to drop the lock in order to call 195*9b4f018dSJeff Dike * kmalloc, which might sleep. 196*9b4f018dSJeff Dike * If something else came in and changed the pollfds array 197*9b4f018dSJeff Dike * so we will not be able to put new pollfd struct to pollfds 198*9b4f018dSJeff Dike * then we free the buffer tmp_fds and try again. 199*9b4f018dSJeff Dike */ 200*9b4f018dSJeff Dike irq_unlock(flags); 201*9b4f018dSJeff Dike if (tmp_pfd != NULL) { 202*9b4f018dSJeff Dike kfree(tmp_pfd); 203*9b4f018dSJeff Dike tmp_pfd = NULL; 204*9b4f018dSJeff Dike } 205*9b4f018dSJeff Dike 206*9b4f018dSJeff Dike tmp_pfd = um_kmalloc(n); 207*9b4f018dSJeff Dike if (tmp_pfd == NULL) 208*9b4f018dSJeff Dike goto out_kfree; 209*9b4f018dSJeff Dike 210*9b4f018dSJeff Dike flags = irq_lock(); 211*9b4f018dSJeff Dike } 212*9b4f018dSJeff Dike /*-------------*/ 213*9b4f018dSJeff Dike 214*9b4f018dSJeff Dike *last_irq_ptr = new_fd; 215*9b4f018dSJeff Dike last_irq_ptr = &new_fd->next; 216*9b4f018dSJeff Dike 217*9b4f018dSJeff Dike irq_unlock(flags); 218*9b4f018dSJeff Dike 219*9b4f018dSJeff Dike /* This calls activate_fd, so it has to be outside the critical 220*9b4f018dSJeff Dike * section. 221*9b4f018dSJeff Dike */ 222*9b4f018dSJeff Dike maybe_sigio_broken(fd, type); 223*9b4f018dSJeff Dike 224*9b4f018dSJeff Dike return(0); 225*9b4f018dSJeff Dike 226*9b4f018dSJeff Dike out_unlock: 227*9b4f018dSJeff Dike irq_unlock(flags); 228*9b4f018dSJeff Dike out_kfree: 229*9b4f018dSJeff Dike kfree(new_fd); 230*9b4f018dSJeff Dike out: 231*9b4f018dSJeff Dike return(err); 232*9b4f018dSJeff Dike } 233*9b4f018dSJeff Dike 234*9b4f018dSJeff Dike static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) 235*9b4f018dSJeff Dike { 236*9b4f018dSJeff Dike unsigned long flags; 237*9b4f018dSJeff Dike 238*9b4f018dSJeff Dike flags = irq_lock(); 239*9b4f018dSJeff Dike os_free_irq_by_cb(test, arg, active_fds, &last_irq_ptr); 240*9b4f018dSJeff Dike irq_unlock(flags); 241*9b4f018dSJeff Dike } 242*9b4f018dSJeff Dike 243*9b4f018dSJeff Dike struct irq_and_dev { 244*9b4f018dSJeff Dike int irq; 245*9b4f018dSJeff Dike void *dev; 246*9b4f018dSJeff Dike }; 247*9b4f018dSJeff Dike 248*9b4f018dSJeff Dike static int same_irq_and_dev(struct irq_fd *irq, void *d) 249*9b4f018dSJeff Dike { 250*9b4f018dSJeff Dike struct irq_and_dev *data = d; 251*9b4f018dSJeff Dike 252*9b4f018dSJeff Dike return((irq->irq == data->irq) && (irq->id == data->dev)); 253*9b4f018dSJeff Dike } 254*9b4f018dSJeff Dike 255*9b4f018dSJeff Dike void free_irq_by_irq_and_dev(unsigned int irq, void *dev) 256*9b4f018dSJeff Dike { 257*9b4f018dSJeff Dike struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq, 258*9b4f018dSJeff Dike .dev = dev }); 259*9b4f018dSJeff Dike 260*9b4f018dSJeff Dike free_irq_by_cb(same_irq_and_dev, &data); 261*9b4f018dSJeff Dike } 262*9b4f018dSJeff Dike 263*9b4f018dSJeff Dike static int same_fd(struct irq_fd *irq, void *fd) 264*9b4f018dSJeff Dike { 265*9b4f018dSJeff Dike return(irq->fd == *((int *) fd)); 266*9b4f018dSJeff Dike } 267*9b4f018dSJeff Dike 268*9b4f018dSJeff Dike void free_irq_by_fd(int fd) 269*9b4f018dSJeff Dike { 270*9b4f018dSJeff Dike free_irq_by_cb(same_fd, &fd); 271*9b4f018dSJeff Dike } 272*9b4f018dSJeff Dike 273*9b4f018dSJeff Dike static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) 274*9b4f018dSJeff Dike { 275*9b4f018dSJeff Dike struct irq_fd *irq; 276*9b4f018dSJeff Dike int i = 0; 277*9b4f018dSJeff Dike int fdi; 278*9b4f018dSJeff Dike 279*9b4f018dSJeff Dike for(irq=active_fds; irq != NULL; irq = irq->next){ 280*9b4f018dSJeff Dike if((irq->fd == fd) && (irq->irq == irqnum)) break; 281*9b4f018dSJeff Dike i++; 282*9b4f018dSJeff Dike } 283*9b4f018dSJeff Dike if(irq == NULL){ 284*9b4f018dSJeff Dike printk("find_irq_by_fd doesn't have descriptor %d\n", fd); 285*9b4f018dSJeff Dike goto out; 286*9b4f018dSJeff Dike } 287*9b4f018dSJeff Dike fdi = os_get_pollfd(i); 288*9b4f018dSJeff Dike if((fdi != -1) && (fdi != fd)){ 289*9b4f018dSJeff Dike printk("find_irq_by_fd - mismatch between active_fds and " 290*9b4f018dSJeff Dike "pollfds, fd %d vs %d, need %d\n", irq->fd, 291*9b4f018dSJeff Dike fdi, fd); 292*9b4f018dSJeff Dike irq = NULL; 293*9b4f018dSJeff Dike goto out; 294*9b4f018dSJeff Dike } 295*9b4f018dSJeff Dike *index_out = i; 296*9b4f018dSJeff Dike out: 297*9b4f018dSJeff Dike return(irq); 298*9b4f018dSJeff Dike } 299*9b4f018dSJeff Dike 300*9b4f018dSJeff Dike void reactivate_fd(int fd, int irqnum) 301*9b4f018dSJeff Dike { 302*9b4f018dSJeff Dike struct irq_fd *irq; 303*9b4f018dSJeff Dike unsigned long flags; 304*9b4f018dSJeff Dike int i; 305*9b4f018dSJeff Dike 306*9b4f018dSJeff Dike flags = irq_lock(); 307*9b4f018dSJeff Dike irq = find_irq_by_fd(fd, irqnum, &i); 308*9b4f018dSJeff Dike if(irq == NULL){ 309*9b4f018dSJeff Dike irq_unlock(flags); 310*9b4f018dSJeff Dike return; 311*9b4f018dSJeff Dike } 312*9b4f018dSJeff Dike os_set_pollfd(i, irq->fd); 313*9b4f018dSJeff Dike irq_unlock(flags); 314*9b4f018dSJeff Dike 315*9b4f018dSJeff Dike /* This calls activate_fd, so it has to be outside the critical 316*9b4f018dSJeff Dike * section. 317*9b4f018dSJeff Dike */ 318*9b4f018dSJeff Dike maybe_sigio_broken(fd, irq->type); 319*9b4f018dSJeff Dike } 320*9b4f018dSJeff Dike 321*9b4f018dSJeff Dike void deactivate_fd(int fd, int irqnum) 322*9b4f018dSJeff Dike { 323*9b4f018dSJeff Dike struct irq_fd *irq; 324*9b4f018dSJeff Dike unsigned long flags; 325*9b4f018dSJeff Dike int i; 326*9b4f018dSJeff Dike 327*9b4f018dSJeff Dike flags = irq_lock(); 328*9b4f018dSJeff Dike irq = find_irq_by_fd(fd, irqnum, &i); 329*9b4f018dSJeff Dike if(irq == NULL) 330*9b4f018dSJeff Dike goto out; 331*9b4f018dSJeff Dike os_set_pollfd(i, -1); 332*9b4f018dSJeff Dike out: 333*9b4f018dSJeff Dike irq_unlock(flags); 334*9b4f018dSJeff Dike } 335*9b4f018dSJeff Dike 336*9b4f018dSJeff Dike int deactivate_all_fds(void) 337*9b4f018dSJeff Dike { 338*9b4f018dSJeff Dike struct irq_fd *irq; 339*9b4f018dSJeff Dike int err; 340*9b4f018dSJeff Dike 341*9b4f018dSJeff Dike for(irq=active_fds;irq != NULL;irq = irq->next){ 342*9b4f018dSJeff Dike err = os_clear_fd_async(irq->fd); 343*9b4f018dSJeff Dike if(err) 344*9b4f018dSJeff Dike return(err); 345*9b4f018dSJeff Dike } 346*9b4f018dSJeff Dike /* If there is a signal already queued, after unblocking ignore it */ 347*9b4f018dSJeff Dike os_set_ioignore(); 348*9b4f018dSJeff Dike 349*9b4f018dSJeff Dike return(0); 350*9b4f018dSJeff Dike } 351*9b4f018dSJeff Dike 352*9b4f018dSJeff Dike void forward_interrupts(int pid) 353*9b4f018dSJeff Dike { 354*9b4f018dSJeff Dike struct irq_fd *irq; 355*9b4f018dSJeff Dike unsigned long flags; 356*9b4f018dSJeff Dike int err; 357*9b4f018dSJeff Dike 358*9b4f018dSJeff Dike flags = irq_lock(); 359*9b4f018dSJeff Dike for(irq=active_fds;irq != NULL;irq = irq->next){ 360*9b4f018dSJeff Dike err = os_set_owner(irq->fd, pid); 361*9b4f018dSJeff Dike if(err < 0){ 362*9b4f018dSJeff Dike /* XXX Just remove the irq rather than 363*9b4f018dSJeff Dike * print out an infinite stream of these 364*9b4f018dSJeff Dike */ 365*9b4f018dSJeff Dike printk("Failed to forward %d to pid %d, err = %d\n", 366*9b4f018dSJeff Dike irq->fd, pid, -err); 367*9b4f018dSJeff Dike } 368*9b4f018dSJeff Dike 369*9b4f018dSJeff Dike irq->pid = pid; 370*9b4f018dSJeff Dike } 371*9b4f018dSJeff Dike irq_unlock(flags); 372*9b4f018dSJeff Dike } 373*9b4f018dSJeff Dike 3741da177e4SLinus Torvalds /* 3751da177e4SLinus Torvalds * do_IRQ handles all normal device IRQ's (the special 3761da177e4SLinus Torvalds * SMP cross-CPU interrupts have their own specific 3771da177e4SLinus Torvalds * handlers). 3781da177e4SLinus Torvalds */ 3791da177e4SLinus Torvalds unsigned int do_IRQ(int irq, union uml_pt_regs *regs) 3801da177e4SLinus Torvalds { 3811da177e4SLinus Torvalds irq_enter(); 3821da177e4SLinus Torvalds __do_IRQ(irq, (struct pt_regs *) regs); 3831da177e4SLinus Torvalds irq_exit(); 3841da177e4SLinus Torvalds return 1; 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds int um_request_irq(unsigned int irq, int fd, int type, 3881da177e4SLinus Torvalds irqreturn_t (*handler)(int, void *, struct pt_regs *), 3891da177e4SLinus Torvalds unsigned long irqflags, const char * devname, 3901da177e4SLinus Torvalds void *dev_id) 3911da177e4SLinus Torvalds { 3921da177e4SLinus Torvalds int err; 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds err = request_irq(irq, handler, irqflags, devname, dev_id); 3951da177e4SLinus Torvalds if(err) 3961da177e4SLinus Torvalds return(err); 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds if(fd != -1) 3991da177e4SLinus Torvalds err = activate_fd(irq, fd, type, dev_id); 4001da177e4SLinus Torvalds return(err); 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds EXPORT_SYMBOL(um_request_irq); 4031da177e4SLinus Torvalds EXPORT_SYMBOL(reactivate_fd); 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds static DEFINE_SPINLOCK(irq_spinlock); 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds unsigned long irq_lock(void) 4081da177e4SLinus Torvalds { 4091da177e4SLinus Torvalds unsigned long flags; 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds spin_lock_irqsave(&irq_spinlock, flags); 4121da177e4SLinus Torvalds return(flags); 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds void irq_unlock(unsigned long flags) 4161da177e4SLinus Torvalds { 4171da177e4SLinus Torvalds spin_unlock_irqrestore(&irq_spinlock, flags); 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 420dbce706eSPaolo 'Blaisorblade' Giarrusso /* hw_interrupt_type must define (startup || enable) && 421dbce706eSPaolo 'Blaisorblade' Giarrusso * (shutdown || disable) && end */ 4221da177e4SLinus Torvalds static void dummy(unsigned int irq) 4231da177e4SLinus Torvalds { 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 426dbce706eSPaolo 'Blaisorblade' Giarrusso /* This is used for everything else than the timer. */ 427dbce706eSPaolo 'Blaisorblade' Giarrusso static struct hw_interrupt_type normal_irq_type = { 4281da177e4SLinus Torvalds .typename = "SIGIO", 429dbce706eSPaolo 'Blaisorblade' Giarrusso .release = free_irq_by_irq_and_dev, 4301da177e4SLinus Torvalds .disable = dummy, 4311da177e4SLinus Torvalds .enable = dummy, 4321da177e4SLinus Torvalds .ack = dummy, 4331da177e4SLinus Torvalds .end = dummy 4341da177e4SLinus Torvalds }; 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds static struct hw_interrupt_type SIGVTALRM_irq_type = { 4371da177e4SLinus Torvalds .typename = "SIGVTALRM", 438dbce706eSPaolo 'Blaisorblade' Giarrusso .release = free_irq_by_irq_and_dev, 4391da177e4SLinus Torvalds .shutdown = dummy, /* never called */ 4401da177e4SLinus Torvalds .disable = dummy, 4411da177e4SLinus Torvalds .enable = dummy, 4421da177e4SLinus Torvalds .ack = dummy, 4431da177e4SLinus Torvalds .end = dummy 4441da177e4SLinus Torvalds }; 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds void __init init_IRQ(void) 4471da177e4SLinus Torvalds { 4481da177e4SLinus Torvalds int i; 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds irq_desc[TIMER_IRQ].status = IRQ_DISABLED; 4511da177e4SLinus Torvalds irq_desc[TIMER_IRQ].action = NULL; 4521da177e4SLinus Torvalds irq_desc[TIMER_IRQ].depth = 1; 4531da177e4SLinus Torvalds irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type; 4541da177e4SLinus Torvalds enable_irq(TIMER_IRQ); 4551da177e4SLinus Torvalds for(i=1;i<NR_IRQS;i++){ 4561da177e4SLinus Torvalds irq_desc[i].status = IRQ_DISABLED; 4571da177e4SLinus Torvalds irq_desc[i].action = NULL; 4581da177e4SLinus Torvalds irq_desc[i].depth = 1; 459dbce706eSPaolo 'Blaisorblade' Giarrusso irq_desc[i].handler = &normal_irq_type; 4601da177e4SLinus Torvalds enable_irq(i); 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 46475e5584cSJeff Dike int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *, 46575e5584cSJeff Dike struct pt_regs *)) 46675e5584cSJeff Dike { 46775e5584cSJeff Dike int fds[2], err; 46875e5584cSJeff Dike 46975e5584cSJeff Dike err = os_pipe(fds, 1, 1); 47075e5584cSJeff Dike if(err){ 47175e5584cSJeff Dike printk("init_aio_irq - os_pipe failed, err = %d\n", -err); 47275e5584cSJeff Dike goto out; 47375e5584cSJeff Dike } 47475e5584cSJeff Dike 47575e5584cSJeff Dike err = um_request_irq(irq, fds[0], IRQ_READ, handler, 47675e5584cSJeff Dike SA_INTERRUPT | SA_SAMPLE_RANDOM, name, 47775e5584cSJeff Dike (void *) (long) fds[0]); 47875e5584cSJeff Dike if(err){ 47975e5584cSJeff Dike printk("init_aio_irq - : um_request_irq failed, err = %d\n", 48075e5584cSJeff Dike err); 48175e5584cSJeff Dike goto out_close; 48275e5584cSJeff Dike } 48375e5584cSJeff Dike 48475e5584cSJeff Dike err = fds[1]; 48575e5584cSJeff Dike goto out; 48675e5584cSJeff Dike 48775e5584cSJeff Dike out_close: 48875e5584cSJeff Dike os_close_file(fds[0]); 48975e5584cSJeff Dike os_close_file(fds[1]); 49075e5584cSJeff Dike out: 49175e5584cSJeff Dike return(err); 49275e5584cSJeff Dike } 493