linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / m68k / atari / ataints.c
index ece13cb..076f479 100644 (file)
  * the sr copy in the frame.
  */
 
-#if 0
 
 #define        NUM_INT_SOURCES (8 + NUM_ATARI_SOURCES)
 
@@ -134,6 +133,13 @@ static struct irqhandler irq_handler[NUM_INT_SOURCES];
  */
 static struct irqparam irq_param[NUM_INT_SOURCES];
 
+/*
+ * Bitmap for free interrupt vector numbers
+ * (new vectors starting from 0x70 can be allocated by
+ * atari_register_vme_int())
+ */
+static int free_vme_vec_bitmap;
+
 /* check for valid int number (complex, sigh...) */
 #define        IS_VALID_INTNO(n)                                                                                       \
        ((n) > 0 &&                                                                                                             \
@@ -295,14 +301,6 @@ __asm__ (__ALIGN_STR "\n"
 );
        for (;;);
 }
-#endif
-
-/*
- * Bitmap for free interrupt vector numbers
- * (new vectors starting from 0x70 can be allocated by
- * atari_register_vme_int())
- */
-static int free_vme_vec_bitmap;
 
 /* GK:
  * HBL IRQ handler for Falcon. Nobody needs it :-)
@@ -315,33 +313,12 @@ __ALIGN_STR "\n\t"
        "orw    #0x200,%sp@\n\t"        /* set saved ipl to 2 */
        "rte");
 
-extern void atari_microwire_cmd(int cmd);
-
-extern int atari_SCC_reset_done;
-
-static int atari_startup_irq(unsigned int irq)
-{
-       m68k_irq_startup(irq);
-       atari_turnon_irq(irq);
-       atari_enable_irq(irq);
-       return 0;
-}
+/* Defined in entry.S; only increments 'num_spurious' */
+asmlinkage void bad_interrupt(void);
 
-static void atari_shutdown_irq(unsigned int irq)
-{
-       atari_disable_irq(irq);
-       atari_turnoff_irq(irq);
-       m68k_irq_shutdown(irq);
-}
+extern void atari_microwire_cmd( int cmd );
 
-static struct irq_controller atari_irq_controller = {
-       .name           = "atari",
-       .lock           = SPIN_LOCK_UNLOCKED,
-       .startup        = atari_startup_irq,
-       .shutdown       = atari_shutdown_irq,
-       .enable         = atari_enable_irq,
-       .disable        = atari_disable_irq,
-};
+extern int atari_SCC_reset_done;
 
 /*
  * void atari_init_IRQ (void)
@@ -356,8 +333,12 @@ static struct irq_controller atari_irq_controller = {
 
 void __init atari_init_IRQ(void)
 {
-       m68k_setup_user_interrupt(VEC_USER, 192, NULL);
-       m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1);
+       int i;
+
+       /* initialize the vector table */
+       for (i = 0; i < NUM_INT_SOURCES; ++i) {
+               vectors[IRQ_SOURCE_TO_VECTOR(i)] = bad_interrupt;
+       }
 
        /* Initialize the MFP(s) */
 
@@ -397,7 +378,8 @@ void __init atari_init_IRQ(void)
                                                                         * enabled in VME mask
                                                                         */
                tt_scu.vme_mask = 0x60;         /* enable MFP and SCC ints */
