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