Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
6.3 KiB

  1. //
  2. // Fake Keyboard rom support
  3. //
  4. // This file provides interrim support for keyboard rom bios services.
  5. // It is only intended for use until Insignia produces proper rom support
  6. // for NTVDM
  7. //
  8. // Note: portions of this code were lifted from the following source.
  9. /* x86 v1.0
  10. *
  11. * XBIOSKBD.C
  12. * Guest ROM BIOS keyboard emulation
  13. *
  14. * History
  15. * Created 20-Oct-90 by Jeff Parsons
  16. *
  17. * COPYRIGHT NOTICE
  18. * This source file may not be distributed, modified or incorporated into
  19. * another product without prior approval from the author, Jeff Parsons.
  20. * This file may be copied to designated servers and machines authorized to
  21. * access those servers, but that does not imply any form of approval.
  22. */
  23. #include <windows.h>
  24. #include <stdio.h>
  25. #include <conio.h>
  26. #include <string.h>
  27. #include "softpc.h"
  28. #include "bop.h"
  29. #include "xbios.h"
  30. #include "xbioskbd.h"
  31. #include "xwincon.h"
  32. #include "fun.h"
  33. #include <conapi.h>
  34. extern HANDLE InputHandle;
  35. #define MAX_KBD_BUFFER 256
  36. CHAR KbdBuffer[MAX_KBD_BUFFER];
  37. ULONG Head=0,Tail=0;
  38. HANDLE KbdSyncEvent;
  39. CRITICAL_SECTION csKbd;
  40. CRITICAL_SECTION csConsole;
  41. CRITICAL_SECTION csCtrlc;
  42. BOOL fEventThreadBlock = FALSE;
  43. HANDLE hConsoleWait;
  44. ULONG nCtrlc=0;
  45. HANDLE StdIn;
  46. static BYTE ServiceRoutine[] = { 0xC4, 0xC4, BOP_KBD, 0x50, 0x55, 0x8B,
  47. 0xEC, 0x9C, 0x58, 0x89, 0x46, 0x08, 0x5d, 0x58, 0xCF };
  48. #define SERVICE_LENGTH sizeof(ServiceRoutine)
  49. /* BiosKbdInit - Initialize ROM BIOS keyboard support
  50. *
  51. * ENTRY
  52. * argc - # of command-line options
  53. * argv - pointer to first option pointer
  54. * ServiceAddress - linear address to put service routine at
  55. *
  56. * EXIT
  57. * TRUE if successful, FALSE if not
  58. */
  59. BOOL BiosKbdInit(int argc, char *argv[], PVOID *ServiceAddress)
  60. {
  61. PVOID Address;
  62. argc, argv;
  63. memcpy(*ServiceAddress, ServiceRoutine, SERVICE_LENGTH);
  64. Address = (PVOID)(BIOSINT_KBD * 4);
  65. *((PWORD)Address) = RMOFF(*ServiceAddress);
  66. *(((PWORD)Address) + 1) = RMSEG(*ServiceAddress);
  67. (PCHAR)*ServiceAddress += SERVICE_LENGTH;
  68. StdIn = GetStdHandle(STD_INPUT_HANDLE);
  69. KbdSyncEvent = CreateEvent( NULL, TRUE, FALSE,NULL );
  70. InitializeCriticalSection (&csKbd);
  71. InitializeCriticalSection(&csConsole);
  72. InitializeCriticalSection(&csCtrlc);
  73. hConsoleWait = CreateEvent (NULL,TRUE,FALSE,NULL);
  74. return TRUE;
  75. }
  76. /* BiosKbd - Emulate ROM BIOS keyboard functions
  77. *
  78. * ENTRY
  79. * None (x86 registers contain parameters)
  80. *
  81. * EXIT
  82. * None (x86 registers/memory updated appropriately)
  83. *
  84. * This function receives control on INT 16h, routes control to the
  85. * appropriate subfunction based on the function # in AH, and
  86. * then simulates an IRET and returns back to the instruction emulator.
  87. */
  88. VOID BiosKbdReadLoop (VOID)
  89. {
  90. ULONG Temp;
  91. while (1) {
  92. Temp = Head + 1;
  93. if(Temp >= MAX_KBD_BUFFER)
  94. Temp =0;
  95. if(Temp == Tail){
  96. Sleep (20);
  97. continue;
  98. }
  99. KbdBuffer[Head] = getche();
  100. EnterCriticalSection(&csConsole);
  101. if(fEventThreadBlock == TRUE){
  102. LeaveCriticalSection(&csConsole);
  103. WaitForSingleObject(hConsoleWait,-1);
  104. ResetEvent(hConsoleWait);
  105. continue;
  106. }
  107. else{
  108. LeaveCriticalSection(&csConsole);
  109. }
  110. EnterCriticalSection(&csKbd);
  111. Head = Temp;
  112. LeaveCriticalSection(&csKbd);
  113. SetEvent(KbdSyncEvent);
  114. }
  115. }
  116. BOOL tkbhit(VOID)
  117. {
  118. if (Tail != Head || nCtrlc)
  119. return TRUE;
  120. return FALSE;
  121. }
  122. CHAR tgetch(VOID)
  123. {
  124. CHAR ch;
  125. while(TRUE) {
  126. EnterCriticalSection(&csCtrlc);
  127. if (nCtrlc){
  128. nCtrlc--;
  129. LeaveCriticalSection(&csCtrlc);
  130. return (CHAR)0x3; // return ctrlc
  131. }
  132. LeaveCriticalSection(&csCtrlc);
  133. if (Tail != Head) {
  134. EnterCriticalSection(&csKbd);
  135. ch = KbdBuffer[Tail++];
  136. if (Tail >= MAX_KBD_BUFFER)
  137. Tail = 0;
  138. LeaveCriticalSection(&csKbd);
  139. return ch;
  140. }
  141. WaitForSingleObject(KbdSyncEvent, -1);
  142. ResetEvent(KbdSyncEvent);
  143. }
  144. }
  145. VOID BiosKbd()
  146. {
  147. static ULONG ulch;
  148. DWORD nRead=0;
  149. switch(getAH()) {
  150. case KBDFUNC_READCHAR:
  151. if (ulch) {
  152. setAL(ulch & 0xff);
  153. setAH(ulch & 0xFF00);
  154. ulch = 0;
  155. }
  156. else {
  157. setAH(0); // zero scan code field for now
  158. setAL((BYTE)tgetch());
  159. if (getAL() == 0 || getAL() == 0xE0) {
  160. setAL(0);
  161. setAH((BYTE)tgetch());
  162. }
  163. }
  164. break;
  165. case KBDFUNC_PEEKCHAR:
  166. setZF(1);
  167. if (ulch) {
  168. setAL(ulch & 0xFF);
  169. setAH(ulch & 0xFF00);
  170. setZF(0);
  171. }
  172. else if(tkbhit()) {
  173. setAH(0); // zero scan code field for now
  174. setAL((BYTE)tgetch());
  175. if (getAL() == 0 || getAL() == 0xE0) {
  176. setAL(0);
  177. setAH((BYTE)tgetch());
  178. }
  179. ulch = getAL() | getAH()<<8 | 0x10000;
  180. setZF(0);
  181. }
  182. break;
  183. }
  184. }
  185. void nt_block_event_thread(void)
  186. {
  187. INPUT_RECORD InputRecord;
  188. DWORD nRecordsWritten;
  189. InputRecord.EventType = 1;
  190. InputRecord.Event.KeyEvent.bKeyDown = 1;
  191. InputRecord.Event.KeyEvent.wRepeatCount = 1;
  192. InputRecord.Event.KeyEvent.wVirtualKeyCode = 32;
  193. InputRecord.Event.KeyEvent.wVirtualScanCode = 41;
  194. InputRecord.Event.KeyEvent.uChar.AsciiChar = ' ';
  195. InputRecord.Event.KeyEvent.dwControlKeyState = 32;
  196. EnterCriticalSection(&csConsole);
  197. WriteConsoleInput(InputHandle,&InputRecord,1,&nRecordsWritten);
  198. InputRecord.EventType = 1;
  199. InputRecord.Event.KeyEvent.bKeyDown = 0;
  200. InputRecord.Event.KeyEvent.wRepeatCount = 1;
  201. InputRecord.Event.KeyEvent.wVirtualKeyCode = 32;
  202. InputRecord.Event.KeyEvent.wVirtualScanCode = 41;
  203. InputRecord.Event.KeyEvent.uChar.AsciiChar = ' ';
  204. InputRecord.Event.KeyEvent.dwControlKeyState = 32;
  205. WriteConsoleInput(InputHandle,&InputRecord,1,&nRecordsWritten);
  206. fEventThreadBlock = TRUE;
  207. LeaveCriticalSection(&csConsole);
  208. return;
  209. }
  210. void nt_resume_event_thread(void)
  211. {
  212. fEventThreadBlock = FALSE;
  213. SetEvent (hConsoleWait);
  214. return;
  215. }
  216. // TEMP Till we have proper multitasking in WOW
  217. extern BOOL VDMForWOW;
  218. extern ULONG iWOWTaskId;
  219. VOID VDMCtrlCHandler(ULONG ulCtrlType)
  220. {
  221. // DebugBreak();
  222. if(ulCtrlType == SYSTEM_ROOT_CONSOLE_EVENT) {
  223. if(VDMForWOW)
  224. // Kill everything for WOW VDM
  225. ExitVDM(VDMForWOW,(ULONG)-1);
  226. else
  227. ExitVDM(FALSE,0);
  228. ExitProcess(0);
  229. return;
  230. }
  231. EnterCriticalSection(&csCtrlc);
  232. nCtrlc++;
  233. LeaveCriticalSection(&csCtrlc);
  234. SetEvent(KbdSyncEvent);
  235. }