| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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/irq.h" | 
 | 13 | #include "linux/kernel_stat.h" | 
 | 14 | #include "linux/interrupt.h" | 
 | 15 | #include "linux/random.h" | 
 | 16 | #include "linux/slab.h" | 
 | 17 | #include "linux/file.h" | 
 | 18 | #include "linux/proc_fs.h" | 
 | 19 | #include "linux/init.h" | 
 | 20 | #include "linux/seq_file.h" | 
 | 21 | #include "linux/profile.h" | 
 | 22 | #include "linux/hardirq.h" | 
 | 23 | #include "asm/irq.h" | 
 | 24 | #include "asm/hw_irq.h" | 
 | 25 | #include "asm/atomic.h" | 
 | 26 | #include "asm/signal.h" | 
 | 27 | #include "asm/system.h" | 
 | 28 | #include "asm/errno.h" | 
 | 29 | #include "asm/uaccess.h" | 
 | 30 | #include "user_util.h" | 
 | 31 | #include "kern_util.h" | 
 | 32 | #include "irq_user.h" | 
 | 33 | #include "irq_kern.h" | 
 | 34 |  | 
 | 35 |  | 
 | 36 | /* | 
 | 37 |  * Generic, controller-independent functions: | 
 | 38 |  */ | 
 | 39 |  | 
 | 40 | int show_interrupts(struct seq_file *p, void *v) | 
 | 41 | { | 
 | 42 | 	int i = *(loff_t *) v, j; | 
 | 43 | 	struct irqaction * action; | 
 | 44 | 	unsigned long flags; | 
 | 45 |  | 
 | 46 | 	if (i == 0) { | 
 | 47 | 		seq_printf(p, "           "); | 
 | 48 | 		for_each_online_cpu(j) | 
 | 49 | 			seq_printf(p, "CPU%d       ",j); | 
 | 50 | 		seq_putc(p, '\n'); | 
 | 51 | 	} | 
 | 52 |  | 
 | 53 | 	if (i < NR_IRQS) { | 
 | 54 | 		spin_lock_irqsave(&irq_desc[i].lock, flags); | 
 | 55 | 		action = irq_desc[i].action; | 
 | 56 | 		if (!action)  | 
 | 57 | 			goto skip; | 
 | 58 | 		seq_printf(p, "%3d: ",i); | 
 | 59 | #ifndef CONFIG_SMP | 
 | 60 | 		seq_printf(p, "%10u ", kstat_irqs(i)); | 
 | 61 | #else | 
 | 62 | 		for_each_online_cpu(j) | 
 | 63 | 			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | 
 | 64 | #endif | 
 | 65 | 		seq_printf(p, " %14s", irq_desc[i].handler->typename); | 
 | 66 | 		seq_printf(p, "  %s", action->name); | 
 | 67 |  | 
 | 68 | 		for (action=action->next; action; action = action->next) | 
 | 69 | 			seq_printf(p, ", %s", action->name); | 
 | 70 |  | 
 | 71 | 		seq_putc(p, '\n'); | 
 | 72 | skip: | 
 | 73 | 		spin_unlock_irqrestore(&irq_desc[i].lock, flags); | 
 | 74 | 	} else if (i == NR_IRQS) { | 
 | 75 | 		seq_putc(p, '\n'); | 
 | 76 | 	} | 
 | 77 |  | 
 | 78 | 	return 0; | 
 | 79 | } | 
 | 80 |  | 
 | 81 | /* | 
 | 82 |  * do_IRQ handles all normal device IRQ's (the special | 
 | 83 |  * SMP cross-CPU interrupts have their own specific | 
 | 84 |  * handlers). | 
 | 85 |  */ | 
 | 86 | unsigned int do_IRQ(int irq, union uml_pt_regs *regs) | 
 | 87 | { | 
 | 88 |        irq_enter(); | 
 | 89 |        __do_IRQ(irq, (struct pt_regs *) regs); | 
 | 90 |        irq_exit(); | 
 | 91 |        return 1; | 
 | 92 | } | 
 | 93 |  | 
 | 94 | int um_request_irq(unsigned int irq, int fd, int type, | 
 | 95 | 		   irqreturn_t (*handler)(int, void *, struct pt_regs *), | 
 | 96 | 		   unsigned long irqflags, const char * devname, | 
 | 97 | 		   void *dev_id) | 
 | 98 | { | 
 | 99 | 	int err; | 
 | 100 |  | 
 | 101 | 	err = request_irq(irq, handler, irqflags, devname, dev_id); | 
 | 102 | 	if(err) | 
 | 103 | 		return(err); | 
 | 104 |  | 
 | 105 | 	if(fd != -1) | 
 | 106 | 		err = activate_fd(irq, fd, type, dev_id); | 
 | 107 | 	return(err); | 
 | 108 | } | 
 | 109 | EXPORT_SYMBOL(um_request_irq); | 
 | 110 | EXPORT_SYMBOL(reactivate_fd); | 
 | 111 |  | 
 | 112 | static DEFINE_SPINLOCK(irq_spinlock); | 
 | 113 |  | 
 | 114 | unsigned long irq_lock(void) | 
 | 115 | { | 
 | 116 | 	unsigned long flags; | 
 | 117 |  | 
 | 118 | 	spin_lock_irqsave(&irq_spinlock, flags); | 
 | 119 | 	return(flags); | 
 | 120 | } | 
 | 121 |  | 
 | 122 | void irq_unlock(unsigned long flags) | 
 | 123 | { | 
 | 124 | 	spin_unlock_irqrestore(&irq_spinlock, flags); | 
 | 125 | } | 
 | 126 |  | 
