1 /* auto_irq.c: Auto-configure IRQ lines for linux. */ 2 /* 3 Written 1994 by Donald Becker. 4
5 The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O 6 Center of Excellence in Space Data and Information Sciences 7 Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 8
9 This code is a general-purpose IRQ line detector for devices with 10 jumpered IRQ lines. If you can make the device raise an IRQ (and 11 that IRQ line isn't already being used), these routines will tell 12 you what IRQ line it's using -- perfect for those oh-so-cool boot-time 13 device probes! 14
15 To use this, first call autoirq_setup(timeout). TIMEOUT is how many 16 'jiffies' (1/100 sec.) to detect other devices that have active IRQ lines, 17 and can usually be zero at boot. 'autoirq_setup()' returns the bit 18 vector of nominally-available IRQ lines (lines may be physically in-use, 19 but not yet registered to a device). 20 Next, set up your device to trigger an interrupt. 21 Finally call autoirq_report(TIMEOUT) to find out which IRQ line was 22 most recently active. The TIMEOUT should usually be zero, but may 23 be set to the number of jiffies to wait for a slow device to raise an IRQ. 24
25 The idea of using the setup timeout to filter out bogus IRQs came from 26 the serial driver. 27 */ 28
29
30 #ifdefversion 31 staticconstchar *version=
32 "auto_irq.c:v1.11 Donald Becker (becker@cesdis.gsfc.nasa.gov)";
33 #endif 34
35 #include <linux/sched.h>
36 #include <linux/delay.h>
37 #include <asm/bitops.h>
38 #include <asm/io.h>
39 #include <asm/irq.h>
40 #include <linux/netdevice.h>
41
42 structdevice *irq2dev_map[16] = {0, 0, /* ... zeroed */};
43
44 unsignedlongirqs_busy = 0x2147; /* The set of fixed IRQs (keyboard, timer, etc) */ 45 unsignedlongirqs_used = 0x0001; /* The set of fixed IRQs sometimes enabled. */ 46 unsignedlong irqs_reserved = 0x0000; /* An advisory "reserved" table. */ 47 unsignedlong irqs_shared = 0x0000; /* IRQ lines "shared" among conforming cards.*/ 48
49 staticvolatileunsignedlongirq_bitmap; /* The irqs we actually found. */ 50 staticunsignedlongirq_handled; /* The irq lines we have a handler on. */ 51 staticvolatileintirq_number; /* The latest irq number we actually found. */ 52
53 staticvoidautoirq_probe(intirq, void *dev_id, structpt_regs * regs)
/* */ 54 { 55 irq_number = irq;
56 set_bit(irq, (void *)&irq_bitmap); /* irq_bitmap |= 1 << irq; */ 57 disable_irq(irq);
58 return;
59 } 60
61 intautoirq_setup(intwaittime)
/* */ 62 { 63 inti, mask;
64 inttimeout = jiffies + waittime;
65 intboguscount = (waittime*loops_per_sec) / 100;
66
67 irq_handled = 0;
68 for (i = 0; i < 16; i++) { 69 if (test_bit(i, &irqs_busy) == 0
70 && request_irq(i, autoirq_probe, SA_INTERRUPT, "irq probe", NULL) == 0)
71 set_bit(i, (void *)&irq_handled); /* irq_handled |= 1 << i;*/ 72 } 73 /* Update our USED lists. */ 74 irqs_used |= ~irq_handled;
75 irq_number = 0;
76 irq_bitmap = 0;
77
78 /* Hang out at least <waittime> jiffies waiting for bogus IRQ hits. */ 79 while (timeout > jiffies && --boguscount > 0)
80 ;
81
82 for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) { 83 if (irq_bitmap & irq_handled & mask) { 84 irq_handled &= ~mask;
85 #ifdef notdef
86 printk(" Spurious interrupt on IRQ %d\n", i);
87 #endif 88 free_irq(i, NULL);
89 } 90 } 91 returnirq_handled;
92 } 93
94 intautoirq_report(intwaittime)
/* */ 95 { 96 inti;
97 inttimeout = jiffies+waittime;
98 intboguscount = (waittime*loops_per_sec) / 100;
99
100 /* Hang out at least <waittime> jiffies waiting for the IRQ. */ 101
102 while (timeout > jiffies && --boguscount > 0)
103 if (irq_number)
104 break;
105
106 /* Retract the irq handlers that we installed. */ 107 for (i = 0; i < 16; i++) { 108 if (test_bit(i, (void *)&irq_handled))
109 free_irq(i, NULL);
110 } 111 returnirq_number;
112 } 113
114 /* 115 * Local variables: 116 * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c auto_irq.c" 117 * version-control: t 118 * kept-new-versions: 5 119 * c-indent-level: 4 120 * tab-width: 4 121 * End: 122 */