Cleanup handling of interrupt controller (PIC).
authorKevin O'Connor <kevin@koconnor.net>
Sat, 14 Jun 2008 19:56:16 +0000 (15:56 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Sat, 14 Jun 2008 19:56:16 +0000 (15:56 -0400)
Add new file (pic.h) with helpers for accessing the PIC.
Move irq enabling code to the files that use those interrupts.
Also, don't setup for floppy if floppy support not enabled.

12 files changed:
Makefile
src/ata.c
src/clock.c
src/disk.c
src/floppy.c
src/ioport.h
src/kbd.c
src/mouse.c
src/pic.h [new file with mode: 0644]
src/post.c
src/system.c
src/util.h

index b89170ddc406f0ce4b8b2ca9a951c804caf6cfed..ca2a93088c64dcddb0b0d8888191434738485c82 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,8 +8,9 @@
 OUT=out/
 
 # Source files
-SRCBOTH=output.c util.c floppy.c ata.c kbd.c pci.c boot.c serial.c clock.c
-SRC16=$(SRCBOTH) disk.c system.c mouse.c cdrom.c apm.c pcibios.c
+SRCBOTH=output.c util.c floppy.c ata.c system.c mouse.c kbd.c pci.c boot.c \
+        serial.c clock.c
+SRC16=$(SRCBOTH) disk.c cdrom.c apm.c pcibios.c
 SRC32=$(SRCBOTH) post.c shadow.c rombios32.c post_menu.c memmap.c coreboot.c \
       acpi.c pirtable.c
 TABLESRC=font.c cbt.c floppy_dbt.c
index 998576cd519c773140549f99bd236705ad0a5c28..4d3c66070594f2c29b3064b33efce3ddd920e82a 100644 (file)
--- a/src/ata.c
+++ b/src/ata.c
@@ -10,6 +10,7 @@
 #include "ioport.h" // inb
 #include "util.h" // dprintf
 #include "cmos.h" // inb_cmos
+#include "pic.h" // unmask_pic2
 
 #define TIMEOUT 0
 #define BSY 1
@@ -947,4 +948,7 @@ hard_drive_setup()
     SET_BDA(disk_count, GET_EBDA(ata.hdcount));
 
     SET_BDA(disk_control_byte, 0xc0);
+
+    // Enable IRQ14 (handle_76)
+    unmask_pic2(PIC2_IRQ14);
 }
index 5bf4642b73b7e4fa80e88bbd8b14000da53b503b..605d436739402ab82307596c47b88f982aa1a86f 100644 (file)
@@ -9,6 +9,7 @@
 #include "util.h" // debug_enter
 #include "disk.h" // floppy_tick
 #include "cmos.h" // inb_cmos
+#include "pic.h" // unmask_pic1
 
 #define DEBUGF1(fmt, args...) bprintf(0, fmt , ##args)
 #define DEBUGF(fmt, args...)
@@ -55,6 +56,9 @@ timer_setup()
     ticks += (hours * 65543427) / 1000;
     SET_BDA(timer_counter, ticks);
     SET_BDA(timer_rollover, 0);
+
+    // Enable IRQ0 (handle_08)
+    unmask_pic1(PIC1_IRQ0);
 }
 
 static void
@@ -237,7 +241,7 @@ handle_1a06(struct bregs *regs)
     outb_cmos(regs->dh, CMOS_RTC_SECONDS_ALARM);
     outb_cmos(regs->cl, CMOS_RTC_MINUTES_ALARM);
     outb_cmos(regs->ch, CMOS_RTC_HOURS_ALARM);
-    outb(inb(PORT_PIC2_DATA) & ~PIC2_IRQ8, PORT_PIC2_DATA); // enable IRQ 8
+    unmask_pic2(PIC2_IRQ8); // enable IRQ 8
     // enable Status Reg B alarm bit, clear halt clock bit
     outb_cmos((val8 & ~RTC_B_SET) | RTC_B_AIE, CMOS_STATUS_B);
     set_success(regs);
@@ -325,7 +329,7 @@ handle_08()
 
     irq_disable();
 
-    eoi_master_pic();
+    eoi_pic1();
 }
 
 
@@ -345,8 +349,7 @@ set_usertimer(u32 usecs, u16 seg, u16 offset)
     SET_BDA(user_wait_timeout, usecs);
 
     // Unmask IRQ8 so INT70 will get through.
