]> 4ch.mooo.com Git - 16.git/blob - src/lib/dl/8259.c
meh
[16.git] / src / lib / dl / 8259.c
1 /* 8259.c
2  *
3  * 8259 programmable interrupt controller library.
4  * (C) 2009-2012 Jonathan Campbell.
5  * Hackipedia DOS library.
6  *
7  * This code is licensed under the LGPL.
8  * <insert LGPL legal text here>
9  *
10  * Compiles for intended target environments:
11  *   - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box]
12  *
13  * In PC hardware the 8259 is responsible for taking IRQ signals off the ISA bus, prioritizing
14  * them, and interrupting the CPU to service the interrupts. The chip includes logic to keep
15  * track of what interrupts are pending, active, not yet acknowledged by the CPU, etc. so that
16  * the x86 CPU can properly handle them.
17  *
18  * In mid 1990s hardware the PIC was retained and often connected through a PCI core chipset
19  * that routed both ISA and PCI interrupts into it. Some chipsets have additional registers
20  * that allow "routing control", to determine whether a particular IRQ is to be associated
21  * with a PCI device or the ISA bus.
22  *
23  * Starting in late 1990s hardware, the APIC (Advanced Programmable Interrupt Controller)
24  * appeared on motherboards and was either put alongside with, or replaced, the traditional
25  * PIC. But the traditional I/O ports are emulated just the same to ensure compatibility with
26  * older software. Even today (in 2012) DOS programs can still communicate with I/O ports
27  * 20-21h and A0-A1h to manage interrupts, at least until an APIC aware OS or program takes
28  * control.
29  */
30
31 /* NTS: As of 2011/02/27 the 8254 routines no longer do cli/sti for us, we are expected
32  *      to do them ourself. This is for performance reasons as well as for sanity reasons
33  *      should we ever need to use the subroutines from within an interrupt handler */
34
35 #include <stdio.h>
36 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <dos.h>
41
42 #include "src/lib/doslib/8259.h"
43
44 unsigned char p8259_slave_present = 0;
45 signed char p8259_probed = 0;
46
47 void p8259_ICW(unsigned char a,unsigned char b,unsigned char c,unsigned char d) {
48         outp(p8259_irq_to_base_port(c,0),a | 0x10);     /* D4 == 1 */
49         outp(p8259_irq_to_base_port(c,1),b);
50         outp(p8259_irq_to_base_port(c,1),c);
51         if (a & 1) outp(p8259_irq_to_base_port(c,1),d);
52 }
53
54 /* NTS: bit 7 is set if there was an interrupt */
55 /* WARNING: This code crashes DOSBox 0.74 with "PIC poll not handled" error message */
56 unsigned char p8259_poll(unsigned char c) {
57         /* issue poll command to read and ack an interrupt */
58         p8259_OCW3(c,0x0C);     /* OCW3 = POLL=1 SMM=0 RR=0 */
59         return inp(p8259_irq_to_base_port(c,0));
60 }
61
62 int probe_8259() {
63         unsigned char om,cm,c2;
64         unsigned int flags;
65
66         if (p8259_probed < 0)
67                 return (int)p8259_probed;
68
69         /* don't let the BIOS fiddle with the mask during
70            the test. Fixes: Pentium machine where 1 out of
71            100 times programs fail with "cannot init PIC" */
72         flags = get_cpu_flags(); _cli();
73         om = p8259_read_mask(0);
74         p8259_write_mask(0,0xFF);
75         cm = p8259_read_mask(0);
76         p8259_write_mask(0,0x00);
77         c2 = p8259_read_mask(0);
78         p8259_write_mask(0,om);
79         set_cpu_flags(flags);
80
81         if (cm != 0xFF || c2 != 0x00)
82                 return (p8259_probed=0);
83
84         /* is a slave present too? */
85         flags = get_cpu_flags(); _cli();
86         om = p8259_read_mask(8);
87         p8259_write_mask(8,0xFF);
88         cm = p8259_read_mask(8);
89         p8259_write_mask(8,0x00);
90         c2 = p8259_read_mask(8);
91         p8259_write_mask(8,om);
92         set_cpu_flags(flags);
93
94         if (cm == 0xFF && c2 == 0x00)
95                 p8259_slave_present = 1;
96
97         return (p8259_probed=1);
98 }
99