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