1 /* 2 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) 3 * Licensed under the GPL 4 * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c: 5 * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar 6 */ 7 8 #include "linux/config.h" 9 #include "linux/kernel.h" 10 #include "linux/module.h" 11 #include "linux/smp.h" 12 #include "linux/kernel_stat.h" 13 #include "linux/interrupt.h" 14 #include "linux/random.h" 15 #include "linux/slab.h" 16 #include "linux/file.h" 17 #include "linux/proc_fs.h" 18 #include "linux/init.h" 19 #include "linux/seq_file.h" 20 #include "linux/profile.h" 21 #include "linux/hardirq.h" 22 #include "asm/irq.h" 23 #include "asm/hw_irq.h" 24 #include "asm/atomic.h" 25 #include "asm/signal.h" 26 #include "asm/system.h" 27 #include "asm/errno.h" 28 #include "asm/uaccess.h" 29 #include "user_util.h" 30 #include "kern_util.h" 31 #include "irq_user.h" 32 #include "irq_kern.h" 33 #include "os.h" 34 35 /* 36 * Generic, controller-independent functions: 37 */ 38 39 int show_interrupts(struct seq_file *p, void *v) 40 { 41 int i = *(loff_t *) v, j; 42 struct irqaction * action; 43 unsigned long flags; 44 45 if (i == 0) { 46 seq_printf(p, " "); 47 for_each_online_cpu(j) 48 seq_printf(p, "CPU%d ",j); 49 seq_putc(p, '\n'); 50 } 51 52 if (i < NR_IRQS) { 53 spin_lock_irqsave(&irq_desc[i].lock, flags); 54 action = irq_desc[i].action; 55 if (!action) 56 goto skip; 57 seq_printf(p, "%3d: ",i); 58 #ifndef CONFIG_SMP 59 seq_printf(p, "%10u ", kstat_irqs(i)); 60 #else 61 for_each_online_cpu(j) 62 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); 63 #endif 64 seq_printf(p, " %14s", irq_desc[i].handler->typename); 65 seq_printf(p, " %s", action->name); 66 67 for (action=action->next; action; action = action->next) 68 seq_printf(p, ", %s", action->name); 69 70 seq_putc(p, '\n'); 71 skip: 72 spin_unlock_irqrestore(&irq_desc[i].lock, flags); 73 } else if (i == NR_IRQS) { 74 seq_putc(p, '\n'); 75 } 76 77 return 0; 78 } 79 80 /* 81 * do_IRQ handles all normal device IRQ's (the special 82 * SMP cross-CPU interrupts have their own specific 83 * handlers). 84 */ 85 unsigned int do_IRQ(int irq, union uml_pt_regs *regs) 86 { 87 irq_enter(); 88 __do_IRQ(irq, (struct pt_regs *) regs); 89 irq_exit(); 90 return 1; 91 } 92 93 int um_request_irq(unsigned int irq, int fd, int type, 94 irqreturn_t (*handler)(int, void *, struct pt_regs *), 95 unsigned long irqflags, const char * devname, 96 void *dev_id) 97 { 98 int err; 99 100 err = request_irq(irq, handler, irqflags, devname, dev_id); 101 if(err) 102 return(err); 103 104 if(fd != -1) 105 err = activate_fd(irq, fd, type, dev_id); 106 return(err); 107 } 108 EXPORT_SYMBOL(um_request_irq); 109 EXPORT_SYMBOL(reactivate_fd); 110 111 static DEFINE_SPINLOCK(irq_spinlock); 112 113 unsigned long irq_lock(void) 114 { 115 unsigned long flags; 116 117 spin_lock_irqsave(&irq_spinlock, flags); 118 return(flags); 119 } 120 121 void irq_unlock(unsigned long flags) 122 { 123 spin_unlock_irqrestore(&irq_spinlock, flags); 124 } 125 126 /* hw_interrupt_type must define (startup || enable) && 127 * (shutdown || disable) && end */ 128 static void dummy(unsigned int irq) 129 { 130 } 131 132 /* This is used for everything else than the timer. */ 133 static struct hw_interrupt_type normal_irq_type = { 134 .typename = "SIGIO", 135 .release = free_irq_by_irq_and_dev, 136 .disable = dummy, 137 .enable = dummy, 138 .ack = dummy, 139 .end = dummy 140 }; 141 142 static struct hw_interrupt_type SIGVTALRM_irq_type = { 143 .typename = "SIGVTALRM", 144 .release = free_irq_by_irq_and_dev, 145 .shutdown = dummy, /* never called */ 146 .disable = dummy, 147 .enable = dummy, 148 .ack = dummy, 149 .end = dummy 150 }; 151 152 void __init init_IRQ(void) 153 { 154 int i; 155 156 irq_desc[TIMER_IRQ].status = IRQ_DISABLED; 157 irq_desc[TIMER_IRQ].action = NULL; 158 irq_desc[TIMER_IRQ].depth = 1; 159 irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type; 160 enable_irq(TIMER_IRQ); 161 for(i=1;i<NR_IRQS;i++){ 162 irq_desc[i].status = IRQ_DISABLED; 163 irq_desc[i].action = NULL; 164 irq_desc[i].depth = 1; 165 irq_desc[i].handler = &normal_irq_type; 166 enable_irq(i); 167 } 168 } 169 170 int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *, 171 struct pt_regs *)) 172 { 173 int fds[2], err; 174 175 err = os_pipe(fds, 1, 1); 176 if(err){ 177 printk("init_aio_irq - os_pipe failed, err = %d\n", -err); 178 goto out; 179 } 180 181 err = um_request_irq(irq, fds[0], IRQ_READ, handler, 182 SA_INTERRUPT | SA_SAMPLE_RANDOM, name, 183 (void *) (long) fds[0]); 184 if(err){ 185 printk("init_aio_irq - : um_request_irq failed, err = %d\n", 186 err); 187 goto out_close; 188 } 189 190 err = fds[1]; 191 goto out; 192 193 out_close: 194 os_close_file(fds[0]); 195 os_close_file(fds[1]); 196 out: 197 return(err); 198 } 199