Support sleeping until an irq fires, and use where applicable.
authorKevin O'Connor <kevin@koconnor.net>
Sun, 20 Sep 2009 19:33:08 +0000 (15:33 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Sun, 20 Sep 2009 19:33:08 +0000 (15:33 -0400)
Add wait_irq() - it's more efficient than looping with cpu_relax().
Also, move kbd irq enables down - only kbd_command needs it.
Also, make some minor code layout improvements to kbd.c.

src/clock.c
src/floppy.c
src/kbd.c
src/util.h

index 9009d49ca142c8c7fbe10d328893ddc95a612e01..ee2d05fe40ed34be5749ba0edea35d4b9fb41c03 100644 (file)
@@ -488,10 +488,8 @@ handle_1586(struct bregs *regs)
         set_code_fail(regs, RET_ECLOCKINUSE);
         return;
     }
-    irq_enable();
     while (!statusflag)
-        cpu_relax();
-    irq_disable();
+        wait_irq();
     set_success(regs);
 }
 
index 922a2f51d42f12dc463648852557f7904e40a18e..ad7aa7f159d98d06f0dbeb68463043d98af9d285 100644 (file)
@@ -176,7 +176,6 @@ floppy_reset_controller()
 static int
 wait_floppy_irq()
 {
-    irq_enable();
     u8 v;
     for (;;) {
         if (!GET_BDA(floppy_motor_counter)) {
@@ -186,9 +185,8 @@ wait_floppy_irq()
         v = GET_BDA(floppy_recalibration_status);
         if (v & FRS_TIMEOUT)
             break;
-        cpu_relax();
+        wait_irq();
     }
-    irq_disable();
 
     v &= ~FRS_TIMEOUT;
     SET_BDA(floppy_recalibration_status, v);
index 3714d336c5f9ab773e664469c3becded912244b7..650f1d4e4fdd2a063e83ff2a187cb990b779cf39 100644 (file)
--- a/src/kbd.c
+++ b/src/kbd.c
@@ -23,6 +23,7 @@
 
 #define KF1_LCTRL        (1<<0)
 #define KF1_LALT         (1<<1)
+#define KF1_PAUSEACTIVE  (1<<3)
 #define KF1_SCROLL       (1<<4)
 #define KF1_NUM          (1<<5)
 #define KF1_CAPS         (1<<6)
@@ -160,7 +161,7 @@ dequeue_key(struct bregs *regs, int incr, int extended)
             regs->flags |= F_ZF;
             return;
         }
-        cpu_relax();
+        wait_irq();
     }
 
     u8 ascii_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0));
@@ -233,7 +234,9 @@ static void
 handle_160a(struct bregs *regs)
 {
     u8 param[2];
+    irq_enable();
     int ret = kbd_command(ATKBD_CMD_GETID, param);
+    irq_disable();
     if (ret) {
         regs->bx = 0;
         return;
@@ -303,7 +306,9 @@ set_leds()
     if (shift_flags == led_flags)
         return;
 
+    irq_enable();
     int ret = kbd_command(ATKBD_CMD_SETLEDS, &shift_flags);
+    irq_disable();
     if (ret)
         // Error
         return;
@@ -319,8 +324,7 @@ handle_16(struct bregs *regs)
     if (! CONFIG_KEYBOARD)
         return;
 
-    irq_enable();
-
+    // XXX - set_leds should be called from irq handler
     set_leds();
 
     switch (regs->ah) {
@@ -443,10 +447,10 @@ static struct scaninfo {
 };
 
 // Handle a scancode read from the ps2 port.  Note that "noinline" is
-// used to make sure the call to call16_simpint in handle_09 doesn't
+// used to make sure the call to call16_simpint in process_key doesn't
 // have the overhead of this function's stack.
 static void noinline
-process_key(u8 scancode)
+__process_key(u8 scancode)
 {
     u8 flags0 = GET_BDA(kbd_flag0);
     u8 flags1 = GET_BDA(kbd_flag1);
@@ -457,15 +461,22 @@ process_key(u8 scancode)
         if ((scancode & ~0x80) == 0x1d)
             // Second key of sequence
             return;
-        // Third key of sequence
+        // Third key of sequence - clear flag.
+        flags2 &= ~KF2_LAST_E1;
+        SET_BDA(kbd_flag2, flags2);
+
         if (scancode == 0xc5) {
+            // Final key in sequence.
+
             // XXX - do actual pause.
         }
-        flags2 &= ~KF2_LAST_E1;
-        SET_BDA(kbd_flag2, flags2);
         return;
     }
 
+    // XXX - PrtScr should cause int 0x05
+    // XXX - Ctrl+Break should cause int 0x1B
+    // XXX - SysReq should cause int 0x15/0x85
+
     switch (scancode) {
     case 0x00:
         dprintf(1, "KBD: int09 handler: AL=0\n");
@@ -611,6 +622,21 @@ process_key(u8 scancode)
     SET_BDA(kbd_flag2, flags2);
 }
 
+static void
+process_key(u8 key)
+{
+    if (CONFIG_KBD_CALL_INT15_4F) {
+        // allow for keyboard intercept
+        u32 eax = (0x4f << 8) | key;
+        u32 flags;
+        call16_simpint(0x15, &eax, &flags);
+        if (!(flags & F_CF))
+            return;
+        key = eax;
+    }
+    __process_key(key);
+}
+
 // INT09h : Keyboard Hardware Service Entry Point
 void VISIBLE16
 handle_09()
@@ -625,18 +651,9 @@ handle_09()
         dprintf(1, "keyboard irq but no keyboard data.\n");
         goto done;
     }
-    u8 key = inb(PORT_PS2_DATA);
+    v = inb(PORT_PS2_DATA);
 
-    if (CONFIG_KBD_CALL_INT15_4F) {
-        // allow for keyboard intercept
-        u32 eax = (0x4f << 8) | key;
-        u32 flags;
-        call16_simpint(0x15, &eax, &flags);
-        if (!(flags & F_CF))
-            goto done;
-        key = eax;
-    }
-    process_key(key);
+    process_key(v);
 
 done:
     eoi_pic1();
index c18fbbaa9763b620a3f93b9dbc2f90270c2bf16c..7601b482f25369dbfd6a2bf7210097fef75ddb97 100644 (file)
@@ -36,6 +36,12 @@ static inline void cpu_relax(void)
     asm volatile("rep ; nop": : :"memory");
 }
 
+// Atomically enable irqs and sleep until an irq; then re-disable irqs.
+static inline void wait_irq(void)
+{
+    asm volatile("sti ; hlt ; cli ; cld": : :"memory");
+}
+
 static inline void nop(void)
 {
     asm volatile("nop");