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