patch-1.3.70 linux/arch/mips/kernel/irq.c
Next file: linux/arch/ppc/kernel/irq.c
Previous file: linux/arch/i386/kernel/time.c
Back to the patch index
Back to the overall index
- Lines: 298
- Date:
Fri Mar 1 07:50:38 1996
- Orig file:
v1.3.69/linux/arch/mips/kernel/irq.c
- Orig date:
Sun Dec 17 11:43:10 1995
diff -u --recursive --new-file v1.3.69/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c
@@ -32,6 +32,7 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
+#include <linux/malloc.h>
#include <linux/random.h>
#include <asm/bitops.h>
@@ -42,6 +43,8 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
+#define TIMER_IRQ 0 /* Keep this in sync with time.c */
+
unsigned char cache_21 = 0xff;
unsigned char cache_A1 = 0xff;
@@ -98,36 +101,34 @@
/*
* Initial irq handlers.
*/
-struct irqaction {
- void (*handler)(int, struct pt_regs *);
- unsigned long flags;
- unsigned long mask;
- const char *name;
-};
-
-static struct irqaction irq_action[16] = {
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
+static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
+static struct irqaction cascade_irq = { NULL, 0, 0, NULL, NULL, NULL};
+static struct irqaction math_irq = { NULL, 0, 0, NULL, NULL, NULL};
+
+static struct irqaction *irq_action[16] = {
+ NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
};
int get_irq_list(char *buf)
{
int i, len = 0;
- struct irqaction * action = irq_action;
+ struct irqaction * action;
- for (i = 0 ; i < 16 ; i++, action++) {
- if (!action->handler)
- continue;
- len += sprintf(buf+len, "%3d: %8d %c %s\n",
+ for (i = 0 ; i < 16 ; i++) {
+ action = *(i + irq_action);
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
i, kstat.interrupts[i],
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, "\n");
}
return len;
}
@@ -141,12 +142,15 @@
*/
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action = *(irq + irq_action);
kstat.interrupts[irq]++;
if (action->flags & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
- action->handler(irq, regs);
+ while (action) {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ }
}
/*
@@ -156,38 +160,74 @@
*/
asmlinkage void do_fast_IRQ(int irq)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action = *(irq + irq_action);
kstat.interrupts[irq]++;
if (action->flags & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
- action->handler(irq, NULL);
+ while (action) {
+ action->handler(irq, action->dev_id, NULL);
+ action = action->next;
+ }
}
#define SA_PROBE SA_ONESHOT
-int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
- unsigned long irqflags, const char * devname)
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
{
- struct irqaction * action;
+ struct irqaction * action, *tmp = NULL;
unsigned long flags;
if (irq > 15)
return -EINVAL;
- action = irq + irq_action;
- if (action->handler)
- return -EBUSY;
if (!handler)
- return -EINVAL;
+ return -EINVAL;
+ action = *(irq + irq_action);
+ if (action) {
+ if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
+ for (tmp = action; tmp->next; tmp = tmp->next);
+ } else {
+ return -EBUSY;
+ }
+ if ((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+ printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
+ return -EBUSY;
+ }
+ }
if (irqflags & SA_SAMPLE_RANDOM)
rand_initialize_irq(irq);
save_flags(flags);
cli();
+ if (irq == 2)
+ action = &cascade_irq;
+ else if (irq == 13)
+ action = &math_irq;
+ else if (irq == TIMER_IRQ)
+ action = &timer_irq;
+ else
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+
+ if (!action) {
+ restore_flags(flags);
+ return -ENOMEM;
+ }
+
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
action->name = devname;
- if (!(action->flags & SA_PROBE)) { /* SA_ONESHOT is used by probing */
+ action->next = NULL;
+ action->dev_id = dev_id;
+
+ if (tmp) {
+ tmp->next = action;
+ } else {
+ *(irq + irq_action) = action;
+ if (!(action->flags & SA_PROBE)) {/* SA_ONESHOT used by probing */
/*
* FIXME: Does the SA_INTERRUPT flag make any sense on MIPS???
*/
@@ -195,23 +235,25 @@
set_int_vector(irq,fast_interrupt);
else
set_int_vector(irq,interrupt);
- }
- if (irq < 8) {
+ }
+ if (irq < 8) {
cache_21 &= ~(1<<irq);
outb(cache_21,0x21);
- } else {
+ } else {
cache_21 &= ~(1<<2);
cache_A1 &= ~(1<<(irq-8));
outb(cache_21,0x21);
outb(cache_A1,0xA1);
+ }
}
restore_flags(flags);
return 0;
}
-void free_irq(unsigned int irq)
+void free_irq(unsigned int irq, void *dev_id)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action = *(irq + irq_action);
+ struct irqaction * tmp = NULL;
unsigned long flags;
if (irq > 15) {
@@ -222,24 +264,46 @@
printk("Trying to free free IRQ%d\n",irq);
return;
}
+ if (dev_id) {
+ for (; action; action = action->next) {
+ if (action->dev_id == dev_id) break;
+ tmp = action;
+ }
+ if (!action) {
+ printk("Trying to free free shared IRQ%d\n",irq);
+ return;
+ }
+ } else if (action->flags & SA_SHIRQ) {
+ printk("Trying to free shared IRQ%d with NULL device ID\n", irq);
+ return;
+ }
save_flags(flags);
cli();
- if (irq < 8) {
+ if (action && tmp) {
+ tmp->next = action->next;
+ } else {
+ *(irq + irq_action) = action->next;
+ }
+
+ if ((irq == 2) || (irq == 13) | (irq == TIMER_IRQ))
+ memset(action, 0, sizeof(struct irqaction));
+ else
+ kfree_s(action, sizeof(struct irqaction));
+
+ if (!(*(irq + irq_action))) {
+ if (irq < 8) {
cache_21 |= 1 << irq;
outb(cache_21,0x21);
- } else {
+ } else {
cache_A1 |= 1 << (irq-8);
outb(cache_A1,0xA1);
+ }
+ set_int_vector(irq,bad_interrupt);
}
- set_int_vector(irq,bad_interrupt);
- action->handler = NULL;
- action->flags = 0;
- action->mask = 0;
- action->name = NULL;
restore_flags(flags);
}
-static void no_action(int cpl, struct pt_regs * regs) { }
+static void no_action(int cpl, void *dev_id, struct pt_regs * regs) { }
unsigned long probe_irq_on (void)
{
@@ -248,7 +312,7 @@
/* first, snaffle up any unassigned irqs */
for (i = 15; i > 0; i--) {
- if (!request_irq(i, no_action, SA_PROBE, "probe")) {
+ if (!request_irq(i, no_action, SA_PROBE, "probe", NULL)) {
enable_irq(i);
irqs |= (1 << i);
}
@@ -262,7 +326,7 @@
for (i = 15; i > 0; i--) {
if (irqs & (1 << i) & irqmask) {
irqs ^= (1 << i);
- free_irq(i);
+ free_irq(i, NULL);
}
}
#ifdef DEBUG
@@ -278,7 +342,7 @@
irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
for (i = 15; i > 0; i--) {
if (irqs & (1 << i)) {
- free_irq(i);
+ free_irq(i, NULL);
}
}
#ifdef DEBUG
@@ -317,7 +381,7 @@
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
+ if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
printk("Unable to get IRQ2 for cascade\n");
break;
default:
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this