[NTVDM]
[reactos.git] / subsystems / ntvdm / bios.c
index 0791c27..eb61cc0 100644 (file)
@@ -17,6 +17,8 @@
 #include "ps2.h"
 #include "timer.h"
 
+#include "registers.h"
+
 /* PRIVATE VARIABLES **********************************************************/
 
 PBIOS_DATA_AREA Bda;
@@ -267,14 +269,14 @@ static LPBYTE VideoModes[] =
 
 static BOOLEAN BiosKbdBufferPush(WORD Data)
 {
-    /* Get the location of the element after the head */
-    WORD NextElement = Bda->KeybdBufferHead + 2;
+    /* Get the location of the element after the tail */
+    WORD NextElement = Bda->KeybdBufferTail + 2;
 
     /* Wrap it around if it's at or beyond the end */
     if (NextElement >= Bda->KeybdBufferEnd) NextElement = Bda->KeybdBufferStart;
 
     /* If it's full, fail */
-    if (NextElement == Bda->KeybdBufferTail) return FALSE;
+    if (NextElement == Bda->KeybdBufferHead) return FALSE;
 
     /* Put the value in the queue */
     *((LPWORD)((ULONG_PTR)Bda + Bda->KeybdBufferTail)) = Data;
@@ -468,19 +470,33 @@ BOOLEAN BiosInitialize(VOID)
         IntVecTable[i * 2] = Offset;
         IntVecTable[i * 2 + 1] = BIOS_SEGMENT;
 
-        BiosCode[Offset++] = 0xFA; // cli
+        BiosCode[Offset++] = 0xFB; // sti
 
         BiosCode[Offset++] = 0x6A; // push i
         BiosCode[Offset++] = (BYTE)i;
 
+        BiosCode[Offset++] = 0x6A; // push 0
+        BiosCode[Offset++] = 0x00;
+
+        BiosCode[Offset++] = 0xF8; // clc
+
         BiosCode[Offset++] = LOBYTE(EMULATOR_BOP); // BOP sequence
         BiosCode[Offset++] = HIBYTE(EMULATOR_BOP);
         BiosCode[Offset++] = LOBYTE(EMULATOR_INT_BOP);
         BiosCode[Offset++] = HIBYTE(EMULATOR_INT_BOP);
 
-        BiosCode[Offset++] = 0x83; // add sp, 2
+        BiosCode[Offset++] = 0x73; // jnc +3
+        BiosCode[Offset++] = 0x03;
+
+        // HACK: The following instruction should be HLT!
+        BiosCode[Offset++] = 0x90; // nop
+
+        BiosCode[Offset++] = 0xEB; // jmp -10
+        BiosCode[Offset++] = 0xF6;
+
+        BiosCode[Offset++] = 0x83; // add sp, 4
         BiosCode[Offset++] = 0xC4;
-        BiosCode[Offset++] = 0x02;
+        BiosCode[Offset++] = 0x04;
 
         BiosCode[Offset++] = 0xCF; // iret
     }
@@ -591,9 +607,7 @@ WORD BiosPeekCharacter(VOID)
 
 WORD BiosGetCharacter(VOID)
 {
-    WORD CharacterData;
-    INPUT_RECORD InputRecord;
-    DWORD Count;
+    WORD CharacterData = 0;
 
     /* Check if there is a key available */
     if (Bda->KeybdBufferHead != Bda->KeybdBufferTail)
@@ -604,22 +618,8 @@ WORD BiosGetCharacter(VOID)
     }
     else
     {
-        while (TRUE)
-        {
-            /* Wait for a console event */
-            WaitForSingleObject(BiosConsoleInput, INFINITE);
-    
-            /* Read the event, and make sure it's a keypress */
-            if (!ReadConsoleInput(BiosConsoleInput, &InputRecord, 1, &Count)) continue;
-            if (InputRecord.EventType != KEY_EVENT) continue;
-            if (!InputRecord.Event.KeyEvent.bKeyDown) continue;
-
-            /* Save the scan code and end the loop */
-            CharacterData = (InputRecord.Event.KeyEvent.wVirtualScanCode << 8)
-                            | InputRecord.Event.KeyEvent.uChar.AsciiChar;
-
-            break;
-        }
+        /* Set the handler CF to repeat the BOP */
+        EmulatorSetFlag(EMULATOR_FLAG_CF);
     }
 
     return CharacterData;