-    u8 irqDisable = inb(PORT_PIC2_DATA);
-    outb(irqDisable & ~PIC2_IRQ8, PORT_PIC2_DATA);
+    unmask_pic2(PIC2_IRQ8);
     // Turn on the Periodic Interrupt timer
     u8 bRegister = inb_cmos(CMOS_STATUS_B);
     outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B);
@@ -489,5 +492,5 @@ handle_70()
     }
 
 done:
-    eoi_both_pics();
+    eoi_pic2();
 }
index c45d6adcab2ee244fc29b6adb984f2c2cc01cddf..e6b82b097d2fe6bb29f921f8ed698b6480bbf830 100644 (file)
@@ -10,6 +10,7 @@
 #include "config.h" // CONFIG_*
 #include "util.h" // debug_enter
 #include "ata.h" // ATA_*
+#include "pic.h" // eoi_pic2
 
 #define DEBUGF1(fmt, args...) bprintf(0, fmt , ##args)
 #define DEBUGF(fmt, args...)
@@ -678,5 +679,5 @@ handle_76()
 {
     debug_isr(DEBUG_ISR_76);
     SET_BDA(disk_interrupt_flag, 0xff);
-    eoi_both_pics();
+    eoi_pic2();
 }
index e0b46c2079fa78c08f409da5c17090a9b16311cd..efe9592f5927060b1fff17ff502316372529b78f 100644 (file)
@@ -11,6 +11,7 @@
 #include "biosvar.h" // struct bregs
 #include "util.h" // irq_disable
 #include "cmos.h" // inb_cmos
+#include "pic.h" // unmask_pic1
 
 #define DEBUGF1(fmt, args...) bprintf(0, fmt , ##args)
 #define DEBUGF(fmt, args...)
@@ -43,6 +44,8 @@ struct floppy_ext_dbt_s diskette_param_table2 VISIBLE16 = {
 void
 floppy_drive_setup()
 {
+    if (! CONFIG_FLOPPY_SUPPORT)
+        return;
     dprintf(3, "init floppy drives\n");
     u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
     u8 out = 0;
@@ -67,6 +70,9 @@ floppy_drive_setup()
         SETBITS_BDA(equipment_list_flags, 0x41);
 
     outb(0x02, PORT_DMA1_MASK_REG);
+
+    // Enable IRQ6 (handle_0e)
+    unmask_pic1(PIC1_IRQ6);
 }
 
 static inline void
@@ -753,7 +759,7 @@ handle_0e()
             inb(PORT_FD_DATA);
         } while ((inb(PORT_FD_STATUS) & 0xc0) == 0xc0);
     }
-    eoi_master_pic();
+    eoi_pic1();
     // diskette interrupt has occurred
     SETBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
 }
index a51d7135c409d886fceac36c30573e88342b8c66..2ac8602daffd4ad7e4380ba90306863518ae1e62 100644 (file)
@@ -14,7 +14,7 @@
 #define PORT_DMA1_MODE_REG     0x000b
 #define PORT_DMA1_CLEAR_FF_REG 0x000c
 #define PORT_DMA1_MASTER_CLEAR 0x000d
-#define PORT_PIC1              0x0020
+#define PORT_PIC1_CMD          0x0020
 #define PORT_PIC1_DATA         0x0021
 #define PORT_PIT_COUNTER0      0x0040
 #define PORT_PIT_COUNTER1      0x0041
@@ -28,7 +28,7 @@
 #define PORT_DIAG              0x0080
 #define PORT_DMA_PAGE_2        0x0081
 #define PORT_A20               0x0092
-#define PORT_PIC2              0x00a0
+#define PORT_PIC2_CMD          0x00a0
 #define PORT_PIC2_DATA         0x00a1
 #define PORT_DMA2_MASK_REG     0x00d4
 #define PORT_DMA2_MODE_REG     0x00d6
 #define PORT_BIOS_DEBUG        0x0403
 #define PORT_BIOS_APM          0x8900
 
-// PORT_PIC1 bitdefs
-#define PIC1_IRQ5  (1<<5)
-// PORT_PIC2 bitdefs
-#define PIC2_IRQ8  (1<<0)
-#define PIC2_IRQ13 (1<<5)
-
 // PORT_KBD_CTRLB bitdefs
 #define KBD_REFRESH (1<<4)
 
index fe2a77d489c4d9fa3f4e6ae26b8956425d5793ec..4304c0dc7c4aa65be61a1e056b8206a3938226ad 100644 (file)
--- a/src/kbd.c
+++ b/src/kbd.c
@@ -8,6 +8,7 @@
 #include "biosvar.h" // struct bregs
 #include "util.h" // debug_enter
 #include "config.h" // CONFIG_*