-       } else {
+       }
+       else {
                /* If no SCU and no Hades, the HSYNC interrupt needs to be
                 * disabled this way. (Else _inthandler in kernel/sys_call.S
                 * gets overruns)
@@ -422,6 +404,184 @@ void __init atari_init_IRQ(void)
 }
 
 
+static irqreturn_t atari_call_irq_list( int irq, void *dev_id, struct pt_regs *fp )
+{
+       irq_node_t *node;
+
+       for (node = (irq_node_t *)dev_id; node; node = node->next)
+               node->handler(irq, node->dev_id, fp);
+       return IRQ_HANDLED;
+}
+
+
+/*
+ * atari_request_irq : add an interrupt service routine for a particular
+ *                     machine specific interrupt source.
+ *                     If the addition was successful, it returns 0.
+ */
+
+int atari_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
+                      unsigned long flags, const char *devname, void *dev_id)
+{
+       int vector;
+       unsigned long oflags = flags;
+
+       /*
+        * The following is a hack to make some PCI card drivers work,
+        * which set the SA_SHIRQ flag.
+        */
+
+       flags &= ~SA_SHIRQ;
+
+       if (flags == SA_INTERRUPT) {
+               printk ("%s: SA_INTERRUPT changed to IRQ_TYPE_SLOW for %s\n",
+                       __FUNCTION__, devname);
+               flags = IRQ_TYPE_SLOW;
+       }
+       if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) {
+               printk ("%s: Bad irq type 0x%lx <0x%lx> requested from %s\n",
+                       __FUNCTION__, flags, oflags, devname);
+               return -EINVAL;
+       }
+       if (!IS_VALID_INTNO(irq)) {
+               printk ("%s: Unknown irq %d requested from %s\n",
+                       __FUNCTION__, irq, devname);
+               return -ENXIO;
+       }
+       vector = IRQ_SOURCE_TO_VECTOR(irq);
+
+       /*
+        * Check type/source combination: slow ints are (currently)
+        * only possible for MFP-interrupts.
+        */
+       if (flags == IRQ_TYPE_SLOW &&
+               (irq < STMFP_SOURCE_BASE || irq >= SCC_SOURCE_BASE)) {
+               printk ("%s: Slow irq requested for non-MFP source %d from %s\n",
+                       __FUNCTION__, irq, devname);
+               return -EINVAL;
+       }
+
+       if (vectors[vector] == bad_interrupt) {
+               /* int has no handler yet */
+               irq_handler[irq].handler = handler;
+               irq_handler[irq].dev_id  = dev_id;
+               irq_param[irq].flags   = flags;
+               irq_param[irq].devname = devname;
+               vectors[vector] =
+                       (flags == IRQ_TYPE_SLOW) ? slow_handlers[irq-STMFP_SOURCE_BASE] :
+                       (flags == IRQ_TYPE_FAST) ? atari_fast_irq_handler :
+                                                 atari_prio_irq_handler;
+               /* If MFP int, also enable and umask it */
+               atari_turnon_irq(irq);
+               atari_enable_irq(irq);
+
+               return 0;
+       }
+       else if (irq_param[irq].flags == flags) {
+               /* old handler is of same type -> handlers can be chained */
+               irq_node_t *node;
+               unsigned long flags;
+
+               local_irq_save(flags);
+
+               if (irq_handler[irq].handler != atari_call_irq_list) {
+                       /* Only one handler yet, make a node for this first one */
+                       if (!(node = new_irq_node()))
+                               return -ENOMEM;
+                       node->handler = irq_handler[irq].handler;
+                       node->dev_id  = irq_handler[irq].dev_id;
+                       node->devname = irq_param[irq].devname;
+                       node->next = NULL;
+
+                       irq_handler[irq].handler = atari_call_irq_list;
+                       irq_handler[irq].dev_id  = node;
+                       irq_param[irq].devname   = "chained";
+               }
+
+               if (!(node = new_irq_node()))
+                       return -ENOMEM;
+               node->handler = handler;
+               node->dev_id  = dev_id;
+               node->devname = devname;
+               /* new handlers are put in front of the queue */
+               node->next = irq_handler[irq].dev_id;
+               irq_handler[irq].dev_id = node;
+
+               local_irq_restore(flags);
+               return 0;
+       } else {
+               printk ("%s: Irq %d allocated by other type int (call from %s)\n",
+                       __FUNCTION__, irq, devname);
+               return -EBUSY;
+       }
+}
+
+void atari_free_irq(unsigned int irq, void *dev_id)
+{
+       unsigned long flags;
+       int vector;
+       irq_node_t **list, *node;
+
+       if (!IS_VALID_INTNO(irq)) {
+               printk("%s: Unknown irq %d\n", __FUNCTION__, irq);
+               return;
+       }
+
+       vector = IRQ_SOURCE_TO_VECTOR(irq);
+       if (vectors[vector] == bad_interrupt)
+               goto not_found;
+
+       local_irq_save(flags);
+
+       if (irq_handler[irq].handler != atari_call_irq_list) {
+               /* It's the only handler for the interrupt */
+               if (irq_handler[irq].dev_id != dev_id) {
+                       local_irq_restore(flags);
+                       goto not_found;
+               }
+               irq_handler[irq].handler = NULL;
+               irq_handler[irq].dev_id  = NULL;
+               irq_param[irq].devname   = NULL;
+               vectors[vector] = bad_interrupt;
+               /* If MFP int, also disable it */
+               atari_disable_irq(irq);
+               atari_turnoff_irq(irq);
+
+               local_irq_restore(flags);
+               return;
+       }
+
+       /* The interrupt is chained, find the irq on the list */
+       for(list = (irq_node_t **)&irq_handler[irq].dev_id; *list; list = &(*list)->next) {
+               if ((*list)->dev_id == dev_id) break;
+       }
+       if (!*list) {
+               local_irq_restore(flags);
+               goto not_found;
+       }
+
+       (*list)->handler = NULL; /* Mark it as free for reallocation */
+       *list = (*list)->next;
+
+       /* If there's now only one handler, unchain the interrupt, i.e. plug in
+        * the handler directly again and omit atari_call_irq_list */
+       node = (irq_node_t *)irq_handler[irq].dev_id;
+       if (node && !node->next) {
+               irq_handler[irq].handler = node->handler;
+               irq_handler[irq].dev_id  = node->dev_id;
+               irq_param[irq].devname   = node->devname;
+               node->handler = NULL; /* Mark it as free for reallocation */
+       }
+
+       local_irq_restore(flags);
+       return;
+
+not_found:
+       printk("%s: tried to remove invalid irq\n", __FUNCTION__);
+       return;
+}
+
+
 /*
  * atari_register_vme_int() returns the number of a free interrupt vector for
  * hardware with a programmable int vector (probably a VME board).
@@ -431,24 +591,58 @@ unsigned long atari_register_vme_int(void)
 {
        int i;
 
-       for (i = 0; i < 32; i++)
-               if ((free_vme_vec_bitmap & (1 << i)) == 0)
+       for(i = 0; i < 32; i++)
+               if((free_vme_vec_bitmap & (1 << i)) == 0)
                        break;
 
-       if (i == 16)
+       if(i == 16)
                return 0;
 
        free_vme_vec_bitmap |= 1 << i;
-       return VME_SOURCE_BASE + i;
+       return (VME_SOURCE_BASE + i);
 }
 
 
 void atari_unregister_vme_int(unsigned long irq)
 {
-       if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
+       if(irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
                irq -= VME_SOURCE_BASE;
                free_vme_vec_bitmap &= ~(1 << irq);
        }
 }
 
 
+int show_atari_interrupts(struct seq_file *p, void *v)
+{
+       int i;
+
+       for (i = 0; i < NUM_INT_SOURCES; ++i) {
+               if (vectors[IRQ_SOURCE_TO_VECTOR(i)] == bad_interrupt)
+                       continue;
+               if (i < STMFP_SOURCE_BASE)
+                       seq_printf(p, "auto %2d: %10u ",
+                                      i, kstat_cpu(0).irqs[i]);
+               else
+                       seq_printf(p, "vec $%02x: %10u ",
+                                      IRQ_SOURCE_TO_VECTOR(i),
+                                      kstat_cpu(0).irqs[i]);
+
+               if (irq_handler[i].handler != atari_call_irq_list) {
+                       seq_printf(p, "%s\n", irq_param[i].devname);
+               }
+               else {
+                       irq_node_t *n;
+                       for( n = (irq_node_t *)irq_handler[i].dev_id; n; n = n->next ) {
+                               seq_printf(p, "%s\n", n->devname);
+                               if (n->next)
+                                       seq_puts(p, "                    " );
+                       }
+               }
+       }
+       if (num_spurious)
+               seq_printf(p, "spurio.: %10u\n", num_spurious);
+
+       return 0;
+}
+
+