@@ -984,15 +984,20 @@ VOID BiosKeyboardService(LPWORD Stack)
 
     switch (HIBYTE(Eax))
     {
+        /* Wait for keystroke and read */
         case 0x00:
+        /* Wait for extended keystroke and read */
+        case 0x10:  // FIXME: Temporarily do the same as INT 16h, 00h
         {
             /* Read the character (and wait if necessary) */
             EmulatorSetRegister(EMULATOR_REG_AX, BiosGetCharacter());
-
             break;
         }
 
+        /* Get keystroke status */
         case 0x01:
+        /* Get extended keystroke status */
+        case 0x11:  // FIXME: Temporarily do the same as INT 16h, 01h
         {
             WORD Data = BiosPeekCharacter();
 
@@ -1010,7 +1015,45 @@ VOID BiosKeyboardService(LPWORD Stack)
 
             break;
         }
-        
+
+        /* Get shift status */
+        case 0x02:
+        {
+            /* Return the lower byte of the keyboard shift status word */
+            setAL(LOBYTE(Bda->KeybdShiftFlags));
+            break;
+        }
+
+        /* Reserved */
+        case 0x04:
+        {
+            DPRINT1("BIOS Function INT 16h, AH = 0x04 is RESERVED\n");
+            break;
+        }
+
+        /* Push keystroke */
+        case 0x05:
+        {
+            /* Return 0 if success, 1 if failure */
+            setAL(BiosKbdBufferPush(getCX()) == FALSE);
+            break;
+        }
+
+        /* Get extended shift status */
+        case 0x12:
+        {
+            /*
+             * Be careful! The returned word is similar to Bda->KeybdShiftFlags
+             * but the high byte is organized differently:
+             * the bytes 2 and 3 of the high byte are not the same...
+             */
+            WORD KeybdShiftFlags = (Bda->KeybdShiftFlags & 0xF3FF);
+
+            /* Return the extended keyboard shift status word */
+            setAX(KeybdShiftFlags);
+            break;
+        }
+
         default:
         {
             DPRINT1("BIOS Function INT 16h, AH = 0x%02X NOT IMPLEMENTED\n",
@@ -1094,39 +1137,45 @@ VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack)
             BYTE ScanCode, VirtualKey;
             WORD Character;
             
-            /* Check if there is a scancode available */
-            if (!(KeyboardReadStatus() & 1)) break;
-
-            /* Get the scan code and virtual key code */
-            ScanCode = KeyboardReadData();
-            VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
-
-            /* Check if this is a key press or release */
-            if (!(ScanCode & (1 << 7)))
+            /* Loop while there is a scancode available */
+            while (KeyboardReadStatus() & 1)
             {
-                /* Key press */
-                if (VirtualKey == VK_NUMLOCK
-                    || VirtualKey == VK_CAPITAL
-                    || VirtualKey == VK_SCROLL)
+                /* Get the scan code and virtual key code */
+                ScanCode = KeyboardReadData();
+                VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
+
+                /* Check if this is a key press or release */
+                if (!(ScanCode & (1 << 7)))
                 {
-                    /* For toggle keys, toggle the lowest bit in the keyboard map */
-                    BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
-                }
+                    /* Key press */
+                    if (VirtualKey == VK_NUMLOCK
+                        || VirtualKey == VK_CAPITAL
+                        || VirtualKey == VK_SCROLL)
+                    {
+                        /* For toggle keys, toggle the lowest bit in the keyboard map */
+                        BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
+                    }
+    
+                    /* Set the highest bit */
+                    BiosKeyboardMap[VirtualKey] |= (1 << 7);
 
-                /* Set the highest bit */
-                BiosKeyboardMap[VirtualKey] |= (1 << 7);
+                    /* Find out which character this is */
+                    Character = 0;
+                    if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) == 0)
+                    {
+                        /* Not ASCII */
+                        Character = 0;
+                    }
 
-                /* Find out which character this is */
-                if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) > 0)
-                {
                     /* Push it onto the BIOS keyboard queue */
                     BiosKbdBufferPush((ScanCode << 8) | (Character & 0xFF));
+
+                }
+                else
+                {
+                    /* Key release, unset the highest bit */
+                    BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
                 }
-            }
-            else
-            {
-                /* Key release, unset the highest bit */
-                BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
             }
 
             break;