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.

748 lines
18 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. abiosc.c
  5. Abstract:
  6. This module implements keybaord detection C routines.
  7. Author:
  8. Shie-Lin Tzong (shielint) 18-Dec-1991
  9. Environment:
  10. Real Mode.
  11. Revision History:
  12. --*/
  13. #include "hwdetect.h"
  14. #include "string.h"
  15. #if !defined(_GAMBIT_)
  16. extern
  17. UCHAR
  18. GetKeyboardFlags (
  19. VOID
  20. );
  21. extern
  22. USHORT
  23. HwGetKey (
  24. VOID
  25. );
  26. extern BOOLEAN NoBiosKbdCheck;
  27. #endif // _GAMBIT_
  28. #if defined(NEC_98)
  29. ULONG
  30. GetKeyboard2ndIDNEC98(
  31. VOID
  32. );
  33. //
  34. // Definitions for the keyboard type returned from
  35. // the detect keyboard function.
  36. //
  37. #define PC98_106KEY 10
  38. #define PC98_NmodeKEY 11
  39. #define PC98_HmodeKEY 12
  40. #define PC98_LaptopKEY 13
  41. #define PC98_N106KEY 14
  42. #define N5200E_KEY 15
  43. #define PC98_KEYBOARD_ID_FIRST_BYTE 0xA0
  44. #define PC98_KEYBOARD_ID_2ND_BYTE_STD 0x80
  45. #define PC98_KEYBOARD_ID_2ND_BYTE_N106 0x82
  46. #define PC98_KEYBOARD_ID_2ND_BYTE_Win95 0x83
  47. #define READ_KEYBOARD_2ND_ID 0x96
  48. #define PC98_8251_BUFFER_EMPTY 0x01
  49. #define PC98_8251_DATA_READY 0x02
  50. #define ACKNOWLEDGE 0xFA
  51. #define RESEND 0xFC
  52. #define STATUS_SUCCESS 0x00000000L // from ntstatus.h
  53. #define STATUS_IO_TIMEOUT 0xC00000B5L // from ntstatus.h
  54. #define POLLING_ITERATION 12000
  55. #define RESEND_ITERATION 3
  56. #define KBD_COMMAND_STATUS_PORT 0x43
  57. #define KBD_DATA_PORT 0x41
  58. #define PIC1_PORT1 0x02
  59. #endif // PC98
  60. //
  61. // SavedKey is used to save the key left in the keyboard type-ahead buffer
  62. // before we start our keyboard/mouse tests. The key will be push back
  63. // to the type-ahead buffer once the mouse detection is done.
  64. //
  65. USHORT SavedKey = 0;
  66. //
  67. // String table to map keyboard id to an ascii string.
  68. //
  69. PUCHAR KeyboardIdentifier[] = {
  70. "UNKNOWN_KEYBOARD",
  71. "OLI_83KEY",
  72. "OLI_102KEY",
  73. "OLI_86KEY",
  74. "OLI_A101_102KEY",
  75. "XT_83KEY",
  76. "ATT_302",
  77. "PCAT_ENHANCED",
  78. "PCAT_86KEY",
  79. "PCXT_84KEY"
  80. #if defined(NEC_98)
  81. ,
  82. "PC98_106KEY",
  83. "PC98_NmodeKEY",
  84. "PC98_HmodeKEY",
  85. "PC98_LaptopKEY",
  86. "PC98_N106KEY",
  87. "N5200/E_KEY"
  88. #endif // PC98
  89. };
  90. UCHAR KeyboardType[] = {
  91. -1,
  92. 1,
  93. 2,
  94. 3,
  95. 4,
  96. 1,
  97. 1,
  98. 4,
  99. 3,
  100. 1
  101. #if defined(NEC_98)
  102. ,
  103. 7, //Japanese Keyboard Type
  104. 7, //Japanese Keyboard Type
  105. 7, //Japanese Keyboard Type
  106. 7, //Japanese Keyboard Type
  107. 7, //Japanese Keyboard Type
  108. 7 //Japanese Keyboard Type
  109. #endif // PC98
  110. };
  111. UCHAR KeyboardSubtype[] = {
  112. -1,
  113. 0,
  114. 1,
  115. 10,
  116. 4,
  117. 42,
  118. 4,
  119. 0,
  120. 0,
  121. 0
  122. #if defined(NEC_98)
  123. ,
  124. 1, //10 PC-9800 Serise S/W Lock Keyboard
  125. 2, //11 PC-9801 VX/UX,PC-98XL/XL2 H/W Lock Keyboard
  126. 3, //12 PC-98XL/XL2 H/W Lock Keyboard
  127. 4, //13 PC-9800 Serise Laptop Keyboard
  128. 5, //14 PC-9801-116 Keyboard
  129. 6 //15 N5200/E Serise Keyboard
  130. #endif // PC98
  131. };
  132. USHORT
  133. GetKeyboardId(
  134. VOID
  135. )
  136. /*++
  137. Routine Description:
  138. This routine determines the Id of the keyboard. It calls GetKeyboardIdBytes
  139. to complete the task.
  140. Arguments:
  141. None.
  142. Return Value:
  143. Keyboard ID.
  144. --*/
  145. {
  146. #if defined(_GAMBIT_)
  147. return (7); // PCAT_ENHANCED
  148. #else
  149. #if defined(NEC_98)
  150. char KeybID_Bytes[5];
  151. int Num_ID_Bytes;
  152. ULONG NEC2ndKeyID;
  153. int keytype = UNKNOWN_KEYBOARD;
  154. Num_ID_Bytes = GetKeyboardIdBytes(KeybID_Bytes, 0x05);
  155. if (Num_ID_Bytes > 0) {
  156. switch(KeybID_Bytes[0] & 0x00ff) {
  157. case 0x80:
  158. keytype = PC98_NmodeKEY;
  159. break;
  160. case 0x88:
  161. keytype = PC98_HmodeKEY;
  162. break;
  163. case 0x40:
  164. NEC2ndKeyID = GetKeyboard2ndIDNEC98();
  165. if (NEC2ndKeyID == PC98_N106KEY) {
  166. keytype = PC98_N106KEY;
  167. }else{
  168. keytype = PC98_106KEY;
  169. }
  170. break;
  171. case 0x08:
  172. case 0x48:
  173. keytype = PC98_LaptopKEY;
  174. break;
  175. default:
  176. keytype = UNKNOWN_KEYBOARD;
  177. break;
  178. }
  179. } else {
  180. keytype = PCAT_ENHANCED;
  181. }
  182. return(keytype);
  183. #else // PC98
  184. char KeybID_Bytes[5];
  185. int Num_ID_Bytes;
  186. int keytype = UNKNOWN_KEYBOARD;
  187. SavedKey = HwGetKey();
  188. Num_ID_Bytes = GetKeyboardIdBytes(KeybID_Bytes, 0x05);
  189. if (Num_ID_Bytes > 0) {
  190. switch(KeybID_Bytes[0] & 0x00ff) {
  191. case 0x02:
  192. keytype = OLI_83KEY;
  193. break;
  194. case 0x01:
  195. keytype = OLI_102KEY;
  196. break;
  197. case 0x10:
  198. keytype = OLI_86KEY;
  199. break;
  200. case 0x40:
  201. keytype = OLI_A101_102KEY;
  202. break;
  203. case 0x42:
  204. keytype = XT_83KEY;
  205. break;
  206. case 0x9c:
  207. keytype = PCXT_84KEY;
  208. break;
  209. case 0x04:
  210. keytype = ATT_302;
  211. break;
  212. case 0xfe:
  213. Num_ID_Bytes = GetKeyboardIdBytes(KeybID_Bytes, 0xf2);
  214. if (Num_ID_Bytes > 0) {
  215. if ((KeybID_Bytes[0] & 0x00ff) == 0xfa) {
  216. keytype = PCAT_86KEY;
  217. } else if ((KeybID_Bytes[0] & 0x00ff) == 0xfe) {
  218. keytype = PCAT_86KEY;
  219. } else if (Num_ID_Bytes >= 3 &&
  220. ((KeybID_Bytes[1] & 0x00ff) == 0xAB) &&
  221. ((KeybID_Bytes[2] & 0x00ff) == 0x41)) {
  222. keytype = PCAT_ENHANCED;
  223. } else {
  224. keytype = UNKNOWN_KEYBOARD;
  225. }
  226. } else {
  227. keytype = UNKNOWN_KEYBOARD;
  228. }
  229. break;
  230. default:
  231. keytype = UNKNOWN_KEYBOARD;
  232. break;
  233. }
  234. } else {
  235. keytype = PCXT_84KEY;
  236. }
  237. if (!NoBiosKbdCheck) {
  238. //
  239. // Sometimes enhanced keyboards get detected as 84/86 key keyboards
  240. // So we will look into the ROM DATA area (40:96) and see if the
  241. // Enhanced Keyboard bit is set. If it is we will assume that the
  242. // detection failed to detect the presence of an enhanced keyb.
  243. //
  244. if ((keytype == PCXT_84KEY) ||
  245. (keytype == PCAT_86KEY) ||
  246. (keytype == UNKNOWN_KEYBOARD)) {
  247. if (IsEnhancedKeyboard()) {
  248. keytype = PCAT_ENHANCED;
  249. }
  250. }
  251. }
  252. return(keytype);
  253. #endif // PC98
  254. #endif // _GAMBIT_
  255. }
  256. FPFWCONFIGURATION_COMPONENT_DATA
  257. SetKeyboardConfigurationData (
  258. USHORT KeyboardId
  259. )
  260. /*++
  261. Routine Description:
  262. This routine maps Keyboard Id information to an ASCII string and
  263. stores the string in configuration data heap.
  264. Arguments:
  265. KeyboardId - Supplies a USHORT which describes the keyboard id information.
  266. Buffer - Supplies a pointer to a buffer where to put the ascii.
  267. Returns:
  268. None.
  269. --*/
  270. {
  271. FPFWCONFIGURATION_COMPONENT_DATA Controller, CurrentEntry;
  272. FPFWCONFIGURATION_COMPONENT Component;
  273. HWCONTROLLER_DATA ControlData;
  274. FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
  275. CM_KEYBOARD_DEVICE_DATA far *KeyboardData;
  276. USHORT z, Length;
  277. //
  278. // Set up Keyboard COntroller component
  279. //
  280. ControlData.NumberPortEntries = 0;
  281. ControlData.NumberIrqEntries = 0;
  282. ControlData.NumberMemoryEntries = 0;
  283. ControlData.NumberDmaEntries = 0;
  284. z = 0;
  285. Controller = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  286. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  287. Component = &Controller->ComponentEntry;
  288. Component->Class = ControllerClass;
  289. Component->Type = KeyboardController;
  290. Component->Flags.ConsoleIn = 1;
  291. Component->Flags.Input = 1;
  292. Component->Version = 0;
  293. Component->Key = 0;
  294. Component->AffinityMask = 0xffffffff;
  295. //
  296. // Set up Port information
  297. //
  298. #if !defined(_GAMBIT_)
  299. ControlData.NumberPortEntries = 2;
  300. ControlData.DescriptorList[z].Type = RESOURCE_PORT;
  301. ControlData.DescriptorList[z].ShareDisposition =
  302. CmResourceShareDeviceExclusive;
  303. ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
  304. #if defined(NEC_98)
  305. ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x41;
  306. #else // PC98
  307. ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x60;
  308. #endif // PC98
  309. ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
  310. ControlData.DescriptorList[z].u.Port.Length = 1;
  311. z++;
  312. ControlData.DescriptorList[z].Type = RESOURCE_PORT;
  313. ControlData.DescriptorList[z].ShareDisposition =
  314. CmResourceShareDeviceExclusive;
  315. ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
  316. #if defined(NEC_98)
  317. ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x43;
  318. #else // PC98
  319. ControlData.DescriptorList[z].u.Port.Start.LowPart = 0x64;
  320. #endif // PC98
  321. ControlData.DescriptorList[z].u.Port.Start.HighPart = 0;
  322. ControlData.DescriptorList[z].u.Port.Length = 1;
  323. z++;
  324. //
  325. // Set up Irq information
  326. //
  327. ControlData.NumberIrqEntries = 1;
  328. ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
  329. ControlData.DescriptorList[z].ShareDisposition =
  330. CmResourceShareUndetermined;
  331. ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
  332. ControlData.DescriptorList[z].u.Interrupt.Level = 1;
  333. ControlData.DescriptorList[z].u.Interrupt.Vector = 1;
  334. if (HwBusType == MACHINE_TYPE_MCA) {
  335. ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
  336. } else {
  337. //
  338. // For EISA the LevelTriggered is temporarily set to FALSE.
  339. //
  340. ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
  341. }
  342. #endif // _GAMBIT_
  343. Controller->ConfigurationData =
  344. HwSetUpResourceDescriptor(Component,
  345. NULL,
  346. &ControlData,
  347. 0,
  348. NULL
  349. );
  350. //
  351. // Set up Keyboard peripheral component
  352. //
  353. CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  354. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  355. Component = &CurrentEntry->ComponentEntry;
  356. Component->Class = PeripheralClass;
  357. Component->Type = KeyboardPeripheral;
  358. Component->Flags.ConsoleIn = 1;
  359. Component->Flags.Input = 1;
  360. Component->Version = 0;
  361. Component->Key = 0;
  362. Component->AffinityMask = 0xffffffff;
  363. Component->ConfigurationDataLength = 0;
  364. CurrentEntry->ConfigurationData = (FPVOID)NULL;
  365. Length = strlen(KeyboardIdentifier[KeyboardId]) + 1;
  366. Component->IdentifierLength = Length;
  367. Component->Identifier = HwAllocateHeap(Length, FALSE);
  368. _fstrcpy(Component->Identifier, KeyboardIdentifier[KeyboardId]);
  369. if (KeyboardId != UNKNOWN_KEYBOARD) {
  370. Length = sizeof(HWRESOURCE_DESCRIPTOR_LIST) +
  371. sizeof(CM_KEYBOARD_DEVICE_DATA);
  372. DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(
  373. Length,
  374. TRUE);
  375. CurrentEntry->ConfigurationData = DescriptorList;
  376. Component->ConfigurationDataLength = Length;
  377. DescriptorList->Count = 1;
  378. DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
  379. DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
  380. sizeof(CM_KEYBOARD_DEVICE_DATA);
  381. KeyboardData = (CM_KEYBOARD_DEVICE_DATA far *)(DescriptorList + 1);
  382. #if defined(_GAMBIT_)
  383. KeyboardData->KeyboardFlags = 0;
  384. #else
  385. KeyboardData->KeyboardFlags = GetKeyboardFlags();
  386. #endif
  387. KeyboardData->Type = KeyboardType[KeyboardId];
  388. KeyboardData->Subtype = KeyboardSubtype[KeyboardId];
  389. }
  390. Controller->Child = CurrentEntry;
  391. Controller->Sibling = NULL;
  392. CurrentEntry->Parent = Controller;
  393. CurrentEntry->Sibling = NULL;
  394. CurrentEntry->Child = NULL;
  395. return(Controller);
  396. }
  397. #if defined(NEC_98)
  398. ULONG
  399. KbdGetBytePolled(
  400. OUT PUCHAR Byte
  401. )
  402. /*++
  403. --*/
  404. {
  405. ULONG i;
  406. UCHAR response;
  407. UCHAR desiredMask;
  408. i = 0;
  409. desiredMask = (UCHAR)PC98_8251_DATA_READY;
  410. IoDelay(34); // 20 micro second
  411. //
  412. // Poll until we get back a controller status value that indicates
  413. // the output buffer is full. If we want to read a byte from the mouse,
  414. // further ensure that the auxiliary device output buffer full bit is
  415. // set.
  416. //
  417. while ((i < POLLING_ITERATION ) &&
  418. ((UCHAR)((response = READ_PORT_UCHAR((PUCHAR)KBD_COMMAND_STATUS_PORT))
  419. & desiredMask) != desiredMask)) {
  420. IoDelay(83); // 50 micro second
  421. i += 1;
  422. }
  423. if (i >= (ULONG)POLLING_ITERATION) {
  424. return(STATUS_IO_TIMEOUT);
  425. }
  426. IoDelay(34); // 20 micro second
  427. //
  428. // Grab the byte from the hardware, and return success.
  429. //
  430. *Byte = READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT);
  431. return(STATUS_SUCCESS);
  432. }
  433. ULONG
  434. NEC98_KeyboardCommandByte(
  435. IN UCHAR KeyboardCommand
  436. )
  437. /*++
  438. Routine Description:
  439. This routine is command out routine for NEC_98 Keyboard controller
  440. Arguments:
  441. KeyboardCommand - A command sent to keyboard.
  442. Return Value:
  443. None.
  444. --*/
  445. {
  446. ULONG i,j;
  447. ULONG Status;
  448. WRITE_PORT_UCHAR( (PUCHAR)KBD_COMMAND_STATUS_PORT, (UCHAR)0x37 );
  449. IoDelay(17); // 10 micro second
  450. WRITE_PORT_UCHAR( (PUCHAR)KBD_DATA_PORT, (UCHAR)KeyboardCommand );
  451. IoDelay(75); // 45 micro second
  452. Status = STATUS_SUCCESS;
  453. for (j = 0; j < RESEND_ITERATION; j++) {
  454. //
  455. // Make sure the Input Buffer Full controller status bit is clear.
  456. // Time out if necessary.
  457. //
  458. i = 0;
  459. while ((i++ < POLLING_ITERATION) &&
  460. (READ_PORT_UCHAR((PUCHAR)KBD_COMMAND_STATUS_PORT)
  461. & PC98_8251_BUFFER_EMPTY) != PC98_8251_BUFFER_EMPTY) {
  462. IoDelay(83); // 50 micro second
  463. }
  464. if (i >= POLLING_ITERATION) {
  465. Status = STATUS_IO_TIMEOUT;
  466. break;
  467. }
  468. }
  469. WRITE_PORT_UCHAR( (PUCHAR)KBD_COMMAND_STATUS_PORT, (UCHAR)0x16 );
  470. IoDelay(167); // 100 micro second
  471. return(Status);
  472. }
  473. ULONG
  474. KbdPutBytePolled(
  475. IN UCHAR Byte
  476. )
  477. /*++
  478. Routine Description:
  479. This routine sends a command or data byte to the controller or keyboard
  480. or mouse, in polling mode. It waits for acknowledgment and resends
  481. the command/data if necessary.
  482. Arguments:
  483. Byte - The byte to send to the hardware.
  484. Return Value:
  485. STATUS_IO_TIMEOUT - The hardware was not ready for input or did not
  486. respond.
  487. STATUS_SUCCESS - The byte was successfully sent to the hardware.
  488. --*/
  489. {
  490. ULONG i,j;
  491. UCHAR response;
  492. ULONG status;
  493. BOOLEAN keepTrying;
  494. UCHAR byte, d;
  495. for (j=0;j < RESEND_ITERATION;j++) {
  496. //
  497. // Drain the i8042 output buffer to get rid of stale data.
  498. //
  499. while (d = READ_PORT_UCHAR((PUCHAR)KBD_COMMAND_STATUS_PORT) &
  500. PC98_8251_DATA_READY) {
  501. //
  502. // Eat the output buffer byte.
  503. //
  504. byte = READ_PORT_UCHAR((PUCHAR)KBD_DATA_PORT);
  505. }
  506. //
  507. // Send the byte to the appropriate (command/data) hardware register.
  508. //
  509. status = NEC98_KeyboardCommandByte( Byte );
  510. if (status != STATUS_SUCCESS){
  511. return(status);
  512. }
  513. //
  514. // Wait for an ACK back from the controller. If we get an ACK,
  515. // the operation was successful. If we get a RESEND, break out to
  516. // the for loop and try the operation again. Ignore anything other
  517. // than ACK or RESEND.
  518. //
  519. keepTrying = FALSE;
  520. while ((status = KbdGetBytePolled(&response)) == STATUS_SUCCESS) {
  521. if (response == ACKNOWLEDGE) {
  522. break;
  523. } else if (response == RESEND) {
  524. keepTrying = TRUE;
  525. break;
  526. }
  527. //
  528. // Ignore any other response, and keep trying.
  529. //
  530. }
  531. if (!keepTrying)
  532. break;
  533. }
  534. //
  535. // Check to see if the number of allowable retries was exceeded.
  536. //
  537. if (j >= RESEND_ITERATION) {
  538. status = STATUS_IO_TIMEOUT;
  539. }
  540. return(status);
  541. }
  542. ULONG
  543. GetKeyboard2ndIDNEC98(
  544. VOID
  545. )
  546. /*++
  547. Routine Description:
  548. This routine detects keyboard hardware for NEC_98.
  549. Arguments:
  550. Return Value:
  551. keyboard type(see i8042prt.h)
  552. --*/
  553. {
  554. UCHAR IDStatus = 0;
  555. ULONG KeyboardType;
  556. UCHAR temp;
  557. KeyboardType = PC98_106KEY; // default keyboard type.
  558. //
  559. // mask keyboard interrupt.
  560. //
  561. _asm{ cli }
  562. temp = READ_PORT_UCHAR((PUCHAR)PIC1_PORT1);
  563. WRITE_PORT_UCHAR((PUCHAR)PIC1_PORT1,(temp | 0x02));
  564. _asm{ sti }
  565. if (KbdPutBytePolled( (UCHAR)READ_KEYBOARD_2ND_ID) == STATUS_SUCCESS) {
  566. while( KbdGetBytePolled( &IDStatus ) != STATUS_SUCCESS);
  567. switch(IDStatus){
  568. case PC98_KEYBOARD_ID_FIRST_BYTE:
  569. while ( KbdGetBytePolled( &IDStatus ) != STATUS_SUCCESS);
  570. switch(IDStatus){
  571. case PC98_KEYBOARD_ID_2ND_BYTE_N106:
  572. KeyboardType = PC98_N106KEY;
  573. break;
  574. case PC98_KEYBOARD_ID_2ND_BYTE_Win95:
  575. default:
  576. break;
  577. }
  578. break;
  579. default:
  580. break;
  581. }
  582. }
  583. //
  584. // unmask keyboard interrupt.
  585. //
  586. WRITE_PORT_UCHAR((PUCHAR)PIC1_PORT1,temp);
  587. return KeyboardType;
  588. }
  589. #endif // defined(NEC_98)