* the sr copy in the frame.
*/
-#if 0
#define NUM_INT_SOURCES (8 + NUM_ATARI_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 && \
);
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 :-)
"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)
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) */
* 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)
}
+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).
{
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;
+}
+
+