patch-2.0.21-2.1.0 linux/arch/m68k/kernel/ints.c

Next file: linux/arch/m68k/kernel/ksyms.c
Previous file: linux/arch/m68k/kernel/head.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file lx2.0/v2.0.21/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
@@ -1,5 +1,5 @@
 /*
- * ints.c -- 680x0 Linux general interrupt handling code
+ * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
@@ -11,6 +11,18 @@
  *           remove_isr() to request_irq() and free_irq()
  *           respectively, so they are compliant with the other
  *           architectures.                                     /Jes
+ * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls.
+ *           Removed irq list support, if any machine needs an irq server
+ *           it must implement this itself (as it's already done), instead
+ *           only default handler are used with mach_default_handler.
+ *           request_irq got some flags different from other architectures:
+ *           - IRQ_FLG_REPLACE : Replace an existing handler (the default one
+ *                               can be replaced without this flag)
+ *           - IRQ_FLG_LOCK : handler can't be replaced
+ *           There are other machine depending flags, see there
+ *           If you want to replace a default handler you should know what
+ *           you're doing, since it might handle different other irq sources
+ *           which must be served                               /Roman Zippel
  */
 
 #include <linux/types.h>
@@ -24,14 +36,19 @@
 #include <asm/page.h>
 #include <asm/machdep.h>
 
-/* list is accessed 0-6 for IRQs 1-7 */
-static isr_node_t *isr_list[7];
+/* table for system interrupt handlers */
+static irq_handler_t irq_list[SYS_IRQS];
+
+static const char *default_names[SYS_IRQS] = {
+	"spurious int", "int1 handler", "int2 handler", "int3 handler",
+	"int4 handler", "int5 handler", "int6 handler", "int7 handler"
+};
 
 /* The number of spurious interrupts */
-volatile unsigned long num_spurious;
-/*
-unsigned long interrupt_stack[PAGE_SIZE/sizeof(long)];
-*/
+volatile unsigned int num_spurious;
+
+#define NUM_IRQ_NODES 100
+static irq_node_t nodes[NUM_IRQ_NODES];
 
 /*
  * void init_IRQ(void)
@@ -46,147 +63,85 @@
 
 void init_IRQ(void)
 {
-    /* Setup interrupt stack pointer */
-  /*
-    asm ("movec %0,%/isp"
-	 : : "r" (interrupt_stack + sizeof (interrupt_stack) / sizeof (long)));
-	 */
-    mach_init_INTS ();
-}
-
-void insert_isr (isr_node_t **listp, isr_node_t *node)
-{
-    unsigned long spl;
-    isr_node_t *cur;
-
-    save_flags(spl);
-    cli();
-
-    cur = *listp;
-
-    while (cur && cur->pri <= node->pri)
-    {
-	listp = &cur->next;
-	cur = cur->next;
-    }
-
-    node->next = cur;
-    *listp = node;
-
-    restore_flags(spl);
-}
-
-void delete_isr (isr_node_t **listp, isrfunc isr, void *data)
-{
-    unsigned long flags;
-    isr_node_t *np;
+	int i;
 
-    save_flags(flags);
-    cli();
-    for (np = *listp; np; listp = &np->next, np = *listp) {
-	if (np->isr == isr && np->data == data) {
-	    *listp = np->next;
-	    /* Mark it as free. */
-	    np->isr = NULL;
-	    restore_flags(flags);
-	    return;
+	for (i = 0; i < SYS_IRQS; i++) {
+		if (mach_default_handler)
+			irq_list[i].handler = (*mach_default_handler)[i];
+		irq_list[i].flags   = IRQ_FLG_STD;
+		irq_list[i].dev_id  = NULL;
+		irq_list[i].devname = default_names[i];
 	}
-    }
-    restore_flags(flags);
-    printk ("delete_isr: isr %p not found on list!\n", isr);
-}
 
-#define NUM_ISR_NODES 100
-static isr_node_t nodes[NUM_ISR_NODES];
-
-isr_node_t *new_isr_node(void)
-{
-    isr_node_t *np;
+	for (i = 0; i < NUM_IRQ_NODES; i++)
+		nodes[i].handler = NULL;
 
-    for (np = nodes; np < &nodes[NUM_ISR_NODES]; np++)
-	if (np->isr == NULL)
-	    return np;
-
-    printk ("new_isr_node: out of nodes");
-    return NULL;
+	mach_init_IRQ ();
 }
 
-int add_isr (unsigned long source, isrfunc isr, int pri, void *data,
-	     char *name)
+irq_node_t *new_irq_node(void)
 {
-    isr_node_t *p;
-
-    if (source & IRQ_MACHSPEC)
-    {
-	return mach_add_isr (source, isr, pri, data, name);
-    }
+	irq_node_t *node;
+	short i;
 
-    if (source < IRQ1 || source > IRQ7)
-	panic ("add_isr: Incorrect IRQ source %ld from %s\n", source, name);
+	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
+		if (!node->handler)
+			return node;
 
-    p = new_isr_node();
-    if (p == NULL)
-	return 0;
-    p->isr = isr;
-    p->pri = pri;
-    p->data = data;
-    p->name = name;
-    p->next = NULL;
-
-    insert_isr (&isr_list[source-1], p);
-
-    return 1;
+	printk ("new_irq_node: out of nodes\n");
+	return NULL;
 }
 
-int remove_isr (unsigned long source, isrfunc isr, void *data)
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
 {
-    if (source & IRQ_MACHSPEC)
-	return mach_remove_isr (source, isr, data);
-
-    if (source < IRQ1 || source > IRQ7) {
-	printk ("remove_isr: Incorrect IRQ source %ld\n", source);
-	return 0;
-    }
+	if (irq & IRQ_MACHSPEC)
+		return mach_request_irq(IRQ_IDX(irq), handler, flags, devname, dev_id);
 
-    delete_isr (&isr_list[source - 1], isr, data);
-    return 1;
-}
+	if (irq < IRQ1 || irq > IRQ7) {
+		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
 
-void call_isr_list(int irq, isr_node_t *p, struct pt_regs *fp)
-{
-    while (p) {
-	p->isr (irq, fp, p->data);
-	p = p->next;
-    }
+	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
+		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %d from %s is not replaceable\n",
+			       __FUNCTION__, irq, irq_list[irq].devname);
+			return -EBUSY;
+		}
+		if (flags & IRQ_FLG_REPLACE) {
+			printk("%s: %s can't replace IRQ %d from %s\n",
+			       __FUNCTION__, devname, irq, irq_list[irq].devname);
+			return -EBUSY;
+		}
+	}
+	irq_list[irq].handler = handler;
+	irq_list[irq].flags   = flags;
+	irq_list[irq].dev_id  = dev_id;
+	irq_list[irq].devname = devname;
+	return 0;
 }
 
