X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fm68k%2Fatari%2Fataints.c;fp=arch%2Fm68k%2Fatari%2Fataints.c;h=076f4791784256a03482aa0dcda3311e34e15ae2;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=ece13cbf9950a1b69a966b2b99766eeeeeca2be7;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index ece13cbf9..076f47917 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -104,7 +104,6 @@ * 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; +} + +