+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;
+}
+
+