EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/CommPs2.c

Go to the documentation of this file.
00001 
00015 #include "Ps2MouseAbsolutePointer.h"
00016 #include "CommPs2.h"
00017 
00018 UINT8 SampleRateTbl[MaxSampleRate]  = { 0xa, 0x14, 0x28, 0x3c, 0x50, 0x64, 0xc8 };
00019 
00020 UINT8 ResolutionTbl[MaxResolution]  = { 0, 1, 2, 3 };
00021 
00030 EFI_STATUS
00031 KbcSelfTest (
00032   IN EFI_ISA_IO_PROTOCOL                  *IsaIo
00033   )
00034 {
00035   EFI_STATUS  Status;
00036   UINT8       Data;
00037 
00038   //
00039   // Keyboard controller self test
00040   //
00041   Status = Out8042Command (IsaIo, SELF_TEST);
00042   if (EFI_ERROR (Status)) {
00043     return Status;
00044   }
00045   //
00046   // Read return code
00047   //
00048   Status = In8042Data (IsaIo, &Data);
00049   if (EFI_ERROR (Status)) {
00050     return Status;
00051   }
00052 
00053   if (Data != 0x55) {
00054     return EFI_DEVICE_ERROR;
00055   }
00056   //
00057   // Set system flag
00058   //
00059   Status = Out8042Command (IsaIo, READ_CMD_BYTE);
00060   if (EFI_ERROR (Status)) {
00061     return Status;
00062   }
00063 
00064   Status = In8042Data (IsaIo, &Data);
00065   if (EFI_ERROR (Status)) {
00066     return Status;
00067   }
00068 
00069   Status = Out8042Command (IsaIo, WRITE_CMD_BYTE);
00070   if (EFI_ERROR (Status)) {
00071     return Status;
00072   }
00073 
00074   Data |= CMD_SYS_FLAG;
00075   Status = Out8042Data (IsaIo, Data);
00076   if (EFI_ERROR (Status)) {
00077     return Status;
00078   }
00079 
00080   return EFI_SUCCESS;
00081 }
00082 
00090 EFI_STATUS
00091 KbcEnableAux (
00092   IN EFI_ISA_IO_PROTOCOL                  *IsaIo
00093   )
00094 {
00095   //
00096   // Send 8042 enable mouse command
00097   //
00098   return Out8042Command (IsaIo, ENABLE_AUX);
00099 }
00100 
00108 EFI_STATUS
00109 KbcDisableAux (
00110   IN EFI_ISA_IO_PROTOCOL                  *IsaIo
00111   )
00112 {
00113   //
00114   // Send 8042 disable mouse command
00115   //
00116   return Out8042Command (IsaIo, DISABLE_AUX);
00117 }
00118 
00126 EFI_STATUS
00127 KbcEnableKb (
00128   IN EFI_ISA_IO_PROTOCOL                  *IsaIo
00129   )
00130 {
00131   //
00132   // Send 8042 enable keyboard command
00133   //
00134   return Out8042Command (IsaIo, ENABLE_KB);
00135 }
00136 
00144 EFI_STATUS
00145 KbcDisableKb (
00146   IN EFI_ISA_IO_PROTOCOL                  *IsaIo
00147   )
00148 {
00149   //
00150   // Send 8042 disable keyboard command
00151   //
00152   return Out8042Command (IsaIo, DISABLE_KB);
00153 }
00154 
00163 EFI_STATUS
00164 CheckKbStatus (
00165   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00166   OUT BOOLEAN                             *KeyboardEnable
00167   )
00168 {
00169   EFI_STATUS  Status;
00170   UINT8       Data;
00171 
00172   //
00173   // Send command to read KBC command byte
00174   //
00175   Status = Out8042Command (IsaIo, READ_CMD_BYTE);
00176   if (EFI_ERROR (Status)) {
00177     return Status;
00178   }
00179 
00180   Status = In8042Data (IsaIo, &Data);
00181   if (EFI_ERROR (Status)) {
00182     return Status;
00183   }
00184   //
00185   // Check keyboard enable or not
00186   //
00187   if ((Data & CMD_KB_STS) == CMD_KB_DIS) {
00188     *KeyboardEnable = FALSE;
00189   } else {
00190     *KeyboardEnable = TRUE;
00191   }
00192 
00193   return EFI_SUCCESS;
00194 }
00195 
00203 EFI_STATUS
00204 PS2MouseReset (
00205   IN EFI_ISA_IO_PROTOCOL                  *IsaIo
00206   )
00207 {
00208   EFI_STATUS  Status;
00209   UINT8       Data;
00210 
00211   Status = Out8042AuxCommand (IsaIo, RESET_CMD, FALSE);
00212   if (EFI_ERROR (Status)) {
00213     return Status;
00214   }
00215 
00216   Status = In8042AuxData (IsaIo, &Data);
00217   if (EFI_ERROR (Status)) {
00218     return Status;
00219   }
00220   //
00221   // Check BAT Complete Code
00222   //
00223   if (Data != PS2MOUSE_BAT1) {
00224     return EFI_DEVICE_ERROR;
00225   }
00226 
00227   Status = In8042AuxData (IsaIo, &Data);
00228   if (EFI_ERROR (Status)) {
00229     return Status;
00230   }
00231   //
00232   // Check BAT Complete Code
00233   //
00234   if (Data != PS2MOUSE_BAT2) {
00235     return EFI_DEVICE_ERROR;
00236   }
00237 
00238   return EFI_SUCCESS;
00239 }
00240 
00249 EFI_STATUS
00250 PS2MouseSetSampleRate (
00251   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00252   IN MOUSE_SR                             SampleRate
00253   )
00254 {
00255   EFI_STATUS  Status;
00256 
00257   //
00258   // Send auxiliary command to set mouse sample rate
00259   //
00260   Status = Out8042AuxCommand (IsaIo, SETSR_CMD, FALSE);
00261   if (EFI_ERROR (Status)) {
00262     return Status;
00263   }
00264 
00265   Status = Out8042AuxData (IsaIo, SampleRateTbl[SampleRate]);
00266 
00267   return Status;
00268 }
00269 
00278 EFI_STATUS
00279 PS2MouseSetResolution (
00280   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00281   IN MOUSE_RE                             Resolution
00282   )
00283 {
00284   EFI_STATUS  Status;
00285 
00286   //
00287   // Send auxiliary command to set mouse resolution
00288   //
00289   Status = Out8042AuxCommand (IsaIo, SETRE_CMD, FALSE);
00290   if (EFI_ERROR (Status)) {
00291     return Status;
00292   }
00293 
00294   Status = Out8042AuxData (IsaIo, ResolutionTbl[Resolution]);
00295 
00296   return Status;
00297 }
00298 
00307 EFI_STATUS
00308 PS2MouseSetScaling (
00309   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00310   IN MOUSE_SF                             Scaling
00311   )
00312 {
00313   UINT8 Command;
00314 
00315   Command = (UINT8) (Scaling == Scaling1 ? SETSF1_CMD : SETSF2_CMD);
00316 
00317   //
00318   // Send auxiliary command to set mouse scaling data
00319   //
00320   return Out8042AuxCommand (IsaIo, Command, FALSE);
00321 }
00322 
00330 EFI_STATUS
00331 PS2MouseEnable (
00332   IN EFI_ISA_IO_PROTOCOL                  *IsaIo
00333   )
00334 {
00335   //
00336   // Send auxiliary command to enable mouse
00337   //
00338   return Out8042AuxCommand (IsaIo, ENABLE_CMD, FALSE);
00339 }
00340 
00350 EFI_STATUS
00351 PS2MouseGetPacket (
00352   PS2_MOUSE_ABSOLUTE_POINTER_DEV     *MouseAbsolutePointerDev
00353   )
00354 
00355 {
00356   EFI_STATUS  Status;
00357   BOOLEAN     KeyboardEnable;
00358   UINT8       Packet[PS2_PACKET_LENGTH];
00359   UINT8       Data;
00360   UINTN       Count;
00361   UINTN       State;
00362   INT16       RelativeMovementX;
00363   INT16       RelativeMovementY;
00364   BOOLEAN     LButton;
00365   BOOLEAN     RButton;
00366 
00367   KeyboardEnable  = FALSE;
00368   Count           = 1;
00369   State           = PS2_READ_BYTE_ONE;
00370 
00371   //
00372   // State machine to get mouse packet
00373   //
00374   while (1) {
00375 
00376     switch (State) {
00377     case PS2_READ_BYTE_ONE:
00378       //
00379       // Read mouse first byte data, if failed, immediately return
00380       //
00381       KbcDisableAux (MouseAbsolutePointerDev->IsaIo);
00382       Status = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, &Data, &Count, State);
00383       if (EFI_ERROR (Status)) {
00384         KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
00385         return EFI_NOT_READY;
00386       }
00387 
00388       if (Count != 1) {
00389         KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
00390         return EFI_NOT_READY;
00391       }
00392 
00393       if (IS_PS2_SYNC_BYTE (Data)) {
00394         Packet[0] = Data;
00395         State     = PS2_READ_DATA_BYTE;
00396 
00397         CheckKbStatus (MouseAbsolutePointerDev->IsaIo, &KeyboardEnable);
00398         KbcDisableKb (MouseAbsolutePointerDev->IsaIo);
00399         KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
00400       }
00401       break;
00402 
00403     case PS2_READ_DATA_BYTE:
00404       Count   = 2;
00405       Status  = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, (Packet + 1), &Count, State);
00406       if (EFI_ERROR (Status)) {
00407         if (KeyboardEnable) {
00408           KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
00409         }
00410 
00411         return EFI_NOT_READY;
00412       }
00413 
00414       if (Count != 2) {
00415         if (KeyboardEnable) {
00416           KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
00417         }
00418 
00419         return EFI_NOT_READY;
00420       }
00421 
00422       State = PS2_PROCESS_PACKET;
00423       break;
00424 
00425     case PS2_PROCESS_PACKET:
00426       if (KeyboardEnable) {
00427         KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
00428       }
00429       //
00430       // Decode the packet
00431       //
00432       RelativeMovementX = Packet[1];
00433       RelativeMovementY = Packet[2];
00434       //
00435       //               Bit 7   |    Bit 6   |    Bit 5   |   Bit 4    |   Bit 3  |   Bit 2    |   Bit 1   |   Bit 0 
00436       //  Byte 0  | Y overflow | X overflow | Y sign bit | X sign bit | Always 1 | Middle Btn | Right Btn | Left Btn 
00437       //  Byte 1  |                                           8 bit X Movement 
00438       //  Byte 2  |                                           8 bit Y Movement 
00439       // 
00440       // 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.
00441       // Y sign bit + 8 bit Y Movement : Same as X sign bit + 8 bit X Movement.
00442       //
00443       //
00444       // First, Clear X and Y high 8 bits
00445       //
00446       RelativeMovementX = (INT16) (RelativeMovementX & 0xFF); 
00447       RelativeMovementY = (INT16) (RelativeMovementY & 0xFF); 
00448       //
00449       // Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff
00450       //
00451       if ((Packet[0] & 0x10) != 0) {
00452         RelativeMovementX = (INT16) (RelativeMovementX | 0xFF00);
00453       }
00454       if ((Packet[0] & 0x20) != 0) {
00455         RelativeMovementY = (INT16) (RelativeMovementY | 0xFF00);
00456       }
00457 
00458       
00459       RButton           = (UINT8) (Packet[0] & 0x2);
00460       LButton           = (UINT8) (Packet[0] & 0x1);
00461 
00462       //
00463       // Update mouse state
00464       //
00465       MouseAbsolutePointerDev->State.CurrentX += RelativeMovementX;
00466       MouseAbsolutePointerDev->State.CurrentY -= RelativeMovementY;
00467       MouseAbsolutePointerDev->State.CurrentZ = 0;
00468       MouseAbsolutePointerDev->State.ActiveButtons = (UINT8) (LButton || RButton) & 0x3;
00469       MouseAbsolutePointerDev->StateChanged      = TRUE;
00470 
00471       return EFI_SUCCESS;
00472     }
00473   }
00474 }
00475 
00486 EFI_STATUS
00487 PS2MouseRead (
00488   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00489   OUT VOID                                *Buffer,
00490   IN OUT UINTN                            *BufSize,
00491   IN  UINTN                               State
00492   )
00493 {
00494   EFI_STATUS  Status;
00495   UINTN       BytesRead;
00496 
00497   Status    = EFI_SUCCESS;
00498   BytesRead = 0;
00499 
00500   if (State == PS2_READ_BYTE_ONE) {
00501     //
00502     // Check input for mouse
00503     //
00504     Status = CheckForInput (IsaIo);
00505 
00506     if (EFI_ERROR (Status)) {
00507       return Status;
00508     }
00509   }
00510 
00511   while (BytesRead < *BufSize) {
00512 
00513     Status = WaitOutputFull (IsaIo, TIMEOUT);
00514     if (EFI_ERROR (Status)) {
00515       break;
00516     }
00517 
00518     IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Buffer);
00519 
00520     BytesRead++;
00521     Buffer = (UINT8 *) Buffer + 1;
00522   }
00523   //
00524   // Verify the correct number of bytes read
00525   //
00526   if (BytesRead == 0 || BytesRead != *BufSize) {
00527     Status = EFI_NOT_FOUND;
00528   }
00529 
00530   *BufSize = BytesRead;
00531   return Status;
00532 }
00533 
00534 //
00535 // 8042 I/O function
00536 //
00546 EFI_STATUS
00547 Out8042Command (
00548   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00549   IN UINT8                                Command
00550   )
00551 {
00552   EFI_STATUS  Status;
00553   UINT8       Data;
00554 
00555   //
00556   // Wait keyboard controller input buffer empty
00557   //
00558   Status = WaitInputEmpty (IsaIo, TIMEOUT);
00559   if (EFI_ERROR (Status)) {
00560     return Status;
00561   }
00562   //
00563   // Send command
00564   //
00565   Data = Command;
00566   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
00567 
00568   Status = WaitInputEmpty (IsaIo, TIMEOUT);
00569   if (EFI_ERROR (Status)) {
00570     return Status;
00571   }
00572 
00573   return EFI_SUCCESS;
00574 }
00575 
00585 EFI_STATUS
00586 Out8042Data (
00587   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00588   IN UINT8                                Data
00589   )
00590 {
00591   EFI_STATUS  Status;
00592   UINT8       Temp;
00593   //
00594   // Wait keyboard controller input buffer empty
00595   //
00596   Status = WaitInputEmpty (IsaIo, TIMEOUT);
00597   if (EFI_ERROR (Status)) {
00598     return Status;
00599   }
00600 
00601   Temp = Data;
00602   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
00603 
00604   Status = WaitInputEmpty (IsaIo, TIMEOUT);
00605   if (EFI_ERROR (Status)) {
00606     return Status;
00607   }
00608 
00609   return EFI_SUCCESS;
00610 }
00611 
00621 EFI_STATUS
00622 In8042Data (
00623   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00624   IN OUT UINT8                            *Data
00625   )
00626 {
00627   UINTN Delay;
00628   UINT8 Temp;
00629 
00630   Delay = TIMEOUT / 50;
00631 
00632   do {
00633     IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
00634 
00635     //
00636     // Check keyboard controller status bit 0(output buffer status)
00637     //
00638     if ((Temp & KBC_OUTB) == KBC_OUTB) {
00639       break;
00640     }
00641 
00642     gBS->Stall (50);
00643     Delay--;
00644   } while (Delay != 0);
00645 
00646   if (Delay == 0) {
00647     return EFI_TIMEOUT;
00648   }
00649 
00650   IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
00651 
00652   return EFI_SUCCESS;
00653 }
00654 
00665 EFI_STATUS
00666 Out8042AuxCommand (
00667   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00668   IN UINT8                                Command,
00669   IN BOOLEAN                              Resend
00670   )
00671 {
00672   EFI_STATUS  Status;
00673   UINT8       Data;
00674 
00675   //
00676   // Wait keyboard controller input buffer empty
00677   //
00678   Status = WaitInputEmpty (IsaIo, TIMEOUT);
00679   if (EFI_ERROR (Status)) {
00680     return Status;
00681   }
00682   //
00683   // Send write to auxiliary device command
00684   //
00685   Data = WRITE_AUX_DEV;
00686   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
00687 
00688   Status = WaitInputEmpty (IsaIo, TIMEOUT);
00689   if (EFI_ERROR (Status)) {
00690     return Status;
00691   }
00692   //
00693   // Send auxiliary device command
00694   //
00695   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Command);
00696 
00697   //
00698   // Read return code
00699   //
00700   Status = In8042AuxData (IsaIo, &Data);
00701   if (EFI_ERROR (Status)) {
00702     return Status;
00703   }
00704 
00705   if (Data == PS2_ACK) {
00706     //
00707     // Receive mouse acknowledge, command send success
00708     //
00709     return EFI_SUCCESS;
00710 
00711   } else if (Resend) {
00712     //
00713     // Resend fail
00714     //
00715     return EFI_DEVICE_ERROR;
00716 
00717   } else if (Data == PS2_RESEND) {
00718     //
00719     // Resend command
00720     //
00721     Status = Out8042AuxCommand (IsaIo, Command, TRUE);
00722     if (EFI_ERROR (Status)) {
00723       return Status;
00724     }
00725 
00726   } else {
00727     //
00728     // Invalid return code
00729     //
00730     return EFI_DEVICE_ERROR;
00731 
00732   }
00733 
00734   return EFI_SUCCESS;
00735 }
00736 
00746 EFI_STATUS
00747 Out8042AuxData (
00748   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00749   IN UINT8                                Data
00750   )
00751 {
00752   EFI_STATUS  Status;
00753   UINT8       Temp;
00754   //
00755   // Wait keyboard controller input buffer empty
00756   //
00757   Status = WaitInputEmpty (IsaIo, TIMEOUT);
00758   if (EFI_ERROR (Status)) {
00759     return Status;
00760   }
00761   //
00762   // Send write to auxiliary device command
00763   //
00764   Temp = WRITE_AUX_DEV;
00765   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
00766 
00767   Status = WaitInputEmpty (IsaIo, TIMEOUT);
00768   if (EFI_ERROR (Status)) {
00769     return Status;
00770   }
00771 
00772   Temp = Data;
00773   IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
00774 
00775   Status = WaitInputEmpty (IsaIo, TIMEOUT);
00776   if (EFI_ERROR (Status)) {
00777     return Status;
00778   }
00779 
00780   return EFI_SUCCESS;
00781 }
00782 
00792 EFI_STATUS
00793 In8042AuxData (
00794   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00795   IN OUT UINT8                            *Data
00796   )
00797 {
00798   EFI_STATUS  Status;
00799 
00800   //
00801   // wait for output data
00802   //
00803   Status = WaitOutputFull (IsaIo, BAT_TIMEOUT);
00804   if (EFI_ERROR (Status)) {
00805     return Status;
00806   }
00807 
00808   IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
00809 
00810   return EFI_SUCCESS;
00811 }
00812 
00813 
00822 EFI_STATUS
00823 CheckForInput (
00824   IN EFI_ISA_IO_PROTOCOL                  *IsaIo
00825   )
00826 {
00827   UINT8 Data;
00828 
00829   IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
00830 
00831   //
00832   // Check keyboard controller status, if it is output buffer full and for auxiliary device
00833   //
00834   if ((Data & (KBC_OUTB | KBC_AUXB)) != (KBC_OUTB | KBC_AUXB)) {
00835     return EFI_NOT_READY;
00836   }
00837 
00838   return EFI_SUCCESS;
00839 }
00840 
00850 EFI_STATUS
00851 WaitInputEmpty (
00852   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00853   IN UINTN                                Timeout
00854   )
00855 {
00856   UINTN Delay;
00857   UINT8 Data;
00858 
00859   Delay = Timeout / 50;
00860 
00861   do {
00862     IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
00863 
00864     //
00865     // Check keyboard controller status bit 1(input buffer status)
00866     //
00867     if ((Data & KBC_INPB) == 0) {
00868       break;
00869     }
00870 
00871     gBS->Stall (50);
00872     Delay--;
00873   } while (Delay != 0);
00874 
00875   if (Delay == 0) {
00876     return EFI_TIMEOUT;
00877   }
00878 
00879   return EFI_SUCCESS;
00880 }
00881 
00891 EFI_STATUS
00892 WaitOutputFull (
00893   IN EFI_ISA_IO_PROTOCOL                  *IsaIo,
00894   IN UINTN                                Timeout
00895   )
00896 {
00897   UINTN Delay;
00898   UINT8 Data;
00899 
00900   Delay = Timeout / 50;
00901 
00902   do {
00903     IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
00904 
00905     //
00906     // Check keyboard controller status bit 0(output buffer status)
00907     //  & bit5(output buffer for auxiliary device)
00908     //
00909     if ((Data & (KBC_OUTB | KBC_AUXB)) == (KBC_OUTB | KBC_AUXB)) {
00910       break;
00911     }
00912 
00913     gBS->Stall (50);
00914     Delay--;
00915   } while (Delay != 0);
00916 
00917   if (Delay == 0) {
00918     return EFI_TIMEOUT;
00919   }
00920 
00921   return EFI_SUCCESS;
00922 }
00923 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines