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

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)