aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/q40/q40ints.c
diff options
context:
space:
mode:
authorRoman Zippel <zippel@linux-m68k.org>2006-06-25 08:47:05 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:00:58 -0400
commit77dda339e512c729bb27abd452e6632465490986 (patch)
tree6c3bdba69fbf9b27ebf2dfe4e52a78d14d649390 /arch/m68k/q40/q40ints.c
parent9c5f4afdfbe72d5d1c814ad7286a4524d00c7b96 (diff)
[PATCH] m68k: convert q40 irq code
Signed-off-by: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/m68k/q40/q40ints.c')
-rw-r--r--arch/m68k/q40/q40ints.c464
1 files changed, 168 insertions, 296 deletions
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index ff80cba110d4..472f41c4158b 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -14,13 +14,8 @@
14#include <linux/types.h> 14#include <linux/types.h>
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/string.h>
18#include <linux/sched.h>
19#include <linux/seq_file.h>
20#include <linux/interrupt.h> 17#include <linux/interrupt.h>
21#include <linux/hardirq.h>
22 18
23#include <asm/rtc.h>
24#include <asm/ptrace.h> 19#include <asm/ptrace.h>
25#include <asm/system.h> 20#include <asm/system.h>
26#include <asm/irq.h> 21#include <asm/irq.h>
@@ -39,28 +34,37 @@
39 * 34 *
40*/ 35*/
41 36
42extern int ints_inited; 37static void q40_irq_handler(unsigned int, struct pt_regs *fp);
38static void q40_enable_irq(unsigned int);
39static void q40_disable_irq(unsigned int);
43 40
41unsigned short q40_ablecount[35];
42unsigned short q40_state[35];
44 43
45irqreturn_t q40_irq2_handler (int, void *, struct pt_regs *fp); 44static int q40_irq_startup(unsigned int irq)
46 45{
47 46 /* test for ISA ints not implemented by HW */
48static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp); 47 switch (irq) {
49 48 case 1: case 2: case 8: case 9:
50 49 case 11: case 12: case 13:
51#define DEVNAME_SIZE 24 50 printk("%s: ISA IRQ %d not implemented by HW\n", __FUNCTION__, irq);
51 return -ENXIO;
52 }
53 return 0;
54}
52 55
53static struct q40_irq_node { 56static void q40_irq_shutdown(unsigned int irq)
54 irqreturn_t (*handler)(int, void *, struct pt_regs *); 57{
55 unsigned long flags; 58}
56 void *dev_id;
57 /* struct q40_irq_node *next;*/
58 char devname[DEVNAME_SIZE];
59 unsigned count;
60 unsigned short state;
61} irq_tab[Q40_IRQ_MAX+1];
62 59
63short unsigned q40_ablecount[Q40_IRQ_MAX+1]; 60static struct irq_controller q40_irq_controller = {
61 .name = "q40",
62 .lock = SPIN_LOCK_UNLOCKED,
63 .startup = q40_irq_startup,
64 .shutdown = q40_irq_shutdown,
65 .enable = q40_enable_irq,
66 .disable = q40_disable_irq,
67};
64 68
65/* 69/*
66 * void q40_init_IRQ (void) 70 * void q40_init_IRQ (void)
@@ -73,139 +77,29 @@ short unsigned q40_ablecount[Q40_IRQ_MAX+1];
73 * the q40 IRQ handling routines. 77 * the q40 IRQ handling routines.
74 */ 78 */
75 79
76static int disabled=0; 80static int disabled;
77 81
78void q40_init_IRQ (void) 82void q40_init_IRQ(void)
79{ 83{
80 int i; 84 m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX);
81
82 disabled=0;
83 for (i = 0; i <= Q40_IRQ_MAX; i++) {
84 irq_tab[i].handler = q40_defhand;
85 irq_tab[i].flags = 0;
86 irq_tab[i].dev_id = NULL;
87 /* irq_tab[i].next = NULL;*/
88 irq_tab[i].devname[0] = 0;
89 irq_tab[i].count = 0;
90 irq_tab[i].state =0;
91 q40_ablecount[i]=0; /* all enabled */
92 }
93 85
94 /* setup handler for ISA ints */ 86 /* setup handler for ISA ints */
95 cpu_request_irq(IRQ_AUTO_2, q40_irq2_handler, 0, 87 m68k_setup_auto_interrupt(q40_irq_handler);
96 "q40 ISA and master chip", NULL); 88
89 m68k_irq_startup(IRQ_AUTO_2);
90 m68k_irq_startup(IRQ_AUTO_4);
97 91
98 /* now enable some ints.. */ 92 /* now enable some ints.. */
99 master_outb(1,EXT_ENABLE_REG); /* ISA IRQ 5-15 */ 93 master_outb(1, EXT_ENABLE_REG); /* ISA IRQ 5-15 */
100 94
101 /* make sure keyboard IRQ is disabled */ 95 /* make sure keyboard IRQ is disabled */
102 master_outb(0,KEY_IRQ_ENABLE_REG); 96 master_outb(0, KEY_IRQ_ENABLE_REG);
103} 97}
104 98
105int q40_request_irq(unsigned int irq,
106 irqreturn_t (*handler)(int, void *, struct pt_regs *),
107 unsigned long flags, const char *devname, void *dev_id)
108{
109 /*printk("q40_request_irq %d, %s\n",irq,devname);*/
110
111 if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
112 printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
113 return -ENXIO;
114 }
115
116 /* test for ISA ints not implemented by HW */
117 switch (irq)
118 {
119 case 1: case 2: case 8: case 9:
120 case 12: case 13:
121 printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
122 return -ENXIO;
123 case 11:
124 printk("warning IRQ 10 and 11 not distinguishable\n");
125 irq=10;
126 default:
127 ;
128 }
129
130 if (irq<Q40_IRQ_SAMPLE)
131 {
132 if (irq_tab[irq].dev_id != NULL)
133 {
134 printk("%s: IRQ %d from %s is not replaceable\n",
135 __FUNCTION__, irq, irq_tab[irq].devname);
136 return -EBUSY;
137 }
138 /*printk("IRQ %d set to handler %p\n",irq,handler);*/
139 if (dev_id==NULL)
140 {
141 printk("WARNING: dev_id == NULL in request_irq\n");
142 dev_id=(void*)1;
143 }
144 irq_tab[irq].handler = handler;
145 irq_tab[irq].flags = flags;
146 irq_tab[irq].dev_id = dev_id;
147 strlcpy(irq_tab[irq].devname,devname,sizeof(irq_tab[irq].devname));
148 irq_tab[irq].state = 0;
149 return 0;
150 }
151 else {
152 /* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/
153 cpu_request_irq(4, handler, flags, devname, dev_id);
154 cpu_request_irq(6, handler, flags, devname, dev_id);
155 return 0;
156 }
157}
158
159void q40_free_irq(unsigned int irq, void *dev_id)
160{
161 if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
162 printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id);
163 return;
164 }
165
166 /* test for ISA ints not implemented by HW */
167 switch (irq)
168 {
169 case 1: case 2: case 8: case 9:
170 case 12: case 13:
171 printk("%s: ISA IRQ %d from %x invalid\n", __FUNCTION__, irq, (unsigned)dev_id);
172 return;
173 case 11: irq=10;
174 default:
175 ;
176 }
177
178 if (irq<Q40_IRQ_SAMPLE)
179 {
180 if (irq_tab[irq].dev_id != dev_id)
181 printk("%s: Removing probably wrong IRQ %d from %s\n",
182 __FUNCTION__, irq, irq_tab[irq].devname);
183
184 irq_tab[irq].handler = q40_defhand;
185 irq_tab[irq].flags = 0;
186 irq_tab[irq].dev_id = NULL;
187 /* irq_tab[irq].devname = NULL; */
188 /* do not reset state !! */
189 }
190 else
191 { /* == Q40_IRQ_SAMPLE */
192 cpu_free_irq(4, dev_id);
193 cpu_free_irq(6, dev_id);
194 }
195}
196
197
198irqreturn_t q40_process_int (int level, struct pt_regs *fp)
199{
200 printk("unexpected interrupt vec=%x, pc=%lx, d0=%lx, d0_orig=%lx, d1=%lx, d2=%lx\n",
201 level, fp->pc, fp->d0, fp->orig_d0, fp->d1, fp->d2);
202 printk("\tIIRQ_REG = %x, EIRQ_REG = %x\n",master_inb(IIRQ_REG),master_inb(EIRQ_REG));
203 return IRQ_HANDLED;
204}
205 99
206/* 100/*
207 * this stuff doesn't really belong here.. 101 * this stuff doesn't really belong here..
208*/ 102 */
209 103
210int ql_ticks; /* 200Hz ticks since last jiffie */ 104int ql_ticks; /* 200Hz ticks since last jiffie */
211static int sound_ticks; 105static int sound_ticks;
@@ -214,54 +108,53 @@ static int sound_ticks;
214 108
215void q40_mksound(unsigned int hz, unsigned int ticks) 109void q40_mksound(unsigned int hz, unsigned int ticks)
216{ 110{
217 /* for now ignore hz, except that hz==0 switches off sound */ 111 /* for now ignore hz, except that hz==0 switches off sound */
218 /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */ 112 /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
219 if (hz==0) 113 if (hz == 0) {
220 { 114 if (sound_ticks)
221 if (sound_ticks) 115 sound_ticks = 1;
222 sound_ticks=1; 116
223 117 *DAC_LEFT = 128;
224 *DAC_LEFT=128; 118 *DAC_RIGHT = 128;
225 *DAC_RIGHT=128; 119
226 120 return;
227 return; 121 }
228 } 122 /* sound itself is done in q40_timer_int */
229 /* sound itself is done in q40_timer_int */ 123 if (sound_ticks == 0)
230 if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */ 124 sound_ticks = 1000; /* pretty long beep */
231 sound_ticks=ticks<<1; 125 sound_ticks = ticks << 1;
232} 126}
233 127
234static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *); 128static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *);
235 129
236static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs) 130static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs)
237{ 131{
238 ql_ticks = ql_ticks ? 0 : 1; 132 ql_ticks = ql_ticks ? 0 : 1;
239 if (sound_ticks) 133 if (sound_ticks) {
240 { 134 unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
241 unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL; 135 sound_ticks--;
242 sound_ticks--; 136 *DAC_LEFT=sval;
243 *DAC_LEFT=sval; 137 *DAC_RIGHT=sval;
244 *DAC_RIGHT=sval; 138 }
245 } 139
246 140 if (!ql_ticks)
247 if (!ql_ticks) 141 q40_timer_routine(irq, dev, regs);
248 q40_timer_routine(irq, dev, regs); 142 return IRQ_HANDLED;
249 return IRQ_HANDLED;
250} 143}
251 144
252void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) 145void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
253{ 146{
254 int timer_irq; 147 int timer_irq;
255 148
256 q40_timer_routine = timer_routine; 149 q40_timer_routine = timer_routine;
257 timer_irq=Q40_IRQ_FRAME; 150 timer_irq = Q40_IRQ_FRAME;
258 151
259 if (request_irq(timer_irq, q40_timer_int, 0, 152 if (request_irq(timer_irq, q40_timer_int, 0,
260 "timer", q40_timer_int)) 153 "timer", q40_timer_int))
261 panic ("Couldn't register timer int"); 154 panic("Couldn't register timer int");
262 155
263 master_outb(-1,FRAME_CLEAR_REG); 156 master_outb(-1, FRAME_CLEAR_REG);
264 master_outb( 1,FRAME_RATE_REG); 157 master_outb( 1, FRAME_RATE_REG);
265} 158}
266 159
267 160
@@ -307,153 +200,132 @@ static int mext_disabled=0; /* ext irq disabled by master chip? */
307static int aliased_irq=0; /* how many times inside handler ?*/ 200static int aliased_irq=0; /* how many times inside handler ?*/
308 201
309 202
310/* got level 2 interrupt, dispatch to ISA or keyboard/timer IRQs */ 203/* got interrupt, dispatch to ISA or keyboard/timer IRQs */
311irqreturn_t q40_irq2_handler (int vec, void *devname, struct pt_regs *fp) 204static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
312{ 205{
313 unsigned mir, mer; 206 unsigned mir, mer;
314 int irq,i; 207 int i;
315 208
316//repeat: 209//repeat:
317 mir=master_inb(IIRQ_REG); 210 mir = master_inb(IIRQ_REG);
318 if (mir&Q40_IRQ_FRAME_MASK) { 211#ifdef CONFIG_BLK_DEV_FD
319 irq_tab[Q40_IRQ_FRAME].count++; 212 if ((mir & Q40_IRQ_EXT_MASK) &&
320 irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp); 213 (master_inb(EIRQ_REG) & Q40_IRQ6_MASK)) {
321 master_outb(-1,FRAME_CLEAR_REG); 214 floppy_hardint();
322 } 215 return;
323 if ((mir&Q40_IRQ_SER_MASK) || (mir&Q40_IRQ_EXT_MASK)) { 216 }
324 mer=master_inb(EIRQ_REG); 217#endif
325 for (i=0; eirqs[i].mask; i++) { 218 switch (irq) {
326 if (mer&(eirqs[i].mask)) { 219 case 4:
327 irq=eirqs[i].irq; 220 case 6:
221 m68k_handle_int(Q40_IRQ_SAMPLE, fp);
222 return;
223 }
224 if (mir & Q40_IRQ_FRAME_MASK) {
225 m68k_handle_int(Q40_IRQ_FRAME, fp);
226 master_outb(-1, FRAME_CLEAR_REG);
227 }
228 if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
229 mer = master_inb(EIRQ_REG);
230 for (i = 0; eirqs[i].mask; i++) {
231 if (mer & eirqs[i].mask) {
232 irq = eirqs[i].irq;
328/* 233/*
329 * There is a little mess wrt which IRQ really caused this irq request. The 234 * There is a little mess wrt which IRQ really caused this irq request. The
330 * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they 235 * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they
331 * are read - which is long after the request came in. In theory IRQs should 236 * are read - which is long after the request came in. In theory IRQs should
332 * not just go away but they occassionally do 237 * not just go away but they occassionally do
333 */ 238 */
334 if (irq>4 && irq<=15 && mext_disabled) { 239 if (irq > 4 && irq <= 15 && mext_disabled) {
335 /*aliased_irq++;*/ 240 /*aliased_irq++;*/
336 goto iirq; 241 goto iirq;
337 } 242 }
338 if (irq_tab[irq].handler == q40_defhand ) { 243 if (q40_state[irq] & IRQ_INPROGRESS) {
339 printk("handler for IRQ %d not defined\n",irq); 244 /* some handlers do local_irq_enable() for irq latency reasons, */
340 continue; /* ignore uninited INTs :-( */ 245 /* however reentering an active irq handler is not permitted */
341 }
342 if ( irq_tab[irq].state & IRQ_INPROGRESS ) {
343 /* some handlers do local_irq_enable() for irq latency reasons, */
344 /* however reentering an active irq handler is not permitted */
345#ifdef IP_USE_DISABLE 246#ifdef IP_USE_DISABLE
346 /* in theory this is the better way to do it because it still */ 247 /* in theory this is the better way to do it because it still */
347 /* lets through eg the serial irqs, unfortunately it crashes */ 248 /* lets through eg the serial irqs, unfortunately it crashes */
348 disable_irq(irq); 249 disable_irq(irq);
349 disabled=1; 250 disabled = 1;
350#else 251#else
351 /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */ 252 /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",
352 fp->sr = (((fp->sr) & (~0x700))+0x200); 253 irq, disabled ? "already" : "not yet"); */
353 disabled=1; 254 fp->sr = (((fp->sr) & (~0x700))+0x200);
255 disabled = 1;
354#endif 256#endif
355 goto iirq; 257 goto iirq;
356 } 258 }
357 irq_tab[irq].count++; 259 q40_state[irq] |= IRQ_INPROGRESS;
358 irq_tab[irq].state |= IRQ_INPROGRESS; 260 m68k_handle_int(irq, fp);
359 irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp); 261 q40_state[irq] &= ~IRQ_INPROGRESS;
360 irq_tab[irq].state &= ~IRQ_INPROGRESS; 262
361 263 /* naively enable everything, if that fails than */
362 /* naively enable everything, if that fails than */ 264 /* this function will be reentered immediately thus */
363 /* this function will be reentered immediately thus */ 265 /* getting another chance to disable the IRQ */
364 /* getting another chance to disable the IRQ */ 266
365 267 if (disabled) {
366 if ( disabled ) {
367#ifdef IP_USE_DISABLE 268#ifdef IP_USE_DISABLE
368 if (irq>4){ 269 if (irq > 4) {
369 disabled=0; 270 disabled = 0;
370 enable_irq(irq);} 271 enable_irq(irq);
272 }
371#else 273#else
372 disabled=0; 274 disabled = 0;
373 /*printk("reenabling irq %d\n",irq); */ 275 /*printk("reenabling irq %d\n", irq); */
374#endif 276#endif
375 } 277 }
376// used to do 'goto repeat;' here, this delayed bh processing too long 278// used to do 'goto repeat;' here, this delayed bh processing too long
377 return IRQ_HANDLED; 279 return;
378 } 280 }
379 } 281 }
380 if (mer && ccleirq>0 && !aliased_irq) 282 if (mer && ccleirq > 0 && !aliased_irq) {
381 printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--; 283 printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer);
382 } 284 ccleirq--;
383 iirq: 285 }
384 mir=master_inb(IIRQ_REG);
385 /* should test whether keyboard irq is really enabled, doing it in defhand */
386 if (mir&Q40_IRQ_KEYB_MASK) {
387 irq_tab[Q40_IRQ_KEYBOARD].count++;
388 irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp);
389 }
390 return IRQ_HANDLED;
391}
392
393int show_q40_interrupts (struct seq_file *p, void *v)
394{
395 int i;
396
397 for (i = 0; i <= Q40_IRQ_MAX; i++) {
398 if (irq_tab[i].count)
399 seq_printf(p, "%sIRQ %02d: %8d %s%s\n",
400 (i<=15) ? "ISA-" : " " ,
401 i, irq_tab[i].count,
402 irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
403 irq_tab[i].handler == q40_defhand ?
404 " (now unassigned)" : "");
405 } 286 }
406 return 0; 287 iirq:
407} 288 mir = master_inb(IIRQ_REG);
408 289 /* should test whether keyboard irq is really enabled, doing it in defhand */
290 if (mir & Q40_IRQ_KEYB_MASK)
291 m68k_handle_int(Q40_IRQ_KEYBOARD, fp);
409 292
410static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp) 293 return;
411{
412 if (irq!=Q40_IRQ_KEYBOARD)
413 printk ("Unknown q40 interrupt %d\n", irq);
414 else master_outb(-1,KEYBOARD_UNLOCK_REG);
415 return IRQ_NONE;
416} 294}
417 295
418 296void q40_enable_irq(unsigned int irq)
419void q40_enable_irq (unsigned int irq)
420{ 297{
421 if ( irq>=5 && irq<=15 ) 298 if (irq >= 5 && irq <= 15) {
422 { 299 mext_disabled--;
423 mext_disabled--; 300 if (mext_disabled > 0)
424 if (mext_disabled>0) 301 printk("q40_enable_irq : nested disable/enable\n");
425 printk("q40_enable_irq : nested disable/enable\n"); 302 if (mext_disabled == 0)
426 if (mext_disabled==0) 303 master_outb(1, EXT_ENABLE_REG);
427 master_outb(1,EXT_ENABLE_REG); 304 }
428 }
429} 305}
430 306
431 307
432void q40_disable_irq (unsigned int irq) 308void q40_disable_irq(unsigned int irq)
433{ 309{
434 /* disable ISA iqs : only do something if the driver has been 310 /* disable ISA iqs : only do something if the driver has been
435 * verified to be Q40 "compatible" - right now IDE, NE2K 311 * verified to be Q40 "compatible" - right now IDE, NE2K
436 * Any driver should not attempt to sleep across disable_irq !! 312 * Any driver should not attempt to sleep across disable_irq !!
437 */ 313 */
438 314
439 if ( irq>=5 && irq<=15 ) { 315 if (irq >= 5 && irq <= 15) {
440 master_outb(0,EXT_ENABLE_REG); 316 master_outb(0, EXT_ENABLE_REG);
441 mext_disabled++; 317 mext_disabled++;
442 if (mext_disabled>1) printk("disable_irq nesting count %d\n",mext_disabled); 318 if (mext_disabled > 1)
443 } 319 printk("disable_irq nesting count %d\n",mext_disabled);
320 }
444} 321}
445 322
446unsigned long q40_probe_irq_on (void) 323unsigned long q40_probe_irq_on(void)
447{ 324{
448 printk("irq probing not working - reconfigure the driver to avoid this\n"); 325 printk("irq probing not working - reconfigure the driver to avoid this\n");
449 return -1; 326 return -1;
450} 327}
451int q40_probe_irq_off (unsigned long irqs) 328int q40_probe_irq_off(unsigned long irqs)
452{ 329{
453 return -1; 330 return -1;
454} 331}
455/*
456 * Local variables:
457 * compile-command: "m68k-linux-gcc -D__KERNEL__ -I/home/rz/lx/linux-2.2.6/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -m68040 -c -o q40ints.o q40ints.c"
458 * End:
459 */