1 /** @file
2 PS2 Mouse Communication Interface.
3
4 Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
5 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
9
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.
12
13 **/
14
15 #include "Ps2MouseAbsolutePointer.h"
16 #include "CommPs2.h"
17
18 UINT8 SampleRateTbl[MaxSampleRate] = { 0xa, 0x14, 0x28, 0x3c, 0x50, 0x64, 0xc8 };
19
20 UINT8 ResolutionTbl[MaxResolution] = { 0, 1, 2, 3 };
21
22 /**
23 Issue self test command via IsaIo interface.
24
25 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
26
27 @return EFI_SUCCESS Success to do keyboard self testing.
28 @return others Fail to do keyboard self testing.
29 **/
30 EFI_STATUS
KbcSelfTest(IN EFI_ISA_IO_PROTOCOL * IsaIo)31 KbcSelfTest (
32 IN EFI_ISA_IO_PROTOCOL *IsaIo
33 )
34 {
35 EFI_STATUS Status;
36 UINT8 Data;
37
38 //
39 // Keyboard controller self test
40 //
41 Status = Out8042Command (IsaIo, SELF_TEST);
42 if (EFI_ERROR (Status)) {
43 return Status;
44 }
45 //
46 // Read return code
47 //
48 Status = In8042Data (IsaIo, &Data);
49 if (EFI_ERROR (Status)) {
50 return Status;
51 }
52
53 if (Data != 0x55) {
54 return EFI_DEVICE_ERROR;
55 }
56 //
57 // Set system flag
58 //
59 Status = Out8042Command (IsaIo, READ_CMD_BYTE);
60 if (EFI_ERROR (Status)) {
61 return Status;
62 }
63
64 Status = In8042Data (IsaIo, &Data);
65 if (EFI_ERROR (Status)) {
66 return Status;
67 }
68
69 Status = Out8042Command (IsaIo, WRITE_CMD_BYTE);
70 if (EFI_ERROR (Status)) {
71 return Status;
72 }
73
74 Data |= CMD_SYS_FLAG;
75 Status = Out8042Data (IsaIo, Data);
76 if (EFI_ERROR (Status)) {
77 return Status;
78 }
79
80 return EFI_SUCCESS;
81 }
82
83 /**
84 Issue command to enable keyboard AUX functionality.
85
86 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
87
88 @return Status of command issuing.
89 **/
90 EFI_STATUS
KbcEnableAux(IN EFI_ISA_IO_PROTOCOL * IsaIo)91 KbcEnableAux (
92 IN EFI_ISA_IO_PROTOCOL *IsaIo
93 )
94 {
95 //
96 // Send 8042 enable mouse command
97 //
98 return Out8042Command (IsaIo, ENABLE_AUX);
99 }
100
101 /**
102 Issue command to disable keyboard AUX functionality.
103
104 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
105
106 @return Status of command issuing.
107 **/
108 EFI_STATUS
KbcDisableAux(IN EFI_ISA_IO_PROTOCOL * IsaIo)109 KbcDisableAux (
110 IN EFI_ISA_IO_PROTOCOL *IsaIo
111 )
112 {
113 //
114 // Send 8042 disable mouse command
115 //
116 return Out8042Command (IsaIo, DISABLE_AUX);
117 }
118
119 /**
120 Issue command to enable keyboard.
121
122 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
123
124 @return Status of command issuing.
125 **/
126 EFI_STATUS
KbcEnableKb(IN EFI_ISA_IO_PROTOCOL * IsaIo)127 KbcEnableKb (
128 IN EFI_ISA_IO_PROTOCOL *IsaIo
129 )
130 {
131 //
132 // Send 8042 enable keyboard command
133 //
134 return Out8042Command (IsaIo, ENABLE_KB);
135 }
136
137 /**
138 Issue command to disable keyboard.
139
140 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
141
142 @return Status of command issuing.
143 **/
144 EFI_STATUS
KbcDisableKb(IN EFI_ISA_IO_PROTOCOL * IsaIo)145 KbcDisableKb (
146 IN EFI_ISA_IO_PROTOCOL *IsaIo
147 )
148 {
149 //
150 // Send 8042 disable keyboard command
151 //
152 return Out8042Command (IsaIo, DISABLE_KB);
153 }
154
155 /**
156 Issue command to check keyboard status.
157
158 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
159 @param KeyboardEnable return whether keyboard is enable.
160
161 @return Status of command issuing.
162 **/
163 EFI_STATUS
CheckKbStatus(IN EFI_ISA_IO_PROTOCOL * IsaIo,OUT BOOLEAN * KeyboardEnable)164 CheckKbStatus (
165 IN EFI_ISA_IO_PROTOCOL *IsaIo,
166 OUT BOOLEAN *KeyboardEnable
167 )
168 {
169 EFI_STATUS Status;
170 UINT8 Data;
171
172 //
173 // Send command to read KBC command byte
174 //
175 Status = Out8042Command (IsaIo, READ_CMD_BYTE);
176 if (EFI_ERROR (Status)) {
177 return Status;
178 }
179
180 Status = In8042Data (IsaIo, &Data);
181 if (EFI_ERROR (Status)) {
182 return Status;
183 }
184 //
185 // Check keyboard enable or not
186 //
187 if ((Data & CMD_KB_STS) == CMD_KB_DIS) {
188 *KeyboardEnable = FALSE;
189 } else {
190 *KeyboardEnable = TRUE;
191 }
192
193 return EFI_SUCCESS;
194 }
195
196 /**
197 Issue command to reset keyboard.
198
199 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
200
201 @return Status of command issuing.
202 **/
203 EFI_STATUS
PS2MouseReset(IN EFI_ISA_IO_PROTOCOL * IsaIo)204 PS2MouseReset (
205 IN EFI_ISA_IO_PROTOCOL *IsaIo
206 )
207 {
208 EFI_STATUS Status;
209 UINT8 Data;
210
211 Status = Out8042AuxCommand (IsaIo, RESET_CMD, FALSE);
212 if (EFI_ERROR (Status)) {
213 return Status;
214 }
215
216 Status = In8042AuxData (IsaIo, &Data);
217 if (EFI_ERROR (Status)) {
218 return Status;
219 }
220 //
221 // Check BAT Complete Code
222 //
223 if (Data != PS2MOUSE_BAT1) {
224 return EFI_DEVICE_ERROR;
225 }
226
227 Status = In8042AuxData (IsaIo, &Data);
228 if (EFI_ERROR (Status)) {
229 return Status;
230 }
231 //
232 // Check BAT Complete Code
233 //
234 if (Data != PS2MOUSE_BAT2) {
235 return EFI_DEVICE_ERROR;
236 }
237
238 return EFI_SUCCESS;
239 }
240
241 /**
242 Issue command to set mouse's sample rate
243
244 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
245 @param SampleRate value of sample rate
246
247 @return Status of command issuing.
248 **/
249 EFI_STATUS
PS2MouseSetSampleRate(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN MOUSE_SR SampleRate)250 PS2MouseSetSampleRate (
251 IN EFI_ISA_IO_PROTOCOL *IsaIo,
252 IN MOUSE_SR SampleRate
253 )
254 {
255 EFI_STATUS Status;
256
257 //
258 // Send auxiliary command to set mouse sample rate
259 //
260 Status = Out8042AuxCommand (IsaIo, SETSR_CMD, FALSE);
261 if (EFI_ERROR (Status)) {
262 return Status;
263 }
264
265 Status = Out8042AuxData (IsaIo, SampleRateTbl[SampleRate]);
266
267 return Status;
268 }
269
270 /**
271 Issue command to set mouse's resolution.
272
273 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
274 @param Resolution value of resolution
275
276 @return Status of command issuing.
277 **/
278 EFI_STATUS
PS2MouseSetResolution(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN MOUSE_RE Resolution)279 PS2MouseSetResolution (
280 IN EFI_ISA_IO_PROTOCOL *IsaIo,
281 IN MOUSE_RE Resolution
282 )
283 {
284 EFI_STATUS Status;
285
286 //
287 // Send auxiliary command to set mouse resolution
288 //
289 Status = Out8042AuxCommand (IsaIo, SETRE_CMD, FALSE);
290 if (EFI_ERROR (Status)) {
291 return Status;
292 }
293
294 Status = Out8042AuxData (IsaIo, ResolutionTbl[Resolution]);
295
296 return Status;
297 }
298
299 /**
300 Issue command to set mouse's scaling.
301
302 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
303 @param Scaling value of scaling
304
305 @return Status of command issuing.
306 **/
307 EFI_STATUS
PS2MouseSetScaling(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN MOUSE_SF Scaling)308 PS2MouseSetScaling (
309 IN EFI_ISA_IO_PROTOCOL *IsaIo,
310 IN MOUSE_SF Scaling
311 )
312 {
313 UINT8 Command;
314
315 Command = (UINT8) (Scaling == Scaling1 ? SETSF1_CMD : SETSF2_CMD);
316
317 //
318 // Send auxiliary command to set mouse scaling data
319 //
320 return Out8042AuxCommand (IsaIo, Command, FALSE);
321 }
322
323 /**
324 Issue command to enable Ps2 mouse.
325
326 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
327
328 @return Status of command issuing.
329 **/
330 EFI_STATUS
PS2MouseEnable(IN EFI_ISA_IO_PROTOCOL * IsaIo)331 PS2MouseEnable (
332 IN EFI_ISA_IO_PROTOCOL *IsaIo
333 )
334 {
335 //
336 // Send auxiliary command to enable mouse
337 //
338 return Out8042AuxCommand (IsaIo, ENABLE_CMD, FALSE);
339 }
340
341 /**
342 Get mouse packet . Only care first 3 bytes
343
344 @param MouseAbsolutePointerDev Pointer to PS2 Absolute Pointer Simulation Device Private Data Structure
345
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.
348
349 **/
350 EFI_STATUS
PS2MouseGetPacket(PS2_MOUSE_ABSOLUTE_POINTER_DEV * MouseAbsolutePointerDev)351 PS2MouseGetPacket (
352 PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev
353 )
354
355 {
356 EFI_STATUS Status;
357 BOOLEAN KeyboardEnable;
358 UINT8 Packet[PS2_PACKET_LENGTH];
359 UINT8 Data;
360 UINTN Count;
361 UINTN State;
362 INT16 RelativeMovementX;
363 INT16 RelativeMovementY;
364 BOOLEAN LButton;
365 BOOLEAN RButton;
366
367 KeyboardEnable = FALSE;
368 Count = 1;
369 State = PS2_READ_BYTE_ONE;
370
371 //
372 // State machine to get mouse packet
373 //
374 while (1) {
375
376 switch (State) {
377 case PS2_READ_BYTE_ONE:
378 //
379 // Read mouse first byte data, if failed, immediately return
380 //
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;
386 }
387
388 if (Count != 1) {
389 KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
390 return EFI_NOT_READY;
391 }
392
393 if (IS_PS2_SYNC_BYTE (Data)) {
394 Packet[0] = Data;
395 State = PS2_READ_DATA_BYTE;
396
397 CheckKbStatus (MouseAbsolutePointerDev->IsaIo, &KeyboardEnable);
398 KbcDisableKb (MouseAbsolutePointerDev->IsaIo);
399 KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
400 }
401 break;
402
403 case PS2_READ_DATA_BYTE:
404 Count = 2;
405 Status = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, (Packet + 1), &Count, State);
406 if (EFI_ERROR (Status)) {
407 if (KeyboardEnable) {
408 KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
409 }
410
411 return EFI_NOT_READY;
412 }
413
414 if (Count != 2) {
415 if (KeyboardEnable) {
416 KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
417 }
418
419 return EFI_NOT_READY;
420 }
421
422 State = PS2_PROCESS_PACKET;
423 break;
424
425 case PS2_PROCESS_PACKET:
426 if (KeyboardEnable) {
427 KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
428 }
429 //
430 // Decode the packet
431 //
432 RelativeMovementX = Packet[1];
433 RelativeMovementY = Packet[2];
434 //
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
439 //
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.
442 //
443 //
444 // First, Clear X and Y high 8 bits
445 //
446 RelativeMovementX = (INT16) (RelativeMovementX & 0xFF);
447 RelativeMovementY = (INT16) (RelativeMovementY & 0xFF);
448 //
449 // Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff
450 //
451 if ((Packet[0] & 0x10) != 0) {
452 RelativeMovementX = (INT16) (RelativeMovementX | 0xFF00);
453 }
454 if ((Packet[0] & 0x20) != 0) {
455 RelativeMovementY = (INT16) (RelativeMovementY | 0xFF00);
456 }
457
458
459 RButton = (UINT8) (Packet[0] & 0x2);
460 LButton = (UINT8) (Packet[0] & 0x1);
461
462 //
463 // Update mouse state
464 //
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;
470
471 return EFI_SUCCESS;
472 }
473 }
474 }
475
476 /**
477 Read data via IsaIo protocol with given number.
478
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
483
484 @return status of reading mouse data.
485 **/
486 EFI_STATUS
PS2MouseRead(IN EFI_ISA_IO_PROTOCOL * IsaIo,OUT VOID * Buffer,IN OUT UINTN * BufSize,IN UINTN State)487 PS2MouseRead (
488 IN EFI_ISA_IO_PROTOCOL *IsaIo,
489 OUT VOID *Buffer,
490 IN OUT UINTN *BufSize,
491 IN UINTN State
492 )
493 {
494 EFI_STATUS Status;
495 UINTN BytesRead;
496
497 Status = EFI_SUCCESS;
498 BytesRead = 0;
499
500 if (State == PS2_READ_BYTE_ONE) {
501 //
502 // Check input for mouse
503 //
504 Status = CheckForInput (IsaIo);
505
506 if (EFI_ERROR (Status)) {
507 return Status;
508 }
509 }
510
511 while (BytesRead < *BufSize) {
512
513 Status = WaitOutputFull (IsaIo, TIMEOUT);
514 if (EFI_ERROR (Status)) {
515 break;
516 }
517
518 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Buffer);
519
520 BytesRead++;
521 Buffer = (UINT8 *) Buffer + 1;
522 }
523 //
524 // Verify the correct number of bytes read
525 //
526 if (BytesRead == 0 || BytesRead != *BufSize) {
527 Status = EFI_NOT_FOUND;
528 }
529
530 *BufSize = BytesRead;
531 return Status;
532 }
533
534 //
535 // 8042 I/O function
536 //
537 /**
538 I/O work flow of outing 8042 command.
539
540 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
541 @param Command I/O command.
542
543 @retval EFI_SUCCESS Success to excute I/O work flow
544 @retval EFI_TIMEOUT Keyboard controller time out.
545 **/
546 EFI_STATUS
Out8042Command(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN UINT8 Command)547 Out8042Command (
548 IN EFI_ISA_IO_PROTOCOL *IsaIo,
549 IN UINT8 Command
550 )
551 {
552 EFI_STATUS Status;
553 UINT8 Data;
554
555 //
556 // Wait keyboard controller input buffer empty
557 //
558 Status = WaitInputEmpty (IsaIo, TIMEOUT);
559 if (EFI_ERROR (Status)) {
560 return Status;
561 }
562 //
563 // Send command
564 //
565 Data = Command;
566 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
567
568 Status = WaitInputEmpty (IsaIo, TIMEOUT);
569 if (EFI_ERROR (Status)) {
570 return Status;
571 }
572
573 return EFI_SUCCESS;
574 }
575
576 /**
577 I/O work flow of outing 8042 data.
578
579 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
580 @param Data Data value
581
582 @retval EFI_SUCCESS Success to excute I/O work flow
583 @retval EFI_TIMEOUT Keyboard controller time out.
584 **/
585 EFI_STATUS
Out8042Data(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN UINT8 Data)586 Out8042Data (
587 IN EFI_ISA_IO_PROTOCOL *IsaIo,
588 IN UINT8 Data
589 )
590 {
591 EFI_STATUS Status;
592 UINT8 Temp;
593 //
594 // Wait keyboard controller input buffer empty
595 //
596 Status = WaitInputEmpty (IsaIo, TIMEOUT);
597 if (EFI_ERROR (Status)) {
598 return Status;
599 }
600
601 Temp = Data;
602 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
603
604 Status = WaitInputEmpty (IsaIo, TIMEOUT);
605 if (EFI_ERROR (Status)) {
606 return Status;
607 }
608
609 return EFI_SUCCESS;
610 }
611
612 /**
613 I/O work flow of in 8042 data.
614
615 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
616 @param Data Data value
617
618 @retval EFI_SUCCESS Success to excute I/O work flow
619 @retval EFI_TIMEOUT Keyboard controller time out.
620 **/
621 EFI_STATUS
In8042Data(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN OUT UINT8 * Data)622 In8042Data (
623 IN EFI_ISA_IO_PROTOCOL *IsaIo,
624 IN OUT UINT8 *Data
625 )
626 {
627 UINTN Delay;
628 UINT8 Temp;
629
630 Delay = TIMEOUT / 50;
631
632 do {
633 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
634
635 //
636 // Check keyboard controller status bit 0(output buffer status)
637 //
638 if ((Temp & KBC_OUTB) == KBC_OUTB) {
639 break;
640 }
641
642 gBS->Stall (50);
643 Delay--;
644 } while (Delay != 0);
645
646 if (Delay == 0) {
647 return EFI_TIMEOUT;
648 }
649
650 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
651
652 return EFI_SUCCESS;
653 }
654
655 /**
656 I/O work flow of outing 8042 Aux command.
657
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.
661
662 @retval EFI_SUCCESS Success to excute I/O work flow
663 @retval EFI_TIMEOUT Keyboard controller time out.
664 **/
665 EFI_STATUS
Out8042AuxCommand(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN UINT8 Command,IN BOOLEAN Resend)666 Out8042AuxCommand (
667 IN EFI_ISA_IO_PROTOCOL *IsaIo,
668 IN UINT8 Command,
669 IN BOOLEAN Resend
670 )
671 {
672 EFI_STATUS Status;
673 UINT8 Data;
674
675 //
676 // Wait keyboard controller input buffer empty
677 //
678 Status = WaitInputEmpty (IsaIo, TIMEOUT);
679 if (EFI_ERROR (Status)) {
680 return Status;
681 }
682 //
683 // Send write to auxiliary device command
684 //
685 Data = WRITE_AUX_DEV;
686 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
687
688 Status = WaitInputEmpty (IsaIo, TIMEOUT);
689 if (EFI_ERROR (Status)) {
690 return Status;
691 }
692 //
693 // Send auxiliary device command
694 //
695 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Command);
696
697 //
698 // Read return code
699 //
700 Status = In8042AuxData (IsaIo, &Data);
701 if (EFI_ERROR (Status)) {
702 return Status;
703 }
704
705 if (Data == PS2_ACK) {
706 //
707 // Receive mouse acknowledge, command send success
708 //
709 return EFI_SUCCESS;
710
711 } else if (Resend) {
712 //
713 // Resend fail
714 //
715 return EFI_DEVICE_ERROR;
716
717 } else if (Data == PS2_RESEND) {
718 //
719 // Resend command
720 //
721 Status = Out8042AuxCommand (IsaIo, Command, TRUE);
722 if (EFI_ERROR (Status)) {
723 return Status;
724 }
725
726 } else {
727 //
728 // Invalid return code
729 //
730 return EFI_DEVICE_ERROR;
731
732 }
733
734 return EFI_SUCCESS;
735 }
736
737 /**
738 I/O work flow of outing 8042 Aux data.
739
740 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
741 @param Data Buffer holding return value
742
743 @retval EFI_SUCCESS Success to excute I/O work flow.
744 @retval EFI_TIMEOUT Keyboard controller time out.
745 **/
746 EFI_STATUS
Out8042AuxData(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN UINT8 Data)747 Out8042AuxData (
748 IN EFI_ISA_IO_PROTOCOL *IsaIo,
749 IN UINT8 Data
750 )
751 {
752 EFI_STATUS Status;
753 UINT8 Temp;
754 //
755 // Wait keyboard controller input buffer empty
756 //
757 Status = WaitInputEmpty (IsaIo, TIMEOUT);
758 if (EFI_ERROR (Status)) {
759 return Status;
760 }
761 //
762 // Send write to auxiliary device command
763 //
764 Temp = WRITE_AUX_DEV;
765 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
766
767 Status = WaitInputEmpty (IsaIo, TIMEOUT);
768 if (EFI_ERROR (Status)) {
769 return Status;
770 }
771
772 Temp = Data;
773 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
774
775 Status = WaitInputEmpty (IsaIo, TIMEOUT);
776 if (EFI_ERROR (Status)) {
777 return Status;
778 }
779
780 return EFI_SUCCESS;
781 }
782
783 /**
784 I/O work flow of in 8042 Aux data.
785
786 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
787 @param Data Buffer holding return value.
788
789 @retval EFI_SUCCESS Success to excute I/O work flow
790 @retval EFI_TIMEOUT Keyboard controller time out.
791 **/
792 EFI_STATUS
In8042AuxData(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN OUT UINT8 * Data)793 In8042AuxData (
794 IN EFI_ISA_IO_PROTOCOL *IsaIo,
795 IN OUT UINT8 *Data
796 )
797 {
798 EFI_STATUS Status;
799
800 //
801 // wait for output data
802 //
803 Status = WaitOutputFull (IsaIo, BAT_TIMEOUT);
804 if (EFI_ERROR (Status)) {
805 return Status;
806 }
807
808 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
809
810 return EFI_SUCCESS;
811 }
812
813
814 /**
815 Check keyboard controller status, if it is output buffer full and for auxiliary device.
816
817 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
818
819 @retval EFI_SUCCESS Keyboard controller is ready
820 @retval EFI_NOT_READY Keyboard controller is not ready
821 **/
822 EFI_STATUS
CheckForInput(IN EFI_ISA_IO_PROTOCOL * IsaIo)823 CheckForInput (
824 IN EFI_ISA_IO_PROTOCOL *IsaIo
825 )
826 {
827 UINT8 Data;
828
829 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
830
831 //
832 // Check keyboard controller status, if it is output buffer full and for auxiliary device
833 //
834 if ((Data & (KBC_OUTB | KBC_AUXB)) != (KBC_OUTB | KBC_AUXB)) {
835 return EFI_NOT_READY;
836 }
837
838 return EFI_SUCCESS;
839 }
840
841 /**
842 I/O work flow to wait input buffer empty in given time.
843
844 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
845 @param Timeout Wating time.
846
847 @retval EFI_TIMEOUT if input is still not empty in given time.
848 @retval EFI_SUCCESS input is empty.
849 **/
850 EFI_STATUS
WaitInputEmpty(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN UINTN Timeout)851 WaitInputEmpty (
852 IN EFI_ISA_IO_PROTOCOL *IsaIo,
853 IN UINTN Timeout
854 )
855 {
856 UINTN Delay;
857 UINT8 Data;
858
859 Delay = Timeout / 50;
860
861 do {
862 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
863
864 //
865 // Check keyboard controller status bit 1(input buffer status)
866 //
867 if ((Data & KBC_INPB) == 0) {
868 break;
869 }
870
871 gBS->Stall (50);
872 Delay--;
873 } while (Delay != 0);
874
875 if (Delay == 0) {
876 return EFI_TIMEOUT;
877 }
878
879 return EFI_SUCCESS;
880 }
881
882 /**
883 I/O work flow to wait output buffer full in given time.
884
885 @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
886 @param Timeout given time
887
888 @retval EFI_TIMEOUT output is not full in given time
889 @retval EFI_SUCCESS output is full in given time.
890 **/
891 EFI_STATUS
WaitOutputFull(IN EFI_ISA_IO_PROTOCOL * IsaIo,IN UINTN Timeout)892 WaitOutputFull (
893 IN EFI_ISA_IO_PROTOCOL *IsaIo,
894 IN UINTN Timeout
895 )
896 {
897 UINTN Delay;
898 UINT8 Data;
899
900 Delay = Timeout / 50;
901
902 do {
903 IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
904
905 //
906 // Check keyboard controller status bit 0(output buffer status)
907 // & bit5(output buffer for auxiliary device)
908 //
909 if ((Data & (KBC_OUTB | KBC_AUXB)) == (KBC_OUTB | KBC_AUXB)) {
910 break;
911 }
912
913 gBS->Stall (50);
914 Delay--;
915 } while (Delay != 0);
916
917 if (Delay == 0) {
918 return EFI_TIMEOUT;
919 }
920
921 return EFI_SUCCESS;
922 }
923
924