/** Get mouse packet . Only care first 3 bytes @param MouseAbsolutePointerDev Pointer to PS2 Absolute Pointer Simulation Device Private Data Structure @retval EFI_NOT_READY Mouse Device not ready to input data packet, or some error happened during getting the packet @retval EFI_SUCCESS The data packet is gotten successfully. **/ EFI_STATUS PS2MouseGetPacket ( PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev ) { EFI_STATUS Status; BOOLEAN KeyboardEnable; UINT8 Packet[PS2_PACKET_LENGTH]; UINT8 Data; UINTN Count; UINTN State; INT16 RelativeMovementX; INT16 RelativeMovementY; BOOLEAN LButton; BOOLEAN RButton; KeyboardEnable = FALSE; Count = 1; State = PS2_READ_BYTE_ONE; // // State machine to get mouse packet // while (1) { switch (State) { case PS2_READ_BYTE_ONE: // // Read mouse first byte data, if failed, immediately return // KbcDisableAux (MouseAbsolutePointerDev->IsaIo); Status = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, &Data, &Count, State); if (EFI_ERROR (Status)) { KbcEnableAux (MouseAbsolutePointerDev->IsaIo); return EFI_NOT_READY; } if (Count != 1) { KbcEnableAux (MouseAbsolutePointerDev->IsaIo); return EFI_NOT_READY; } if (IS_PS2_SYNC_BYTE (Data)) { Packet[0] = Data; State = PS2_READ_DATA_BYTE; CheckKbStatus (MouseAbsolutePointerDev->IsaIo, &KeyboardEnable); KbcDisableKb (MouseAbsolutePointerDev->IsaIo); KbcEnableAux (MouseAbsolutePointerDev->IsaIo); } break; case PS2_READ_DATA_BYTE: Count = 2; Status = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, (Packet + 1), &Count, State); if (EFI_ERROR (Status)) { if (KeyboardEnable) { KbcEnableKb (MouseAbsolutePointerDev->IsaIo); } return EFI_NOT_READY; } if (Count != 2) { if (KeyboardEnable) { KbcEnableKb (MouseAbsolutePointerDev->IsaIo); } return EFI_NOT_READY; } State = PS2_PROCESS_PACKET; break; case PS2_PROCESS_PACKET: if (KeyboardEnable) { KbcEnableKb (MouseAbsolutePointerDev->IsaIo); } // // Decode the packet // RelativeMovementX = Packet[1]; RelativeMovementY = Packet[2]; // // Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 // Byte 0 | Y overflow | X overflow | Y sign bit | X sign bit | Always 1 | Middle Btn | Right Btn | Left Btn // Byte 1 | 8 bit X Movement // Byte 2 | 8 bit Y Movement // // 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. // Y sign bit + 8 bit Y Movement : Same as X sign bit + 8 bit X Movement. // // // First, Clear X and Y high 8 bits // RelativeMovementX = (INT16) (RelativeMovementX & 0xFF); RelativeMovementY = (INT16) (RelativeMovementY & 0xFF); // // Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff // if ((Packet[0] & 0x10) != 0) { RelativeMovementX = (INT16) (RelativeMovementX | 0xFF00); } if ((Packet[0] & 0x20) != 0) { RelativeMovementY = (INT16) (RelativeMovementY | 0xFF00); } RButton = (UINT8) (Packet[0] & 0x2); LButton = (UINT8) (Packet[0] & 0x1); // // Update mouse state // MouseAbsolutePointerDev->State.CurrentX += RelativeMovementX; MouseAbsolutePointerDev->State.CurrentY -= RelativeMovementY; MouseAbsolutePointerDev->State.CurrentZ = 0; MouseAbsolutePointerDev->State.ActiveButtons = (UINT8) (LButton || RButton) & 0x3; MouseAbsolutePointerDev->StateChanged = TRUE; return EFI_SUCCESS; } } }
/** Reset the Mouse and do BAT test for it, if ExtendedVerification is TRUE and there is a mouse device connectted to system. @param This - Pointer of simple pointer Protocol. @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip. @retval EFI_SUCCESS - The command byte is written successfully. @retval EFI_DEVICE_ERROR - Errors occurred during reseting keyboard. **/ EFI_STATUS EFIAPI MouseReset ( IN EFI_SIMPLE_POINTER_PROTOCOL *This, IN BOOLEAN ExtendedVerification ) { EFI_STATUS Status; PS2_MOUSE_DEV *MouseDev; EFI_TPL OldTpl; BOOLEAN KeyboardEnable; UINT8 Data; MouseDev = PS2_MOUSE_DEV_FROM_THIS (This); // // Report reset progress code // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET, MouseDev->DevicePath ); KeyboardEnable = FALSE; // // Raise TPL to avoid keyboard operation impact // OldTpl = gBS->RaiseTPL (TPL_NOTIFY); ZeroMem (&MouseDev->State, sizeof (EFI_SIMPLE_POINTER_STATE)); MouseDev->StateChanged = FALSE; // // Exhaust input data // Status = EFI_SUCCESS; while (!EFI_ERROR (Status)) { Status = In8042Data (&Data); } CheckKbStatus (&KeyboardEnable); KbcDisableKb (); // // if there's data block on KBC data port, read it out // if ((IoRead8 (KBC_CMD_STS_PORT) & KBC_OUTB) == KBC_OUTB) { IoRead8 (KBC_DATA_PORT); } Status = EFI_SUCCESS; // // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system. // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling // if (ExtendedVerification && CheckMouseConnect (MouseDev)) { // // Send mouse reset command and set mouse default configure // Status = PS2MouseReset (); if (EFI_ERROR (Status)) { Status = EFI_DEVICE_ERROR; goto Exit; } Status = PS2MouseSetSampleRate (MouseDev->SampleRate); if (EFI_ERROR (Status)) { Status = EFI_DEVICE_ERROR; goto Exit; } Status = PS2MouseSetResolution (MouseDev->Resolution); if (EFI_ERROR (Status)) { Status = EFI_DEVICE_ERROR; goto Exit; } Status = PS2MouseSetScaling (MouseDev->Scaling); if (EFI_ERROR (Status)) { Status = EFI_DEVICE_ERROR; goto Exit; } Status = PS2MouseEnable (); if (EFI_ERROR (Status)) { Status = EFI_DEVICE_ERROR; goto Exit; } } Exit: gBS->RestoreTPL (OldTpl); if (KeyboardEnable) { KbcEnableKb (); } return Status; }