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
HalpIoWait(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
HalpInitializeLegacyPICs(VOID)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