Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code | |
3 | * | |
4 | * This file is subject to the terms and conditions of the GNU General Public | |
5 | * License. See the file COPYING in the main directory of this archive | |
6 | * for more details. | |
7 | * | |
8 | * 11/07/96: rewritten interrupt handling, irq lists are exists now only for | |
9 | * this sources where it makes sense (VERTB/PORTS/EXTER) and you must | |
10 | * be careful that dev_id for this sources is unique since this the | |
11 | * only possibility to distinguish between different handlers for | |
12 | * free_irq. irq lists also have different irq flags: | |
13 | * - IRQ_FLG_FAST: handler is inserted at top of list (after other | |
14 | * fast handlers) | |
15 | * - IRQ_FLG_SLOW: handler is inserted at bottom of list and before | |
16 | * they're executed irq level is set to the previous | |
17 | * one, but handlers don't need to be reentrant, if | |
18 | * reentrance occurred, slow handlers will be just | |
19 | * called again. | |
20 | * The whole interrupt handling for CIAs is moved to cia.c | |
21 | * /Roman Zippel | |
22 | * | |
23 | * 07/08/99: rewamp of the interrupt handling - we now have two types of | |
24 | * interrupts, normal and fast handlers, fast handlers being | |
b0b9fdc1 | 25 | * marked with IRQF_DISABLED and runs with all other interrupts |
1da177e4 LT |
26 | * disabled. Normal interrupts disable their own source but |
27 | * run with all other interrupt sources enabled. | |
28 | * PORTS and EXTER interrupts are always shared even if the | |
29 | * drivers do not explicitly mark this when calling | |
30 | * request_irq which they really should do. | |
31 | * This is similar to the way interrupts are handled on all | |
32 | * other architectures and makes a ton of sense besides | |
33 | * having the advantage of making it easier to share | |
34 | * drivers. | |
35 | * /Jes | |
36 | */ | |
37 | ||
1da177e4 | 38 | #include <linux/init.h> |
b5dc7840 | 39 | #include <linux/interrupt.h> |
1da177e4 | 40 | #include <linux/errno.h> |
1da177e4 | 41 | |
1da177e4 LT |
42 | #include <asm/irq.h> |
43 | #include <asm/traps.h> | |
44 | #include <asm/amigahw.h> | |
45 | #include <asm/amigaints.h> | |
46 | #include <asm/amipcmcia.h> | |
47 | ||
74be8d08 RZ |
48 | static void amiga_enable_irq(unsigned int irq); |
49 | static void amiga_disable_irq(unsigned int irq); | |
2850bc27 AV |
50 | static irqreturn_t ami_int1(int irq, void *dev_id); |
51 | static irqreturn_t ami_int3(int irq, void *dev_id); | |
52 | static irqreturn_t ami_int4(int irq, void *dev_id); | |
53 | static irqreturn_t ami_int5(int irq, void *dev_id); | |
74be8d08 RZ |
54 | |
55 | static struct irq_controller amiga_irq_controller = { | |
56 | .name = "amiga", | |
241258d1 | 57 | .lock = __SPIN_LOCK_UNLOCKED(amiga_irq_controller.lock), |
74be8d08 RZ |
58 | .enable = amiga_enable_irq, |
59 | .disable = amiga_disable_irq, | |
1da177e4 LT |
60 | }; |
61 | ||
1da177e4 LT |
62 | /* |
63 | * void amiga_init_IRQ(void) | |
64 | * | |
65 | * Parameters: None | |
66 | * | |
67 | * Returns: Nothing | |
68 | * | |
69 | * This function should be called during kernel startup to initialize | |
70 | * the amiga IRQ handling routines. | |
71 | */ | |
72 | ||
73 | void __init amiga_init_IRQ(void) | |
74 | { | |
66acd258 GU |
75 | if (request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL)) |
76 | pr_err("Couldn't register int%d\n", 1); | |
77 | if (request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL)) | |
78 | pr_err("Couldn't register int%d\n", 3); | |
79 | if (request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL)) | |
80 | pr_err("Couldn't register int%d\n", 4); | |
81 | if (request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL)) | |
82 | pr_err("Couldn't register int%d\n", 5); | |
1da177e4 | 83 | |
74be8d08 | 84 | m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS); |
1da177e4 LT |
85 | |
86 | /* turn off PCMCIA interrupts */ | |
87 | if (AMIGAHW_PRESENT(PCMCIA)) | |
88 | gayle.inten = GAYLE_IRQ_IDE; | |
89 | ||
90 | /* turn off all interrupts and enable the master interrupt bit */ | |
b4290a23 AV |
91 | amiga_custom.intena = 0x7fff; |
92 | amiga_custom.intreq = 0x7fff; | |
93 | amiga_custom.intena = IF_SETCLR | IF_INTEN; | |
1da177e4 LT |
94 | |
95 | cia_init_IRQ(&ciaa_base); | |
96 | cia_init_IRQ(&ciab_base); | |
97 | } | |
98 | ||
1da177e4 LT |
99 | /* |
100 | * Enable/disable a particular machine specific interrupt source. | |
101 | * Note that this may affect other interrupts in case of a shared interrupt. | |
102 | * This function should only be called for a _very_ short time to change some | |
103 | * internal data, that may not be changed by the interrupt at the same time. | |
1da177e4 LT |
104 | */ |
105 | ||
74be8d08 | 106 | static void amiga_enable_irq(unsigned int irq) |
1da177e4 | 107 | { |
74be8d08 | 108 | amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER)); |
1da177e4 LT |
109 | } |
110 | ||
74be8d08 | 111 | static void amiga_disable_irq(unsigned int irq) |
1da177e4 | 112 | { |
74be8d08 | 113 | amiga_custom.intena = 1 << (irq - IRQ_USER); |
1da177e4 LT |
114 | } |
115 | ||
116 | /* | |
117 | * The builtin Amiga hardware interrupt handlers. | |
118 | */ | |
119 | ||
2850bc27 | 120 | static irqreturn_t ami_int1(int irq, void *dev_id) |
1da177e4 | 121 | { |
b4290a23 | 122 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
1da177e4 LT |
123 | |
124 | /* if serial transmit buffer empty, interrupt */ | |
125 | if (ints & IF_TBE) { | |
b4290a23 | 126 | amiga_custom.intreq = IF_TBE; |
2850bc27 | 127 | m68k_handle_int(IRQ_AMIGA_TBE); |
1da177e4 LT |
128 | } |
129 | ||
130 | /* if floppy disk transfer complete, interrupt */ | |
131 | if (ints & IF_DSKBLK) { | |
b4290a23 | 132 | amiga_custom.intreq = IF_DSKBLK; |
2850bc27 | 133 | m68k_handle_int(IRQ_AMIGA_DSKBLK); |
1da177e4 LT |
134 | } |
135 | ||
136 | /* if software interrupt set, interrupt */ | |
137 | if (ints & IF_SOFT) { | |
b4290a23 | 138 | amiga_custom.intreq = IF_SOFT; |
2850bc27 | 139 | m68k_handle_int(IRQ_AMIGA_SOFT); |
1da177e4 LT |
140 | } |
141 | return IRQ_HANDLED; | |
142 | } | |
143 | ||
2850bc27 | 144 | static irqreturn_t ami_int3(int irq, void *dev_id) |
1da177e4 | 145 | { |
b4290a23 | 146 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
1da177e4 LT |
147 | |
148 | /* if a blitter interrupt */ | |
149 | if (ints & IF_BLIT) { | |
b4290a23 | 150 | amiga_custom.intreq = IF_BLIT; |
2850bc27 | 151 | m68k_handle_int(IRQ_AMIGA_BLIT); |
1da177e4 LT |
152 | } |
153 | ||
154 | /* if a copper interrupt */ | |
155 | if (ints & IF_COPER) { | |
b4290a23 | 156 | amiga_custom.intreq = IF_COPER; |
2850bc27 | 157 | m68k_handle_int(IRQ_AMIGA_COPPER); |
1da177e4 LT |
158 | } |
159 | ||
160 | /* if a vertical blank interrupt */ | |
74be8d08 RZ |
161 | if (ints & IF_VERTB) { |
162 | amiga_custom.intreq = IF_VERTB; | |
2850bc27 | 163 | m68k_handle_int(IRQ_AMIGA_VERTB); |
74be8d08 | 164 | } |
1da177e4 LT |
165 | return IRQ_HANDLED; |
166 | } | |
167 | ||
2850bc27 | 168 | static irqreturn_t ami_int4(int irq, void *dev_id) |
1da177e4 | 169 | { |
b4290a23 | 170 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
1da177e4 LT |
171 | |
172 | /* if audio 0 interrupt */ | |
173 | if (ints & IF_AUD0) { | |
b4290a23 | 174 | amiga_custom.intreq = IF_AUD0; |
2850bc27 | 175 | m68k_handle_int(IRQ_AMIGA_AUD0); |
1da177e4 LT |
176 | } |
177 | ||
178 | /* if audio 1 interrupt */ | |
179 | if (ints & IF_AUD1) { | |
b4290a23 | 180 | amiga_custom.intreq = IF_AUD1; |
2850bc27 | 181 | m68k_handle_int(IRQ_AMIGA_AUD1); |
1da177e4 LT |
182 | } |
183 | ||
184 | /* if audio 2 interrupt */ | |
185 | if (ints & IF_AUD2) { | |
b4290a23 | 186 | amiga_custom.intreq = IF_AUD2; |
2850bc27 | 187 | m68k_handle_int(IRQ_AMIGA_AUD2); |
1da177e4 LT |
188 | } |
189 | ||
190 | /* if audio 3 interrupt */ | |
191 | if (ints & IF_AUD3) { | |
b4290a23 | 192 | amiga_custom.intreq = IF_AUD3; |
2850bc27 | 193 | m68k_handle_int(IRQ_AMIGA_AUD3); |
1da177e4 LT |
194 | } |
195 | return IRQ_HANDLED; | |
196 | } | |
197 | ||
2850bc27 | 198 | static irqreturn_t ami_int5(int irq, void *dev_id) |
1da177e4 | 199 | { |
b4290a23 | 200 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
1da177e4 LT |
201 | |
202 | /* if serial receive buffer full interrupt */ | |
203 | if (ints & IF_RBF) { | |
204 | /* acknowledge of IF_RBF must be done by the serial interrupt */ | |
2850bc27 | 205 | m68k_handle_int(IRQ_AMIGA_RBF); |
1da177e4 LT |
206 | } |
207 | ||
208 | /* if a disk sync interrupt */ | |
209 | if (ints & IF_DSKSYN) { | |
b4290a23 | 210 | amiga_custom.intreq = IF_DSKSYN; |
2850bc27 | 211 | m68k_handle_int(IRQ_AMIGA_DSKSYN); |
1da177e4 LT |
212 | } |
213 | return IRQ_HANDLED; | |
214 | } |