xref: /reactos/hal/halx86/pc98/pic.c (revision 682f85ad)
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