patch-2.4.0-test12 linux/arch/m68k/q40/q40ints.c
Next file: linux/arch/mips/ddb5074/pci.c
Previous file: linux/arch/m68k/q40/config.c
Back to the patch index
Back to the overall index
- Lines: 496
- Date:
Mon Nov 27 17:11:26 2000
- Orig file:
v2.4.0-test11/linux/arch/m68k/q40/q40ints.c
- Orig date:
Tue Aug 17 10:39:32 1999
diff -u --recursive --new-file v2.4.0-test11/linux/arch/m68k/q40/q40ints.c linux/arch/m68k/q40/q40ints.c
@@ -7,18 +7,22 @@
* License. See the file COPYING in the main directory of this archive
* for more details.
*
- * losely based on bvme6000ints.c
+ * .. used to be losely based on bvme6000ints.c
*
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/sched.h>
+#include <asm/rtc.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/irq.h>
+#include <asm/hardirq.h>
#include <asm/traps.h>
#include <asm/q40_master.h>
@@ -71,13 +75,16 @@
* the q40 IRQ handling routines.
*/
+static int disabled=0;
+
void q40_init_IRQ (void)
{
int i;
+ disabled=0;
for (i = 0; i <= Q40_IRQ_MAX; i++) {
irq_tab[i].handler = q40_defhand;
- irq_tab[i].flags = IRQ_FLG_STD;
+ irq_tab[i].flags = 0;
irq_tab[i].dev_id = NULL;
/* irq_tab[i].next = NULL;*/
irq_tab[i].devname[0] = 0;
@@ -87,14 +94,10 @@
}
/* setup handler for ISA ints */
- sys_request_irq(IRQ2,q40_irq2_handler, IRQ_FLG_LOCK, "q40 ISA and master chip", NULL);
+ sys_request_irq(IRQ2,q40_irq2_handler, 0, "q40 ISA and master chip", NULL);
/* now enable some ints.. */
-
-#if 0 /* has been abandoned */
- master_outb(1,SER_ENABLE_REG);
-#endif
- master_outb(1,EXT_ENABLE_REG);
+ master_outb(1,EXT_ENABLE_REG); /* hm, aint that too early? */
/* would be spurious ints by now, q40kbd_init_hw() does that */
master_outb(0,KEY_IRQ_ENABLE_REG);
@@ -124,24 +127,20 @@
default:
}
- if (irq<Q40_IRQ_TIMER)
+ if (irq<Q40_IRQ_SAMPLE)
{
- if (!(irq_tab[irq].flags & IRQ_FLG_STD))
- {
- if (irq_tab[irq].flags & IRQ_FLG_LOCK)
+ if (irq_tab[irq].dev_id != NULL)
{
printk("%s: IRQ %d from %s is not replaceable\n",
__FUNCTION__, irq, irq_tab[irq].devname);
return -EBUSY;
}
- if (flags & IRQ_FLG_REPLACE)
+ /*printk("IRQ %d set to handler %p\n",irq,handler);*/
+ if (dev_id==NULL)
{
- printk("%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, irq_tab[irq].devname);
- return -EBUSY;
- }
+ printk("WARNING: dev_id == NULL in request_irq\n");
+ dev_id=1;
}
- /*printk("IRQ %d set to handler %p\n",irq,handler);*/
irq_tab[irq].handler = handler;
irq_tab[irq].flags = flags;
irq_tab[irq].dev_id = dev_id;
@@ -150,7 +149,7 @@
return 0;
}
else {
- /* Q40_IRQ_TIMER :somewhat special actions required here ..*/
+ /* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/
sys_request_irq(4,handler,flags,devname,dev_id);
sys_request_irq(6,handler,flags,devname,dev_id);
return 0;
@@ -175,31 +174,120 @@
default:
}
- if (irq<Q40_IRQ_TIMER)
+ if (irq<Q40_IRQ_SAMPLE)
{
if (irq_tab[irq].dev_id != dev_id)
printk("%s: Removing probably wrong IRQ %d from %s\n",
__FUNCTION__, irq, irq_tab[irq].devname);
irq_tab[irq].handler = q40_defhand;
- irq_tab[irq].flags = IRQ_FLG_STD;
+ irq_tab[irq].flags = 0;
irq_tab[irq].dev_id = NULL;
/* irq_tab[irq].devname = NULL; */
/* do not reset state !! */
}
else
- { /* == Q40_IRQ_TIMER */
+ { /* == Q40_IRQ_SAMPLE */
sys_free_irq(4,dev_id);
sys_free_irq(6,dev_id);
}
}
-#if 1
+
void q40_process_int (int level, struct pt_regs *fp)
{
printk("unexpected interrupt %x\n",level);
}
+
+/*
+ * this stuff doesn't really belong here..
+*/
+int ql_ticks=0;
+static int sound_ticks=0;
+
+#define SVOL 45
+
+void q40_mksound(unsigned int hz, unsigned int ticks)
+{
+ /* for now ignore hz, except that hz==0 switches off sound */
+ /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
+ if (hz==0)
+ {
+ if (sound_ticks)
+ sound_ticks=1; /* atomic - no irq spinlock used */
+
+ *DAC_LEFT=128;
+ *DAC_RIGHT=128;
+
+ return;
+ }
+ /* sound itself is done in q40_timer_int */
+ if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
+ sound_ticks=ticks<<1;
+}
+
+static void (*q40_timer_routine)(int, void *, struct pt_regs *);
+static short rtc_oldsecs=0;
+unsigned rtc_irq_flags=0;
+unsigned rtc_irq_ctrl=0;
+
+static void q40_timer_int (int irq, void * dev, struct pt_regs * regs)
+{
+
+
+#if (HZ==100)
+ ql_ticks = ql_ticks ? 0 : 1;
+ if (sound_ticks)
+ {
+ unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
+ sound_ticks--;
+ *DAC_LEFT=sval;
+ *DAC_RIGHT=sval;
+ }
+#ifdef CONFIG_Q40RTC
+ if (rtc_irq_ctrl && (rtc_oldsecs != RTC_SECS))
+ {
+ rtc_oldsecs = RTC_SECS;
+ rtc_irq_flags = RTC_UIE;
+ rtc_interrupt();
+ }
+#endif
+ if (ql_ticks) return;
#endif
+ q40_timer_routine(irq, dev, regs);
+}
+
+void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+ int timer_irq;
+
+ q40_timer_routine = timer_routine;
+
+#if (HZ==10000)
+ timer_irq=Q40_IRQ_SAMPLE;
+#else
+ timer_irq=Q40_IRQ_FRAME;
+#endif
+
+ /*printk("registering sched/timer IRQ %d, handler %p\n", timer_irq,q40_timer_int);*/
+ /*printk("timer routine %p\n",q40_timer_routine);*/
+
+ if (request_irq(timer_irq, q40_timer_int, 0,
+ "timer", q40_timer_int))
+ panic ("Couldn't register timer int");
+
+#if (HZ==10000)
+ master_outb(SAMPLE_LOW,SAMPLE_RATE_REG);
+ master_outb(-1,SAMPLE_CLEAR_REG);
+ master_outb(1,SAMPLE_ENABLE_REG);
+#else
+ master_outb(-1,FRAME_CLEAR_REG); /* not necessary ? */
+#if (HZ==100)
+ master_outb( 1,FRAME_RATE_REG);
+#endif
+#endif
+}
+
/*
* tables to translate bits into IRQ numbers
@@ -208,11 +296,12 @@
*/
struct IRQ_TABLE{ unsigned mask; int irq ;};
-
+#if 0
static struct IRQ_TABLE iirqs[]={
{IRQ_FRAME_MASK,Q40_IRQ_FRAME},
{IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
{0,0}};
+#endif
static struct IRQ_TABLE eirqs[]={
{IRQ3_MASK,3}, /* ser 1 */
{IRQ4_MASK,4}, /* ser 2 */
@@ -231,103 +320,124 @@
/* complain only this many times about spurious ints : */
static int ccleirq=60; /* ISA dev IRQ's*/
-static int cclirq=60; /* internal */
+/*static int cclirq=60;*/ /* internal */
/* FIX: add shared ints,mask,unmask,probing.... */
-/* this is an awfull hack.. */
+
#define IRQ_INPROGRESS 1
-static int disabled=0;
/*static unsigned short saved_mask;*/
+static int do_tint=0;
+
+#define DEBUG_Q40INT
+#define IP_USE_DISABLE /* would be nice, but crashes ???? */
+/*static int dd_count=0;*/
+
+static int mext_disabled=0; /* ext irq disabled by master chip? */
+static int aliased_irq=0; /* how many times inside handler ?*/
+
+/* got level 2 interrupt, dispatch to ISA or keyboard/timer IRQs */
void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
{
- /* got level 2 interrupt, dispatch to ISA or keyboard IRQs */
-
- unsigned mir=master_inb(IIRQ_REG);
+ unsigned mir;
unsigned mer;
int irq,i;
+ repeat:
+ mir=master_inb(IIRQ_REG);
+ if (mir&IRQ_FRAME_MASK)
+ { /* dont loose ticks */
+ do_tint++;
+ master_outb(-1,FRAME_CLEAR_REG);
+ }
if ((mir&IRQ_SER_MASK) || (mir&IRQ_EXT_MASK))
{
-
/* some ISA dev caused the int */
-
mer=master_inb(EIRQ_REG);
-
for (i=0; eirqs[i].mask; i++)
{
if (mer&(eirqs[i].mask))
{
irq=eirqs[i].irq;
- irq_tab[irq].count++;
+/*
+ * There is a little mess wrt which IRQ really caused this irq request. The
+ * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they
+ * are read - which is long after the request came in. In theory IRQs should
+ * not just go away but they occassionally do
+ */
+ if (irq>4 && irq<=15 && mext_disabled)
+ {
+ /*aliased_irq++;*/
+ goto iirq;
+ }
if (irq_tab[irq].handler == q40_defhand )
{
printk("handler for IRQ %d not defined\n",irq);
continue; /* ignore uninited INTs :-( */
}
-
if ( irq_tab[irq].state & IRQ_INPROGRESS )
{
+ /* some handlers do sti() for irq latency reasons, */
+ /* however reentering an active irq handler is not permitted */
+#ifdef IP_USE_DISABLE
+ /* in theory this is the better way to do it because it still */
+ /* lets through eg the serial irqs, unfortunately it crashes */
+ disable_irq(irq);
+ disabled=1;
+#else
/*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */
-
- /*saved_mask = fp->sr;*/
- fp->sr = (fp->sr & (~0x700))+0x200;
+ fp->sr = (((fp->sr) & (~0x700))+0x200);
disabled=1;
- return;
+#endif
+ goto iirq;
}
+ irq_tab[irq].count++;
irq_tab[irq].state |= IRQ_INPROGRESS;
irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+ irq_tab[irq].state &= ~IRQ_INPROGRESS;
/* naively enable everything, if that fails than */
/* this function will be reentered immediately thus */
/* getting another chance to disable the IRQ */
- irq_tab[irq].state &= ~IRQ_INPROGRESS;
if ( disabled )
{
+#ifdef IP_USE_DISABLE
+ if (irq>4){
+ disabled=0;
+ /*dd_count--;*/
+ enable_irq(irq);}
+#else
+ disabled=0;
/*printk("reenabling irq %d\n",irq); */
- fp->sr = (fp->sr & (~0x700)); /*saved_mask; */
- disabled=0;
+#if 0
+ fp->sr = ((fp->sr) & (~0x700)); /* unneeded ?! */
+#endif
+#endif
}
- else if ( fp->sr &0x200 )
- printk("exiting irq handler: fp->sr &0x200 !!\n");
-
- return;
+ goto repeat; /* return; */
}
}
- if (ccleirq>0)
+ if (mer && ccleirq>0 && !aliased_irq)
printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
}
- else
+ iirq:
+ mir=master_inb(IIRQ_REG);
+ if (mir&IRQ_FRAME_MASK)
{
- /* internal */
-
- for (i=0; iirqs[i].mask; i++)
+ do_tint++;
+ master_outb(-1,FRAME_CLEAR_REG);
+ }
+ for(;do_tint>0;do_tint--)
{
- if (mir&(iirqs[i].mask))
- {
- irq=iirqs[i].irq;
- irq_tab[irq].count++;
- if (irq_tab[irq].handler == q40_defhand )
- continue; /* ignore uninited INTs :-( */
-
- /* the INPROGRESS stuff should be completely useless*/
- /* for internal ints, nevertheless test it..*/
- if ( irq_tab[irq].state & IRQ_INPROGRESS )
+ irq_tab[Q40_IRQ_FRAME].count++;
+ irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp);
+ }
+ if (mir&IRQ_KEYB_MASK) /* may handle it even if actually disabled*/
{
- /*disable_irq(irq);
- return;*/
- printk("rentering handler for IRQ %d !!\n",irq);
- }
- irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
- irq_tab[irq].state &= ~IRQ_INPROGRESS;
- /*enable_irq(irq);*/ /* better not try luck !*/
- return;
- }
- }
- if (cclirq>0)
- printk("internal level 2 interrupt from unknown source ? IIRQ_REG=%x\n",mir),cclirq--;
+ irq_tab[Q40_IRQ_KEYBOARD].count++;
+ irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp);
}
}
@@ -335,9 +445,11 @@
{
int i, len = 0;
- for (i = 0; i <= Q40_IRQ_MAX; i++) {
+ for (i = 0; i <= Q40_IRQ_MAX; i++)
+ {
if (irq_tab[i].count)
- len += sprintf (buf+len, "Vec 0x%02x: %8d %s%s\n",
+ len += sprintf (buf+len, "%sIRQ %02d: %8d %s%s\n",
+ (i<=15) ? "ISA-" : " " ,
i, irq_tab[i].count,
irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
irq_tab[i].handler == q40_defhand ?
@@ -370,30 +482,17 @@
sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler
};
-int irq_disabled=0;
+
void q40_enable_irq (unsigned int irq)
{
- /* enable ISA iqs */
- if ( irq>=0 && irq<=15 ) /* the moderately bad case */
+ if ( irq>=5 && irq<=15 )
+ {
+ mext_disabled--;
+ if (mext_disabled>0)
+ printk("q40_enable_irq : nested disable/enable\n");
+ if (mext_disabled==0)
master_outb(1,EXT_ENABLE_REG);
-#if 0
- unsigned long flags;
- int i;
-
- if (irq>=10 && irq <= 15)
- {
- if ( !(--q40_ablecount[irq]))
- for (i=10,irq_disabled=0; i<=15; i++)
- {
- irq_disabled |= (q40_ablecount[irq] !=0);
- }
- if ( !irq_disabled )
- {
- save_flags(flags);
- restore_flags(flags & (~0x700));
- }
}
-#endif
}
@@ -404,19 +503,12 @@
* Any driver should not attempt to sleep accross disable_irq !!
*/
- if ( irq>=10 && irq<=15 ) /* the moderately bad case */
- master_outb(0,EXT_ENABLE_REG);
-#if 0
- unsigned long flags;
-
- if (irq>=10 && irq <= 15)
+ if ( irq>=5 && irq<=15 )
{
- save_flags(flags);
- restore_flags(flags | 0x200 );
- irq_disabled=1;
- q40_ablecount[irq]++;
+ master_outb(0,EXT_ENABLE_REG);
+ mext_disabled++;
+ if (mext_disabled>1) printk("disable_irq nesting count %d\n",mext_disabled);
}
-#endif
}
unsigned long q40_probe_irq_on (void)
@@ -428,3 +520,7 @@
{
return -1;
}
+/*
+ * Local variables:
+ * 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"
+ */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)