+#include "pic.h" // eoi_pic1
 
 //--------------------------------------------------------------------------
 // keyboard_panic
@@ -160,6 +161,9 @@ kbd_setup()
             , x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf));
 
     keyboard_init();
+
+    // Enable IRQ1 (handle_09)
+    unmask_pic1(PIC1_IRQ1);
 }
 
 static u8
@@ -705,8 +709,8 @@ handle_09()
     // disable keyboard
     outb(0xad, PORT_PS2_STATUS);
 
-    outb(0x0b, PORT_PIC1);
-    if ((inb(PORT_PIC1) & 0x02) == 0)
+    // Make sure there really is a keyboard irq pending.
+    if (! (get_pic1_isr() & PIC1_IRQ1))
         goto done;
 
     // read key from keyboard controller
@@ -727,7 +731,7 @@ handle_09()
     process_key(key);
 
     irq_disable();
-    eoi_master_pic();
+    eoi_pic1();
 
 done:
     // enable keyboard
index 23e17dedf819c4e36170a7cdf726c6db12dbc2f2..8f6775f24f1683a8c6d42371c8f72d5b75e007e3 100644 (file)
@@ -7,12 +7,25 @@
 
 #include "biosvar.h" // struct bregs
 #include "util.h" // debug_isr
+#include "pic.h" // unmask_pic2
 
 #define DEBUGF1(fmt, args...) bprintf(0, fmt , ##args)
 #define DEBUGF(fmt, args...)
 
 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
 
+void
+mouse_setup()
+{
+    if (! CONFIG_PS2_MOUSE)
+        return;
+    dprintf(3, "init mouse\n");
+    // pointing device installed
+    SETBITS_BDA(equipment_list_flags, 0x04);
+    // Enable IRQ12 (handle_74)
+    unmask_pic2(PIC2_IRQ12);
+}
+
 static void
 set_kbd_command_byte(u8 command_byte)
 {
@@ -421,5 +434,5 @@ handle_74()
     int74_function();
     irq_disable();
 
-    eoi_both_pics();
+    eoi_pic2();
 }
diff --git a/src/pic.h b/src/pic.h
new file mode 100644 (file)
index 0000000..0eb70ee
--- /dev/null
+++ b/src/pic.h
@@ -0,0 +1,77 @@
+// Helpers for working with i8259 interrupt controller.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002  MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "ioport.h" // PORT_PIC*
+#include "util.h" // dprintf
+
+// PORT_PIC1 bitdefs
+#define PIC1_IRQ0  (1<<0)
+#define PIC1_IRQ1  (1<<1)
+#define PIC1_IRQ2  (1<<2)
+#define PIC1_IRQ5  (1<<5)
+#define PIC1_IRQ6  (1<<6)
+// PORT_PIC2 bitdefs
+#define PIC2_IRQ8  (1<<0)
+#define PIC2_IRQ12 (1<<4)
+#define PIC2_IRQ13 (1<<5)
+#define PIC2_IRQ14 (1<<6)
+
+static inline void
+eoi_pic1()
+{
+    // Send eoi (select OCW2 + eoi)
+    outb(0x20, PORT_PIC1_CMD);
+}
+
+static inline void
+eoi_pic2()
+{
+    // Send eoi (select OCW2 + eoi)
+    outb(0x20, PORT_PIC2_CMD);
+    eoi_pic1();
+}
+
+static inline void
+unmask_pic1(u8 irq)
+{
+    outb(inb(PORT_PIC1_DATA) & ~irq, PORT_PIC1_DATA);
+}
+
+static inline void
+unmask_pic2(u8 irq)
+{
+    outb(inb(PORT_PIC2_DATA) & ~irq, PORT_PIC2_DATA);
+}
+
+static inline u8
+get_pic1_isr()
+{
+    // 0x0b == select OCW1 + read ISR
+    outb(0x0b, PORT_PIC1_CMD);
+    return inb(PORT_PIC1_CMD);
+}
+
+static inline void
+pic_setup()
+{
+    dprintf(3, "init pic\n");
+    // Send ICW1 (select OCW1 + will send ICW4)
+    outb(0x11, PORT_PIC1_CMD);
+    outb(0x11, PORT_PIC2_CMD);
+    // Send ICW2 (base irqs: 0x08-0x0f for irq0-7, 0x70-0x78 for irq8-15)
+    outb(0x08, PORT_PIC1_DATA);
+    outb(0x70, PORT_PIC2_DATA);
+    // Send ICW3 (cascaded pic ids)
+    outb(0x04, PORT_PIC1_DATA);
+    outb(0x02, PORT_PIC2_DATA);
+    // Send ICW4 (enable 8086 mode)
+    outb(0x01, PORT_PIC1_DATA);
+    outb(0x01, PORT_PIC2_DATA);
+    // Mask all irqs (except cascaded PIC2 irq)
+    outb(~PIC1_IRQ2, PORT_PIC1_DATA);
+    outb(~0, PORT_PIC2_DATA);
+}
index afbd36093a344be2f914f1e806ddd467ba1b46a5..766e8984e765634a99989fbbd5cec74c914586a2 100644 (file)
@@ -15,6 +15,7 @@
 #include "kbd.h" // kbd_setup
 #include "disk.h" // floppy_drive_setup
 #include "memmap.h" // add_e820
