File: /usr/src/linux/arch/m68k/kernel/ints.c

1     /*
2      * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
3      *
4      * This file is subject to the terms and conditions of the GNU General Public
5      * License.  See the file COPYING in the main directory of this archive
6      * for more details.
7      *
8      * 07/03/96: Timer initialization, and thus mach_sched_init(),
9      *           removed from request_irq() and moved to init_time().
10      *           We should therefore consider renaming our add_isr() and
11      *           remove_isr() to request_irq() and free_irq()
12      *           respectively, so they are compliant with the other
13      *           architectures.                                     /Jes
14      * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls.
15      *           Removed irq list support, if any machine needs an irq server
16      *           it must implement this itself (as it's already done), instead
17      *           only default handler are used with mach_default_handler.
18      *           request_irq got some flags different from other architectures:
19      *           - IRQ_FLG_REPLACE : Replace an existing handler (the default one
20      *                               can be replaced without this flag)
21      *           - IRQ_FLG_LOCK : handler can't be replaced
22      *           There are other machine depending flags, see there
23      *           If you want to replace a default handler you should know what
24      *           you're doing, since it might handle different other irq sources
25      *           which must be served                               /Roman Zippel
26      */
27     
28     #include <linux/config.h>
29     #include <linux/types.h>
30     #include <linux/sched.h>
31     #include <linux/kernel_stat.h>
32     #include <linux/errno.h>
33     #include <linux/init.h>
34     
35     #include <asm/setup.h>
36     #include <asm/system.h>
37     #include <asm/irq.h>
38     #include <asm/traps.h>
39     #include <asm/page.h>
40     #include <asm/machdep.h>
41     
42     #ifdef CONFIG_Q40
43     #include <asm/q40ints.h>
44     #endif
45     
46     /* table for system interrupt handlers */
47     static irq_handler_t irq_list[SYS_IRQS];
48     
49     static const char *default_names[SYS_IRQS] = {
50     	"spurious int", "int1 handler", "int2 handler", "int3 handler",
51     	"int4 handler", "int5 handler", "int6 handler", "int7 handler"
52     };
53     
54     /* The number of spurious interrupts */
55     volatile unsigned int num_spurious;
56     
57     #define NUM_IRQ_NODES 100
58     static irq_node_t nodes[NUM_IRQ_NODES];
59     
60     static void dummy_enable_irq(unsigned int irq);
61     static void dummy_disable_irq(unsigned int irq);
62     static int dummy_request_irq(unsigned int irq,
63     		void (*handler) (int, void *, struct pt_regs *),
64     		unsigned long flags, const char *devname, void *dev_id);
65     static void dummy_free_irq(unsigned int irq, void *dev_id);
66     
67     void (*enable_irq) (unsigned int) = dummy_enable_irq;
68     void (*disable_irq) (unsigned int) = dummy_disable_irq;
69     
70     int (*mach_request_irq) (unsigned int, void (*)(int, void *, struct pt_regs *),
71                           unsigned long, const char *, void *) = dummy_request_irq;
72     void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
73     
74     void init_irq_proc(void);
75     
76     /*
77      * void init_IRQ(void)
78      *
79      * Parameters:	None
80      *
81      * Returns:	Nothing
82      *
83      * This function should be called during kernel startup to initialize
84      * the IRQ handling routines.
85      */
86     
87     void __init init_IRQ(void)
88     {
89     	int i;
90     
91     	for (i = 0; i < SYS_IRQS; i++) {
92     		if (mach_default_handler)
93     			irq_list[i].handler = (*mach_default_handler)[i];
94     		irq_list[i].flags   = 0;
95     		irq_list[i].dev_id  = NULL;
96     		irq_list[i].devname = default_names[i];
97     	}
98     
99     	for (i = 0; i < NUM_IRQ_NODES; i++)
100     		nodes[i].handler = NULL;
101     
102     	mach_init_IRQ ();
103     }
104     
105     irq_node_t *new_irq_node(void)
106     {
107     	irq_node_t *node;
108     	short i;
109     
110     	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
111     		if (!node->handler)
112     			return node;
113     
114     	printk ("new_irq_node: out of nodes\n");
115     	return NULL;
116     }
117     
118     /*
119      * We will keep these functions until I have convinced Linus to move
120      * the declaration of them from include/linux/sched.h to
121      * include/asm/irq.h.
122      */
123     int request_irq(unsigned int irq,
124     		void (*handler) (int, void *, struct pt_regs *),
125     		unsigned long flags, const char *devname, void *dev_id)
126     {
127     	return mach_request_irq(irq, handler, flags, devname, dev_id);
128     }
129     
130     void free_irq(unsigned int irq, void *dev_id)
131     {
132     	mach_free_irq(irq, dev_id);
133     }
134     
135     int sys_request_irq(unsigned int irq, 
136                         void (*handler)(int, void *, struct pt_regs *), 
137                         unsigned long flags, const char *devname, void *dev_id)
138     {
139     	if (irq < IRQ1 || irq > IRQ7) {
140     		printk("%s: Incorrect IRQ %d from %s\n",
141     		       __FUNCTION__, irq, devname);
142     		return -ENXIO;
143     	}
144     
145     #if 0
146     	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
147     		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
148     			printk("%s: IRQ %d from %s is not replaceable\n",
149     			       __FUNCTION__, irq, irq_list[irq].devname);
150     			return -EBUSY;
151     		}
152     		if (!(flags & IRQ_FLG_REPLACE)) {
153     			printk("%s: %s can't replace IRQ %d from %s\n",
154     			       __FUNCTION__, devname, irq, irq_list[irq].devname);
155     			return -EBUSY;
156     		}
157     	}
158     #endif
159     
160     	irq_list[irq].handler = handler;
161     	irq_list[irq].flags   = flags;
162     	irq_list[irq].dev_id  = dev_id;
163     	irq_list[irq].devname = devname;
164     	return 0;
165     }
166     
167     void sys_free_irq(unsigned int irq, void *dev_id)
168     {
169     	if (irq < IRQ1 || irq > IRQ7) {
170     		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
171     		return;
172     	}
173     
174     	if (irq_list[irq].dev_id != dev_id)
175     		printk("%s: Removing probably wrong IRQ %d from %s\n",
176     		       __FUNCTION__, irq, irq_list[irq].devname);
177     
178     	irq_list[irq].handler = (*mach_default_handler)[irq];
179     	irq_list[irq].flags   = 0;
180     	irq_list[irq].dev_id  = NULL;
181     	irq_list[irq].devname = default_names[irq];
182     }
183     
184     /*
185      * Do we need these probe functions on the m68k?
186      *
187      *  ... may be useful with ISA devices
188      */
189     unsigned long probe_irq_on (void)
190     {
191     #ifdef CONFIG_Q40
192     	if (MACH_IS_Q40)
193     		return q40_probe_irq_on();
194     #endif
195     	return 0;
196     }
197     
198     int probe_irq_off (unsigned long irqs)
199     {
200     #ifdef CONFIG_Q40
201     	if (MACH_IS_Q40)
202     		return q40_probe_irq_off(irqs);
203     #endif
204     	return 0;
205     }
206     
207     static void dummy_enable_irq(unsigned int irq)
208     {
209     	printk("calling uninitialized enable_irq()\n");
210     }
211     
212     static void dummy_disable_irq(unsigned int irq)
213     {
214     	printk("calling uninitialized disable_irq()\n");
215     }
216     
217     static int dummy_request_irq(unsigned int irq,
218     		void (*handler) (int, void *, struct pt_regs *),
219     		unsigned long flags, const char *devname, void *dev_id)
220     {
221     	printk("calling uninitialized request_irq()\n");
222     	return 0;
223     }
224     
225     static void dummy_free_irq(unsigned int irq, void *dev_id)
226     {
227     	printk("calling uninitialized disable_irq()\n");
228     }
229     
230     asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
231     {
232     	if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) {
233     		vec -= VEC_SPUR;
234     		kstat.irqs[0][vec]++;
235     		irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
236     	} else {
237     		if (mach_process_int)
238     			mach_process_int(vec, fp);
239     		else
240     			panic("Can't process interrupt vector %ld\n", vec);
241     		return;
242     	}
243     }
244     
245     int get_irq_list(char *buf)
246     {
247     	int i, len = 0;
248     
249     	/* autovector interrupts */
250     	if (mach_default_handler) {
251     		for (i = 0; i < SYS_IRQS; i++) {
252     			len += sprintf(buf+len, "auto %2d: %10u ", i,
253     			               i ? kstat.irqs[0][i] : num_spurious);
254     				len += sprintf(buf+len, "  ");
255     			len += sprintf(buf+len, "%s\n", irq_list[i].devname);
256     		}
257     	}
258     
259     	len += mach_get_irq_list(buf+len);
260     	return len;
261     }
262     
263     void init_irq_proc(void)
264     {
265     	/* Insert /proc/irq driver here */
266     }
267     
268