-asmlinkage void process_int(int vec, struct pt_regs *regs)
+void free_irq(unsigned int irq, void *dev_id)
 {
-	int level;
-
-	if (vec >= VECOFF(VEC_INT1) && vec <= VECOFF(VEC_INT7))
-		level = (vec - VECOFF(VEC_SPUR)) >> 2;
-	else {
-		if (mach_process_int)
-			mach_process_int(vec, regs);
-		else
-			panic("Can't process interrupt vector 0x%03x\n", vec);
+	if (irq & IRQ_MACHSPEC) {
+		mach_free_irq(IRQ_IDX(irq), dev_id);
 		return;
 	}
 
-	kstat.interrupts[level]++;  	
-	call_isr_list (level, isr_list[level-1], regs);
-}
-
-int request_irq(unsigned int irq,
-		void (*handler)(int, void *, struct pt_regs *),
-		unsigned long flags, const char * devname, void *dev_id)
-{
-	return -EINVAL;
-}
+	if (irq < IRQ1 || irq > IRQ7) {
+		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
 
-void free_irq(unsigned int irq, void *dev_id)
-{
+	if (irq_list[irq].dev_id != dev_id)
+		printk("%s: Removing probably wrong IRQ %d from %s\n",
+		       __FUNCTION__, irq, irq_list[irq].devname);
+
+	irq_list[irq].handler = (*mach_default_handler)[irq];
+	irq_list[irq].flags   = IRQ_FLG_STD;
+	irq_list[irq].dev_id  = NULL;
+	irq_list[irq].devname = default_names[irq];
 }
 
 /*
@@ -194,43 +149,58 @@
  */
 unsigned long probe_irq_on (void)
 {
-  return 0;
+	return 0;
 }
 
 int probe_irq_off (unsigned long irqs)
 {
-  return 0;
+	return 0;
 }
 
-void enable_irq(unsigned int irq_nr)
+void enable_irq(unsigned int irq)
 {
-	if ((irq_nr & IRQ_MACHSPEC) && mach_enable_irq)
-		mach_enable_irq(irq_nr);
+	if ((irq & IRQ_MACHSPEC) && mach_enable_irq)
+		mach_enable_irq(IRQ_IDX(irq));
 }
 
-void disable_irq(unsigned int irq_nr)
+void disable_irq(unsigned int irq)
 {
-	if ((irq_nr & IRQ_MACHSPEC) && mach_disable_irq)
-		mach_disable_irq(irq_nr);
+	if ((irq & IRQ_MACHSPEC) && mach_disable_irq)
+		mach_disable_irq(IRQ_IDX(irq));
+}
+
+asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
+{
+	if (vec < VEC_INT1 || vec > VEC_INT7) {
+		if (mach_process_int)
+			mach_process_int(vec, fp);
+		else
+			panic("Can't process interrupt vector %ld\n", vec);
+		return;
+	}
+
+	vec -= VEC_SPUR;
+	kstat.interrupts[vec]++;
+	irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
 }
 
 int get_irq_list(char *buf)
 {
-    int i, len = 0;
-    isr_node_t *p;
-    
-    /* autovector interrupts */
-    for (i = IRQ1; i <= IRQ7; ++i) {
-	if (!isr_list[i-1])
-	    continue;
-	len += sprintf(buf+len, "auto %2d: %8d ", i, kstat.interrupts[i]);
-	for (p = isr_list[i-1]; p; p = p->next) {
-	    len += sprintf(buf+len, "%s\n", p->name);
-	    if (p->next)
-		len += sprintf(buf+len, "                  ");
+	int i, len = 0;
+
+	/* autovector interrupts */
+	if (mach_default_handler) {
+		for (i = 0; i < SYS_IRQS; i++) {
+			len += sprintf(buf+len, "auto %2d: %10u ", i,
+			               i ? kstat.interrupts[i] : num_spurious);
+			if (irq_list[i].flags & IRQ_FLG_LOCK)
+				len += sprintf(buf+len, "L ");
+			else
+				len += sprintf(buf+len, "  ");
+			len += sprintf(buf+len, "%s\n", irq_list[i].devname);
+		}
 	}
-    }
 
-    len = mach_get_irq_list(buf, len);
-    return len;
+	len += mach_get_irq_list(buf+len);
+	return len;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov