aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/mac/oss.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/mac/oss.c')
-rw-r--r--arch/m68k/mac/oss.c157
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 @@
30int oss_present; 30int oss_present;
31volatile struct mac_oss *oss; 31volatile struct mac_oss *oss;
32 32
33extern 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
73static void oss_irq(unsigned int irq, struct irq_desc *desc) 68static 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
137void __init oss_register_interrupts(void) 144void __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
230void 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
258int 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}