diff options
Diffstat (limited to 'arch/m68k/mac/oss.c')
-rw-r--r-- | arch/m68k/mac/oss.c | 157 |
1 files changed, 52 insertions, 105 deletions
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index a4c82dab9ff1..6c4c882c126e 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * OSS handling | 2 | * Operating System Services (OSS) chip handling |
3 | * Written by Joshua M. Thompson (funaho@jurai.org) | 3 | * Written by Joshua M. Thompson (funaho@jurai.org) |
4 | * | 4 | * |
5 | * | 5 | * |
@@ -30,8 +30,6 @@ | |||
30 | int oss_present; | 30 | int oss_present; |
31 | volatile struct mac_oss *oss; | 31 | volatile struct mac_oss *oss; |
32 | 32 | ||
33 | extern void via1_irq(unsigned int irq, struct irq_desc *desc); | ||
34 | |||
35 | /* | 33 | /* |
36 | * Initialize the OSS | 34 | * Initialize the OSS |
37 | * | 35 | * |
@@ -51,10 +49,8 @@ void __init oss_init(void) | |||
51 | /* do this by setting the source's interrupt level to zero. */ | 49 | /* do this by setting the source's interrupt level to zero. */ |
52 | 50 | ||
53 | for (i = 0; i <= OSS_NUM_SOURCES; i++) { | 51 | for (i = 0; i <= OSS_NUM_SOURCES; i++) { |
54 | oss->irq_level[i] = OSS_IRQLEV_DISABLED; | 52 | oss->irq_level[i] = 0; |
55 | } | 53 | } |
56 | /* If we disable VIA1 here, we never really handle it... */ | ||
57 | oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1; | ||
58 | } | 54 | } |
59 | 55 | ||
60 | /* | 56 | /* |
@@ -66,17 +62,13 @@ void __init oss_nubus_init(void) | |||
66 | } | 62 | } |
67 | 63 | ||
68 | /* | 64 | /* |
69 | * Handle miscellaneous OSS interrupts. Right now that's just sound | 65 | * Handle miscellaneous OSS interrupts. |
70 | * and SCSI; everything else is routed to its own autovector IRQ. | ||
71 | */ | 66 | */ |
72 | 67 | ||
73 | static void oss_irq(unsigned int irq, struct irq_desc *desc) | 68 | static void oss_irq(unsigned int irq, struct irq_desc *desc) |
74 | { | 69 | { |
75 | int events; | 70 | int events = oss->irq_pending & |
76 | 71 | (OSS_IP_IOPSCC | OSS_IP_SCSI | OSS_IP_IOPISM); | |
77 | events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI); | ||
78 | if (!events) | ||
79 | return; | ||
80 | 72 | ||
81 | #ifdef DEBUG_IRQS | 73 | #ifdef DEBUG_IRQS |
82 | if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) { | 74 | if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) { |
@@ -84,16 +76,20 @@ static void oss_irq(unsigned int irq, struct irq_desc *desc) | |||
84 | (int) oss->irq_pending); | 76 | (int) oss->irq_pending); |
85 | } | 77 | } |
86 | #endif | 78 | #endif |
87 | /* FIXME: how do you clear a pending IRQ? */ | ||
88 | 79 | ||
89 | if (events & OSS_IP_SOUND) { | 80 | if (events & OSS_IP_IOPSCC) { |
90 | oss->irq_pending &= ~OSS_IP_SOUND; | 81 | oss->irq_pending &= ~OSS_IP_IOPSCC; |
91 | /* FIXME: call sound handler */ | 82 | generic_handle_irq(IRQ_MAC_SCC); |
92 | } else if (events & OSS_IP_SCSI) { | 83 | } |
84 | |||
85 | if (events & OSS_IP_SCSI) { | ||
93 | oss->irq_pending &= ~OSS_IP_SCSI; | 86 | oss->irq_pending &= ~OSS_IP_SCSI; |
94 | generic_handle_irq(IRQ_MAC_SCSI); | 87 | generic_handle_irq(IRQ_MAC_SCSI); |
95 | } else { | 88 | } |
96 | /* FIXME: error check here? */ | 89 | |
90 | if (events & OSS_IP_IOPISM) { | ||
91 | oss->irq_pending &= ~OSS_IP_IOPISM; | ||
92 | generic_handle_irq(IRQ_MAC_ADB); | ||
97 | } | 93 | } |
98 | } | 94 | } |
99 | 95 | ||
@@ -132,14 +128,29 @@ static void oss_nubus_irq(unsigned int irq, struct irq_desc *desc) | |||
132 | 128 | ||
133 | /* | 129 | /* |
134 | * Register the OSS and NuBus interrupt dispatchers. | 130 | * Register the OSS and NuBus interrupt dispatchers. |
131 | * | ||
132 | * This IRQ mapping is laid out with two things in mind: first, we try to keep | ||
133 | * things on their own levels to avoid having to do double-dispatches. Second, | ||
134 | * the levels match as closely as possible the alternate IRQ mapping mode (aka | ||
135 | * "A/UX mode") available on some VIA machines. | ||
135 | */ | 136 | */ |
136 | 137 | ||
138 | #define OSS_IRQLEV_IOPISM IRQ_AUTO_1 | ||
139 | #define OSS_IRQLEV_SCSI IRQ_AUTO_2 | ||
140 | #define OSS_IRQLEV_NUBUS IRQ_AUTO_3 | ||
141 | #define OSS_IRQLEV_IOPSCC IRQ_AUTO_4 | ||
142 | #define OSS_IRQLEV_VIA1 IRQ_AUTO_6 | ||
143 | |||
137 | void __init oss_register_interrupts(void) | 144 | void __init oss_register_interrupts(void) |
138 | { | 145 | { |
139 | irq_set_chained_handler(OSS_IRQLEV_SCSI, oss_irq); | 146 | irq_set_chained_handler(OSS_IRQLEV_IOPISM, oss_irq); |
140 | irq_set_chained_handler(OSS_IRQLEV_NUBUS, oss_nubus_irq); | 147 | irq_set_chained_handler(OSS_IRQLEV_SCSI, oss_irq); |
141 | irq_set_chained_handler(OSS_IRQLEV_SOUND, oss_irq); | 148 | irq_set_chained_handler(OSS_IRQLEV_NUBUS, oss_nubus_irq); |
142 | irq_set_chained_handler(OSS_IRQLEV_VIA1, via1_irq); | 149 | irq_set_chained_handler(OSS_IRQLEV_IOPSCC, oss_irq); |
150 | irq_set_chained_handler(OSS_IRQLEV_VIA1, via1_irq); | ||
151 | |||
152 | /* OSS_VIA1 gets enabled here because it has no machspec interrupt. */ | ||
153 | oss->irq_level[OSS_VIA1] = IRQ_AUTO_6; | ||
143 | } | 154 | } |
144 | 155 | ||
145 | /* | 156 | /* |
@@ -158,13 +169,13 @@ void oss_irq_enable(int irq) { | |||
158 | switch(irq) { | 169 | switch(irq) { |
159 | case IRQ_MAC_SCC: | 170 | case IRQ_MAC_SCC: |
160 | oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_IOPSCC; | 171 | oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_IOPSCC; |
161 | break; | 172 | return; |
162 | case IRQ_MAC_ADB: | 173 | case IRQ_MAC_ADB: |
163 | oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_IOPISM; | 174 | oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_IOPISM; |
164 | break; | 175 | return; |
165 | case IRQ_MAC_SCSI: | 176 | case IRQ_MAC_SCSI: |
166 | oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; | 177 | oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; |
167 | break; | 178 | return; |
168 | case IRQ_NUBUS_9: | 179 | case IRQ_NUBUS_9: |
169 | case IRQ_NUBUS_A: | 180 | case IRQ_NUBUS_A: |
170 | case IRQ_NUBUS_B: | 181 | case IRQ_NUBUS_B: |
@@ -173,13 +184,11 @@ void oss_irq_enable(int irq) { | |||
173 | case IRQ_NUBUS_E: | 184 | case IRQ_NUBUS_E: |
174 | irq -= NUBUS_SOURCE_BASE; | 185 | irq -= NUBUS_SOURCE_BASE; |
175 | oss->irq_level[irq] = OSS_IRQLEV_NUBUS; | 186 | oss->irq_level[irq] = OSS_IRQLEV_NUBUS; |
176 | break; | 187 | return; |
177 | #ifdef DEBUG_IRQUSE | ||
178 | default: | ||
179 | printk("%s unknown irq %d\n", __func__, irq); | ||
180 | break; | ||
181 | #endif | ||
182 | } | 188 | } |
189 | |||
190 | if (IRQ_SRC(irq) == 1) | ||
191 | via_irq_enable(irq); | ||
183 | } | 192 | } |
184 | 193 | ||
185 | /* | 194 | /* |
@@ -195,50 +204,14 @@ void oss_irq_disable(int irq) { | |||
195 | #endif | 204 | #endif |
196 | switch(irq) { | 205 | switch(irq) { |
197 | case IRQ_MAC_SCC: | 206 | case IRQ_MAC_SCC: |
198 | oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_DISABLED; | 207 | oss->irq_level[OSS_IOPSCC] = 0; |
199 | break; | 208 | return; |
200 | case IRQ_MAC_ADB: | ||
201 | oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_DISABLED; | ||
202 | break; | ||
203 | case IRQ_MAC_SCSI: | ||
204 | oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; | ||
205 | break; | ||
206 | case IRQ_NUBUS_9: | ||
207 | case IRQ_NUBUS_A: | ||
208 | case IRQ_NUBUS_B: | ||
209 | case IRQ_NUBUS_C: | ||
210 | case IRQ_NUBUS_D: | ||
211 | case IRQ_NUBUS_E: | ||
212 | irq -= NUBUS_SOURCE_BASE; | ||
213 | oss->irq_level[irq] = OSS_IRQLEV_DISABLED; | ||
214 | break; | ||
215 | #ifdef DEBUG_IRQUSE | ||
216 | default: | ||
217 | printk("%s unknown irq %d\n", __func__, irq); | ||
218 | break; | ||
219 | #endif | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * Clear an OSS interrupt | ||
225 | * | ||
226 | * Not sure if this works or not but it's the only method I could | ||
227 | * think of based on the contents of the mac_oss structure. | ||
228 | */ | ||
229 | |||
230 | void oss_irq_clear(int irq) { | ||
231 | /* FIXME: how to do this on OSS? */ | ||
232 | switch(irq) { | ||
233 | case IRQ_MAC_SCC: | ||
234 | oss->irq_pending &= ~OSS_IP_IOPSCC; | ||
235 | break; | ||
236 | case IRQ_MAC_ADB: | 209 | case IRQ_MAC_ADB: |
237 | oss->irq_pending &= ~OSS_IP_IOPISM; | 210 | oss->irq_level[OSS_IOPISM] = 0; |
238 | break; | 211 | return; |
239 | case IRQ_MAC_SCSI: | 212 | case IRQ_MAC_SCSI: |
240 | oss->irq_pending &= ~OSS_IP_SCSI; | 213 | oss->irq_level[OSS_SCSI] = 0; |
241 | break; | 214 | return; |
242 | case IRQ_NUBUS_9: | 215 | case IRQ_NUBUS_9: |
243 | case IRQ_NUBUS_A: | 216 | case IRQ_NUBUS_A: |
244 | case IRQ_NUBUS_B: | 217 | case IRQ_NUBUS_B: |
@@ -246,36 +219,10 @@ void oss_irq_clear(int irq) { | |||
246 | case IRQ_NUBUS_D: | 219 | case IRQ_NUBUS_D: |
247 | case IRQ_NUBUS_E: | 220 | case IRQ_NUBUS_E: |
248 | irq -= NUBUS_SOURCE_BASE; | 221 | irq -= NUBUS_SOURCE_BASE; |
249 | oss->irq_pending &= ~(1 << irq); | 222 | oss->irq_level[irq] = 0; |
250 | break; | 223 | return; |
251 | } | 224 | } |
252 | } | ||
253 | |||
254 | /* | ||
255 | * Check to see if a specific OSS interrupt is pending | ||
256 | */ | ||
257 | 225 | ||
258 | int oss_irq_pending(int irq) | 226 | if (IRQ_SRC(irq) == 1) |
259 | { | 227 | via_irq_disable(irq); |
260 | switch(irq) { | ||
261 | case IRQ_MAC_SCC: | ||
262 | return oss->irq_pending & OSS_IP_IOPSCC; | ||
263 | break; | ||
264 | case IRQ_MAC_ADB: | ||
265 | return oss->irq_pending & OSS_IP_IOPISM; | ||
266 | break; | ||
267 | case IRQ_MAC_SCSI: | ||
268 | return oss->irq_pending & OSS_IP_SCSI; | ||
269 | break; | ||
270 | case IRQ_NUBUS_9: | ||
271 | case IRQ_NUBUS_A: | ||
272 | case IRQ_NUBUS_B: | ||
273 | case IRQ_NUBUS_C: | ||
274 | case IRQ_NUBUS_D: | ||
275 | case IRQ_NUBUS_E: | ||
276 | irq -= NUBUS_SOURCE_BASE; | ||
277 | return oss->irq_pending & (1 << irq); | ||
278 | break; | ||
279 | } | ||
280 | return 0; | ||
281 | } | 228 | } |