+#include "pic.h" // pic_setup
 
 #define bda ((struct bios_data_area_s *)MAKE_FARPTR(SEG_BDA, 0))
 #define ebda ((struct extended_bios_data_area_s *)MAKE_FARPTR(SEG_EBDA, 0))
@@ -25,42 +26,39 @@ init_bda()
     dprintf(3, "init bda\n");
     memset(bda, 0, sizeof(*bda));
 
+    SET_BDA(mem_size_kb, BASE_MEM_IN_K);
+
     int i;
     for (i=0; i<256; i++) {
         SET_BDA(ivecs[i].seg, SEG_BIOS);
         SET_BDA(ivecs[i].offset, OFFSET_dummy_iret_handler);
     }
 
-    SET_BDA(mem_size_kb, BASE_MEM_IN_K);
-
-    // Set BDA Equipment Word - 0x06 = FPU enable, mouse installed
-    SET_BDA(equipment_list_flags, 0x06);
-
-    // set vector 0x79 to zero
-    // this is used by 'gardian angel' protection system
-    SET_BDA(ivecs[0x79].seg, 0);
-    SET_BDA(ivecs[0x79].offset, 0);
-
-    SET_BDA(ivecs[0x40].offset, OFFSET_entry_40);
+    SET_BDA(ivecs[0x08].offset, OFFSET_entry_08);
+    SET_BDA(ivecs[0x09].offset, OFFSET_entry_09);
     SET_BDA(ivecs[0x0e].offset, OFFSET_entry_0e);
+    SET_BDA(ivecs[0x10].offset, OFFSET_entry_10);
+    SET_BDA(ivecs[0x11].offset, OFFSET_entry_11);
+    SET_BDA(ivecs[0x12].offset, OFFSET_entry_12);
     SET_BDA(ivecs[0x13].offset, OFFSET_entry_13);
-    SET_BDA(ivecs[0x76].offset, OFFSET_entry_76);
+    SET_BDA(ivecs[0x14].offset, OFFSET_entry_14);
+    SET_BDA(ivecs[0x15].offset, OFFSET_entry_15);
+    SET_BDA(ivecs[0x16].offset, OFFSET_entry_16);
     SET_BDA(ivecs[0x17].offset, OFFSET_entry_17);
     SET_BDA(ivecs[0x18].offset, OFFSET_entry_18);
     SET_BDA(ivecs[0x19].offset, OFFSET_entry_19);
-    SET_BDA(ivecs[0x1c].offset, OFFSET_entry_1c);
-    SET_BDA(ivecs[0x12].offset, OFFSET_entry_12);
-    SET_BDA(ivecs[0x11].offset, OFFSET_entry_11);
-    SET_BDA(ivecs[0x15].offset, OFFSET_entry_15);
-    SET_BDA(ivecs[0x08].offset, OFFSET_entry_08);
-    SET_BDA(ivecs[0x09].offset, OFFSET_entry_09);
-    SET_BDA(ivecs[0x16].offset, OFFSET_entry_16);
-    SET_BDA(ivecs[0x14].offset, OFFSET_entry_14);
     SET_BDA(ivecs[0x1a].offset, OFFSET_entry_1a);
+    SET_BDA(ivecs[0x1c].offset, OFFSET_entry_1c);
+    SET_BDA(ivecs[0x40].offset, OFFSET_entry_40);
     SET_BDA(ivecs[0x70].offset, OFFSET_entry_70);
     SET_BDA(ivecs[0x74].offset, OFFSET_entry_74);
     SET_BDA(ivecs[0x75].offset, OFFSET_entry_75);
