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 };
23 Issue self test command via IsaIo interface.
25 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
27 @return EFI_SUCCESS Success to do keyboard self testing.
28 @return others Fail to do keyboard self testing.
32 IN EFI_ISA_IO_PROTOCOL
*IsaIo
39 // Keyboard controller self test
41 Status
= Out8042Command (IsaIo
, SELF_TEST
);
42 if (EFI_ERROR (Status
)) {
48 Status
= In8042Data (IsaIo
, &Data
);
49 if (EFI_ERROR (Status
)) {
54 return EFI_DEVICE_ERROR
;
59 Status
= Out8042Command (IsaIo
, READ_CMD_BYTE
);
60 if (EFI_ERROR (Status
)) {
64 Status
= In8042Data (IsaIo
, &Data
);
65 if (EFI_ERROR (Status
)) {
69 Status
= Out8042Command (IsaIo
, WRITE_CMD_BYTE
);
70 if (EFI_ERROR (Status
)) {
75 Status
= Out8042Data (IsaIo
, Data
);
76 if (EFI_ERROR (Status
)) {
84 Issue command to enable keyboard AUX functionality.
86 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
88 @return Status of command issuing.
92 IN EFI_ISA_IO_PROTOCOL
*IsaIo
96 // Send 8042 enable mouse command
98 return Out8042Command (IsaIo
, ENABLE_AUX
);
102 Issue command to disable keyboard AUX functionality.
104 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
106 @return Status of command issuing.
110 IN EFI_ISA_IO_PROTOCOL
*IsaIo
114 // Send 8042 disable mouse command
116 return Out8042Command (IsaIo
, DISABLE_AUX
);
120 Issue command to enable keyboard.
122 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
124 @return Status of command issuing.
128 IN EFI_ISA_IO_PROTOCOL
*IsaIo
132 // Send 8042 enable keyboard command
134 return Out8042Command (IsaIo
, ENABLE_KB
);
138 Issue command to disable keyboard.
140 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
142 @return Status of command issuing.
146 IN EFI_ISA_IO_PROTOCOL
*IsaIo
150 // Send 8042 disable keyboard command
152 return Out8042Command (IsaIo
, DISABLE_KB
);
156 Issue command to check keyboard status.
158 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
159 @param KeyboardEnable return whether keyboard is enable.
161 @return Status of command issuing.
165 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
166 OUT BOOLEAN
*KeyboardEnable
173 // Send command to read KBC command byte
175 Status
= Out8042Command (IsaIo
, READ_CMD_BYTE
);
176 if (EFI_ERROR (Status
)) {
180 Status
= In8042Data (IsaIo
, &Data
);
181 if (EFI_ERROR (Status
)) {
185 // Check keyboard enable or not
187 if ((Data
& CMD_KB_STS
) == CMD_KB_DIS
) {
188 *KeyboardEnable
= FALSE
;
190 *KeyboardEnable
= TRUE
;
197 Issue command to reset keyboard.
199 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
201 @return Status of command issuing.
205 IN EFI_ISA_IO_PROTOCOL
*IsaIo
211 Status
= Out8042AuxCommand (IsaIo
, RESET_CMD
, FALSE
);
212 if (EFI_ERROR (Status
)) {
216 Status
= In8042AuxData (IsaIo
, &Data
);
217 if (EFI_ERROR (Status
)) {
221 // Check BAT Complete Code
223 if (Data
!= PS2MOUSE_BAT1
) {
224 return EFI_DEVICE_ERROR
;
227 Status
= In8042AuxData (IsaIo
, &Data
);
228 if (EFI_ERROR (Status
)) {
232 // Check BAT Complete Code
234 if (Data
!= PS2MOUSE_BAT2
) {
235 return EFI_DEVICE_ERROR
;
242 Issue command to set mouse's sample rate
244 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
245 @param SampleRate value of sample rate
247 @return Status of command issuing.
250 PS2MouseSetSampleRate (
251 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
252 IN MOUSE_SR SampleRate
258 // Send auxiliary command to set mouse sample rate
260 Status
= Out8042AuxCommand (IsaIo
, SETSR_CMD
, FALSE
);
261 if (EFI_ERROR (Status
)) {
265 Status
= Out8042AuxData (IsaIo
, SampleRateTbl
[SampleRate
]);
271 Issue command to set mouse's resolution.
273 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
274 @param Resolution value of resolution
276 @return Status of command issuing.
279 PS2MouseSetResolution (
280 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
281 IN MOUSE_RE Resolution
287 // Send auxiliary command to set mouse resolution
289 Status
= Out8042AuxCommand (IsaIo
, SETRE_CMD
, FALSE
);
290 if (EFI_ERROR (Status
)) {
294 Status
= Out8042AuxData (IsaIo
, ResolutionTbl
[Resolution
]);
300 Issue command to set mouse's scaling.
302 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
303 @param Scaling value of scaling
305 @return Status of command issuing.
309 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
315 Command
= (UINT8
) (Scaling
== SF1
? SETSF1_CMD
: SETSF2_CMD
);
318 // Send auxiliary command to set mouse scaling data
320 return Out8042AuxCommand (IsaIo
, Command
, FALSE
);
324 Issue command to enable Ps2 mouse.
326 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
328 @return Status of command issuing.
332 IN EFI_ISA_IO_PROTOCOL
*IsaIo
336 // Send auxiliary command to enable mouse
338 return Out8042AuxCommand (IsaIo
, ENABLE_CMD
, FALSE
);
342 Get mouse packet . Only care first 3 bytes
344 @param MouseAbsolutePointerDev Pointer to PS2 Absolute Pointer Simulation Device Private Data Structure
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.
352 PS2_MOUSE_ABSOLUTE_POINTER_DEV
*MouseAbsolutePointerDev
357 BOOLEAN KeyboardEnable
;
358 UINT8 Packet
[PS2_PACKET_LENGTH
];
362 INT16 RelativeMovementX
;
363 INT16 RelativeMovementY
;
367 KeyboardEnable
= FALSE
;
369 State
= PS2_READ_BYTE_ONE
;
372 // State machine to get mouse packet
377 case PS2_READ_BYTE_ONE
:
379 // Read mouse first byte data, if failed, immediately return
381 KbcDisableAux (MouseAbsolutePointerDev
->IsaIo
);
382 Status
= PS2MouseRead (MouseAbsolutePointerDev
->IsaIo
, &Data
, &Count
, State
);
383 if (EFI_ERROR (Status
)) {
384 KbcEnableAux (MouseAbsolutePointerDev
->IsaIo
);
385 return EFI_NOT_READY
;
389 KbcEnableAux (MouseAbsolutePointerDev
->IsaIo
);
390 return EFI_NOT_READY
;
393 if (IS_PS2_SYNC_BYTE (Data
)) {
395 State
= PS2_READ_DATA_BYTE
;
397 CheckKbStatus (MouseAbsolutePointerDev
->IsaIo
, &KeyboardEnable
);
398 KbcDisableKb (MouseAbsolutePointerDev
->IsaIo
);
399 KbcEnableAux (MouseAbsolutePointerDev
->IsaIo
);
403 case PS2_READ_DATA_BYTE
:
405 Status
= PS2MouseRead (MouseAbsolutePointerDev
->IsaIo
, (Packet
+ 1), &Count
, State
);
406 if (EFI_ERROR (Status
)) {
407 if (KeyboardEnable
) {
408 KbcEnableKb (MouseAbsolutePointerDev
->IsaIo
);
411 return EFI_NOT_READY
;
415 if (KeyboardEnable
) {
416 KbcEnableKb (MouseAbsolutePointerDev
->IsaIo
);
419 return EFI_NOT_READY
;
422 State
= PS2_PROCESS_PACKET
;
425 case PS2_PROCESS_PACKET
:
426 if (KeyboardEnable
) {
427 KbcEnableKb (MouseAbsolutePointerDev
->IsaIo
);
432 RelativeMovementX
= Packet
[1];
433 RelativeMovementY
= Packet
[2];
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
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.
444 // First, Clear X and Y high 8 bits
446 RelativeMovementX
= (INT16
) (RelativeMovementX
& 0xFF);
447 RelativeMovementY
= (INT16
) (RelativeMovementY
& 0xFF);
449 // Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff
451 if ((Packet
[0] & 0x10) != 0) {
452 RelativeMovementX
= (INT16
) (RelativeMovementX
| 0xFF00);
454 if ((Packet
[0] & 0x20) != 0) {
455 RelativeMovementY
= (INT16
) (RelativeMovementY
| 0xFF00);
459 RButton
= (UINT8
) (Packet
[0] & 0x2);
460 LButton
= (UINT8
) (Packet
[0] & 0x1);
463 // Update mouse state
465 MouseAbsolutePointerDev
->State
.CurrentX
+= RelativeMovementX
;
466 MouseAbsolutePointerDev
->State
.CurrentY
-= RelativeMovementY
;
467 MouseAbsolutePointerDev
->State
.CurrentZ
= 0;
468 MouseAbsolutePointerDev
->State
.ActiveButtons
= (UINT8
) (LButton
|| RButton
) & 0x3;
469 MouseAbsolutePointerDev
->StateChanged
= TRUE
;
477 Read data via IsaIo protocol with given number.
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
484 @return status of reading mouse data.
488 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
490 IN OUT UINTN
*BufSize
,
497 Status
= EFI_SUCCESS
;
500 if (State
== PS2_READ_BYTE_ONE
) {
502 // Check input for mouse
504 Status
= CheckForInput (IsaIo
);
506 if (EFI_ERROR (Status
)) {
511 while (BytesRead
< *BufSize
) {
513 Status
= WaitOutputFull (IsaIo
, TIMEOUT
);
514 if (EFI_ERROR (Status
)) {
518 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, Buffer
);
521 Buffer
= (UINT8
*) Buffer
+ 1;
524 // Verify the correct number of bytes read
526 if (BytesRead
== 0 || BytesRead
!= *BufSize
) {
527 Status
= EFI_NOT_FOUND
;
530 *BufSize
= BytesRead
;
538 I/O work flow of outing 8042 command.
540 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
541 @param Command I/O command.
543 @retval EFI_SUCCESS Success to excute I/O work flow
544 @retval EFI_TIMEOUT Keyboard controller time out.
548 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
556 // Wait keyboard controller input buffer empty
558 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
559 if (EFI_ERROR (Status
)) {
566 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
568 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
569 if (EFI_ERROR (Status
)) {
577 I/O work flow of outing 8042 data.
579 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
580 @param Data Data value
582 @retval EFI_SUCCESS Success to excute I/O work flow
583 @retval EFI_TIMEOUT Keyboard controller time out.
587 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
594 // Wait keyboard controller input buffer empty
596 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
597 if (EFI_ERROR (Status
)) {
602 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Temp
);
604 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
605 if (EFI_ERROR (Status
)) {
613 I/O work flow of in 8042 data.
615 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
616 @param Data Data value
618 @retval EFI_SUCCESS Success to excute I/O work flow
619 @retval EFI_TIMEOUT Keyboard controller time out.
623 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
630 Delay
= TIMEOUT
/ 50;
633 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Temp
);
636 // Check keyboard controller status bit 0(output buffer status)
638 if ((Temp
& KBC_OUTB
) == KBC_OUTB
) {
644 } while (Delay
!= 0);
650 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, Data
);
656 I/O work flow of outing 8042 Aux command.
658 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
659 @param Command Aux I/O command
660 @param Resend Whether need resend the Aux command.
662 @retval EFI_SUCCESS Success to excute I/O work flow
663 @retval EFI_TIMEOUT Keyboard controller time out.
667 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
676 // Wait keyboard controller input buffer empty
678 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
679 if (EFI_ERROR (Status
)) {
683 // Send write to auxiliary device command
685 Data
= WRITE_AUX_DEV
;
686 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
688 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
689 if (EFI_ERROR (Status
)) {
693 // Send auxiliary device command
695 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Command
);
700 Status
= In8042AuxData (IsaIo
, &Data
);
701 if (EFI_ERROR (Status
)) {
705 if (Data
== PS2_ACK
) {
707 // Receive mouse acknowledge, command send success
715 return EFI_DEVICE_ERROR
;
717 } else if (Data
== PS2_RESEND
) {
721 Status
= Out8042AuxCommand (IsaIo
, Command
, TRUE
);
722 if (EFI_ERROR (Status
)) {
728 // Invalid return code
730 return EFI_DEVICE_ERROR
;
738 I/O work flow of outing 8042 Aux data.
740 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
741 @param Data Buffer holding return value
743 @retval EFI_SUCCESS Success to excute I/O work flow.
744 @retval EFI_TIMEOUT Keyboard controller time out.
748 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
755 // Wait keyboard controller input buffer empty
757 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
758 if (EFI_ERROR (Status
)) {
762 // Send write to auxiliary device command
764 Temp
= WRITE_AUX_DEV
;
765 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Temp
);
767 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
768 if (EFI_ERROR (Status
)) {
773 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Temp
);
775 Status
= WaitInputEmpty (IsaIo
, TIMEOUT
);
776 if (EFI_ERROR (Status
)) {
784 I/O work flow of in 8042 Aux data.
786 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
787 @param Data Buffer holding return value.
789 @retval EFI_SUCCESS Success to excute I/O work flow
790 @retval EFI_TIMEOUT Keyboard controller time out.
794 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
801 // wait for output data
803 Status
= WaitOutputFull (IsaIo
, BAT_TIMEOUT
);
804 if (EFI_ERROR (Status
)) {
808 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, Data
);
815 Check keyboard controller status, if it is output buffer full and for auxiliary device.
817 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
819 @retval EFI_SUCCESS Keyboard controller is ready
820 @retval EFI_NOT_READY Keyboard controller is not ready
824 IN EFI_ISA_IO_PROTOCOL
*IsaIo
829 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
832 // Check keyboard controller status, if it is output buffer full and for auxiliary device
834 if ((Data
& (KBC_OUTB
| KBC_AUXB
)) != (KBC_OUTB
| KBC_AUXB
)) {
835 return EFI_NOT_READY
;
842 I/O work flow to wait input buffer empty in given time.
844 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
845 @param Timeout Wating time.
847 @retval EFI_TIMEOUT if input is still not empty in given time.
848 @retval EFI_SUCCESS input is empty.
852 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
859 Delay
= Timeout
/ 50;
862 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
865 // Check keyboard controller status bit 1(input buffer status)
867 if ((Data
& KBC_INPB
) == 0) {
873 } while (Delay
!= 0);
883 I/O work flow to wait output buffer full in given time.
885 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
886 @param Timeout given time
888 @retval EFI_TIMEOUT output is not full in given time
889 @retval EFI_SUCCESS output is full in given time.
893 IN EFI_ISA_IO_PROTOCOL
*IsaIo
,
900 Delay
= Timeout
/ 50;
903 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
906 // Check keyboard controller status bit 0(output buffer status)
907 // & bit5(output buffer for auxiliary device)
909 if ((Data
& (KBC_OUTB
| KBC_AUXB
)) == (KBC_OUTB
| KBC_AUXB
)) {
915 } while (Delay
!= 0);