1#include <linux/linkage.h>
2#include <linux/errno.h>
3#include <linux/signal.h>
4#include <linux/sched.h>
5#include <linux/ioport.h>
6#include <linux/interrupt.h>
7#include <linux/timex.h>
8#include <linux/slab.h>
9#include <linux/random.h>
10#include <linux/init.h>
11#include <linux/kernel_stat.h>
12#include <linux/sysdev.h>
13#include <linux/bitops.h>
14
15#include <asm/acpi.h>
16#include <asm/atomic.h>
17#include <asm/system.h>
18#include <asm/io.h>
19#include <asm/timer.h>
20#include <asm/hw_irq.h>
21#include <asm/pgtable.h>
22#include <asm/delay.h>
23#include <asm/desc.h>
24#include <asm/apic.h>
25#include <asm/arch_hooks.h>
26#include <asm/i8259.h>
27
28
29
30
31
32
33
34
35static int i8259A_auto_eoi;
36DEFINE_SPINLOCK(i8259A_lock);
37static void mask_and_ack_8259A(unsigned int);
38
39struct irq_chip i8259A_chip = {
40 .name = "XT-PIC",
41 .mask = disable_8259A_irq,
42 .disable = disable_8259A_irq,
43 .unmask = enable_8259A_irq,
44 .mask_ack = mask_and_ack_8259A,
45};
46
47
48
49
50
51
52
53
54unsigned int cached_irq_mask = 0xffff;
55
56
57
58
59
60
61
62
63
64
65unsigned long io_apic_irqs;
66
67void disable_8259A_irq(unsigned int irq)
68{
69 unsigned int mask = 1 << irq;
70 unsigned long flags;
71
72 spin_lock_irqsave(&i8259A_lock, flags);
73 cached_irq_mask |= mask;
74 if (irq & 8)
75 outb(cached_slave_mask, PIC_SLAVE_IMR);
76 else
77 outb(cached_master_mask, PIC_MASTER_IMR);
78 spin_unlock_irqrestore(&i8259A_lock, flags);
79}
80
81void enable_8259A_irq(unsigned int irq)
82{
83 unsigned int mask = ~(1 << irq);
84 unsigned long flags;
85
86 spin_lock_irqsave(&i8259A_lock, flags);
87 cached_irq_mask &= mask;
88 if (irq & 8)
89 outb(cached_slave_mask, PIC_SLAVE_IMR);
90 else
91 outb(cached_master_mask, PIC_MASTER_IMR);
92 spin_unlock_irqrestore(&i8259A_lock, flags);
93}
94
95int i8259A_irq_pending(unsigned int irq)
96{
97 unsigned int mask = 1<<irq;
98 unsigned long flags;
99 int ret;
100
101 spin_lock_irqsave(&i8259A_lock, flags);
102 if (irq < 8)
103 ret = inb(PIC_MASTER_CMD) & mask;
104 else
105 ret = inb(PIC_SLAVE_CMD) & (mask >> 8);
106 spin_unlock_irqrestore(&i8259A_lock, flags);
107
108 return ret;
109}
110
111void make_8259A_irq(unsigned int irq)
112{
113 disable_irq_nosync(irq);
114 io_apic_irqs &= ~(1<<irq);
115 set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
116 "XT");
117 enable_irq(irq);
118}
119
120
121
122
123
124
125
126static inline int i8259A_irq_real(unsigned int irq)
127{
128 int value;
129 int irqmask = 1<<irq;
130
131 if (irq < 8) {
132 outb(0x0B, PIC_MASTER_CMD);
133 value = inb(PIC_MASTER_CMD) & irqmask;
134 outb(0x0A, PIC_MASTER_CMD);
135 return value;
136 }
137 outb(0x0B, PIC_SLAVE_CMD);
138 value = inb(PIC_SLAVE_CMD) & (irqmask >> 8);
139 outb(0x0A, PIC_SLAVE_CMD);
140 return value;
141}
142
143
144
145
146
147
148
149static void mask_and_ack_8259A(unsigned int irq)
150{
151 unsigned int irqmask = 1 << irq;
152 unsigned long flags;
153
154 spin_lock_irqsave(&i8259A_lock, flags);
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 if (cached_irq_mask & irqmask)
171 goto spurious_8259A_irq;
172 cached_irq_mask |= irqmask;
173
174handle_real_irq:
175 if (irq & 8) {
176 inb(PIC_SLAVE_IMR);
177 outb(cached_slave_mask, PIC_SLAVE_IMR);
178
179 outb(0x60+(irq&7), PIC_SLAVE_CMD);
180
181 outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD);
182 } else {
183 inb(PIC_MASTER_IMR);
184 outb(cached_master_mask, PIC_MASTER_IMR);
185 outb(0x60+irq, PIC_MASTER_CMD);
186 }
187 spin_unlock_irqrestore(&i8259A_lock, flags);
188 return;
189
190spurious_8259A_irq:
191
192
193
194 if (i8259A_irq_real(irq))
195
196
197
198
199 goto handle_real_irq;
200
201 {
202 static int spurious_irq_mask;
203
204
205
206
207 if (!(spurious_irq_mask & irqmask)) {
208 printk(KERN_DEBUG
209 "spurious 8259A interrupt: IRQ%d.\n", irq);
210 spurious_irq_mask |= irqmask;
211 }
212 atomic_inc(&irq_err_count);
213
214
215
216
217
218 goto handle_real_irq;
219 }
220}
221
222static char irq_trigger[2];
223
224
225
226static void restore_ELCR(char *trigger)
227{
228 outb(trigger[0], 0x4d0);
229 outb(trigger[1], 0x4d1);
230}
231
232static void save_ELCR(char *trigger)
233{
234
235 trigger[0] = inb(0x4d0) & 0xF8;
236 trigger[1] = inb(0x4d1) & 0xDE;
237}
238
239static int i8259A_resume(struct sys_device *dev)
240{
241 init_8259A(i8259A_auto_eoi);
242 restore_ELCR(irq_trigger);
243 return 0;
244}
245
246static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
247{
248 save_ELCR(irq_trigger);
249 return 0;
250}
251
252static int i8259A_shutdown(struct sys_device *dev)
253{
254
255
256
257
258 outb(0xff, PIC_MASTER_IMR);
259 outb(0xff, PIC_SLAVE_IMR);
260 return 0;
261}
262
263static struct sysdev_class i8259_sysdev_class = {
264 .name = "i8259",
265 .suspend = i8259A_suspend,
266 .resume = i8259A_resume,
267 .shutdown = i8259A_shutdown,
268};
269
270static struct sys_device device_i8259A = {
271 .id = 0,
272 .cls = &i8259_sysdev_class,
273};
274
275static int __init i8259A_init_sysfs(void)
276{
277 int error = sysdev_class_register(&i8259_sysdev_class);
278 if (!error)
279 error = sysdev_register(&device_i8259A);
280 return error;
281}
282
283device_initcall(i8259A_init_sysfs);
284
285void mask_8259A(void)
286{
287 unsigned long flags;
288
289 spin_lock_irqsave(&i8259A_lock, flags);
290
291 outb(0xff, PIC_MASTER_IMR);
292 outb(0xff, PIC_SLAVE_IMR);
293
294 spin_unlock_irqrestore(&i8259A_lock, flags);
295}
296
297void unmask_8259A(void)
298{
299 unsigned long flags;
300
301 spin_lock_irqsave(&i8259A_lock, flags);
302
303 outb(cached_master_mask, PIC_MASTER_IMR);
304 outb(cached_slave_mask, PIC_SLAVE_IMR);
305
306 spin_unlock_irqrestore(&i8259A_lock, flags);
307}
308
309void init_8259A(int auto_eoi)
310{
311 unsigned long flags;
312
313 i8259A_auto_eoi = auto_eoi;
314
315 spin_lock_irqsave(&i8259A_lock, flags);
316
317 outb(0xff, PIC_MASTER_IMR);
318 outb(0xff, PIC_SLAVE_IMR);
319
320
321
322
323 outb_pic(0x11, PIC_MASTER_CMD);
324
325
326
327 outb_pic(IRQ0_VECTOR, PIC_MASTER_IMR);
328
329
330 outb_pic(1U << PIC_CASCADE_IR, PIC_MASTER_IMR);
331
332 if (auto_eoi)
333 outb_pic(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR);
334 else
335 outb_pic(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR);
336
337 outb_pic(0x11, PIC_SLAVE_CMD);
338
339
340 outb_pic(IRQ8_VECTOR, PIC_SLAVE_IMR);
341
342 outb_pic(PIC_CASCADE_IR, PIC_SLAVE_IMR);
343
344 outb_pic(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR);
345
346 if (auto_eoi)
347
348
349
350
351 i8259A_chip.mask_ack = disable_8259A_irq;
352 else
353 i8259A_chip.mask_ack = mask_and_ack_8259A;
354
355 udelay(100);
356
357 outb(cached_master_mask, PIC_MASTER_IMR);
358 outb(cached_slave_mask, PIC_SLAVE_IMR);
359
360 spin_unlock_irqrestore(&i8259A_lock, flags);
361}
362