]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/io/irq/i8259.cc
License change.
[polintos/scott/priv.git] / kernel / io / irq / i8259.cc
1 // io/irq/i8259.cc -- Intel 8259-compatible IRQ support
2 //
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
4 // 
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
8 // 
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
14
15 #include <kern/irq.h>
16 #include <kern/kernel.h>
17 #include <kern/io.h>
18 #include <kern/i8259.h>
19
20 namespace IRQ {
21         using namespace IRQ;
22
23         // This assumes a second i8259 cascaded on IRQ2 of the first i8259,
24         // with I/O port bases of 0x20 and 0xa0, as every i8259 I've
25         // encountered has been configured that way, even on non-x86
26         // platforms.  This can be made more general later if need be.
27         //
28         // FIXME: For non-x86 platforms, the I/O window base must be added in.
29         
30         inline void I8259::output_mask(int off)
31         {
32                 ll_out_8(off ? 0xa1 : 0x21, cached_masks[0]);
33         }
34         
35         inline void I8259::mask(u32 irq)
36         {
37                 assert(irq < 16);
38         
39                 int off = irq / 8;
40                 int bit = irq % 8;
41                 
42                 cached_masks[off] |= (1 << bit);
43                 output_mask(off);
44         }
45                 
46         void I8259::unmask(u32 irq)
47         {
48                 assert(irq < 16);
49
50                 int off = irq / 8;
51                 int bit = irq % 8;
52                 
53                 cached_masks[off] &= ~(1 << bit);
54                 output_mask(off);
55         }
56                 
57         void I8259::mask_and_ack(u32 irq)
58         {
59                 assert(irq < 16);
60                 int bit = irq % 8;
61
62                 mask(irq);
63                 
64                 if (irq < 8) {
65                         ll_out_8(0x20, 0x60 | bit);
66                 } else {
67                         ll_out_8(0xa0, 0x60 | bit);
68                         ll_out_8(0x20, 0x62);
69                 }
70         }
71         
72         int I8259::get_pending_irq()
73         {
74         #if defined(_LL_ARCH_x86) || defined(_LL_ARCH_x64)
75                 assert(0);
76                 return -1;
77         #else
78                 ll_out_8(0x20, 0x0b);
79                 u8 ret = ll_in_8(0x20);
80                 
81                 if (!(ret & 0x80))
82                         return -1;
83                 
84                 ret &= 7;
85                 
86                 if (ret != 2)
87                         return ret;
88                 
89                 ll_out_8(0xa0, 0x0b);
90                 ret = ll_in_8(0xa0);
91                 
92                 // Shouldn't happen, as even if the device de-asserts the
93                 // cascaded interrupt, it should wait for EOI.
94                         
95                 if (!(ret & 0x80))
96                         return -1;
97                 
98                 return (ret & 7) | 8;
99         #endif
100         }
101                 
102         void I8259::init()
103         {
104                 // Initialize each 8259 for edge triggered, cascade, 8086 mode. 
105                 // Interrupt vectors are set to 0x20-0x2f (this only matters on
106                 // x86/x64).
107                 
108                 ll_out_8(0x20, 0x11);
109                 ll_out_8(0x21, 0x20);
110                 ll_out_8(0x21, 0x04);
111                 ll_out_8(0x21, 0x01);
112                 
113                 ll_out_8(0xa0, 0x11);
114                 ll_out_8(0xa1, 0x28);
115                 ll_out_8(0xa1, 0x02);
116                 ll_out_8(0xa1, 0x01);
117                 
118                 // Mask all IRQs initially.
119                 
120                 cached_masks[0] = cached_masks[1] = 0xff;
121                 ll_out_8(0x21, 0xff);
122                 ll_out_8(0xa1, 0xff);
123                 
124                 bzero(irqslots, sizeof(irqslots));
125
126                 for (int i = 0; i < 16; i++)
127                         irqslots[i].controller = this;
128         
129                 irqs = irqslots;
130                 num_irqs = 16;
131         }
132
133         I8259 i8259;
134 }