* better
[mascara-docs.git] / i386 / linux-2.3.21 / arch / m68k / q40 / q40ints.c
blobc6625aad8b09dd545d89714269c70ceaa411eaa0
1 /*
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
8 * for more details.
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>
21 #include <asm/irq.h>
22 #include <asm/traps.h>
24 #include <asm/q40_master.h>
25 #include <asm/q40ints.h>
27 /*
28 * Q40 IRQs are defined as follows:
29 * 3,4,5,6,7,10,11,14,15 : ISA dev IRQs
30 * 16-31: reserved
31 * 32 : keyboard int
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 *);
53 unsigned long flags;
54 void *dev_id;
55 /* struct q40_irq_node *next;*/
56 char devname[DEVNAME_SIZE];
57 unsigned count;
58 unsigned short state;
59 } irq_tab[Q40_IRQ_MAX+1];
61 short unsigned q40_ablecount[Q40_IRQ_MAX+1];
64 * void q40_init_IRQ (void)
66 * Parameters: None
68 * Returns: Nothing
70 * This function is called during kernel startup to initialize
71 * the q40 IRQ handling routines.
74 void q40_init_IRQ (void)
76 int i;
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;
84 irq_tab[i].count = 0;
85 irq_tab[i].state =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);
96 #endif
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);
111 return -ENXIO;
114 /* test for ISA ints not implemented by HW */
115 switch (irq)
117 case 1: case 2: case 8: case 9:
118 case 12: case 13:
119 printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
120 return -ENXIO;
121 case 11:
122 printk("warning IRQ 10 and 11 not distinguishable\n");
123 irq=10;
124 default:
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);
135 return -EBUSY;
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);
141 return -EBUSY;
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;
150 return 0;
152 else {
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);
156 return 0;
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);
164 return;
167 /* test for ISA ints not implemented by HW */
168 switch (irq)
170 case 1: case 2: case 8: case 9:
171 case 12: case 13:
172 printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
173 return;
174 case 11: irq=10;
175 default:
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 !! */
190 else
191 { /* == Q40_IRQ_TIMER */
192 sys_free_irq(4,dev_id);
193 sys_free_irq(6,dev_id);
197 #if 1
198 void q40_process_int (int level, struct pt_regs *fp)
200 printk("unexpected interrupt %x\n",level);
202 #endif
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},
215 {0,0}};
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 */
224 {IRQ5_MASK,5},
225 {IRQ10_MASK,10},
230 {0,0}};
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);
248 unsigned mer;
249 int irq,i;
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))
262 irq=eirqs[i].irq;
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;
276 disabled=1;
277 return;
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;
287 if ( disabled )
289 /*printk("reenabling irq %d\n",irq); */
290 fp->sr = (fp->sr & (~0x700)); /*saved_mask; */
291 disabled=0;
293 else if ( fp->sr &0x200 )
294 printk("exiting irq handler: fp->sr &0x200 !!\n");
296 return;
299 if (ccleirq>0)
300 printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
302 else
304 /* internal */
306 for (i=0; iirqs[i].mask; i++)
308 if (mir&(iirqs[i].mask))
310 irq=iirqs[i].irq;
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 )
319 /*disable_irq(irq);
320 return;*/
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 !*/
326 return;
329 if (cclirq>0)
330 printk("internal level 2 interrupt from unknown source ? IIRQ_REG=%x\n",mir),cclirq--;
334 int q40_get_irq_list (char *buf)
336 int i, len = 0;
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",
341 i, irq_tab[i].count,
342 irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
343 irq_tab[i].handler == q40_defhand ?
344 " (now unassigned)" : "");
346 return len;
350 static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
352 #if 0
353 printk ("Unknown q40 interrupt 0x%02x\n", irq);
354 #endif
356 static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
358 #if 0
359 if (ints_inited)
360 #endif
361 printk ("Uninitialised interrupt level %d\n", lev);
362 #if 0
363 else
364 printk ("Interrupt before interrupt initialisation\n");
365 #endif
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
373 int irq_disabled=0;
374 void q40_enable_irq (unsigned int irq)
376 /* enable ISA iqs */
377 if ( irq>=0 && irq<=15 ) /* the moderately bad case */
378 master_outb(1,EXT_ENABLE_REG);
379 #if 0
380 unsigned long flags;
381 int i;
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);
390 if ( !irq_disabled )
392 save_flags(flags);
393 restore_flags(flags & (~0x700));
396 #endif
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);
409 #if 0
410 unsigned long flags;
412 if (irq>=10 && irq <= 15)
414 save_flags(flags);
415 restore_flags(flags | 0x200 );
416 irq_disabled=1;
417 q40_ablecount[irq]++;
419 #endif
422 unsigned long q40_probe_irq_on (void)
424 printk("irq probing not working - reconfigure the driver to avoid this\n");
425 return -1;
427 int q40_probe_irq_off (unsigned long irqs)
429 return -1;