patch-1.3.70 linux/arch/i386/kernel/irq.c
Next file: linux/arch/i386/kernel/smp.c
Previous file: linux/arch/i386/boot/bootsect.S
Back to the patch index
Back to the overall index
- Lines: 366
- Date:
Fri Mar 1 07:50:38 1996
- Orig file:
v1.3.69/linux/arch/i386/kernel/irq.c
- Orig date:
Wed Feb 7 15:11:21 1996
diff -u --recursive --new-file v1.3.69/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
@@ -23,6 +23,7 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
+#include <linux/malloc.h>
#include <linux/random.h>
#include <asm/system.h>
@@ -32,6 +33,7 @@
#include <asm/smp.h>
#define CR0_NE 32
+#define TIMER_IRQ 0 /* Keep this in sync with time.c */
static unsigned char cache_21 = 0xff;
static unsigned char cache_A1 = 0xff;
@@ -158,36 +160,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");
}
/*
* Linus - should you add NMI counts here ?????
@@ -203,7 +203,7 @@
int get_smp_prof_list(char *buf) {
int i,j, len = 0;
- struct irqaction * action = irq_action;
+ struct irqaction * action;
unsigned long sum_spins = 0;
unsigned long sum_spins_syscall = 0;
unsigned long sum_spins_sys_idle = 0;
@@ -222,7 +222,8 @@
for (i=0;i<smp_num_cpus;i++)
len += sprintf(buf+len," P%1d ",i);
len += sprintf(buf+len,"\n");
- for (i = 0 ; i < NR_IRQS ; i++, action++) {
+ for (i = 0 ; i < NR_IRQS ; i++) {
+ action = *(i + irq_action);
if (!action->handler)
continue;
len += sprintf(buf+len, "%3d: %10d ",
@@ -232,6 +233,11 @@
len += sprintf(buf+len, "%c %s\n",
(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, "LCK: %10lu",
sum_spins);
@@ -273,7 +279,8 @@
*/
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action = *(irq + irq_action);
+
#ifdef __SMP__
if(smp_threads_ready && active_kernel_processor!=smp_processor_id())
panic("IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
@@ -283,9 +290,13 @@
#ifdef __SMP_PROF__
int_count[smp_processor_id()][irq]++;
#endif
- if (action->flags & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- action->handler(irq, regs);
+ while (action) {
+ if (action->flags & SA_SAMPLE_RANDOM) {
+ add_interrupt_randomness(irq);
+ }
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ }
}
/*
@@ -295,7 +306,7 @@
*/
asmlinkage void do_fast_IRQ(int irq)
{
- struct irqaction * action = irq + irq_action;
+ struct irqaction * action = *(irq + irq_action);
#ifdef __SMP__
/* IRQ 13 is allowed - thats an invalidate */
if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13)
@@ -306,56 +317,95 @@
#ifdef __SMP_PROF__
int_count[smp_processor_id()][irq]++;
#endif
- if (action->flags & SA_SAMPLE_RANDOM)
+ while (action) {
+ if (action->flags & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
- action->handler(irq, NULL);
+ 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;
+ return -EINVAL;
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 */
if (action->flags & SA_INTERRUPT)
- set_intr_gate(0x20+irq,fast_interrupt[irq]);
+ set_intr_gate(0x20+irq,fast_interrupt[irq]);
else
- set_intr_gate(0x20+irq,interrupt[irq]);
- }
- if (irq < 8) {
+ set_intr_gate(0x20+irq,interrupt[irq]);
+ }
+ 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) {
@@ -366,20 +416,43 @@
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_intr_gate(0x20+irq,bad_interrupt[irq]);
}
- set_intr_gate(0x20+irq,bad_interrupt[irq]);
- action->handler = NULL;
- action->flags = 0;
- action->mask = 0;
- action->name = NULL;
+
restore_flags(flags);
}
@@ -398,7 +471,7 @@
*/
-static void math_error_irq(int cpl, struct pt_regs *regs)
+static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
{
outb(0,0xF0);
if (ignore_irq13 || !hard_math)
@@ -408,7 +481,7 @@
#endif
-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)
{
@@ -417,7 +490,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);
}
@@ -431,7 +504,7 @@
for (i = 15; i > 0; i--) {
if (irqs & (1 << i) & irqmask) {
irqs ^= (1 << i);
- free_irq(i);
+ free_irq(i, NULL);
}
}
#ifdef DEBUG
@@ -447,7 +520,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
@@ -481,13 +554,13 @@
#ifdef __SMP__
set_intr_gate(0x20+i, interrupt[i]); /* IRQ '16' - IPI for rescheduling */
#endif
- 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");
#ifndef __SMP__
- if (request_irq(13,math_error_irq, 0, "math error"))
+ if (request_irq(13, math_error_irq, 0, "math error", NULL))
printk("Unable to get IRQ13 for math-error handler.\n");
#else
- if (request_irq(13, smp_message_irq, SA_INTERRUPT, "IPI"))
+ if (request_irq(13, smp_message_irq, SA_INTERRUPT, "IPI", NULL))
printk("Unable to get IRQ13 for IPI.\n");
#endif
request_region(0x20,0x20,"pic1");
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