Home | History | Annotate | Download | only in Ps2MouseDxe
      1 /** @file
      2   PS2 Mouse Communication Interface.
      3 
      4 Copyright (c) 2006 - 2009, 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   @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 MouseDev  Pointer of PS2 Mouse 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_DEV     *MouseDev
    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 (MouseDev->IsaIo);
    382       Status = PS2MouseRead (MouseDev->IsaIo, &Data, &Count, State);
    383       if (EFI_ERROR (Status)) {
    384         KbcEnableAux (MouseDev->IsaIo);
    385         return EFI_NOT_READY;
    386       }
    387 
    388       if (Count != 1) {
    389         KbcEnableAux (MouseDev->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 (MouseDev->IsaIo, &KeyboardEnable);
    398         KbcDisableKb (MouseDev->IsaIo);
    399         KbcEnableAux (MouseDev->IsaIo);
    400       }
    401       break;
    402 
    403     case PS2_READ_DATA_BYTE:
    404       Count   = 2;
    405       Status  = PS2MouseRead (MouseDev->IsaIo, (Packet + 1), &Count, State);
    406       if (EFI_ERROR (Status)) {
    407         if (KeyboardEnable) {
    408           KbcEnableKb (MouseDev->IsaIo);
    409         }
    410 
    411         return EFI_NOT_READY;
    412       }
    413 
    414       if (Count != 2) {
    415         if (KeyboardEnable) {
    416           KbcEnableKb (MouseDev->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 (MouseDev->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       MouseDev->State.RelativeMovementX += RelativeMovementX;
    466       MouseDev->State.RelativeMovementY -= RelativeMovementY;
    467       MouseDev->State.RightButton = (UINT8) (RButton ? TRUE : FALSE);
    468       MouseDev->State.LeftButton  = (UINT8) (LButton ? TRUE : FALSE);
    469       MouseDev->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 // 8042 I/O function
    535 //
    536 /**
    537   I/O work flow of outing 8042 command.
    538 
    539   @param IsaIo   Pointer to instance of EFI_ISA_IO_PROTOCOL
    540   @param Command I/O command.
    541 
    542   @retval EFI_SUCCESS Success to execute I/O work flow
    543   @retval EFI_TIMEOUT Keyboard controller time out.
    544 **/
    545 EFI_STATUS
    546 Out8042Command (
    547   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
    548   IN UINT8                                Command
    549   )
    550 {
    551   EFI_STATUS  Status;
    552   UINT8       Data;
    553 
    554   //
    555   // Wait keyboard controller input buffer empty
    556   //
    557   Status = WaitInputEmpty (IsaIo, TIMEOUT);
    558   if (EFI_ERROR (Status)) {
    559     return Status;
    560   }
    561   //
    562   // Send command
    563   //
    564   Data = Command;
    565   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
    566 
    567   Status = WaitInputEmpty (IsaIo, TIMEOUT);
    568   if (EFI_ERROR (Status)) {
    569     return Status;
    570   }
    571 
    572   return EFI_SUCCESS;
    573 }
    574 
    575 /**
    576   I/O work flow of outing 8042 data.
    577 
    578   @param IsaIo   Pointer to instance of EFI_ISA_IO_PROTOCOL
    579   @param Data    Data value
    580 
    581   @retval EFI_SUCCESS Success to execute I/O work flow
    582   @retval EFI_TIMEOUT Keyboard controller time out.
    583 **/
    584 EFI_STATUS
    585 Out8042Data (
    586   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
    587   IN UINT8                                Data
    588   )
    589 {
    590   EFI_STATUS  Status;
    591   UINT8       Temp;
    592   //
    593   // Wait keyboard controller input buffer empty
    594   //
    595   Status = WaitInputEmpty (IsaIo, TIMEOUT);
    596   if (EFI_ERROR (Status)) {
    597     return Status;
    598   }
    599 
    600   Temp = Data;
    601   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
    602 
    603   Status = WaitInputEmpty (IsaIo, TIMEOUT);
    604   if (EFI_ERROR (Status)) {
    605     return Status;
    606   }
    607 
    608   return EFI_SUCCESS;
    609 }
    610 
    611 /**
    612   I/O work flow of in 8042 data.
    613 
    614   @param IsaIo   Pointer to instance of EFI_ISA_IO_PROTOCOL
    615   @param Data    Data value
    616 
    617   @retval EFI_SUCCESS Success to execute I/O work flow
    618   @retval EFI_TIMEOUT Keyboard controller time out.
    619 **/
    620 EFI_STATUS
    621 In8042Data (
    622   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
    623   IN OUT UINT8                            *Data
    624   )
    625 {
    626   UINTN Delay;
    627   UINT8 Temp;
    628 
    629   Delay = TIMEOUT / 50;
    630 
    631   do {
    632     IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
    633 
    634     //
    635     // Check keyboard controller status bit 0(output buffer status)
    636     //
    637     if ((Temp & KBC_OUTB) == KBC_OUTB) {
    638       break;
    639     }
    640 
    641     gBS->Stall (50);
    642     Delay--;
    643   } while (Delay != 0);
    644 
    645   if (Delay == 0) {
    646     return EFI_TIMEOUT;
    647   }
    648 
    649   IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
    650 
    651   return EFI_SUCCESS;
    652 }
    653 
    654 /**
    655   I/O work flow of outing 8042 Aux command.
    656 
    657   @param IsaIo   Pointer to instance of EFI_ISA_IO_PROTOCOL
    658   @param Command Aux I/O command
    659   @param Resend  Whether need resend the Aux command.
    660 
    661   @retval EFI_SUCCESS Success to execute I/O work flow
    662   @retval EFI_TIMEOUT Keyboard controller time out.
    663 **/
    664 EFI_STATUS
    665 Out8042AuxCommand (
    666   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
    667   IN UINT8                                Command,
    668   IN BOOLEAN                              Resend
    669   )
    670 {
    671   EFI_STATUS  Status;
    672   UINT8       Data;
    673 
    674   //
    675   // Wait keyboard controller input buffer empty
    676   //
    677   Status = WaitInputEmpty (IsaIo, TIMEOUT);
    678   if (EFI_ERROR (Status)) {
    679     return Status;
    680   }
    681   //
    682   // Send write to auxiliary device command
    683   //
    684   Data = WRITE_AUX_DEV;
    685   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
    686 
    687   Status = WaitInputEmpty (IsaIo, TIMEOUT);
    688   if (EFI_ERROR (Status)) {
    689     return Status;
    690   }
    691   //
    692   // Send auxiliary device command
    693   //
    694   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Command);
    695 
    696   //
    697   // Read return code
    698   //
    699   Status = In8042AuxData (IsaIo, &Data);
    700   if (EFI_ERROR (Status)) {
    701     return Status;
    702   }
    703 
    704   if (Data == PS2_ACK) {
    705     //
    706     // Receive mouse acknowledge, command send success
    707     //
    708     return EFI_SUCCESS;
    709 
    710   } else if (Resend) {
    711     //
    712     // Resend fail
    713     //
    714     return EFI_DEVICE_ERROR;
    715 
    716   } else if (Data == PS2_RESEND) {
    717     //
    718     // Resend command
    719     //
    720     Status = Out8042AuxCommand (IsaIo, Command, TRUE);
    721     if (EFI_ERROR (Status)) {
    722       return Status;
    723     }
    724 
    725   } else {
    726     //
    727     // Invalid return code
    728     //
    729     return EFI_DEVICE_ERROR;
    730 
    731   }
    732 
    733   return EFI_SUCCESS;
    734 }
    735 
    736 /**
    737   I/O work flow of outing 8042 Aux data.
    738 
    739   @param IsaIo   Pointer to instance of EFI_ISA_IO_PROTOCOL
    740   @param Data    Buffer holding return value
    741 
    742   @retval EFI_SUCCESS Success to execute I/O work flow
    743   @retval EFI_TIMEOUT Keyboard controller time out.
    744 **/
    745 EFI_STATUS
    746 Out8042AuxData (
    747   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
    748   IN UINT8                                Data
    749   )
    750 {
    751   EFI_STATUS  Status;
    752   UINT8       Temp;
    753   //
    754   // Wait keyboard controller input buffer empty
    755   //
    756   Status = WaitInputEmpty (IsaIo, TIMEOUT);
    757   if (EFI_ERROR (Status)) {
    758     return Status;
    759   }
    760   //
    761   // Send write to auxiliary device command
    762   //
    763   Temp = WRITE_AUX_DEV;
    764   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
    765 
    766   Status = WaitInputEmpty (IsaIo, TIMEOUT);
    767   if (EFI_ERROR (Status)) {
    768     return Status;
    769   }
    770 
    771   Temp = Data;
    772   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
    773 
    774   Status = WaitInputEmpty (IsaIo, TIMEOUT);
    775   if (EFI_ERROR (Status)) {
    776     return Status;
    777   }
    778 
    779   return EFI_SUCCESS;
    780 }
    781 
    782 /**
    783   I/O work flow of in 8042 Aux data.
    784 
    785   @param IsaIo   Pointer to instance of EFI_ISA_IO_PROTOCOL
    786   @param Data    Buffer holding return value.
    787 
    788   @retval EFI_SUCCESS Success to execute I/O work flow
    789   @retval EFI_TIMEOUT Keyboard controller time out.
    790 **/
    791 EFI_STATUS
    792 In8042AuxData (
    793   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
    794   IN OUT UINT8                            *Data
    795   )
    796 {
    797   EFI_STATUS  Status;
    798 
    799   //
    800   // wait for output data
    801   //
    802   Status = WaitOutputFull (IsaIo, BAT_TIMEOUT);
    803   if (EFI_ERROR (Status)) {
    804     return Status;
    805   }
    806 
    807   IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
    808 
    809   return EFI_SUCCESS;
    810 }
    811 
    812 
    813 /**
    814   Check keyboard controller status, if it is output buffer full and for auxiliary device.
    815 
    816   @param IsaIo   Pointer to instance of EFI_ISA_IO_PROTOCOL
    817 
    818   @retval EFI_SUCCESS   Keyboard controller is ready
    819   @retval EFI_NOT_READY Keyboard controller is not ready
    820 **/
    821 EFI_STATUS
    822 CheckForInput (
    823   IN EFI_ISA_IO_PROTOCOL                  *IsaIo
    824   )
    825 {
    826   UINT8 Data;
    827 
    828   IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
    829 
    830   //
    831   // Check keyboard controller status, if it is output buffer full and for auxiliary device
    832   //
    833   if ((Data & (KBC_OUTB | KBC_AUXB)) != (KBC_OUTB | KBC_AUXB)) {
    834     return EFI_NOT_READY;
    835   }
    836 
    837   return EFI_SUCCESS;
    838 }
    839 
    840 /**
    841   I/O work flow to wait input buffer empty in given time.
    842 
    843   @param IsaIo   Pointer to instance of EFI_ISA_IO_PROTOCOL
    844   @param Timeout Wating time.
    845 
    846   @retval EFI_TIMEOUT if input is still not empty in given time.
    847   @retval EFI_SUCCESS input is empty.
    848 **/
    849 EFI_STATUS
    850 WaitInputEmpty (
    851   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
    852   IN UINTN                                Timeout
    853   )
    854 {
    855   UINTN Delay;
    856   UINT8 Data;
    857 
    858   Delay = Timeout / 50;
    859 
    860   do {
    861     IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
    862 
    863     //
    864     // Check keyboard controller status bit 1(input buffer status)
    865     //
    866     if ((Data & KBC_INPB) == 0) {
    867       break;
    868     }
    869 
    870     gBS->Stall (50);
    871     Delay--;
    872   } while (Delay != 0);
    873 
    874   if (Delay == 0) {
    875     return EFI_TIMEOUT;
    876   }
    877 
    878   return EFI_SUCCESS;
    879 }
    880 
    881 /**
    882   I/O work flow to wait output buffer full in given time.
    883 
    884   @param IsaIo   Pointer to instance of EFI_ISA_IO_PROTOCOL
    885   @param Timeout given time
    886 
    887   @retval EFI_TIMEOUT  output is not full in given time
    888   @retval EFI_SUCCESS  output is full in given time.
    889 **/
    890 EFI_STATUS
    891 WaitOutputFull (
    892   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
    893   IN UINTN                                Timeout
    894   )
    895 {
    896   UINTN Delay;
    897   UINT8 Data;
    898 
    899   Delay = Timeout / 50;
    900 
    901   do {
    902     IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
    903 
    904     //
    905     // Check keyboard controller status bit 0(output buffer status)
    906     //  & bit5(output buffer for auxiliary device)
    907     //
    908     if ((Data & (KBC_OUTB | KBC_AUXB)) == (KBC_OUTB | KBC_AUXB)) {
    909       break;
    910     }
    911 
    912     gBS->Stall (50);
    913     Delay--;
    914   } while (Delay != 0);
    915 
    916   if (Delay == 0) {
    917     return EFI_TIMEOUT;
    918   }
    919 
    920   return EFI_SUCCESS;
    921 }
    922