3 * 8259 programmable interrupt controller library.
4 * (C) 2009-2012 Jonathan Campbell.
5 * Hackipedia DOS library.
7 * This code is licensed under the LGPL.
8 * <insert LGPL legal text here>
10 * Compiles for intended target environments:
11 * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
13 #ifndef __HW_8259_8259_H
14 #define __HW_8259_8259_H
16 #include "src/lib/doslib/cpu.h"
19 /* PIC hardware register description
21 * ICW1 I/O port base + 0 (NTS: bit D4 == 1 when writing this)
22 * ICW2 I/O port base + 1
23 * ICW3 I/O port base + 1
24 * ICW4 I/O port base + 1
26 * OCW1 R/W interrupt mask register. setting the bit masks the interrupt. Use I/O port base + 0
27 * OCW2 R/? EOI and rotate command opcodes (NTS: bit D3-4 == 0). I/O port base + 1
28 * OCW3 R/? poll/read/etc command opcodes (NTS: bit D3-4 == 1) I/O port base + 1
31 /* PIC library warning:
33 * For performance and sanity reasons this code does NOT mask interrupts during the function. You are
34 * expected to wrap your calls with cli/sti functions. Though it is unlikely, leaving interrupts enabled
35 * while doing this can cause problems in case the BIOS fiddles with the PIC during an IRQ */
37 #define P8259_MASTER_DATA 0x20
38 #define P8259_MASTER_MASK 0x21
40 #define P8259_SLAVE_DATA 0xA0
41 #define P8259_SLAVE_MASK 0xA1
43 /* OCW2 command bits. For most commands you are expected to OR the low 3 bits with the IRQ for the command to take effect on */
44 #define P8259_OCW2_ROTATE_AUTO_EOI_CLEAR (0U << 5U)
45 #define P8259_OCW2_NON_SPECIFIC_EOI (1U << 5U)
46 #define P8259_OCW2_NO_OP (2U << 5U)
47 #define P8259_OCW2_SPECIFIC_EOI (3U << 5U)
48 #define P8259_OCW2_ROTATE_AUTO_EOI_SET (4U << 5U)
49 #define P8259_OCW2_ROTATE_NON_SPECIFIC_EOI (5U << 5U)
50 #define P8259_OCW2_SET_PRIORITY (6U << 5U)
51 #define P8259_OCW2_ROTATE_SPECIFIC_EOI (7U << 5U)
53 #define P8259_MASK_BIT(x) (1U << ((x)&7U))
55 extern unsigned char p8259_slave_present;
57 /* c = IRQ which = I/O port */
58 static inline unsigned char p8259_irq_to_base_port(unsigned char c,unsigned char which) {
59 return ((c & 8) ? P8259_SLAVE_DATA : P8259_MASTER_DATA) + which;
63 static inline unsigned char p8259_read_mask(unsigned char c) { /* mask register AKA OCW1 */
64 outp(p8259_irq_to_base_port(c,0),P8259_OCW2_NO_OP); /* issue NO-OP to make sure the PIC is ready to accept OCW1 */
65 return inp(p8259_irq_to_base_port(c,1)); /* mask register */
68 static inline void p8259_write_mask(unsigned char c,unsigned char m) { /* mask register AKA OCW1 */
69 outp(p8259_irq_to_base_port(c,0),P8259_OCW2_NO_OP); /* issue NO-OP to make sure the PIC is ready to accept OCW1 */
70 outp(p8259_irq_to_base_port(c,1),m); /* write mask register */
73 static inline void p8259_OCW2(unsigned char c,unsigned char w) {
74 outp(p8259_irq_to_base_port(c,0),w & 0xE7); /* D3-4 == 0 */
77 static inline void p8259_OCW3(unsigned char c,unsigned char w) {
78 outp(p8259_irq_to_base_port(c,0),(w & 0xE7) | 0x08); /* D3-4 == 1 */
81 static inline unsigned char p8259_read_IRR(unsigned char c) {
82 p8259_OCW3(c,0x02); /* OCW3 = read register command RR=1 RIS=0 */
83 return inp(p8259_irq_to_base_port(c,0)); /* mask register */
86 static inline unsigned char p8259_read_ISR(unsigned char c) {
87 p8259_OCW3(c,0x03); /* OCW3 = read register command RR=1 RIS=1 */
88 return inp(p8259_irq_to_base_port(c,0)); /* mask register */
91 static inline unsigned char irq2int(unsigned char c) {
93 if (c & 8) return c-8+0x70;
97 static inline void p8259_unmask(unsigned char c) {
98 unsigned char m = p8259_read_mask(c);
99 p8259_write_mask(c,m & ~(1 << (c&7)));
102 static inline void p8259_mask(unsigned char c) {
103 unsigned char m = p8259_read_mask(c);
104 p8259_write_mask(c,m | (1 << (c&7)));
107 static inline unsigned char p8259_is_masked(unsigned char c) {
108 return (p8259_read_mask(c) & (1 << (c&7)));
111 void p8259_ICW(unsigned char a,unsigned char b,unsigned char c,unsigned char d);
112 unsigned char p8259_poll(unsigned char c);
115 #endif /* __HW_8259_8259_H */