1 /* 2 * COPYRIGHT: GPL - See COPYING in the top level directory 3 * PROJECT: ReactOS Virtual DOS Machine 4 * FILE: subsystems/mvdm/ntvdm/hardware/keyboard.c 5 * PURPOSE: Keyboard emulation 6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "ntvdm.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 #include "keyboard.h" 17 #include "ps2.h" 18 19 /* PRIVATE VARIABLES **********************************************************/ 20 21 static BOOLEAN KeyboardReporting = FALSE; 22 static BYTE KeyboardId = 0; // We only support basic old-type keyboard 23 static BYTE KbdDataByteWait = 0; 24 25 static BYTE KbdPS2Port = 0; 26 27 /* PRIVATE FUNCTIONS **********************************************************/ 28 29 static VOID WINAPI KeyboardCommand(LPVOID Param, BYTE Command) 30 { 31 /* Check if we were waiting for a data byte */ 32 if (KbdDataByteWait) 33 { 34 PS2QueuePush(KbdPS2Port, KEYBOARD_ACK); 35 36 switch (KbdDataByteWait) 37 { 38 /* Set/Reset Mode Indicators */ 39 case 0xED: 40 { 41 // Ignore setting the keyboard LEDs 42 break; 43 } 44 45 /* PS/2 Select/Read Alternate Scan Code Sets */ 46 case 0xF0: 47 /* Set Typematic Rate/Delay */ 48 case 0xF3: 49 { 50 // FIXME: UNIMPLEMENTED; just return ACKnowledge. 51 // This unblocks some programs that want to initialize 52 // the keyboard by sending keyboard commands and then 53 // performing polling on the port until "valid" data 54 // comes out. 55 DPRINT1("KeyboardCommand(0x%02X) NOT IMPLEMENTED\n", KbdDataByteWait); 56 break; 57 } 58 59 default: 60 { 61 /* Shouldn't happen */ 62 ASSERT(FALSE); 63 } 64 } 65 66 KbdDataByteWait = 0; 67 return; 68 } 69 70 switch (Command) 71 { 72 /* Set/Reset Mode Indicators */ 73 case 0xED: 74 /* PS/2 Select/Read Alternate Scan Code Sets */ 75 case 0xF0: 76 /* Set Typematic Rate/Delay */ 77 case 0xF3: 78 { 79 KbdDataByteWait = Command; 80 PS2QueuePush(KbdPS2Port, KEYBOARD_ACK); 81 break; 82 } 83 84 /* Echo test command */ 85 case 0xEE: 86 { 87 PS2QueuePush(KbdPS2Port, 0xEE); 88 break; 89 } 90 91 /* Get Keyboard ID */ 92 case 0xF2: 93 { 94 PS2QueuePush(KbdPS2Port, KEYBOARD_ACK); 95 PS2QueuePush(KbdPS2Port, KeyboardId); 96 break; 97 } 98 99 /* Enable Reporting */ 100 case 0xF4: 101 { 102 KeyboardReporting = TRUE; 103 PS2QueuePush(KbdPS2Port, KEYBOARD_ACK); 104 break; 105 } 106 107 /* Disable Reporting */ 108 case 0xF5: 109 { 110 KeyboardReporting = FALSE; 111 PS2QueuePush(KbdPS2Port, KEYBOARD_ACK); 112 break; 113 } 114 115 /* Set Defaults */ 116 case 0xF6: 117 { 118 // So far, nothing to reset 119 PS2QueuePush(KbdPS2Port, KEYBOARD_ACK); 120 break; 121 } 122 123 /* PS/2 Typematic & Make/Break key modes */ 124 case 0xF7: case 0xF8: case 0xF9: 125 case 0xFA: case 0xFB: case 0xFC: case 0xFD: 126 { 127 /* 128 * Unsupported on PC-AT, they are just ignored 129 * and acknowledged as discussed in: 130 * http://stanislavs.org/helppc/keyboard_commands.html 131 */ 132 PS2QueuePush(KbdPS2Port, KEYBOARD_ACK); 133 } 134 135 /* Resend */ 136 case 0xFE: 137 { 138 PS2QueuePush(KbdPS2Port, KEYBOARD_ACK); 139 UNIMPLEMENTED; 140 break; 141 } 142 143 /* Reset */ 144 case 0xFF: 145 { 146 /* Send ACKnowledge */ 147 PS2QueuePush(KbdPS2Port, KEYBOARD_ACK); 148 149 // So far, nothing to reset 150 151 /* Send the Basic Assurance Test success code and the device ID */ 152 PS2QueuePush(KbdPS2Port, KEYBOARD_BAT_SUCCESS); 153 PS2QueuePush(KbdPS2Port, KeyboardId); 154 break; 155 } 156 157 /* Unknown command */ 158 default: 159 { 160 PS2QueuePush(KbdPS2Port, KEYBOARD_ERROR); 161 } 162 } 163 } 164 165 /* PUBLIC FUNCTIONS ***********************************************************/ 166 167 VOID KeyboardEventHandler(PKEY_EVENT_RECORD KeyEvent) 168 { 169 WORD i; 170 BYTE ScanCode = (BYTE)KeyEvent->wVirtualScanCode; 171 172 /* Check if we're not reporting */ 173 if (!KeyboardReporting) return; 174 175 /* If this is a key release, set the highest bit in the scan code */ 176 if (!KeyEvent->bKeyDown) ScanCode |= 0x80; 177 178 /* Push the scan code into the PS/2 queue */ 179 for (i = 0; i < KeyEvent->wRepeatCount; i++) 180 { 181 if (KeyEvent->dwControlKeyState & ENHANCED_KEY) PS2QueuePush(KbdPS2Port, 0xE0); 182 PS2QueuePush(KbdPS2Port, ScanCode); 183 } 184 185 DPRINT("Press 0x%X\n", ScanCode); 186 } 187 188 BOOLEAN KeyboardInit(BYTE PS2Connector) 189 { 190 /* Finish to plug the keyboard to the specified PS/2 port */ 191 KbdPS2Port = PS2Connector; 192 PS2SetDeviceCmdProc(KbdPS2Port, NULL, KeyboardCommand); 193 return TRUE; 194 } 195