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