2 PS2 Mouse Communication Interface.
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 UINT8 SampleRateTbl
[MaxSampleRate
] = { 0xa, 0x14, 0x28, 0x3c, 0x50, 0x64, 0xc8 };
14 UINT8 ResolutionTbl
[MaxResolution
] = { 0, 1, 2, 3 };
17 Issue self test command via IsaIo interface.
19 @return EFI_SUCCESS Success to do keyboard self testing.
20 @return others Fail to do keyboard self testing.
31 // Keyboard controller self test
33 Status
= Out8042Command (SELF_TEST
);
34 if (EFI_ERROR (Status
)) {
41 Status
= In8042Data (&Data
);
42 if (EFI_ERROR (Status
)) {
47 return EFI_DEVICE_ERROR
;
53 Status
= Out8042Command (READ_CMD_BYTE
);
54 if (EFI_ERROR (Status
)) {
58 Status
= In8042Data (&Data
);
59 if (EFI_ERROR (Status
)) {
63 Status
= Out8042Command (WRITE_CMD_BYTE
);
64 if (EFI_ERROR (Status
)) {
69 Status
= Out8042Data (Data
);
70 if (EFI_ERROR (Status
)) {
78 Issue command to enable keyboard AUX functionality.
80 @return Status of command issuing.
88 // Send 8042 enable mouse command
90 return Out8042Command (ENABLE_AUX
);
94 Issue command to disable keyboard AUX functionality.
96 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
98 @return Status of command issuing.
106 // Send 8042 disable mouse command
108 return Out8042Command (DISABLE_AUX
);
112 Issue command to enable keyboard.
114 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
116 @return Status of command issuing.
124 // Send 8042 enable keyboard command
126 return Out8042Command (ENABLE_KB
);
130 Issue command to disable keyboard.
132 @return Status of command issuing.
140 // Send 8042 disable keyboard command
142 return Out8042Command (DISABLE_KB
);
146 Issue command to check keyboard status.
148 @param KeyboardEnable return whether keyboard is enable.
150 @return Status of command issuing.
154 OUT BOOLEAN
*KeyboardEnable
161 // Send command to read KBC command byte
163 Status
= Out8042Command (READ_CMD_BYTE
);
164 if (EFI_ERROR (Status
)) {
168 Status
= In8042Data (&Data
);
169 if (EFI_ERROR (Status
)) {
174 // Check keyboard enable or not
176 if ((Data
& CMD_KB_STS
) == CMD_KB_DIS
) {
177 *KeyboardEnable
= FALSE
;
179 *KeyboardEnable
= TRUE
;
186 Issue command to reset keyboard.
188 @return Status of command issuing.
198 Status
= Out8042AuxCommand (RESET_CMD
, FALSE
);
199 if (EFI_ERROR (Status
)) {
203 Status
= In8042AuxData (&Data
);
204 if (EFI_ERROR (Status
)) {
209 // Check BAT Complete Code
211 if (Data
!= PS2MOUSE_BAT1
) {
212 return EFI_DEVICE_ERROR
;
215 Status
= In8042AuxData (&Data
);
216 if (EFI_ERROR (Status
)) {
221 // Check BAT Complete Code
223 if (Data
!= PS2MOUSE_BAT2
) {
224 return EFI_DEVICE_ERROR
;
231 Issue command to set mouse's sample rate
233 @param SampleRate value of sample rate
235 @return Status of command issuing.
238 PS2MouseSetSampleRate (
239 IN MOUSE_SR SampleRate
245 // Send auxiliary command to set mouse sample rate
247 Status
= Out8042AuxCommand (SETSR_CMD
, FALSE
);
248 if (EFI_ERROR (Status
)) {
252 Status
= Out8042AuxData (SampleRateTbl
[SampleRate
]);
258 Issue command to set mouse's resolution.
260 @param Resolution value of resolution
262 @return Status of command issuing.
265 PS2MouseSetResolution (
266 IN MOUSE_RE Resolution
272 // Send auxiliary command to set mouse resolution
274 Status
= Out8042AuxCommand (SETRE_CMD
, FALSE
);
275 if (EFI_ERROR (Status
)) {
279 Status
= Out8042AuxData (ResolutionTbl
[Resolution
]);
285 Issue command to set mouse's scaling.
287 @param Scaling value of scaling
289 @return Status of command issuing.
297 // Send auxiliary command to set mouse scaling data
299 return Out8042AuxCommand (Scaling
== Scaling1
? SETSF1_CMD
: SETSF2_CMD
, FALSE
);
303 Issue command to enable Ps2 mouse.
305 @return Status of command issuing.
313 // Send auxiliary command to enable mouse
315 return Out8042AuxCommand (ENABLE_CMD
, FALSE
);
319 Get mouse packet . Only care first 3 bytes
321 @param MouseDev Pointer of PS2 Mouse Private Data Structure
323 @retval EFI_NOT_READY Mouse Device not ready to input data packet, or some error happened during getting the packet
324 @retval EFI_SUCCESS The data packet is gotten successfully.
329 PS2_MOUSE_DEV
*MouseDev
334 BOOLEAN KeyboardEnable
;
335 UINT8 Packet
[PS2_PACKET_LENGTH
];
339 INT16 RelativeMovementX
;
340 INT16 RelativeMovementY
;
344 KeyboardEnable
= FALSE
;
345 State
= PS2_READ_BYTE_ONE
;
348 // State machine to get mouse packet
352 case PS2_READ_BYTE_ONE
:
354 // Read mouse first byte data, if failed, immediately return
358 Status
= PS2MouseRead (&Data
, &Count
, State
);
359 if (EFI_ERROR (Status
)) {
361 return EFI_NOT_READY
;
366 return EFI_NOT_READY
;
369 if (IS_PS2_SYNC_BYTE (Data
)) {
371 State
= PS2_READ_DATA_BYTE
;
373 CheckKbStatus (&KeyboardEnable
);
380 case PS2_READ_DATA_BYTE
:
382 Status
= PS2MouseRead ((Packet
+ 1), &Count
, State
);
383 if (EFI_ERROR (Status
)) {
384 if (KeyboardEnable
) {
388 return EFI_NOT_READY
;
392 if (KeyboardEnable
) {
396 return EFI_NOT_READY
;
399 State
= PS2_PROCESS_PACKET
;
402 case PS2_PROCESS_PACKET
:
403 if (KeyboardEnable
) {
410 RelativeMovementX
= Packet
[1];
411 RelativeMovementY
= Packet
[2];
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
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.
422 // First, Clear X and Y high 8 bits
424 RelativeMovementX
= (INT16
)(RelativeMovementX
& 0xFF);
425 RelativeMovementY
= (INT16
)(RelativeMovementY
& 0xFF);
427 // Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff
429 if ((Packet
[0] & 0x10) != 0) {
430 RelativeMovementX
= (INT16
)(RelativeMovementX
| 0xFF00);
433 if ((Packet
[0] & 0x20) != 0) {
434 RelativeMovementY
= (INT16
)(RelativeMovementY
| 0xFF00);
437 RButton
= (UINT8
)(Packet
[0] & 0x2);
438 LButton
= (UINT8
)(Packet
[0] & 0x1);
441 // Update mouse state
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
;
455 Read data via IsaIo protocol with given number.
457 @param Buffer Buffer receive data of mouse
458 @param BufSize The size of buffer
459 @param State Check input or read data
461 @return status of reading mouse data.
466 IN OUT UINTN
*BufSize
,
473 Status
= EFI_SUCCESS
;
475 if (State
== PS2_READ_BYTE_ONE
) {
477 // Check input for mouse
479 Status
= CheckForInput ();
481 if (EFI_ERROR (Status
)) {
486 for (BytesRead
= 0; BytesRead
< *BufSize
; BytesRead
++) {
487 Status
= WaitOutputFull (TIMEOUT
);
488 if (EFI_ERROR (Status
)) {
492 Buffer
[BytesRead
] = IoRead8 (KBC_DATA_PORT
);
496 // Verify the correct number of bytes read
498 if ((BytesRead
== 0) || (BytesRead
!= *BufSize
)) {
499 Status
= EFI_NOT_FOUND
;
502 *BufSize
= BytesRead
;
511 I/O work flow of outing 8042 command.
513 @param Command I/O command.
515 @retval EFI_SUCCESS Success to execute I/O work flow
516 @retval EFI_TIMEOUT Keyboard controller time out.
526 // Wait keyboard controller input buffer empty
528 Status
= WaitInputEmpty (TIMEOUT
);
529 if (EFI_ERROR (Status
)) {
536 IoWrite8 (KBC_CMD_STS_PORT
, Command
);
538 Status
= WaitInputEmpty (TIMEOUT
);
539 if (EFI_ERROR (Status
)) {
547 I/O work flow of outing 8042 data.
549 @param Data Data value
551 @retval EFI_SUCCESS Success to execute I/O work flow
552 @retval EFI_TIMEOUT Keyboard controller time out.
562 // Wait keyboard controller input buffer empty
564 Status
= WaitInputEmpty (TIMEOUT
);
565 if (EFI_ERROR (Status
)) {
569 IoWrite8 (KBC_DATA_PORT
, Data
);
570 return WaitInputEmpty (TIMEOUT
);
574 I/O work flow of in 8042 data.
576 @param Data Data value
578 @retval EFI_SUCCESS Success to execute I/O work flow
579 @retval EFI_TIMEOUT Keyboard controller time out.
588 Delay
= TIMEOUT
/ 50;
592 // Check keyboard controller status bit 0(output buffer status)
594 if ((IoRead8 (KBC_CMD_STS_PORT
) & KBC_OUTB
) == KBC_OUTB
) {
600 } while (Delay
!= 0);
606 *Data
= IoRead8 (KBC_DATA_PORT
);
612 I/O work flow of outing 8042 Aux command.
614 @param Command Aux I/O command
615 @param Resend Whether need resend the Aux command.
617 @retval EFI_SUCCESS Success to execute I/O work flow
618 @retval EFI_TIMEOUT Keyboard controller time out.
630 // Wait keyboard controller input buffer empty
632 Status
= WaitInputEmpty (TIMEOUT
);
633 if (EFI_ERROR (Status
)) {
638 // Send write to auxiliary device command
640 IoWrite8 (KBC_CMD_STS_PORT
, WRITE_AUX_DEV
);
642 Status
= WaitInputEmpty (TIMEOUT
);
643 if (EFI_ERROR (Status
)) {
648 // Send auxiliary device command
650 IoWrite8 (KBC_DATA_PORT
, Command
);
655 Status
= In8042AuxData (&Data
);
656 if (EFI_ERROR (Status
)) {
660 if (Data
== PS2_ACK
) {
662 // Receive mouse acknowledge, command send success
669 return EFI_DEVICE_ERROR
;
670 } else if (Data
== PS2_RESEND
) {
674 Status
= Out8042AuxCommand (Command
, TRUE
);
675 if (EFI_ERROR (Status
)) {
680 // Invalid return code
682 return EFI_DEVICE_ERROR
;
689 I/O work flow of outing 8042 Aux data.
691 @param Data Buffer holding return value
693 @retval EFI_SUCCESS Success to execute I/O work flow.
694 @retval EFI_TIMEOUT Keyboard controller time out.
704 // Wait keyboard controller input buffer empty
706 Status
= WaitInputEmpty (TIMEOUT
);
707 if (EFI_ERROR (Status
)) {
712 // Send write to auxiliary device command
714 IoWrite8 (KBC_CMD_STS_PORT
, WRITE_AUX_DEV
);
716 Status
= WaitInputEmpty (TIMEOUT
);
717 if (EFI_ERROR (Status
)) {
721 IoWrite8 (KBC_DATA_PORT
, Data
);
723 Status
= WaitInputEmpty (TIMEOUT
);
724 if (EFI_ERROR (Status
)) {
732 I/O work flow of in 8042 Aux data.
734 @param Data Buffer holding return value.
736 @retval EFI_SUCCESS Success to execute I/O work flow
737 @retval EFI_TIMEOUT Keyboard controller time out.
747 // wait for output data
749 Status
= WaitOutputFull (BAT_TIMEOUT
);
750 if (EFI_ERROR (Status
)) {
754 *Data
= IoRead8 (KBC_DATA_PORT
);
760 Check keyboard controller status, if it is output buffer full and for auxiliary device.
762 @retval EFI_SUCCESS Keyboard controller is ready
763 @retval EFI_NOT_READY Keyboard controller is not ready
772 Data
= IoRead8 (KBC_CMD_STS_PORT
);
775 // Check keyboard controller status, if it is output buffer full and for auxiliary device
777 if ((Data
& (KBC_OUTB
| KBC_AUXB
)) != (KBC_OUTB
| KBC_AUXB
)) {
778 return EFI_NOT_READY
;
785 I/O work flow to wait input buffer empty in given time.
787 @param Timeout Waiting time.
789 @retval EFI_TIMEOUT if input is still not empty in given time.
790 @retval EFI_SUCCESS input is empty.
800 Delay
= Timeout
/ 50;
803 Data
= IoRead8 (KBC_CMD_STS_PORT
);
806 // Check keyboard controller status bit 1(input buffer status)
808 if ((Data
& KBC_INPB
) == 0) {
814 } while (Delay
!= 0);
824 I/O work flow to wait output buffer full in given time.
826 @param Timeout given time
828 @retval EFI_TIMEOUT output is not full in given time
829 @retval EFI_SUCCESS output is full in given time.
839 Delay
= Timeout
/ 50;
842 Data
= IoRead8 (KBC_CMD_STS_PORT
);
845 // Check keyboard controller status bit 0(output buffer status)
846 // & bit5(output buffer for auxiliary device)
848 if ((Data
& (KBC_OUTB
| KBC_AUXB
)) == (KBC_OUTB
| KBC_AUXB
)) {
854 } while (Delay
!= 0);