-    SET_BDA(ivecs[0x10].offset, OFFSET_entry_10);
+    SET_BDA(ivecs[0x76].offset, OFFSET_entry_76);
+
+    // set vector 0x79 to zero
+    // this is used by 'gardian angel' protection system
+    SET_BDA(ivecs[0x79].seg, 0);
+    SET_BDA(ivecs[0x79].offset, 0);
 
     SET_BDA(ivecs[0x1E].offset, OFFSET_diskette_param_table2);
 }
@@ -109,25 +107,6 @@ ram_probe(void)
     dprintf(1, "ram_size=0x%08x\n", GET_EBDA(ram_size));
 }
 
-static void
-pic_setup()
-{
-    dprintf(3, "init pic\n");
-    outb(0x11, PORT_PIC1);
-    outb(0x11, PORT_PIC2);
-    outb(0x08, PORT_PIC1_DATA);
-    outb(0x70, PORT_PIC2_DATA);
-    outb(0x04, PORT_PIC1_DATA);
-    outb(0x02, PORT_PIC2_DATA);
-    outb(0x01, PORT_PIC1_DATA);
-    outb(0x01, PORT_PIC2_DATA);
-    outb(0xb8, PORT_PIC1_DATA);
-    if (CONFIG_PS2_MOUSE)
-        outb(0x8f, PORT_PIC2_DATA);
-    else
-        outb(0x9f, PORT_PIC2_DATA);
-}
-
 static void
 init_boot_vectors()
 {
@@ -232,11 +211,13 @@ post()
     init_bda();
     init_ebda();
 
+    pic_setup();
     timer_setup();
     kbd_setup();
     lpt_setup();
     serial_setup();
-    pic_setup();
+    mouse_setup();
+    mathcp_setup();
 
     memmap_setup();
 
@@ -301,7 +282,7 @@ check_restart_status()
 
     // XXX - this is supposed to jump without changing any memory -
     // but the stack has been altered by the time the code gets here.
-    eoi_both_pics();
+    eoi_pic2();
     struct bregs br;
     memset(&br, 0, sizeof(br));
     br.cs = GET_BDA(jump_cs_ip) >> 16;
index 0941565976ebe5dca485b3b2970b8c2263334a1c..e73fe5ca82e1ecfe563b3e5b7f6aaaa9023dc70b 100644 (file)
@@ -9,6 +9,7 @@
 #include "biosvar.h" // BIOS_CONFIG_TABLE
 #include "ioport.h" // inb
 #include "memmap.h" // E820_RAM
+#include "pic.h" // eoi_pic2
 
 // Use PS2 System Control port A to set A20 enable
 static inline u8
@@ -368,6 +369,16 @@ handle_nmi()
     BX_PANIC("NMI Handler called\n");
 }
 
+void
+mathcp_setup()
+{
+    dprintf(3, "math cp init\n");
+    // 80x87 coprocessor installed
+    SETBITS_BDA(equipment_list_flags, 0x02);
+    // Enable IRQ13 (handle_75)
+    unmask_pic2(PIC2_IRQ13);
+}
+
 // INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION
 void VISIBLE16
 handle_75()
@@ -377,7 +388,7 @@ handle_75()
     // clear irq13
     outb(0, PORT_MATH_CLEAR);
     // clear interrupt
-    eoi_both_pics();
+    eoi_pic2();
     // legacy nmi call
     struct bregs br;
     memset(&br, 0, sizeof(br));
index 8a715691fe7be409749322c38c0f5c2f63a8d99d..ee42f6c29dba31bacdf89b8132d958d27b2de226 100644 (file)
@@ -56,19 +56,6 @@ void *memset(void *s, int c, size_t n);
 void *memcpy(void *d1, const void *s1, size_t len);
 void *memmove(void *d, const void *s, size_t len);
 
-static inline void
-eoi_master_pic()
-{
-    outb(PIC1_IRQ5, PORT_PIC1);
-}
-
-static inline void
-eoi_both_pics()
-{
-    outb(PIC2_IRQ13, PORT_PIC2);
-    eoi_master_pic();
-}
-
 // Call a function with a specified register state.  Note that on
 // return, the interrupt enable/disable flag may be altered.
 static inline
@@ -170,6 +157,12 @@ void __set_code_fail(const char *fname, struct bregs *regs, u8 code);
 // kbd.c
 void handle_15c2(struct bregs *regs);
 
+// mouse.c
+void mouse_setup();
+
+// system.c
+void mathcp_setup();
+
 // serial.c
 void serial_setup();
 void lpt_setup();