]>
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", | |
57 | .lock = SPIN_LOCK_UNLOCKED, | |
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 | { | |
74be8d08 RZ |
75 | request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL); |
76 | request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL); | |
77 | request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL); | |
78 | request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL); | |
1da177e4 | 79 | |
74be8d08 | 80 | m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS); |
1da177e4 LT |
81 | |
82 | /* turn off PCMCIA interrupts */ | |
83 | if (AMIGAHW_PRESENT(PCMCIA)) | |
84 | gayle.inten = GAYLE_IRQ_IDE; | |
85 | ||
86 | /* turn off all interrupts and enable the master interrupt bit */ | |
b4290a23 AV |
87 | amiga_custom.intena = 0x7fff; |
88 | amiga_custom.intreq = 0x7fff; | |
89 | amiga_custom.intena = IF_SETCLR | IF_INTEN; | |
1da177e4 LT |
90 | |
91 | cia_init_IRQ(&ciaa_base); | |
92 | cia_init_IRQ(&ciab_base); | |
93 | } | |
94 | ||
1da177e4 LT |
95 | /* |
96 | * Enable/disable a particular machine specific interrupt source. | |
97 | * Note that this may affect other interrupts in case of a shared interrupt. | |
98 | * This function should only be called for a _very_ short time to change some | |
99 | * internal data, that may not be changed by the interrupt at the same time. | |
1da177e4 LT |
100 | */ |
101 | ||
74be8d08 | 102 | static void amiga_enable_irq(unsigned int irq) |
1da177e4 | 103 | { |
74be8d08 | 104 | amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER)); |
1da177e4 LT |
105 | } |
106 | ||
74be8d08 | 107 | static void amiga_disable_irq(unsigned int irq) |
1da177e4 | 108 | { |
74be8d08 | 109 | amiga_custom.intena = 1 << (irq - IRQ_USER); |
1da177e4 LT |
110 | } |
111 | ||
112 | /* | |
113 | * The builtin Amiga hardware interrupt handlers. | |
114 | */ | |
115 | ||
2850bc27 | 116 | static irqreturn_t ami_int1(int irq, void *dev_id) |
1da177e4 | 117 | { |
b4290a23 | 118 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
1da177e4 LT |
119 | |
120 | /* if serial transmit buffer empty, interrupt */ | |
121 | if (ints & IF_TBE) { | |
b4290a23 | 122 | amiga_custom.intreq = IF_TBE; |
2850bc27 | 123 | m68k_handle_int(IRQ_AMIGA_TBE); |
1da177e4 LT |
124 | } |
125 | ||
126 | /* if floppy disk transfer complete, interrupt */ | |
127 | if (ints & IF_DSKBLK) { | |
b4290a23 | 128 | amiga_custom.intreq = IF_DSKBLK; |
2850bc27 | 129 | m68k_handle_int(IRQ_AMIGA_DSKBLK); |
1da177e4 LT |
130 | } |
131 | ||
132 | /* if software interrupt set, interrupt */ | |
133 | if (ints & IF_SOFT) { | |
b4290a23 | 134 | amiga_custom.intreq = IF_SOFT; |
2850bc27 | 135 | m68k_handle_int(IRQ_AMIGA_SOFT); |
1da177e4 LT |
136 | } |
137 | return IRQ_HANDLED; | |
138 | } | |
139 | ||
2850bc27 | 140 | static irqreturn_t ami_int3(int irq, void *dev_id) |
1da177e4 | 141 | { |
b4290a23 | 142 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
1da177e4 LT |
143 | |
144 | /* if a blitter interrupt */ | |
145 | if (ints & IF_BLIT) { | |
b4290a23 | 146 | amiga_custom.intreq = IF_BLIT; |
2850bc27 | 147 | m68k_handle_int(IRQ_AMIGA_BLIT); |
1da177e4 LT |
148 | } |
149 | ||
150 | /* if a copper interrupt */ | |
151 | if (ints & IF_COPER) { | |
b4290a23 | 152 | amiga_custom.intreq = IF_COPER; |
2850bc27 | 153 | m68k_handle_int(IRQ_AMIGA_COPPER); |
1da177e4 LT |
154 | } |
155 | ||
156 | /* if a vertical blank interrupt */ | |
74be8d08 RZ |
157 | if (ints & IF_VERTB) { |
158 | amiga_custom.intreq = IF_VERTB; | |
2850bc27 | 159 | m68k_handle_int(IRQ_AMIGA_VERTB); |
74be8d08 | 160 | } |
1da177e4 LT |
161 | return IRQ_HANDLED; |
162 | } | |
163 | ||
2850bc27 | 164 | static irqreturn_t ami_int4(int irq, void *dev_id) |
1da177e4 | 165 | { |
b4290a23 | 166 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
1da177e4 LT |
167 | |
168 | /* if audio 0 interrupt */ | |
169 | if (ints & IF_AUD0) { | |
b4290a23 | 170 | amiga_custom.intreq = IF_AUD0; |
2850bc27 | 171 | m68k_handle_int(IRQ_AMIGA_AUD0); |
1da177e4 LT |
172 | } |
173 | ||
174 | /* if audio 1 interrupt */ | |
175 | if (ints & IF_AUD1) { | |
b4290a23 | 176 | amiga_custom.intreq = IF_AUD1; |
2850bc27 | 177 | m68k_handle_int(IRQ_AMIGA_AUD1); |
1da177e4 LT |
178 | } |
179 | ||
180 | /* if audio 2 interrupt */ | |
181 | if (ints & IF_AUD2) { | |
b4290a23 | 182 | amiga_custom.intreq = IF_AUD2; |
2850bc27 | 183 | m68k_handle_int(IRQ_AMIGA_AUD2); |
1da177e4 LT |
184 | } |
185 | ||
186 | /* if audio 3 interrupt */ | |
187 | if (ints & IF_AUD3) { | |
b4290a23 | 188 | amiga_custom.intreq = IF_AUD3; |
2850bc27 | 189 | m68k_handle_int(IRQ_AMIGA_AUD3); |
1da177e4 LT |
190 | } |
191 | return IRQ_HANDLED; | |
192 | } | |
193 | ||
2850bc27 | 194 | static irqreturn_t ami_int5(int irq, void *dev_id) |
1da177e4 | 195 | { |
b4290a23 | 196 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; |
1da177e4 LT |
197 | |
198 | /* if serial receive buffer full interrupt */ | |
199 | if (ints & IF_RBF) { | |
200 | /* acknowledge of IF_RBF must be done by the serial interrupt */ | |
2850bc27 | 201 | m68k_handle_int(IRQ_AMIGA_RBF); |
1da177e4 LT |
202 | } |
203 | ||
204 | /* if a disk sync interrupt */ | |
205 | if (ints & IF_DSKSYN) { | |
b4290a23 | 206 | amiga_custom.intreq = IF_DSKSYN; |
2850bc27 | 207 | m68k_handle_int(IRQ_AMIGA_DSKSYN); |
1da177e4 LT |
208 | } |
209 | return IRQ_HANDLED; | |
210 | } |