aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/amiga/amiints.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/amiga/amiints.c')
-rw-r--r--arch/m68k/amiga/amiints.c168
1 files changed, 64 insertions, 104 deletions
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index c5b5212cc3f..47b5f90002a 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -1,43 +1,15 @@
1/* 1/*
2 * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code 2 * Amiga Linux interrupt handling code
3 * 3 *
4 * This file is subject to the terms and conditions of the GNU General Public 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 5 * License. See the file COPYING in the main directory of this archive
6 * for more details. 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 */ 7 */
37 8
38#include <linux/init.h> 9#include <linux/init.h>
39#include <linux/interrupt.h> 10#include <linux/interrupt.h>
40#include <linux/errno.h> 11#include <linux/errno.h>
12#include <linux/irq.h>
41 13
42#include <asm/irq.h> 14#include <asm/irq.h>
43#include <asm/traps.h> 15#include <asm/traps.h>
@@ -45,56 +17,6 @@
45#include <asm/amigaints.h> 17#include <asm/amigaints.h>
46#include <asm/amipcmcia.h> 18#include <asm/amipcmcia.h>
47 19
48static void amiga_enable_irq(unsigned int irq);
49static void amiga_disable_irq(unsigned int irq);
50static irqreturn_t ami_int1(int irq, void *dev_id);
51static irqreturn_t ami_int3(int irq, void *dev_id);
52static irqreturn_t ami_int4(int irq, void *dev_id);
53static irqreturn_t ami_int5(int irq, void *dev_id);
54
55static struct irq_controller amiga_irq_controller = {
56 .name = "amiga",
57 .lock = __SPIN_LOCK_UNLOCKED(amiga_irq_controller.lock),
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
73void __init amiga_init_IRQ(void)
74{
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);
83
84 m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS);
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 */
91 amiga_custom.intena = 0x7fff;
92 amiga_custom.intreq = 0x7fff;
93 amiga_custom.intena = IF_SETCLR | IF_INTEN;
94
95 cia_init_IRQ(&ciaa_base);
96 cia_init_IRQ(&ciab_base);
97}
98 20
99/* 21/*
100 * Enable/disable a particular machine specific interrupt source. 22 * Enable/disable a particular machine specific interrupt source.
@@ -103,112 +25,150 @@ void __init amiga_init_IRQ(void)
103 * internal data, that may not be changed by the interrupt at the same time. 25 * internal data, that may not be changed by the interrupt at the same time.
104 */ 26 */
105 27
106static void amiga_enable_irq(unsigned int irq) 28static void amiga_irq_enable(struct irq_data *data)
107{ 29{
108 amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER)); 30 amiga_custom.intena = IF_SETCLR | (1 << (data->irq - IRQ_USER));
109} 31}
110 32
111static void amiga_disable_irq(unsigned int irq) 33static void amiga_irq_disable(struct irq_data *data)
112{ 34{
113 amiga_custom.intena = 1 << (irq - IRQ_USER); 35 amiga_custom.intena = 1 << (data->irq - IRQ_USER);
114} 36}
115 37
38static struct irq_chip amiga_irq_chip = {
39 .name = "amiga",
40 .irq_enable = amiga_irq_enable,
41 .irq_disable = amiga_irq_disable,
42};
43
44
116/* 45/*
117 * The builtin Amiga hardware interrupt handlers. 46 * The builtin Amiga hardware interrupt handlers.
118 */ 47 */
119 48
120static irqreturn_t ami_int1(int irq, void *dev_id) 49static void ami_int1(unsigned int irq, struct irq_desc *desc)
121{ 50{
122 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; 51 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
123 52
124 /* if serial transmit buffer empty, interrupt */ 53 /* if serial transmit buffer empty, interrupt */
125 if (ints & IF_TBE) { 54 if (ints & IF_TBE) {
126 amiga_custom.intreq = IF_TBE; 55 amiga_custom.intreq = IF_TBE;
127 m68k_handle_int(IRQ_AMIGA_TBE); 56 generic_handle_irq(IRQ_AMIGA_TBE);
128 } 57 }
129 58
130 /* if floppy disk transfer complete, interrupt */ 59 /* if floppy disk transfer complete, interrupt */
131 if (ints & IF_DSKBLK) { 60 if (ints & IF_DSKBLK) {
132 amiga_custom.intreq = IF_DSKBLK; 61 amiga_custom.intreq = IF_DSKBLK;
133 m68k_handle_int(IRQ_AMIGA_DSKBLK); 62 generic_handle_irq(IRQ_AMIGA_DSKBLK);
134 } 63 }
135 64
136 /* if software interrupt set, interrupt */ 65 /* if software interrupt set, interrupt */
137 if (ints & IF_SOFT) { 66 if (ints & IF_SOFT) {
138 amiga_custom.intreq = IF_SOFT; 67 amiga_custom.intreq = IF_SOFT;
139 m68k_handle_int(IRQ_AMIGA_SOFT); 68 generic_handle_irq(IRQ_AMIGA_SOFT);
140 } 69 }
141 return IRQ_HANDLED;
142} 70}
143 71
144static irqreturn_t ami_int3(int irq, void *dev_id) 72static void ami_int3(unsigned int irq, struct irq_desc *desc)
145{ 73{
146 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; 74 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
147 75
148 /* if a blitter interrupt */ 76 /* if a blitter interrupt */
149 if (ints & IF_BLIT) { 77 if (ints & IF_BLIT) {
150 amiga_custom.intreq = IF_BLIT; 78 amiga_custom.intreq = IF_BLIT;
151 m68k_handle_int(IRQ_AMIGA_BLIT); 79 generic_handle_irq(IRQ_AMIGA_BLIT);
152 } 80 }
153 81
154 /* if a copper interrupt */ 82 /* if a copper interrupt */
155 if (ints & IF_COPER) { 83 if (ints & IF_COPER) {
156 amiga_custom.intreq = IF_COPER; 84 amiga_custom.intreq = IF_COPER;
157 m68k_handle_int(IRQ_AMIGA_COPPER); 85 generic_handle_irq(IRQ_AMIGA_COPPER);
158 } 86 }
159 87
160 /* if a vertical blank interrupt */ 88 /* if a vertical blank interrupt */
161 if (ints & IF_VERTB) { 89 if (ints & IF_VERTB) {
162 amiga_custom.intreq = IF_VERTB; 90 amiga_custom.intreq = IF_VERTB;
163 m68k_handle_int(IRQ_AMIGA_VERTB); 91 generic_handle_irq(IRQ_AMIGA_VERTB);
164 } 92 }
165 return IRQ_HANDLED;
166} 93}
167 94
168static irqreturn_t ami_int4(int irq, void *dev_id) 95static void ami_int4(unsigned int irq, struct irq_desc *desc)
169{ 96{
170 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; 97 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
171 98
172 /* if audio 0 interrupt */ 99 /* if audio 0 interrupt */
173 if (ints & IF_AUD0) { 100 if (ints & IF_AUD0) {
174 amiga_custom.intreq = IF_AUD0; 101 amiga_custom.intreq = IF_AUD0;
175 m68k_handle_int(IRQ_AMIGA_AUD0); 102 generic_handle_irq(IRQ_AMIGA_AUD0);
176 } 103 }
177 104
178 /* if audio 1 interrupt */ 105 /* if audio 1 interrupt */
179 if (ints & IF_AUD1) { 106 if (ints & IF_AUD1) {
180 amiga_custom.intreq = IF_AUD1; 107 amiga_custom.intreq = IF_AUD1;
181 m68k_handle_int(IRQ_AMIGA_AUD1); 108 generic_handle_irq(IRQ_AMIGA_AUD1);
182 } 109 }
183 110
184 /* if audio 2 interrupt */ 111 /* if audio 2 interrupt */
185 if (ints & IF_AUD2) { 112 if (ints & IF_AUD2) {
186 amiga_custom.intreq = IF_AUD2; 113 amiga_custom.intreq = IF_AUD2;
187 m68k_handle_int(IRQ_AMIGA_AUD2); 114 generic_handle_irq(IRQ_AMIGA_AUD2);
188 } 115 }
189 116
190 /* if audio 3 interrupt */ 117 /* if audio 3 interrupt */
191 if (ints & IF_AUD3) { 118 if (ints & IF_AUD3) {
192 amiga_custom.intreq = IF_AUD3; 119 amiga_custom.intreq = IF_AUD3;
193 m68k_handle_int(IRQ_AMIGA_AUD3); 120 generic_handle_irq(IRQ_AMIGA_AUD3);
194 } 121 }
195 return IRQ_HANDLED;
196} 122}
197 123
198static irqreturn_t ami_int5(int irq, void *dev_id) 124static void ami_int5(unsigned int irq, struct irq_desc *desc)
199{ 125{
200 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; 126 unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
201 127
202 /* if serial receive buffer full interrupt */ 128 /* if serial receive buffer full interrupt */
203 if (ints & IF_RBF) { 129 if (ints & IF_RBF) {
204 /* acknowledge of IF_RBF must be done by the serial interrupt */ 130 /* acknowledge of IF_RBF must be done by the serial interrupt */
205 m68k_handle_int(IRQ_AMIGA_RBF); 131 generic_handle_irq(IRQ_AMIGA_RBF);
206 } 132 }
207 133
208 /* if a disk sync interrupt */ 134 /* if a disk sync interrupt */
209 if (ints & IF_DSKSYN) { 135 if (ints & IF_DSKSYN) {
210 amiga_custom.intreq = IF_DSKSYN; 136 amiga_custom.intreq = IF_DSKSYN;
211 m68k_handle_int(IRQ_AMIGA_DSKSYN); 137 generic_handle_irq(IRQ_AMIGA_DSKSYN);
212 } 138 }
213 return IRQ_HANDLED; 139}
140
141
142/*
143 * void amiga_init_IRQ(void)
144 *
145 * Parameters: None
146 *
147 * Returns: Nothing
148 *
149 * This function should be called during kernel startup to initialize
150 * the amiga IRQ handling routines.
151 */
152
153void __init amiga_init_IRQ(void)
154{
155 m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
156 AMI_STD_IRQS);
157
158 irq_set_chained_handler(IRQ_AUTO_1, ami_int1);
159 irq_set_chained_handler(IRQ_AUTO_3, ami_int3);
160 irq_set_chained_handler(IRQ_AUTO_4, ami_int4);
161 irq_set_chained_handler(IRQ_AUTO_5, ami_int5);
162
163 /* turn off PCMCIA interrupts */
164 if (AMIGAHW_PRESENT(PCMCIA))
165 gayle.inten = GAYLE_IRQ_IDE;
166
167 /* turn off all interrupts and enable the master interrupt bit */
168 amiga_custom.intena = 0x7fff;
169 amiga_custom.intreq = 0x7fff;
170 amiga_custom.intena = IF_SETCLR | IF_INTEN;
171
172 cia_init_IRQ(&ciaa_base);
173 cia_init_IRQ(&ciab_base);
214} 174}