]>
Commit | Line | Data |
---|---|---|
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 | |
25 | * marked with IRQF_DISABLED and runs with all other interrupts | |
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 | ||
38 | #include <linux/init.h> | |
39 | #include <linux/interrupt.h> | |
40 | #include <linux/errno.h> | |
41 | ||
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 | ||
48 | static void amiga_enable_irq(unsigned int irq); | |
49 | static void amiga_disable_irq(unsigned int irq); | |
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); | |
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, | |
60 | }; | |
61 | ||
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 | { | |
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); | |
79 | ||
80 | m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS); | |
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 */ | |
87 | amiga_custom.intena = 0x7fff; | |
88 | amiga_custom.intreq = 0x7fff; | |
89 | amiga_custom.intena = IF_SETCLR | IF_INTEN; | |
90 | ||
91 | cia_init_IRQ(&ciaa_base); | |
92 | cia_init_IRQ(&ciab_base); | |
93 | } | |
94 | ||
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. | |
100 | */ | |
101 | ||
102 | static void amiga_enable_irq(unsigned int irq) | |
103 | { | |
104 | amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER)); | |
105 | } | |
106 | ||
107 | static void amiga_disable_irq(unsigned int irq) | |
108 | { | |
109 | amiga_custom.intena = 1 << (irq - IRQ_USER); | |
110 | } | |
111 | ||
112 | /* | |
113 | * The builtin Amiga hardware interrupt handlers. | |
114 | */ | |
115 | ||
116 | static irqreturn_t ami_int1(int irq, void *dev_id) | |
117 | { | |
118 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; | |
119 | ||
120 | /* if serial transmit buffer empty, interrupt */ | |
121 | if (ints & IF_TBE) { | |
122 | amiga_custom.intreq = IF_TBE; | |
123 | m68k_handle_int(IRQ_AMIGA_TBE); | |
124 | } | |
125 | ||
126 | /* if floppy disk transfer complete, interrupt */ | |
127 | if (ints & IF_DSKBLK) { | |
128 | amiga_custom.intreq = IF_DSKBLK; | |
129 | m68k_handle_int(IRQ_AMIGA_DSKBLK); | |
130 | } | |
131 | ||
132 | /* if software interrupt set, interrupt */ | |
133 | if (ints & IF_SOFT) { | |
134 | amiga_custom.intreq = IF_SOFT; | |
135 | m68k_handle_int(IRQ_AMIGA_SOFT); | |
136 | } | |
137 | return IRQ_HANDLED; | |
138 | } | |
139 | ||
140 | static irqreturn_t ami_int3(int irq, void *dev_id) | |
141 | { | |
142 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; | |
143 | ||
144 | /* if a blitter interrupt */ | |
145 | if (ints & IF_BLIT) { | |
146 | amiga_custom.intreq = IF_BLIT; | |
147 | m68k_handle_int(IRQ_AMIGA_BLIT); | |
148 | } | |
149 | ||
150 | /* if a copper interrupt */ | |
151 | if (ints & IF_COPER) { | |
152 | amiga_custom.intreq = IF_COPER; | |
153 | m68k_handle_int(IRQ_AMIGA_COPPER); | |
154 | } | |
155 | ||
156 | /* if a vertical blank interrupt */ | |
157 | if (ints & IF_VERTB) { | |
158 | amiga_custom.intreq = IF_VERTB; | |
159 | m68k_handle_int(IRQ_AMIGA_VERTB); | |
160 | } | |
161 | return IRQ_HANDLED; | |
162 | } | |
163 | ||
164 | static irqreturn_t ami_int4(int irq, void *dev_id) | |
165 | { | |
166 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; | |
167 | ||
168 | /* if audio 0 interrupt */ | |
169 | if (ints & IF_AUD0) { | |
170 | amiga_custom.intreq = IF_AUD0; | |
171 | m68k_handle_int(IRQ_AMIGA_AUD0); | |
172 | } | |
173 | ||
174 | /* if audio 1 interrupt */ | |
175 | if (ints & IF_AUD1) { | |
176 | amiga_custom.intreq = IF_AUD1; | |
177 | m68k_handle_int(IRQ_AMIGA_AUD1); | |
178 | } | |
179 | ||
180 | /* if audio 2 interrupt */ | |
181 | if (ints & IF_AUD2) { | |
182 | amiga_custom.intreq = IF_AUD2; | |
183 | m68k_handle_int(IRQ_AMIGA_AUD2); | |
184 | } | |
185 | ||
186 | /* if audio 3 interrupt */ | |
187 | if (ints & IF_AUD3) { | |
188 | amiga_custom.intreq = IF_AUD3; | |
189 | m68k_handle_int(IRQ_AMIGA_AUD3); | |
190 | } | |
191 | return IRQ_HANDLED; | |
192 | } | |
193 | ||
194 | static irqreturn_t ami_int5(int irq, void *dev_id) | |
195 | { | |
196 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; | |
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 */ | |
201 | m68k_handle_int(IRQ_AMIGA_RBF); | |
202 | } | |
203 | ||
204 | /* if a disk sync interrupt */ | |
205 | if (ints & IF_DSKSYN) { | |
206 | amiga_custom.intreq = IF_DSKSYN; | |
207 | m68k_handle_int(IRQ_AMIGA_DSKSYN); | |
208 | } | |
209 | return IRQ_HANDLED; | |
210 | } |