| Paolo 'Blaisorblade' Giarrusso | dbce706 | 2005-06-21 17:16:19 -0700 | [diff] [blame] | 127 | /* hw_interrupt_type must define (startup || enable) && | 
 | 128 |  * (shutdown || disable) && end */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | static void dummy(unsigned int irq) | 
 | 130 | { | 
 | 131 | } | 
 | 132 |  | 
| Paolo 'Blaisorblade' Giarrusso | dbce706 | 2005-06-21 17:16:19 -0700 | [diff] [blame] | 133 | /* This is used for everything else than the timer. */ | 
 | 134 | static struct hw_interrupt_type normal_irq_type = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 | 	.typename = "SIGIO", | 
| Paolo 'Blaisorblade' Giarrusso | dbce706 | 2005-06-21 17:16:19 -0700 | [diff] [blame] | 136 | 	.release = free_irq_by_irq_and_dev, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 137 | 	.disable = dummy, | 
 | 138 | 	.enable = dummy, | 
 | 139 | 	.ack = dummy, | 
 | 140 | 	.end = dummy | 
 | 141 | }; | 
 | 142 |  | 
 | 143 | static struct hw_interrupt_type SIGVTALRM_irq_type = { | 
 | 144 | 	.typename = "SIGVTALRM", | 
| Paolo 'Blaisorblade' Giarrusso | dbce706 | 2005-06-21 17:16:19 -0700 | [diff] [blame] | 145 | 	.release = free_irq_by_irq_and_dev, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 | 	.shutdown = dummy, /* never called */ | 
 | 147 | 	.disable = dummy, | 
 | 148 | 	.enable = dummy, | 
 | 149 | 	.ack = dummy, | 
 | 150 | 	.end = dummy | 
 | 151 | }; | 
 | 152 |  | 
 | 153 | void __init init_IRQ(void) | 
 | 154 | { | 
 | 155 | 	int i; | 
 | 156 |  | 
 | 157 | 	irq_desc[TIMER_IRQ].status = IRQ_DISABLED; | 
 | 158 | 	irq_desc[TIMER_IRQ].action = NULL; | 
 | 159 | 	irq_desc[TIMER_IRQ].depth = 1; | 
 | 160 | 	irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type; | 
 | 161 | 	enable_irq(TIMER_IRQ); | 
 | 162 | 	for(i=1;i<NR_IRQS;i++){ | 
 | 163 | 		irq_desc[i].status = IRQ_DISABLED; | 
 | 164 | 		irq_desc[i].action = NULL; | 
 | 165 | 		irq_desc[i].depth = 1; | 
| Paolo 'Blaisorblade' Giarrusso | dbce706 | 2005-06-21 17:16:19 -0700 | [diff] [blame] | 166 | 		irq_desc[i].handler = &normal_irq_type; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | 		enable_irq(i); | 
 | 168 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 169 | } | 
 | 170 |  | 
 | 171 | /* | 
 | 172 |  * Overrides for Emacs so that we follow Linus's tabbing style. | 
 | 173 |  * Emacs will notice this stuff at the end of the file and automatically | 
 | 174 |  * adjust the settings for this buffer only.  This must remain at the end | 
 | 175 |  * of the file. | 
 | 176 |  * --------------------------------------------------------------------------- | 
 | 177 |  * Local variables: | 
 | 178 |  * c-file-style: "linux" | 
 | 179 |  * End: | 
 | 180 |  */ |