1 /** @file 2 PS2 Mouse Communication Interface. 3 4 Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "Ps2MouseAbsolutePointer.h" 16 #include "CommPs2.h" 17 18 UINT8 SampleRateTbl[MaxSampleRate] = { 0xa, 0x14, 0x28, 0x3c, 0x50, 0x64, 0xc8 }; 19 20 UINT8 ResolutionTbl[MaxResolution] = { 0, 1, 2, 3 }; 21 22 /** 23 Issue self test command via IsaIo interface. 24 25 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 26 27 @return EFI_SUCCESS Success to do keyboard self testing. 28 @return others Fail to do keyboard self testing. 29 **/ 30 EFI_STATUS 31 KbcSelfTest ( 32 IN EFI_ISA_IO_PROTOCOL *IsaIo 33 ) 34 { 35 EFI_STATUS Status; 36 UINT8 Data; 37 38 // 39 // Keyboard controller self test 40 // 41 Status = Out8042Command (IsaIo, SELF_TEST); 42 if (EFI_ERROR (Status)) { 43 return Status; 44 } 45 // 46 // Read return code 47 // 48 Status = In8042Data (IsaIo, &Data); 49 if (EFI_ERROR (Status)) { 50 return Status; 51 } 52 53 if (Data != 0x55) { 54 return EFI_DEVICE_ERROR; 55 } 56 // 57 // Set system flag 58 // 59 Status = Out8042Command (IsaIo, READ_CMD_BYTE); 60 if (EFI_ERROR (Status)) { 61 return Status; 62 } 63 64 Status = In8042Data (IsaIo, &Data); 65 if (EFI_ERROR (Status)) { 66 return Status; 67 } 68 69 Status = Out8042Command (IsaIo, WRITE_CMD_BYTE); 70 if (EFI_ERROR (Status)) { 71 return Status; 72 } 73 74 Data |= CMD_SYS_FLAG; 75 Status = Out8042Data (IsaIo, Data); 76 if (EFI_ERROR (Status)) { 77 return Status; 78 } 79 80 return EFI_SUCCESS; 81 } 82 83 /** 84 Issue command to enable keyboard AUX functionality. 85 86 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 87 88 @return Status of command issuing. 89 **/ 90 EFI_STATUS 91 KbcEnableAux ( 92 IN EFI_ISA_IO_PROTOCOL *IsaIo 93 ) 94 { 95 // 96 // Send 8042 enable mouse command 97 // 98 return Out8042Command (IsaIo, ENABLE_AUX); 99 } 100 101 /** 102 Issue command to disable keyboard AUX functionality. 103 104 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 105 106 @return Status of command issuing. 107 **/ 108 EFI_STATUS 109 KbcDisableAux ( 110 IN EFI_ISA_IO_PROTOCOL *IsaIo 111 ) 112 { 113 // 114 // Send 8042 disable mouse command 115 // 116 return Out8042Command (IsaIo, DISABLE_AUX); 117 } 118 119 /** 120 Issue command to enable keyboard. 121 122 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 123 124 @return Status of command issuing. 125 **/ 126 EFI_STATUS 127 KbcEnableKb ( 128 IN EFI_ISA_IO_PROTOCOL *IsaIo 129 ) 130 { 131 // 132 // Send 8042 enable keyboard command 133 // 134 return Out8042Command (IsaIo, ENABLE_KB); 135 } 136 137 /** 138 Issue command to disable keyboard. 139 140 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 141 142 @return Status of command issuing. 143 **/ 144 EFI_STATUS 145 KbcDisableKb ( 146 IN EFI_ISA_IO_PROTOCOL *IsaIo 147 ) 148 { 149 // 150 // Send 8042 disable keyboard command 151 // 152 return Out8042Command (IsaIo, DISABLE_KB); 153 } 154 155 /** 156 Issue command to check keyboard status. 157 158 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 159 @param KeyboardEnable return whether keyboard is enable. 160 161 @return Status of command issuing. 162 **/ 163 EFI_STATUS 164 CheckKbStatus ( 165 IN EFI_ISA_IO_PROTOCOL *IsaIo, 166 OUT BOOLEAN *KeyboardEnable 167 ) 168 { 169 EFI_STATUS Status; 170 UINT8 Data; 171 172 // 173 // Send command to read KBC command byte 174 // 175 Status = Out8042Command (IsaIo, READ_CMD_BYTE); 176 if (EFI_ERROR (Status)) { 177 return Status; 178 } 179 180 Status = In8042Data (IsaIo, &Data); 181 if (EFI_ERROR (Status)) { 182 return Status; 183 } 184 // 185 // Check keyboard enable or not 186 // 187 if ((Data & CMD_KB_STS) == CMD_KB_DIS) { 188 *KeyboardEnable = FALSE; 189 } else { 190 *KeyboardEnable = TRUE; 191 } 192 193 return EFI_SUCCESS; 194 } 195 196 /** 197 Issue command to reset keyboard. 198 199 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 200 201 @return Status of command issuing. 202 **/ 203 EFI_STATUS 204 PS2MouseReset ( 205 IN EFI_ISA_IO_PROTOCOL *IsaIo 206 ) 207 { 208 EFI_STATUS Status; 209 UINT8 Data; 210 211 Status = Out8042AuxCommand (IsaIo, RESET_CMD, FALSE); 212 if (EFI_ERROR (Status)) { 213 return Status; 214 } 215 216 Status = In8042AuxData (IsaIo, &Data); 217 if (EFI_ERROR (Status)) { 218 return Status; 219 } 220 // 221 // Check BAT Complete Code 222 // 223 if (Data != PS2MOUSE_BAT1) { 224 return EFI_DEVICE_ERROR; 225 } 226 227 Status = In8042AuxData (IsaIo, &Data); 228 if (EFI_ERROR (Status)) { 229 return Status; 230 } 231 // 232 // Check BAT Complete Code 233 // 234 if (Data != PS2MOUSE_BAT2) { 235 return EFI_DEVICE_ERROR; 236 } 237 238 return EFI_SUCCESS; 239 } 240 241 /** 242 Issue command to set mouse's sample rate 243 244 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 245 @param SampleRate value of sample rate 246 247 @return Status of command issuing. 248 **/ 249 EFI_STATUS 250 PS2MouseSetSampleRate ( 251 IN EFI_ISA_IO_PROTOCOL *IsaIo, 252 IN MOUSE_SR SampleRate 253 ) 254 { 255 EFI_STATUS Status; 256 257 // 258 // Send auxiliary command to set mouse sample rate 259 // 260 Status = Out8042AuxCommand (IsaIo, SETSR_CMD, FALSE); 261 if (EFI_ERROR (Status)) { 262 return Status; 263 } 264 265 Status = Out8042AuxData (IsaIo, SampleRateTbl[SampleRate]); 266 267 return Status; 268 } 269 270 /** 271 Issue command to set mouse's resolution. 272 273 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 274 @param Resolution value of resolution 275 276 @return Status of command issuing. 277 **/ 278 EFI_STATUS 279 PS2MouseSetResolution ( 280 IN EFI_ISA_IO_PROTOCOL *IsaIo, 281 IN MOUSE_RE Resolution 282 ) 283 { 284 EFI_STATUS Status; 285 286 // 287 // Send auxiliary command to set mouse resolution 288 // 289 Status = Out8042AuxCommand (IsaIo, SETRE_CMD, FALSE); 290 if (EFI_ERROR (Status)) { 291 return Status; 292 } 293 294 Status = Out8042AuxData (IsaIo, ResolutionTbl[Resolution]); 295 296 return Status; 297 } 298 299 /** 300 Issue command to set mouse's scaling. 301 302 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 303 @param Scaling value of scaling 304 305 @return Status of command issuing. 306 **/ 307 EFI_STATUS 308 PS2MouseSetScaling ( 309 IN EFI_ISA_IO_PROTOCOL *IsaIo, 310 IN MOUSE_SF Scaling 311 ) 312 { 313 UINT8 Command; 314 315 Command = (UINT8) (Scaling == Scaling1 ? SETSF1_CMD : SETSF2_CMD); 316 317 // 318 // Send auxiliary command to set mouse scaling data 319 // 320 return Out8042AuxCommand (IsaIo, Command, FALSE); 321 } 322 323 /** 324 Issue command to enable Ps2 mouse. 325 326 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 327 328 @return Status of command issuing. 329 **/ 330 EFI_STATUS 331 PS2MouseEnable ( 332 IN EFI_ISA_IO_PROTOCOL *IsaIo 333 ) 334 { 335 // 336 // Send auxiliary command to enable mouse 337 // 338 return Out8042AuxCommand (IsaIo, ENABLE_CMD, FALSE); 339 } 340 341 /** 342 Get mouse packet . Only care first 3 bytes 343 344 @param MouseAbsolutePointerDev Pointer to PS2 Absolute Pointer Simulation Device Private Data Structure 345 346 @retval EFI_NOT_READY Mouse Device not ready to input data packet, or some error happened during getting the packet 347 @retval EFI_SUCCESS The data packet is gotten successfully. 348 349 **/ 350 EFI_STATUS 351 PS2MouseGetPacket ( 352 PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev 353 ) 354 355 { 356 EFI_STATUS Status; 357 BOOLEAN KeyboardEnable; 358 UINT8 Packet[PS2_PACKET_LENGTH]; 359 UINT8 Data; 360 UINTN Count; 361 UINTN State; 362 INT16 RelativeMovementX; 363 INT16 RelativeMovementY; 364 BOOLEAN LButton; 365 BOOLEAN RButton; 366 367 KeyboardEnable = FALSE; 368 Count = 1; 369 State = PS2_READ_BYTE_ONE; 370 371 // 372 // State machine to get mouse packet 373 // 374 while (1) { 375 376 switch (State) { 377 case PS2_READ_BYTE_ONE: 378 // 379 // Read mouse first byte data, if failed, immediately return 380 // 381 KbcDisableAux (MouseAbsolutePointerDev->IsaIo); 382 Status = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, &Data, &Count, State); 383 if (EFI_ERROR (Status)) { 384 KbcEnableAux (MouseAbsolutePointerDev->IsaIo); 385 return EFI_NOT_READY; 386 } 387 388 if (Count != 1) { 389 KbcEnableAux (MouseAbsolutePointerDev->IsaIo); 390 return EFI_NOT_READY; 391 } 392 393 if (IS_PS2_SYNC_BYTE (Data)) { 394 Packet[0] = Data; 395 State = PS2_READ_DATA_BYTE; 396 397 CheckKbStatus (MouseAbsolutePointerDev->IsaIo, &KeyboardEnable); 398 KbcDisableKb (MouseAbsolutePointerDev->IsaIo); 399 KbcEnableAux (MouseAbsolutePointerDev->IsaIo); 400 } 401 break; 402 403 case PS2_READ_DATA_BYTE: 404 Count = 2; 405 Status = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, (Packet + 1), &Count, State); 406 if (EFI_ERROR (Status)) { 407 if (KeyboardEnable) { 408 KbcEnableKb (MouseAbsolutePointerDev->IsaIo); 409 } 410 411 return EFI_NOT_READY; 412 } 413 414 if (Count != 2) { 415 if (KeyboardEnable) { 416 KbcEnableKb (MouseAbsolutePointerDev->IsaIo); 417 } 418 419 return EFI_NOT_READY; 420 } 421 422 State = PS2_PROCESS_PACKET; 423 break; 424 425 case PS2_PROCESS_PACKET: 426 if (KeyboardEnable) { 427 KbcEnableKb (MouseAbsolutePointerDev->IsaIo); 428 } 429 // 430 // Decode the packet 431 // 432 RelativeMovementX = Packet[1]; 433 RelativeMovementY = Packet[2]; 434 // 435 // Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 436 // Byte 0 | Y overflow | X overflow | Y sign bit | X sign bit | Always 1 | Middle Btn | Right Btn | Left Btn 437 // Byte 1 | 8 bit X Movement 438 // Byte 2 | 8 bit Y Movement 439 // 440 // X sign bit + 8 bit X Movement : 9-bit signed twos complement integer that presents the relative displacement of the device in the X direction since the last data transmission. 441 // Y sign bit + 8 bit Y Movement : Same as X sign bit + 8 bit X Movement. 442 // 443 // 444 // First, Clear X and Y high 8 bits 445 // 446 RelativeMovementX = (INT16) (RelativeMovementX & 0xFF); 447 RelativeMovementY = (INT16) (RelativeMovementY & 0xFF); 448 // 449 // Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff 450 // 451 if ((Packet[0] & 0x10) != 0) { 452 RelativeMovementX = (INT16) (RelativeMovementX | 0xFF00); 453 } 454 if ((Packet[0] & 0x20) != 0) { 455 RelativeMovementY = (INT16) (RelativeMovementY | 0xFF00); 456 } 457 458 459 RButton = (UINT8) (Packet[0] & 0x2); 460 LButton = (UINT8) (Packet[0] & 0x1); 461 462 // 463 // Update mouse state 464 // 465 MouseAbsolutePointerDev->State.CurrentX += RelativeMovementX; 466 MouseAbsolutePointerDev->State.CurrentY -= RelativeMovementY; 467 MouseAbsolutePointerDev->State.CurrentZ = 0; 468 MouseAbsolutePointerDev->State.ActiveButtons = (UINT8) (LButton || RButton) & 0x3; 469 MouseAbsolutePointerDev->StateChanged = TRUE; 470 471 return EFI_SUCCESS; 472 } 473 } 474 } 475 476 /** 477 Read data via IsaIo protocol with given number. 478 479 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 480 @param Buffer Buffer receive data of mouse 481 @param BufSize The size of buffer 482 @param State Check input or read data 483 484 @return status of reading mouse data. 485 **/ 486 EFI_STATUS 487 PS2MouseRead ( 488 IN EFI_ISA_IO_PROTOCOL *IsaIo, 489 OUT VOID *Buffer, 490 IN OUT UINTN *BufSize, 491 IN UINTN State 492 ) 493 { 494 EFI_STATUS Status; 495 UINTN BytesRead; 496 497 Status = EFI_SUCCESS; 498 BytesRead = 0; 499 500 if (State == PS2_READ_BYTE_ONE) { 501 // 502 // Check input for mouse 503 // 504 Status = CheckForInput (IsaIo); 505 506 if (EFI_ERROR (Status)) { 507 return Status; 508 } 509 } 510 511 while (BytesRead < *BufSize) { 512 513 Status = WaitOutputFull (IsaIo, TIMEOUT); 514 if (EFI_ERROR (Status)) { 515 break; 516 } 517 518 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Buffer); 519 520 BytesRead++; 521 Buffer = (UINT8 *) Buffer + 1; 522 } 523 // 524 // Verify the correct number of bytes read 525 // 526 if (BytesRead == 0 || BytesRead != *BufSize) { 527 Status = EFI_NOT_FOUND; 528 } 529 530 *BufSize = BytesRead; 531 return Status; 532 } 533 534 // 535 // 8042 I/O function 536 // 537 /** 538 I/O work flow of outing 8042 command. 539 540 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 541 @param Command I/O command. 542 543 @retval EFI_SUCCESS Success to execute I/O work flow 544 @retval EFI_TIMEOUT Keyboard controller time out. 545 **/ 546 EFI_STATUS 547 Out8042Command ( 548 IN EFI_ISA_IO_PROTOCOL *IsaIo, 549 IN UINT8 Command 550 ) 551 { 552 EFI_STATUS Status; 553 UINT8 Data; 554 555 // 556 // Wait keyboard controller input buffer empty 557 // 558 Status = WaitInputEmpty (IsaIo, TIMEOUT); 559 if (EFI_ERROR (Status)) { 560 return Status; 561 } 562 // 563 // Send command 564 // 565 Data = Command; 566 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data); 567 568 Status = WaitInputEmpty (IsaIo, TIMEOUT); 569 if (EFI_ERROR (Status)) { 570 return Status; 571 } 572 573 return EFI_SUCCESS; 574 } 575 576 /** 577 I/O work flow of outing 8042 data. 578 579 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 580 @param Data Data value 581 582 @retval EFI_SUCCESS Success to execute I/O work flow 583 @retval EFI_TIMEOUT Keyboard controller time out. 584 **/ 585 EFI_STATUS 586 Out8042Data ( 587 IN EFI_ISA_IO_PROTOCOL *IsaIo, 588 IN UINT8 Data 589 ) 590 { 591 EFI_STATUS Status; 592 UINT8 Temp; 593 // 594 // Wait keyboard controller input buffer empty 595 // 596 Status = WaitInputEmpty (IsaIo, TIMEOUT); 597 if (EFI_ERROR (Status)) { 598 return Status; 599 } 600 601 Temp = Data; 602 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp); 603 604 Status = WaitInputEmpty (IsaIo, TIMEOUT); 605 if (EFI_ERROR (Status)) { 606 return Status; 607 } 608 609 return EFI_SUCCESS; 610 } 611 612 /** 613 I/O work flow of in 8042 data. 614 615 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 616 @param Data Data value 617 618 @retval EFI_SUCCESS Success to execute I/O work flow 619 @retval EFI_TIMEOUT Keyboard controller time out. 620 **/ 621 EFI_STATUS 622 In8042Data ( 623 IN EFI_ISA_IO_PROTOCOL *IsaIo, 624 IN OUT UINT8 *Data 625 ) 626 { 627 UINTN Delay; 628 UINT8 Temp; 629 630 Delay = TIMEOUT / 50; 631 632 do { 633 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp); 634 635 // 636 // Check keyboard controller status bit 0(output buffer status) 637 // 638 if ((Temp & KBC_OUTB) == KBC_OUTB) { 639 break; 640 } 641 642 gBS->Stall (50); 643 Delay--; 644 } while (Delay != 0); 645 646 if (Delay == 0) { 647 return EFI_TIMEOUT; 648 } 649 650 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data); 651 652 return EFI_SUCCESS; 653 } 654 655 /** 656 I/O work flow of outing 8042 Aux command. 657 658 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 659 @param Command Aux I/O command 660 @param Resend Whether need resend the Aux command. 661 662 @retval EFI_SUCCESS Success to execute I/O work flow 663 @retval EFI_TIMEOUT Keyboard controller time out. 664 **/ 665 EFI_STATUS 666 Out8042AuxCommand ( 667 IN EFI_ISA_IO_PROTOCOL *IsaIo, 668 IN UINT8 Command, 669 IN BOOLEAN Resend 670 ) 671 { 672 EFI_STATUS Status; 673 UINT8 Data; 674 675 // 676 // Wait keyboard controller input buffer empty 677 // 678 Status = WaitInputEmpty (IsaIo, TIMEOUT); 679 if (EFI_ERROR (Status)) { 680 return Status; 681 } 682 // 683 // Send write to auxiliary device command 684 // 685 Data = WRITE_AUX_DEV; 686 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data); 687 688 Status = WaitInputEmpty (IsaIo, TIMEOUT); 689 if (EFI_ERROR (Status)) { 690 return Status; 691 } 692 // 693 // Send auxiliary device command 694 // 695 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Command); 696 697 // 698 // Read return code 699 // 700 Status = In8042AuxData (IsaIo, &Data); 701 if (EFI_ERROR (Status)) { 702 return Status; 703 } 704 705 if (Data == PS2_ACK) { 706 // 707 // Receive mouse acknowledge, command send success 708 // 709 return EFI_SUCCESS; 710 711 } else if (Resend) { 712 // 713 // Resend fail 714 // 715 return EFI_DEVICE_ERROR; 716 717 } else if (Data == PS2_RESEND) { 718 // 719 // Resend command 720 // 721 Status = Out8042AuxCommand (IsaIo, Command, TRUE); 722 if (EFI_ERROR (Status)) { 723 return Status; 724 } 725 726 } else { 727 // 728 // Invalid return code 729 // 730 return EFI_DEVICE_ERROR; 731 732 } 733 734 return EFI_SUCCESS; 735 } 736 737 /** 738 I/O work flow of outing 8042 Aux data. 739 740 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 741 @param Data Buffer holding return value 742 743 @retval EFI_SUCCESS Success to execute I/O work flow. 744 @retval EFI_TIMEOUT Keyboard controller time out. 745 **/ 746 EFI_STATUS 747 Out8042AuxData ( 748 IN EFI_ISA_IO_PROTOCOL *IsaIo, 749 IN UINT8 Data 750 ) 751 { 752 EFI_STATUS Status; 753 UINT8 Temp; 754 // 755 // Wait keyboard controller input buffer empty 756 // 757 Status = WaitInputEmpty (IsaIo, TIMEOUT); 758 if (EFI_ERROR (Status)) { 759 return Status; 760 } 761 // 762 // Send write to auxiliary device command 763 // 764 Temp = WRITE_AUX_DEV; 765 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp); 766 767 Status = WaitInputEmpty (IsaIo, TIMEOUT); 768 if (EFI_ERROR (Status)) { 769 return Status; 770 } 771 772 Temp = Data; 773 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp); 774 775 Status = WaitInputEmpty (IsaIo, TIMEOUT); 776 if (EFI_ERROR (Status)) { 777 return Status; 778 } 779 780 return EFI_SUCCESS; 781 } 782 783 /** 784 I/O work flow of in 8042 Aux data. 785 786 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 787 @param Data Buffer holding return value. 788 789 @retval EFI_SUCCESS Success to execute I/O work flow 790 @retval EFI_TIMEOUT Keyboard controller time out. 791 **/ 792 EFI_STATUS 793 In8042AuxData ( 794 IN EFI_ISA_IO_PROTOCOL *IsaIo, 795 IN OUT UINT8 *Data 796 ) 797 { 798 EFI_STATUS Status; 799 800 // 801 // wait for output data 802 // 803 Status = WaitOutputFull (IsaIo, BAT_TIMEOUT); 804 if (EFI_ERROR (Status)) { 805 return Status; 806 } 807 808 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data); 809 810 return EFI_SUCCESS; 811 } 812 813 814 /** 815 Check keyboard controller status, if it is output buffer full and for auxiliary device. 816 817 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 818 819 @retval EFI_SUCCESS Keyboard controller is ready 820 @retval EFI_NOT_READY Keyboard controller is not ready 821 **/ 822 EFI_STATUS 823 CheckForInput ( 824 IN EFI_ISA_IO_PROTOCOL *IsaIo 825 ) 826 { 827 UINT8 Data; 828 829 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data); 830 831 // 832 // Check keyboard controller status, if it is output buffer full and for auxiliary device 833 // 834 if ((Data & (KBC_OUTB | KBC_AUXB)) != (KBC_OUTB | KBC_AUXB)) { 835 return EFI_NOT_READY; 836 } 837 838 return EFI_SUCCESS; 839 } 840 841 /** 842 I/O work flow to wait input buffer empty in given time. 843 844 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 845 @param Timeout Wating time. 846 847 @retval EFI_TIMEOUT if input is still not empty in given time. 848 @retval EFI_SUCCESS input is empty. 849 **/ 850 EFI_STATUS 851 WaitInputEmpty ( 852 IN EFI_ISA_IO_PROTOCOL *IsaIo, 853 IN UINTN Timeout 854 ) 855 { 856 UINTN Delay; 857 UINT8 Data; 858 859 Delay = Timeout / 50; 860 861 do { 862 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data); 863 864 // 865 // Check keyboard controller status bit 1(input buffer status) 866 // 867 if ((Data & KBC_INPB) == 0) { 868 break; 869 } 870 871 gBS->Stall (50); 872 Delay--; 873 } while (Delay != 0); 874 875 if (Delay == 0) { 876 return EFI_TIMEOUT; 877 } 878 879 return EFI_SUCCESS; 880 } 881 882 /** 883 I/O work flow to wait output buffer full in given time. 884 885 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL 886 @param Timeout given time 887 888 @retval EFI_TIMEOUT output is not full in given time 889 @retval EFI_SUCCESS output is full in given time. 890 **/ 891 EFI_STATUS 892 WaitOutputFull ( 893 IN EFI_ISA_IO_PROTOCOL *IsaIo, 894 IN UINTN Timeout 895 ) 896 { 897 UINTN Delay; 898 UINT8 Data; 899 900 Delay = Timeout / 50; 901 902 do { 903 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data); 904 905 // 906 // Check keyboard controller status bit 0(output buffer status) 907 // & bit5(output buffer for auxiliary device) 908 // 909 if ((Data & (KBC_OUTB | KBC_AUXB)) == (KBC_OUTB | KBC_AUXB)) { 910 break; 911 } 912 913 gBS->Stall (50); 914 Delay--; 915 } while (Delay != 0); 916 917 if (Delay == 0) { 918 return EFI_TIMEOUT; 919 } 920 921 return EFI_SUCCESS; 922 } 923 924