PIC helper functions to read the ISR, IRR, and IMR
[akaros.git] / kern / arch / i686 / apic.c
index c6411e7..4a930b9 100644 (file)
 #include <arch/x86.h>
 #include <arch/arch.h>
 #include <arch/apic.h>
-#include <ros/timer.h>
+#include <time.h>
 #include <assert.h>
 #include <stdio.h>
 
 system_timing_t RO system_timing = {0, 0, 0xffff, 0};
 
-/*
- * Remaps the Programmable Interrupt Controller to use IRQs 32-47
+/* * Remaps the Programmable Interrupt Controller to use IRQs 32-47
  * http://wiki.osdev.org/PIC
- * Not 100% on this stuff, after looking over 
- * http://bochs.sourceforge.net/techspec/PORTS.LST  The cascading and other 
- * stuff might need to be in one command, and after that all we are doing
- * is toggling masks.
- */
+ * Check osdev for a more thorough explanation/implementation.
+ * http://bochs.sourceforge.net/techspec/PORTS.LST  */
 void pic_remap() 
 {
-       // start initialization
+       /* start initialization (ICW1) */
        outb(PIC1_CMD, 0x11);
        outb(PIC2_CMD, 0x11);
-       // set new offsets
+       /* set new offsets (ICW2) */
        outb(PIC1_DATA, PIC1_OFFSET);
        outb(PIC2_DATA, PIC2_OFFSET);
-       // set up cascading
+       /* set up cascading (ICW3) */
        outb(PIC1_DATA, 0x04);
        outb(PIC2_DATA, 0x02);
-       // other stuff (put in 8086/88 mode, or whatever)
+       /* other stuff (put in 8086/88 mode, or whatever) (ICW4) */
        outb(PIC1_DATA, 0x01);
        outb(PIC2_DATA, 0x01);
-       // set masks, defaulting to all masked for now
+       /* Init done, further data R/W access the interrupt mask */
+       /* set masks, defaulting to all masked for now */
        outb(PIC1_DATA, 0xff);
        outb(PIC2_DATA, 0xff);
 }
@@ -63,6 +60,33 @@ void pic_unmask_irq(uint8_t irq)
                outb(PIC1_DATA, inb(PIC1_DATA) & ~(1 << irq));
 }
 
+/* Aka, the IMR.  Simply reading the data port are OCW1s. */
+uint16_t pic_get_mask(void)
+{
+       return (inb(PIC2_DATA) << 8) | inb(PIC1_DATA);
+}
+
+static uint16_t __pic_get_irq_reg(int ocw3)
+{
+       /* OCW3 to PIC CMD to get the register values.  PIC2 is chained, and
+        * represents IRQs 8-15.  PIC1 is IRQs 0-7, with 2 being the chain */
+       outb(PIC1_CMD, ocw3);
+       outb(PIC2_CMD, ocw3);
+       return (inb(PIC2_CMD) << 8) | inb(PIC1_CMD);
+}
+
+/* Returns the combined value of the cascaded PICs irq request register */
+uint16_t pic_get_irr(void)
+{
+       return __pic_get_irq_reg(PIC_READ_IRR);
+}
+
+/* Returns the combined value of the cascaded PICs irq service register */
+uint16_t pic_get_isr(void)
+{
+       return __pic_get_irq_reg(PIC_READ_ISR);
+}
+
 /*
  * Sets the LAPIC timer to go off after a certain number of ticks.  The primary
  * clock freq is actually the bus clock, which we figure out during timer_init
@@ -102,7 +126,7 @@ void set_core_timer(uint32_t usec, bool periodic)
 uint32_t lapic_get_default_id(void)
 {
        uint32_t ebx;
-       cpuid(1, 0, &ebx, 0, 0);
+       cpuid(0x1, 0x0, 0, &ebx, 0, 0);
        // p6 family only uses 4 bits here, and 0xf is reserved for the IOAPIC
        return (ebx & 0xFF000000) >> 24;
 }
@@ -159,7 +183,7 @@ static int getpit()
     return ((high << 8) | low);
 }
 
-// forces cpu to relax for usec miliseconds.  declared in kern/include/timing.h
+// forces cpu to relax for usec miliseconds.  declared in kern/include/time.h
 void udelay(uint64_t usec)
 {
        #if !defined(__BOCHS__)
@@ -168,7 +192,7 @@ void udelay(uint64_t usec)
                uint64_t start, end, now;
 
                start = read_tsc();
-        end = start + (system_timing.tsc_freq * usec) / 1000000;
+        end = start + usec2tsc(usec);
         //cprintf("start %llu, end %llu\n", start, end);
                if (end == 0) cprintf("This is terribly wrong \n");
                do {