2 PS2 Mouse Communication Interface
4 Copyright (c) 2006 - 2007, Intel Corporation
5 All rights reserved. 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
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.
15 #include "Ps2MouseAbsolutePointer.h"
18 UINT8 SampleRateTbl
[MAX_SR
] = { 0xa, 0x14, 0x28, 0x3c, 0x50, 0x64, 0xc8 };
20 UINT8 ResolutionTbl
[MAX_CMR
] = { 0, 1, 2, 3 };
24 IN EFI_ISA_IO_PROTOCOL
*IsaIo
30 GC_TODO: Add function description
34 IsaIo - GC_TODO: add argument description
38 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
39 EFI_SUCCESS - GC_TODO: Add description for return value
47 // Keyboard controller self test
49 Status
= Out8042Command (IsaIo
, SELF_TEST
);
50 if (EFI_ERROR (Status
)) {
56 Status
= In8042Data (IsaIo
, &Data
);
57 if (EFI_ERROR (Status
)) {
62 return EFI_DEVICE_ERROR
;
67 Status
= Out8042Command (IsaIo
, READ_CMD_BYTE
);
68 if (EFI_ERROR (Status
)) {
72 Status
= In8042Data (IsaIo
, &Data
);
73 if (EFI_ERROR (Status
)) {
77 Status
= Out8042Command (IsaIo
, WRITE_CMD_BYTE
);
78 if (EFI_ERROR (Status
)) {
83 Status
= Out8042Data (IsaIo
, Data
);
84 if (EFI_ERROR (Status
)) {
93 IN EFI_ISA_IO_PROTOCOL
*IsaIo
99 GC_TODO: Add function description
103 IsaIo - GC_TODO: add argument description
107 GC_TODO: add return values
112 // Send 8042 enable mouse command
114 return Out8042Command (IsaIo
, ENABLE_AUX
);
119 IN EFI_ISA_IO_PROTOCOL
*IsaIo
125 GC_TODO: Add function description
129 IsaIo - GC_TODO: add argument description
133 GC_TODO: add return values
138 // Send 8042 disable mouse command
140 return Out8042Command (IsaIo
, DISABLE_AUX
);
145 IN EFI_ISA_IO_PROTOCOL
*IsaIo
151 GC_TODO: Add function description
155 IsaIo - GC_TODO: add argument description
159 GC_TODO: add return values
164 // Send 8042 enable keyboard command
166 return Out8042Command (IsaIo
, ENABLE_KB
);
171 IN EFI_ISA_IO_PROTOCOL
*IsaIo
177 GC_TODO: Add function description
181 IsaIo - GC_TODO: add argument description
185 GC_TODO: add return values
190 // Send 8042 disable keyboard command
192 return Out8042Command (IsaIo
, DISABLE_KB
);
197 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
198 OUT BOOLEAN
*KeyboardEnable
204 GC_TODO: Add function description
208 IsaIo - GC_TODO: add argument description
209 KeyboardEnable - GC_TODO: add argument description
213 EFI_SUCCESS - GC_TODO: Add description for return value
221 // Send command to read KBC command byte
223 Status
= Out8042Command (IsaIo
, READ_CMD_BYTE
);
224 if (EFI_ERROR (Status
)) {
228 Status
= In8042Data (IsaIo
, &Data
);
229 if (EFI_ERROR (Status
)) {
233 // Check keyboard enable or not
235 if ((Data
& CMD_KB_STS
) == CMD_KB_DIS
) {
236 *KeyboardEnable
= FALSE
;
238 *KeyboardEnable
= TRUE
;
246 IN EFI_ISA_IO_PROTOCOL
*IsaIo
252 GC_TODO: Add function description
256 IsaIo - GC_TODO: add argument description
260 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
261 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
262 EFI_SUCCESS - GC_TODO: Add description for return value
269 Status
= Out8042AuxCommand (IsaIo
, RESET_CMD
, FALSE
);
270 if (EFI_ERROR (Status
)) {
274 Status
= In8042AuxData (IsaIo
, &Data
);
275 if (EFI_ERROR (Status
)) {
279 // Check BAT Complete Code
281 if (Data
!= PS2MOUSE_BAT1
) {
282 return EFI_DEVICE_ERROR
;
285 Status
= In8042AuxData (IsaIo
, &Data
);
286 if (EFI_ERROR (Status
)) {
290 // Check BAT Complete Code
292 if (Data
!= PS2MOUSE_BAT2
) {
293 return EFI_DEVICE_ERROR
;
300 PS2MouseSetSampleRate (
301 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
302 IN MOUSE_SR SampleRate
308 GC_TODO: Add function description
312 IsaIo - GC_TODO: add argument description
313 SampleRate - GC_TODO: add argument description
317 GC_TODO: add return values
324 // Send auxiliary command to set mouse sample rate
326 Status
= Out8042AuxCommand (IsaIo
, SETSR_CMD
, FALSE
);
327 if (EFI_ERROR (Status
)) {
331 Status
= Out8042AuxData (IsaIo
, SampleRateTbl
[SampleRate
]);
337 PS2MouseSetResolution (
338 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
339 IN MOUSE_RE Resolution
345 GC_TODO: Add function description
349 IsaIo - GC_TODO: add argument description
350 Resolution - GC_TODO: add argument description
354 GC_TODO: add return values
361 // Send auxiliary command to set mouse resolution
363 Status
= Out8042AuxCommand (IsaIo
, SETRE_CMD
, FALSE
);
364 if (EFI_ERROR (Status
)) {
368 Status
= Out8042AuxData (IsaIo
, ResolutionTbl
[Resolution
]);
375 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
382 GC_TODO: Add function description
386 IsaIo - GC_TODO: add argument description
387 Scaling - GC_TODO: add argument description
391 GC_TODO: add return values
397 Command
= (UINT8
) (Scaling
== SF1
? SETSF1_CMD
: SETSF2_CMD
);
400 // Send auxiliary command to set mouse scaling data
402 return Out8042AuxCommand (IsaIo
, Command
, FALSE
);
407 IN EFI_ISA_IO_PROTOCOL
*IsaIo
413 GC_TODO: Add function description
417 IsaIo - GC_TODO: add argument description
421 GC_TODO: add return values
426 // Send auxiliary command to enable mouse
428 return Out8042AuxCommand (IsaIo
, ENABLE_CMD
, FALSE
);
433 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
439 Get mouse packet . Only care first 3 bytes
443 MouseDev - Pointer of PS2 Mouse Private Data Structure
447 EFI_NOT_READY - Mouse Device not ready to input data packet, or some error happened during getting the packet
448 EFI_SUCCESS - The data packet is gotten successfully.
453 BOOLEAN KeyboardEnable
;
454 UINT8 Packet
[PS2_PACKET_LENGTH
];
458 INT16 RelativeMovementX
;
459 INT16 RelativeMovementY
;
463 KeyboardEnable
= FALSE
;
465 State
= PS2_READ_BYTE_ONE
;
468 // State machine to get mouse packet
473 case PS2_READ_BYTE_ONE
:
475 // Read mouse first byte data, if failed, immediately return
477 KbcDisableAux (MouseAbsolutePointerDev
->IsaIo
);
478 Status
= PS2MouseRead (MouseAbsolutePointerDev
->IsaIo
, &Data
, &Count
, State
);
479 if (EFI_ERROR (Status
)) {
480 KbcEnableAux (MouseAbsolutePointerDev
->IsaIo
);
481 return EFI_NOT_READY
;
485 KbcEnableAux (MouseAbsolutePointerDev
->IsaIo
);
486 return EFI_NOT_READY
;
489 if (IS_PS2_SYNC_BYTE (Data
)) {
491 State
= PS2_READ_DATA_BYTE
;
493 CheckKbStatus (MouseAbsolutePointerDev
->IsaIo
, &KeyboardEnable
);
494 KbcDisableKb (MouseAbsolutePointerDev
->IsaIo
);
495 KbcEnableAux (MouseAbsolutePointerDev
->IsaIo
);
499 case PS2_READ_DATA_BYTE
:
501 Status
= PS2MouseRead (MouseAbsolutePointerDev
->IsaIo
, (Packet
+ 1), &Count
, State
);
502 if (EFI_ERROR (Status
)) {
503 if (KeyboardEnable
) {
504 KbcEnableKb (MouseAbsolutePointerDev
->IsaIo
);
507 return EFI_NOT_READY
;
511 if (KeyboardEnable
) {
512 KbcEnableKb (MouseAbsolutePointerDev
->IsaIo
);
515 return EFI_NOT_READY
;
518 State
= PS2_PROCESS_PACKET
;
521 case PS2_PROCESS_PACKET
:
522 if (KeyboardEnable
) {
523 KbcEnableKb (MouseAbsolutePointerDev
->IsaIo
);
528 RelativeMovementX
= Packet
[1];
529 RelativeMovementY
= Packet
[2];
531 // Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0
532 // Byte 0 | Y overflow | X overflow | Y sign bit | X sign bit | Always 1 | Middle Btn | Right Btn | Left Btn
533 // Byte 1 | 8 bit X Movement
534 // Byte 2 | 8 bit Y Movement
536 // 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.
537 // Y sign bit + 8 bit Y Movement : Same as X sign bit + 8 bit X Movement.
540 // First, Clear X and Y high 8 bits
542 RelativeMovementX
= (INT16
) (RelativeMovementX
& 0xFF);
543 RelativeMovementY
= (INT16
) (RelativeMovementY
& 0xFF);
545 // Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff
547 if ((Packet
[0] & 0x10) != 0) {
548 RelativeMovementX
= (INT16
) (RelativeMovementX
| 0xFF00);
550 if ((Packet
[0] & 0x20) != 0) {
551 RelativeMovementY
= (INT16
) (RelativeMovementY
| 0xFF00);
555 RButton
= (UINT8
) (Packet
[0] & 0x2);
556 LButton
= (UINT8
) (Packet
[0] & 0x1);
559 // Update mouse state
561 MouseAbsolutePointerDev
->State
.CurrentX
+= RelativeMovementX
;
562 MouseAbsolutePointerDev
->State
.CurrentY
-= RelativeMovementY
;
563 MouseAbsolutePointerDev
->State
.CurrentZ
= 0;
564 MouseAbsolutePointerDev
->State
.ActiveButtons
= (UINT8
) (LButton
|| RButton
) & 0x3;
565 MouseAbsolutePointerDev
->StateChanged
= TRUE
;
574 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
576 IN OUT UINTN
*BufSize
,
583 GC_TODO: Add function description
587 IsaIo - GC_TODO: add argument description
588 Buffer - GC_TODO: add argument description
589 BufSize - GC_TODO: add argument description
590 State - GC_TODO: add argument description
594 GC_TODO: add return values
601 Status
= EFI_SUCCESS
;
604 if (State
== PS2_READ_BYTE_ONE
) {
606 // Check input for mouse
608 Status
= CheckForInput (IsaIo
);
610 if (EFI_ERROR (Status
)) {
615 while (BytesRead
< *BufSize
) {
617 Status
= WaitOutputFull (IsaIo
, TIMEOUT
);
618 if (EFI_ERROR (Status
)) {
622 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, Buffer
);
625 Buffer
= (UINT8
*) Buffer
+ 1;
628 // Verify the correct number of bytes read
630 if (BytesRead
== 0 || BytesRead
!= *BufSize
) {
631 Status
= EFI_NOT_FOUND
;
634 *BufSize
= BytesRead
;
642 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
649 GC_TODO: Add function description
653 IsaIo - GC_TODO: add argument description
654 Command - GC_TODO: add argument description
658 EFI_SUCCESS - GC_TODO: Add description for return value
666 // Wait keyboard controller input buffer empty
668 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
669 if (EFI_ERROR (Status
)) {
676 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
678 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
679 if (EFI_ERROR (Status
)) {
688 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
695 GC_TODO: Add function description
699 IsaIo - GC_TODO: add argument description
700 Data - GC_TODO: add argument description
704 EFI_SUCCESS - GC_TODO: Add description for return value
711 // Wait keyboard controller input buffer empty
713 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
714 if (EFI_ERROR (Status
)) {
719 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &temp
);
721 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
722 if (EFI_ERROR (Status
)) {
731 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
738 GC_TODO: Add function description
742 IsaIo - GC_TODO: add argument description
743 Data - GC_TODO: add argument description
747 EFI_TIMEOUT - GC_TODO: Add description for return value
748 EFI_SUCCESS - GC_TODO: Add description for return value
755 Delay
= TIMEOUT
/ 50;
758 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &temp
);
761 // Check keyboard controller status bit 0(output buffer status)
763 if ((temp
& KBC_OUTB
) == KBC_OUTB
) {
775 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, Data
);
782 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
790 GC_TODO: Add function description
794 IsaIo - GC_TODO: add argument description
795 Command - GC_TODO: add argument description
796 Resend - GC_TODO: add argument description
800 EFI_SUCCESS - GC_TODO: Add description for return value
801 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
802 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
803 EFI_SUCCESS - GC_TODO: Add description for return value
811 // Wait keyboard controller input buffer empty
813 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
814 if (EFI_ERROR (Status
)) {
818 // Send write to auxiliary device command
820 Data
= WRITE_AUX_DEV
;
821 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
823 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
824 if (EFI_ERROR (Status
)) {
828 // Send auxiliary device command
830 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Command
);
835 Status
= In8042AuxData (IsaIo
, &Data
);
836 if (EFI_ERROR (Status
)) {
840 if (Data
== PS2_ACK
) {
842 // Receive mouse acknowledge, command send success
850 return EFI_DEVICE_ERROR
;
852 } else if (Data
== PS2_RESEND
) {
856 Status
= Out8042AuxCommand (IsaIo
, Command
, TRUE
);
857 if (EFI_ERROR (Status
)) {
863 // Invalid return code
865 return EFI_DEVICE_ERROR
;
874 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
881 GC_TODO: Add function description
885 IsaIo - GC_TODO: add argument description
886 Data - GC_TODO: add argument description
890 EFI_SUCCESS - GC_TODO: Add description for return value
897 // Wait keyboard controller input buffer empty
899 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
900 if (EFI_ERROR (Status
)) {
904 // Send write to auxiliary device command
906 Temp
= WRITE_AUX_DEV
;
907 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Temp
);
909 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
910 if (EFI_ERROR (Status
)) {
915 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Temp
);
917 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
918 if (EFI_ERROR (Status
)) {
927 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
934 GC_TODO: Add function description
938 IsaIo - GC_TODO: add argument description
939 Data - GC_TODO: add argument description
943 EFI_SUCCESS - GC_TODO: Add description for return value
950 // wait for output data
952 Status
= WaitOutputFull (IsaIo
, BAT_TIMEOUT
);
953 if (EFI_ERROR (Status
)) {
957 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, Data
);
964 IN EFI_ISA_IO_PROTOCOL
*IsaIo
970 GC_TODO: Add function description
974 IsaIo - GC_TODO: add argument description
978 EFI_NOT_READY - GC_TODO: Add description for return value
979 EFI_SUCCESS - GC_TODO: Add description for return value
985 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
988 // Check keyboard controller status, if it is output buffer full and for auxiliary device
990 if ((Data
& (KBC_OUTB
| KBC_AUXB
)) != (KBC_OUTB
| KBC_AUXB
)) {
991 return EFI_NOT_READY
;
999 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
1004 Routine Description:
1006 GC_TODO: Add function description
1010 IsaIo - GC_TODO: add argument description
1011 Timeout - GC_TODO: add argument description
1015 EFI_TIMEOUT - GC_TODO: Add description for return value
1016 EFI_SUCCESS - GC_TODO: Add description for return value
1023 Delay
= Timeout
/ 50;
1026 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
1029 // Check keyboard controller status bit 1(input buffer status)
1031 if ((Data
& KBC_INPB
) == 0) {
1048 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
1053 Routine Description:
1055 GC_TODO: Add function description
1059 IsaIo - GC_TODO: add argument description
1060 Timeout - GC_TODO: add argument description
1064 EFI_TIMEOUT - GC_TODO: Add description for return value
1065 EFI_SUCCESS - GC_TODO: Add description for return value
1072 Delay
= Timeout
/ 50;
1075 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
1078 // Check keyboard controller status bit 0(output buffer status)
1079 // & bit5(output buffer for auxiliary device)
1081 if ((Data
& (KBC_OUTB
| KBC_AUXB
)) == (KBC_OUTB
| KBC_AUXB
)) {