2 * arch/m68k/q40/q40ints.c
4 * Copyright (C) 1999 Richard Zidlicky
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
10 * losely based on bvme6000ints.c
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
19 #include <asm/ptrace.h>
20 #include <asm/system.h>
22 #include <asm/traps.h>
24 #include <asm/q40_master.h>
25 #include <asm/q40ints.h>
28 * Q40 IRQs are defined as follows:
29 * 3,4,5,6,7,10,11,14,15 : ISA dev IRQs
32 * 33 : frame int (50/200 Hz periodic timer)
33 * 34 : sample int (10/20 KHz periodic timer)
37 extern int ints_inited
;
40 void q40_irq2_handler (int, void *, struct pt_regs
*fp
);
43 extern void (*q40_sys_default_handler
[]) (int, void *, struct pt_regs
*); /* added just for debugging */
45 static void q40_defhand (int irq
, void *dev_id
, struct pt_regs
*fp
);
46 static void sys_default_handler(int lev
, void *dev_id
, struct pt_regs
*regs
);
49 #define DEVNAME_SIZE 24
51 static struct q40_irq_node
{
52 void (*handler
)(int, void *, struct pt_regs
*);
55 /* struct q40_irq_node *next;*/
56 char devname
[DEVNAME_SIZE
];
59 } irq_tab
[Q40_IRQ_MAX
+1];
61 short unsigned q40_ablecount
[Q40_IRQ_MAX
+1];
64 * void q40_init_IRQ (void)
70 * This function is called during kernel startup to initialize
71 * the q40 IRQ handling routines.
74 void q40_init_IRQ (void)
78 for (i
= 0; i
<= Q40_IRQ_MAX
; i
++) {
79 irq_tab
[i
].handler
= q40_defhand
;
80 irq_tab
[i
].flags
= IRQ_FLG_STD
;
81 irq_tab
[i
].dev_id
= NULL
;
82 /* irq_tab[i].next = NULL;*/
83 irq_tab
[i
].devname
[0] = 0;
86 q40_ablecount
[i
]=0; /* all enabled */
89 /* setup handler for ISA ints */
90 sys_request_irq(IRQ2
,q40_irq2_handler
, IRQ_FLG_LOCK
, "q40 ISA and master chip", NULL
);
92 /* now enable some ints.. */
94 #if 0 /* has been abandoned */
95 master_outb(1,SER_ENABLE_REG
);
97 master_outb(1,EXT_ENABLE_REG
);
99 /* would be spurious ints by now, q40kbd_init_hw() does that */
100 master_outb(0,KEY_IRQ_ENABLE_REG
);
103 int q40_request_irq(unsigned int irq
,
104 void (*handler
)(int, void *, struct pt_regs
*),
105 unsigned long flags
, const char *devname
, void *dev_id
)
107 /*printk("q40_request_irq %d, %s\n",irq,devname);*/
109 if (irq
> Q40_IRQ_MAX
|| (irq
>15 && irq
<32)) {
110 printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__
, irq
, devname
);
114 /* test for ISA ints not implemented by HW */
117 case 1: case 2: case 8: case 9:
119 printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__
, irq
, devname
);
122 printk("warning IRQ 10 and 11 not distinguishable\n");
127 if (irq
<Q40_IRQ_TIMER
)
129 if (!(irq_tab
[irq
].flags
& IRQ_FLG_STD
))
131 if (irq_tab
[irq
].flags
& IRQ_FLG_LOCK
)
133 printk("%s: IRQ %d from %s is not replaceable\n",
134 __FUNCTION__
, irq
, irq_tab
[irq
].devname
);
137 if (flags
& IRQ_FLG_REPLACE
)
139 printk("%s: %s can't replace IRQ %d from %s\n",
140 __FUNCTION__
, devname
, irq
, irq_tab
[irq
].devname
);
144 /*printk("IRQ %d set to handler %p\n",irq,handler);*/
145 irq_tab
[irq
].handler
= handler
;
146 irq_tab
[irq
].flags
= flags
;
147 irq_tab
[irq
].dev_id
= dev_id
;
148 strncpy(irq_tab
[irq
].devname
,devname
,DEVNAME_SIZE
);
149 irq_tab
[irq
].state
= 0;
153 /* Q40_IRQ_TIMER :somewhat special actions required here ..*/
154 sys_request_irq(4,handler
,flags
,devname
,dev_id
);
155 sys_request_irq(6,handler
,flags
,devname
,dev_id
);
160 void q40_free_irq(unsigned int irq
, void *dev_id
)
162 if (irq
> Q40_IRQ_MAX
|| (irq
>15 && irq
<32)) {
163 printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__
, irq
, (unsigned)dev_id
);
167 /* test for ISA ints not implemented by HW */
170 case 1: case 2: case 8: case 9:
172 printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__
, irq
, (unsigned)dev_id
);
178 if (irq
<Q40_IRQ_TIMER
)
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
);
184 irq_tab
[irq
].handler
= q40_defhand
;
185 irq_tab
[irq
].flags
= IRQ_FLG_STD
;
186 irq_tab
[irq
].dev_id
= NULL
;
187 /* irq_tab[irq].devname = NULL; */
188 /* do not reset state !! */
191 { /* == Q40_IRQ_TIMER */
192 sys_free_irq(4,dev_id
);
193 sys_free_irq(6,dev_id
);
198 void q40_process_int (int level
, struct pt_regs
*fp
)
200 printk("unexpected interrupt %x\n",level
);
205 * tables to translate bits into IRQ numbers
206 * it is a good idea to order the entries by priority
210 struct IRQ_TABLE
{ unsigned mask
; int irq
;};
212 static struct IRQ_TABLE iirqs
[]={
213 {IRQ_FRAME_MASK
,Q40_IRQ_FRAME
},
214 {IRQ_KEYB_MASK
,Q40_IRQ_KEYBOARD
},
216 static struct IRQ_TABLE eirqs
[]={
217 {IRQ3_MASK
,3}, /* ser 1 */
218 {IRQ4_MASK
,4}, /* ser 2 */
219 {IRQ14_MASK
,14}, /* IDE 1 */
220 {IRQ15_MASK
,15}, /* IDE 2 */
221 {IRQ6_MASK
,6}, /* floppy */
222 {IRQ7_MASK
,7}, /* par */
232 /* complain only this many times about spurious ints : */
233 static int ccleirq
=60; /* ISA dev IRQ's*/
234 static int cclirq
=60; /* internal */
236 /* FIX: add shared ints,mask,unmask,probing.... */
238 /* this is an awfull hack.. */
239 #define IRQ_INPROGRESS 1
240 static int disabled
=0;
241 /*static unsigned short saved_mask;*/
243 void q40_irq2_handler (int vec
, void *devname
, struct pt_regs
*fp
)
245 /* got level 2 interrupt, dispatch to ISA or keyboard IRQs */
247 unsigned mir
=master_inb(IIRQ_REG
);
251 if ((mir
&IRQ_SER_MASK
) || (mir
&IRQ_EXT_MASK
))
254 /* some ISA dev caused the int */
256 mer
=master_inb(EIRQ_REG
);
258 for (i
=0; eirqs
[i
].mask
; i
++)
260 if (mer
&(eirqs
[i
].mask
))
263 irq_tab
[irq
].count
++;
264 if (irq_tab
[irq
].handler
== q40_defhand
)
266 printk("handler for IRQ %d not defined\n",irq
);
267 continue; /* ignore uninited INTs :-( */
270 if ( irq_tab
[irq
].state
& IRQ_INPROGRESS
)
272 /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */
274 /*saved_mask = fp->sr;*/
275 fp
->sr
= (fp
->sr
& (~0x700))+0x200;
279 irq_tab
[irq
].state
|= IRQ_INPROGRESS
;
280 irq_tab
[irq
].handler(irq
,irq_tab
[irq
].dev_id
,fp
);
282 /* naively enable everything, if that fails than */
283 /* this function will be reentered immediately thus */
284 /* getting another chance to disable the IRQ */
286 irq_tab
[irq
].state
&= ~IRQ_INPROGRESS
;
289 /*printk("reenabling irq %d\n",irq); */
290 fp
->sr
= (fp
->sr
& (~0x700)); /*saved_mask; */
293 else if ( fp
->sr
&0x200 )
294 printk("exiting irq handler: fp->sr &0x200 !!\n");
300 printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer
),ccleirq
--;
306 for (i
=0; iirqs
[i
].mask
; i
++)
308 if (mir
&(iirqs
[i
].mask
))
311 irq_tab
[irq
].count
++;
312 if (irq_tab
[irq
].handler
== q40_defhand
)
313 continue; /* ignore uninited INTs :-( */
315 /* the INPROGRESS stuff should be completely useless*/
316 /* for internal ints, nevertheless test it..*/
317 if ( irq_tab
[irq
].state
& IRQ_INPROGRESS
)
321 printk("rentering handler for IRQ %d !!\n",irq
);
323 irq_tab
[irq
].handler(irq
,irq_tab
[irq
].dev_id
,fp
);
324 irq_tab
[irq
].state
&= ~IRQ_INPROGRESS
;
325 /*enable_irq(irq);*/ /* better not try luck !*/
330 printk("internal level 2 interrupt from unknown source ? IIRQ_REG=%x\n",mir
),cclirq
--;
334 int q40_get_irq_list (char *buf
)
338 for (i
= 0; i
<= Q40_IRQ_MAX
; i
++) {
339 if (irq_tab
[i
].count
)
340 len
+= sprintf (buf
+len
, "Vec 0x%02x: %8d %s%s\n",
342 irq_tab
[i
].devname
[0] ? irq_tab
[i
].devname
: "?",
343 irq_tab
[i
].handler
== q40_defhand
?
344 " (now unassigned)" : "");
350 static void q40_defhand (int irq
, void *dev_id
, struct pt_regs
*fp
)
353 printk ("Unknown q40 interrupt 0x%02x\n", irq
);
356 static void sys_default_handler(int lev
, void *dev_id
, struct pt_regs
*regs
)
361 printk ("Uninitialised interrupt level %d\n", lev
);
364 printk ("Interrupt before interrupt initialisation\n");
368 void (*q40_sys_default_handler
[SYS_IRQS
]) (int, void *, struct pt_regs
*) = {
369 sys_default_handler
,sys_default_handler
,sys_default_handler
,sys_default_handler
,
370 sys_default_handler
,sys_default_handler
,sys_default_handler
,sys_default_handler
374 void q40_enable_irq (unsigned int irq
)
377 if ( irq
>=0 && irq
<=15 ) /* the moderately bad case */
378 master_outb(1,EXT_ENABLE_REG
);
383 if (irq
>=10 && irq
<= 15)
385 if ( !(--q40_ablecount
[irq
]))
386 for (i
=10,irq_disabled
=0; i
<=15; i
++)
388 irq_disabled
|= (q40_ablecount
[irq
] !=0);
393 restore_flags(flags
& (~0x700));
400 void q40_disable_irq (unsigned int irq
)
402 /* disable ISA iqs : only do something if the driver has been
403 * verified to be Q40 "compatible" - right now only IDE
404 * Any driver should not attempt to sleep accross disable_irq !!
407 if ( irq
>=10 && irq
<=15 ) /* the moderately bad case */
408 master_outb(0,EXT_ENABLE_REG
);
412 if (irq
>=10 && irq
<= 15)
415 restore_flags(flags
| 0x200 );
417 q40_ablecount
[irq
]++;
422 unsigned long q40_probe_irq_on (void)
424 printk("irq probing not working - reconfigure the driver to avoid this\n");
427 int q40_probe_irq_off (unsigned long irqs
)