1 /* 2 * PROJECT: NEC PC-98 series HAL 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: PIC initialization 5 * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com) 6 */ 7 8 /* INCLUDES ******************************************************************/ 9 10 #include <hal.h> 11 12 /* PRIVATE FUNCTIONS *********************************************************/ 13 14 static VOID 15 HalpIoWait(VOID) 16 { 17 UCHAR i; 18 19 /* 20 * Give the old PICs enough time to react to commands. 21 * (KeStallExecutionProcessor is not available at this stage) 22 */ 23 for (i = 0; i < 6; i++) 24 __outbyte(CPU_IO_o_ARTIC_DELAY, 0); 25 } 26 27 VOID 28 NTAPI 29 HalpInitializeLegacyPICs(VOID) 30 { 31 I8259_ICW1 Icw1; 32 I8259_ICW2 Icw2; 33 I8259_ICW3 Icw3; 34 I8259_ICW4 Icw4; 35 36 ASSERT(!(__readeflags() & EFLAGS_INTERRUPT_MASK)); 37 38 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */ 39 Icw1.NeedIcw4 = TRUE; 40 Icw1.OperatingMode = Cascade; 41 Icw1.Interval = Interval8; 42 Icw1.InterruptMode = EdgeTriggered; 43 Icw1.Init = TRUE; 44 Icw1.InterruptVectorAddress = 0; 45 __outbyte(PIC1_CONTROL_PORT, Icw1.Bits); 46 HalpIoWait(); 47 48 /* ICW2 - interrupt vector offset */ 49 Icw2.Bits = PRIMARY_VECTOR_BASE; 50 __outbyte(PIC1_DATA_PORT, Icw2.Bits); 51 HalpIoWait(); 52 53 /* Connect slave to cascade IRQ */ 54 Icw3.Bits = 0; 55 Icw3.SlaveIrq7 = TRUE; 56 __outbyte(PIC1_DATA_PORT, Icw3.Bits); 57 HalpIoWait(); 58 59 /* Enable 8086 mode, non-automatic EOI, buffered mode, special fully nested mode */ 60 Icw4.SystemMode = New8086Mode; 61 Icw4.EoiMode = NormalEoi; 62 Icw4.BufferedMode = BufferedMaster; 63 Icw4.SpecialFullyNestedMode = TRUE; 64 Icw4.Reserved = 0; 65 __outbyte(PIC1_DATA_PORT, Icw4.Bits); 66 HalpIoWait(); 67 68 /* Mask all interrupts */ 69 __outbyte(PIC1_DATA_PORT, 0xFF); 70 HalpIoWait(); 71 72 /* Initialize ICW1 for slave, interval 8, edge-triggered mode with ICW4 */ 73 Icw1.NeedIcw4 = TRUE; 74 Icw1.InterruptMode = EdgeTriggered; 75 Icw1.OperatingMode = Cascade; 76 Icw1.Interval = Interval8; 77 Icw1.Init = TRUE; 78 Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */ 79 __outbyte(PIC2_CONTROL_PORT, Icw1.Bits); 80 HalpIoWait(); 81 82 /* Set interrupt vector base */ 83 Icw2.Bits = PRIMARY_VECTOR_BASE + 8; 84 __outbyte(PIC2_DATA_PORT, Icw2.Bits); 85 HalpIoWait(); 86 87 /* Slave ID */ 88 Icw3.Bits = 0; 89 Icw3.SlaveId = PIC_CASCADE_IRQ; 90 __outbyte(PIC2_DATA_PORT, Icw3.Bits); 91 HalpIoWait(); 92 93 /* Enable 8086 mode, non-automatic EOI, buffered mode, non special fully nested mode */ 94 Icw4.SystemMode = New8086Mode; 95 Icw4.EoiMode = NormalEoi; 96 Icw4.BufferedMode = BufferedSlave; 97 Icw4.SpecialFullyNestedMode = FALSE; 98 Icw4.Reserved = 0; 99 __outbyte(PIC2_DATA_PORT, Icw4.Bits); 100 HalpIoWait(); 101 102 /* Mask all interrupts */ 103 __outbyte(PIC2_DATA_PORT, 0xFF); 104 HalpIoWait(); 105 } 106