Home | History | Annotate | Download | only in Ps2MouseAbsolutePointerDxe
      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