1 /* 2 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 #include <arch/x86/pic.h> 10 11 #include <arch/cpu.h> 12 #include <arch/int.h> 13 14 #include <arch/x86/arch_int.h> 15 16 #include <int.h> 17 18 19 //#define TRACE_PIC 20 #ifdef TRACE_PIC 21 # define TRACE(x) dprintf x 22 #else 23 # define TRACE(x) ; 24 #endif 25 26 27 // Definitions for the PIC 8259 controller 28 // (this is not a complete list, only what we're actually using) 29 30 #define PIC_MASTER_CONTROL 0x20 31 #define PIC_MASTER_MASK 0x21 32 #define PIC_SLAVE_CONTROL 0xa0 33 #define PIC_SLAVE_MASK 0xa1 34 #define PIC_MASTER_INIT1 PIC_MASTER_CONTROL 35 #define PIC_MASTER_INIT2 PIC_MASTER_MASK 36 #define PIC_MASTER_INIT3 PIC_MASTER_MASK 37 #define PIC_MASTER_INIT4 PIC_MASTER_MASK 38 #define PIC_SLAVE_INIT1 PIC_SLAVE_CONTROL 39 #define PIC_SLAVE_INIT2 PIC_SLAVE_MASK 40 #define PIC_SLAVE_INIT3 PIC_SLAVE_MASK 41 #define PIC_SLAVE_INIT4 PIC_SLAVE_MASK 42 43 // the edge/level trigger control registers 44 #define PIC_MASTER_TRIGGER_MODE 0x4d0 45 #define PIC_SLAVE_TRIGGER_MODE 0x4d1 46 47 #define PIC_INIT1 0x10 48 #define PIC_INIT1_SEND_INIT4 0x01 49 #define PIC_INIT3_IR2_IS_SLAVE 0x04 50 #define PIC_INIT3_SLAVE_ID2 0x02 51 #define PIC_INIT4_x86_MODE 0x01 52 53 #define PIC_CONTROL3 0x08 54 #define PIC_CONTROL3_READ_ISR 0x03 55 #define PIC_CONTROL3_READ_IRR 0x02 56 57 #define PIC_NON_SPECIFIC_EOI 0x20 58 59 #define PIC_SLAVE_INT_BASE 8 60 #define PIC_NUM_INTS 0x0f 61 62 63 static uint16 sLevelTriggeredInterrupts = 0; 64 // binary mask: 1 level, 0 edge 65 66 67 /*! Tests if the interrupt in-service register of the responsible 68 PIC is set for interrupts 7 and 15, and if that's not the case, 69 it must assume it's a spurious interrupt. 70 */ 71 static bool 72 pic_is_spurious_interrupt(int32 num) 73 { 74 if (num != 7) 75 return false; 76 77 // Note, detecting spurious interrupts on line 15 obviously doesn't 78 // work correctly - and since those are extremely rare, anyway, we 79 // just ignore them 80 81 out8(PIC_CONTROL3 | PIC_CONTROL3_READ_ISR, PIC_MASTER_CONTROL); 82 int32 isr = in8(PIC_MASTER_CONTROL); 83 out8(PIC_CONTROL3 | PIC_CONTROL3_READ_IRR, PIC_MASTER_CONTROL); 84 85 return (isr & 0x80) == 0; 86 } 87 88 89 static bool 90 pic_is_level_triggered_interrupt(int32 num) 91 { 92 if (num < 0 || num > PIC_NUM_INTS) 93 return false; 94 95 return (sLevelTriggeredInterrupts & (1 << num)) != 0; 96 } 97 98 99 /*! Sends a non-specified EOI (end of interrupt) notice to the PIC in 100 question (or both of them). 101 This clears the PIC interrupt in-service bit. 102 */ 103 static bool 104 pic_end_of_interrupt(int32 num) 105 { 106 if (num < 0 || num > PIC_NUM_INTS) 107 return false; 108 109 // PIC 8259 controlled interrupt 110 if (num >= PIC_SLAVE_INT_BASE) 111 out8(PIC_NON_SPECIFIC_EOI, PIC_SLAVE_CONTROL); 112 113 // we always need to acknowledge the master PIC 114 out8(PIC_NON_SPECIFIC_EOI, PIC_MASTER_CONTROL); 115 return true; 116 } 117 118 119 static void 120 pic_enable_io_interrupt(int32 num) 121 { 122 // interrupt is specified "normalized" 123 if (num < 0 || num > PIC_NUM_INTS) 124 return; 125 126 // enable PIC 8259 controlled interrupt 127 128 TRACE(("pic_enable_io_interrupt: irq %ld\n", num)); 129 130 if (num < PIC_SLAVE_INT_BASE) 131 out8(in8(PIC_MASTER_MASK) & ~(1 << num), PIC_MASTER_MASK); 132 else 133 out8(in8(PIC_SLAVE_MASK) & ~(1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK); 134 } 135 136 137 static void 138 pic_disable_io_interrupt(int32 num) 139 { 140 // interrupt is specified "normalized" 141 // never disable slave pic line IRQ 2 142 if (num < 0 || num > PIC_NUM_INTS || num == 2) 143 return; 144 145 // disable PIC 8259 controlled interrupt 146 147 TRACE(("pic_disable_io_interrupt: irq %ld\n", num)); 148 149 if (num < PIC_SLAVE_INT_BASE) 150 out8(in8(PIC_MASTER_MASK) | (1 << num), PIC_MASTER_MASK); 151 else 152 out8(in8(PIC_SLAVE_MASK) | (1 << (num - PIC_SLAVE_INT_BASE)), PIC_SLAVE_MASK); 153 } 154 155 156 static void 157 pic_configure_io_interrupt(int32 num, uint32 config) 158 { 159 uint8 value; 160 int32 localBit; 161 if (num < 0 || num > PIC_NUM_INTS || num == 2) 162 return; 163 164 TRACE(("pic_configure_io_interrupt: irq %ld; config 0x%08lx\n", num, config)); 165 166 if (num < PIC_SLAVE_INT_BASE) { 167 value = in8(PIC_MASTER_TRIGGER_MODE); 168 localBit = num; 169 } else { 170 value = in8(PIC_SLAVE_TRIGGER_MODE); 171 localBit = num - PIC_SLAVE_INT_BASE; 172 } 173 174 if (config & B_LEVEL_TRIGGERED) 175 value |= 1 << localBit; 176 else 177 value &= ~(1 << localBit); 178 179 if (num < PIC_SLAVE_INT_BASE) 180 out8(value, PIC_MASTER_TRIGGER_MODE); 181 else 182 out8(value, PIC_SLAVE_TRIGGER_MODE); 183 184 sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE) 185 | (in8(PIC_SLAVE_TRIGGER_MODE) << 8); 186 } 187 188 189 void 190 pic_init() 191 { 192 static const interrupt_controller picController = { 193 "8259 PIC", 194 &pic_enable_io_interrupt, 195 &pic_disable_io_interrupt, 196 &pic_configure_io_interrupt, 197 &pic_is_spurious_interrupt, 198 &pic_is_level_triggered_interrupt, 199 &pic_end_of_interrupt, 200 NULL 201 }; 202 203 // Start initialization sequence for the master and slave PICs 204 out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_MASTER_INIT1); 205 out8(PIC_INIT1 | PIC_INIT1_SEND_INIT4, PIC_SLAVE_INIT1); 206 207 // Set start of interrupts to 0x20 for master, 0x28 for slave 208 out8(ARCH_INTERRUPT_BASE, PIC_MASTER_INIT2); 209 out8(ARCH_INTERRUPT_BASE + PIC_SLAVE_INT_BASE, PIC_SLAVE_INIT2); 210 211 // Specify cascading through interrupt 2 212 out8(PIC_INIT3_IR2_IS_SLAVE, PIC_MASTER_INIT3); 213 out8(PIC_INIT3_SLAVE_ID2, PIC_SLAVE_INIT3); 214 215 // Set both to operate in 8086 mode 216 out8(PIC_INIT4_x86_MODE, PIC_MASTER_INIT4); 217 out8(PIC_INIT4_x86_MODE, PIC_SLAVE_INIT4); 218 219 out8(0xfb, PIC_MASTER_MASK); // Mask off all interrupts (except slave pic line IRQ 2). 220 out8(0xff, PIC_SLAVE_MASK); // Mask off interrupts on the slave. 221 222 // determine which interrupts are level or edge triggered 223 224 #if 0 225 // should set everything possible to level triggered 226 out8(0xf8, PIC_MASTER_TRIGGER_MODE); 227 out8(0xde, PIC_SLAVE_TRIGGER_MODE); 228 #endif 229 230 sLevelTriggeredInterrupts = in8(PIC_MASTER_TRIGGER_MODE) 231 | (in8(PIC_SLAVE_TRIGGER_MODE) << 8); 232 233 TRACE(("PIC level trigger mode: 0x%08lx\n", sLevelTriggeredInterrupts)); 234 235 reserve_io_interrupt_vectors(16, 0, INTERRUPT_TYPE_EXCEPTION); 236 237 // make the pic controller the current one 238 arch_int_set_interrupt_controller(picController); 239 } 240 241 242 void 243 pic_disable(uint16& enabledInterrupts) 244 { 245 enabledInterrupts = ~(in8(PIC_MASTER_MASK) | in8(PIC_SLAVE_MASK) << 8); 246 enabledInterrupts &= 0xfffb; // remove slave PIC from the mask 247 248 // Mask off all interrupts on master and slave 249 out8(0xff, PIC_MASTER_MASK); 250 out8(0xff, PIC_SLAVE_MASK); 251 252 free_io_interrupt_vectors(16, 0); 253 } 254