ebf03d30c1d448c94200a350f95789994782362b
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / BiosThunk / KeyboardDxe / BiosKeyboard.c
1 /** @file
2 ConsoleOut Routines that speak VGA.
3
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "BiosKeyboard.h"
18
19 //
20 // EFI Driver Binding Protocol Instance
21 //
22 EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding = {
23 BiosKeyboardDriverBindingSupported,
24 BiosKeyboardDriverBindingStart,
25 BiosKeyboardDriverBindingStop,
26 0x3,
27 NULL,
28 NULL
29 };
30
31
32 /**
33 Enqueue the key.
34
35 @param Queue The queue to be enqueued.
36 @param KeyData The key data to be enqueued.
37
38 @retval EFI_NOT_READY The queue is full.
39 @retval EFI_SUCCESS Successfully enqueued the key data.
40
41 **/
42 EFI_STATUS
43 Enqueue (
44 IN SIMPLE_QUEUE *Queue,
45 IN EFI_KEY_DATA *KeyData
46 )
47 {
48 if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {
49 return EFI_NOT_READY;
50 }
51
52 CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
53 Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;
54
55 return EFI_SUCCESS;
56 }
57
58
59 /**
60 Dequeue the key.
61
62 @param Queue The queue to be dequeued.
63 @param KeyData The key data to be dequeued.
64
65 @retval EFI_NOT_READY The queue is empty.
66 @retval EFI_SUCCESS Successfully dequeued the key data.
67
68 **/
69 EFI_STATUS
70 Dequeue (
71 IN SIMPLE_QUEUE *Queue,
72 IN EFI_KEY_DATA *KeyData
73 )
74 {
75 if (Queue->Front == Queue->Rear) {
76 return EFI_NOT_READY;
77 }
78
79 CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));
80 Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT;
81
82 return EFI_SUCCESS;
83 }
84
85
86 /**
87 Check whether the queue is empty.
88
89 @param Queue The queue to be checked.
90
91 @retval EFI_NOT_READY The queue is empty.
92 @retval EFI_SUCCESS The queue is not empty.
93
94 **/
95 EFI_STATUS
96 CheckQueue (
97 IN SIMPLE_QUEUE *Queue
98 )
99 {
100 if (Queue->Front == Queue->Rear) {
101 return EFI_NOT_READY;
102 }
103
104 return EFI_SUCCESS;
105 }
106
107 //
108 // EFI Driver Binding Protocol Functions
109 //
110
111 /**
112 Check whether the driver supports this device.
113
114 @param This The Udriver binding protocol.
115 @param Controller The controller handle to check.
116 @param RemainingDevicePath The remaining device path.
117
118 @retval EFI_SUCCESS The driver supports this controller.
119 @retval other This device isn't supported.
120
121 **/
122 EFI_STATUS
123 EFIAPI
124 BiosKeyboardDriverBindingSupported (
125 IN EFI_DRIVER_BINDING_PROTOCOL *This,
126 IN EFI_HANDLE Controller,
127 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
128 )
129 {
130 EFI_STATUS Status;
131 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
132 EFI_ISA_IO_PROTOCOL *IsaIo;
133
134 //
135 // See if the Legacy BIOS Protocol is available
136 //
137 Status = gBS->LocateProtocol (
138 &gEfiLegacyBiosProtocolGuid,
139 NULL,
140 (VOID **) &LegacyBios
141 );
142
143 if (EFI_ERROR (Status)) {
144 return Status;
145 }
146 //
147 // Open the IO Abstraction(s) needed to perform the supported test
148 //
149 Status = gBS->OpenProtocol (
150 Controller,
151 &gEfiIsaIoProtocolGuid,
152 (VOID **) &IsaIo,
153 This->DriverBindingHandle,
154 Controller,
155 EFI_OPEN_PROTOCOL_BY_DRIVER
156 );
157
158 if (EFI_ERROR (Status)) {
159 return Status;
160 }
161 //
162 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
163 //
164 if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
165 Status = EFI_UNSUPPORTED;
166 }
167
168 gBS->CloseProtocol (
169 Controller,
170 &gEfiIsaIoProtocolGuid,
171 This->DriverBindingHandle,
172 Controller
173 );
174
175 return Status;
176 }
177
178 /**
179 Starts the device with this driver.
180
181 @param This The driver binding instance.
182 @param Controller Handle of device to bind driver to.
183 @param RemainingDevicePath Optional parameter use to pick a specific child
184 device to start.
185
186 @retval EFI_SUCCESS The controller is controlled by the driver.
187 @retval Other This controller cannot be started.
188
189 **/
190 EFI_STATUS
191 EFIAPI
192 BiosKeyboardDriverBindingStart (
193 IN EFI_DRIVER_BINDING_PROTOCOL *This,
194 IN EFI_HANDLE Controller,
195 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
196 )
197 {
198 EFI_STATUS Status;
199 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
200 EFI_ISA_IO_PROTOCOL *IsaIo;
201 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
202 EFI_IA32_REGISTER_SET Regs;
203 BOOLEAN CarryFlag;
204 EFI_PS2_POLICY_PROTOCOL *Ps2Policy;
205 UINT8 Command;
206 EFI_STATUS_CODE_VALUE StatusCode;
207
208 BiosKeyboardPrivate = NULL;
209 IsaIo = NULL;
210 StatusCode = 0;
211
212 //
213 // Get Ps2 policy to set. Will be use if present.
214 //
215 gBS->LocateProtocol (
216 &gEfiPs2PolicyProtocolGuid,
217 NULL,
218 (VOID **) &Ps2Policy
219 );
220
221 //
222 // See if the Legacy BIOS Protocol is available
223 //
224 Status = gBS->LocateProtocol (
225 &gEfiLegacyBiosProtocolGuid,
226 NULL,
227 (VOID **) &LegacyBios
228 );
229
230 if (EFI_ERROR (Status)) {
231 return Status;
232 }
233 //
234 // Open the IO Abstraction(s) needed
235 //
236 Status = gBS->OpenProtocol (
237 Controller,
238 &gEfiIsaIoProtocolGuid,
239 (VOID **) &IsaIo,
240 This->DriverBindingHandle,
241 Controller,
242 EFI_OPEN_PROTOCOL_BY_DRIVER
243 );
244 if (EFI_ERROR (Status)) {
245 return Status;
246 }
247
248 //
249 // Allocate the private device structure
250 //
251 BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_DEV));
252 if (NULL == BiosKeyboardPrivate) {
253 Status = EFI_OUT_OF_RESOURCES;
254 goto Done;
255 }
256
257 //
258 // Initialize the private device structure
259 //
260 BiosKeyboardPrivate->Signature = BIOS_KEYBOARD_DEV_SIGNATURE;
261 BiosKeyboardPrivate->Handle = Controller;
262 BiosKeyboardPrivate->LegacyBios = LegacyBios;
263 BiosKeyboardPrivate->IsaIo = IsaIo;
264
265 BiosKeyboardPrivate->SimpleTextIn.Reset = BiosKeyboardReset;
266 BiosKeyboardPrivate->SimpleTextIn.ReadKeyStroke = BiosKeyboardReadKeyStroke;
267
268 BiosKeyboardPrivate->DataRegisterAddress = KEYBOARD_8042_DATA_REGISTER;
269 BiosKeyboardPrivate->StatusRegisterAddress = KEYBOARD_8042_STATUS_REGISTER;
270 BiosKeyboardPrivate->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;
271 BiosKeyboardPrivate->ExtendedKeyboard = TRUE;
272
273 BiosKeyboardPrivate->Queue.Front = 0;
274 BiosKeyboardPrivate->Queue.Rear = 0;
275 BiosKeyboardPrivate->QueueForNotify.Front = 0;
276 BiosKeyboardPrivate->QueueForNotify.Rear = 0;
277 BiosKeyboardPrivate->SimpleTextInputEx.Reset = BiosKeyboardResetEx;
278 BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = BiosKeyboardReadKeyStrokeEx;
279 BiosKeyboardPrivate->SimpleTextInputEx.SetState = BiosKeyboardSetState;
280 BiosKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = BiosKeyboardRegisterKeyNotify;
281 BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify;
282 InitializeListHead (&BiosKeyboardPrivate->NotifyList);
283
284 //
285 // Report that the keyboard is being enabled
286 //
287 REPORT_STATUS_CODE (
288 EFI_PROGRESS_CODE,
289 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE
290 );
291
292 //
293 // Setup the WaitForKey event
294 //
295 Status = gBS->CreateEvent (
296 EVT_NOTIFY_WAIT,
297 TPL_NOTIFY,
298 BiosKeyboardWaitForKey,
299 &(BiosKeyboardPrivate->SimpleTextIn),
300 &((BiosKeyboardPrivate->SimpleTextIn).WaitForKey)
301 );
302 if (EFI_ERROR (Status)) {
303 (BiosKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;
304 goto Done;
305 }
306 Status = gBS->CreateEvent (
307 EVT_NOTIFY_WAIT,
308 TPL_NOTIFY,
309 BiosKeyboardWaitForKeyEx,
310 &(BiosKeyboardPrivate->SimpleTextInputEx),
311 &(BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)
312 );
313 if (EFI_ERROR (Status)) {
314 BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;
315 goto Done;
316 }
317
318 //
319 // Setup a periodic timer, used for reading keystrokes at a fixed interval
320 //
321 Status = gBS->CreateEvent (
322 EVT_TIMER | EVT_NOTIFY_SIGNAL,
323 TPL_NOTIFY,
324 BiosKeyboardTimerHandler,
325 BiosKeyboardPrivate,
326 &BiosKeyboardPrivate->TimerEvent
327 );
328 if (EFI_ERROR (Status)) {
329 Status = EFI_OUT_OF_RESOURCES;
330 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
331 goto Done;
332 }
333
334 Status = gBS->SetTimer (
335 BiosKeyboardPrivate->TimerEvent,
336 TimerPeriodic,
337 KEYBOARD_TIMER_INTERVAL
338 );
339 if (EFI_ERROR (Status)) {
340 Status = EFI_OUT_OF_RESOURCES;
341 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
342 goto Done;
343 }
344
345 Status = gBS->CreateEvent (
346 EVT_NOTIFY_SIGNAL,
347 TPL_CALLBACK,
348 KeyNotifyProcessHandler,
349 BiosKeyboardPrivate,
350 &BiosKeyboardPrivate->KeyNotifyProcessEvent
351 );
352 if (EFI_ERROR (Status)) {
353 Status = EFI_OUT_OF_RESOURCES;
354 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
355 goto Done;
356 }
357
358 //
359 // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system
360 //
361 REPORT_STATUS_CODE (
362 EFI_PROGRESS_CODE,
363 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT
364 );
365
366 //
367 // Reset the keyboard device
368 //
369 Status = BiosKeyboardPrivate->SimpleTextInputEx.Reset (
370 &BiosKeyboardPrivate->SimpleTextInputEx,
371 FeaturePcdGet (PcdPs2KbdExtendedVerification)
372 );
373 if (EFI_ERROR (Status)) {
374 DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status));
375 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
376 goto Done;
377 }
378 //
379 // Do platform specific policy like port swapping and keyboard light default
380 //
381 if (Ps2Policy != NULL) {
382
383 Ps2Policy->Ps2InitHardware (Controller);
384
385 Command = 0;
386 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {
387 Command |= 4;
388 }
389
390 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {
391 Command |= 2;
392 }
393
394 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {
395 Command |= 1;
396 }
397
398 KeyboardWrite (BiosKeyboardPrivate, 0xed);
399 KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);
400 KeyboardWrite (BiosKeyboardPrivate, Command);
401 //
402 // Call Legacy BIOS Protocol to set whatever is necessary
403 //
404 LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);
405 }
406 //
407 // Get Configuration
408 //
409 Regs.H.AH = 0xc0;
410 CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (
411 BiosKeyboardPrivate->LegacyBios,
412 0x15,
413 &Regs
414 );
415
416 if (!CarryFlag) {
417 //
418 // Check bit 6 of Feature Byte 2.
419 // If it is set, then Int 16 Func 09 is supported
420 //
421 if (*(UINT8 *) (((UINTN) Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {
422 //
423 // Get Keyboard Functionality
424 //
425 Regs.H.AH = 0x09;
426 CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (
427 BiosKeyboardPrivate->LegacyBios,
428 0x16,
429 &Regs
430 );
431
432 if (!CarryFlag) {
433 //
434 // Check bit 5 of AH.
435 // If it is set, then INT 16 Finc 10-12 are supported.
436 //
437 if ((Regs.H.AL & 0x40) != 0) {
438 //
439 // Set the flag to use INT 16 Func 10-12
440 //
441 BiosKeyboardPrivate->ExtendedKeyboard = TRUE;
442 }
443 }
444 }
445 }
446 DEBUG ((EFI_D_INFO, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN)BiosKeyboardPrivate->ExtendedKeyboard));
447 //
448 // Install protocol interfaces for the keyboard device.
449 //
450 Status = gBS->InstallMultipleProtocolInterfaces (
451 &Controller,
452 &gEfiSimpleTextInProtocolGuid,
453 &BiosKeyboardPrivate->SimpleTextIn,
454 &gEfiSimpleTextInputExProtocolGuid,
455 &BiosKeyboardPrivate->SimpleTextInputEx,
456 NULL
457 );
458
459 Done:
460 if (StatusCode != 0) {
461 //
462 // Report an Error Code for failing to start the keyboard device
463 //
464 REPORT_STATUS_CODE (
465 EFI_ERROR_CODE | EFI_ERROR_MINOR,
466 StatusCode
467 );
468 }
469
470 if (EFI_ERROR (Status)) {
471
472 if (BiosKeyboardPrivate != NULL) {
473 if ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {
474 gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);
475 }
476
477 if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {
478 gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);
479 }
480
481 if (BiosKeyboardPrivate->KeyNotifyProcessEvent != NULL) {
482 gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);
483 }
484
485 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);
486
487 if (BiosKeyboardPrivate->TimerEvent != NULL) {
488 gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);
489 }
490
491 FreePool (BiosKeyboardPrivate);
492 }
493
494 if (IsaIo != NULL) {
495 gBS->CloseProtocol (
496 Controller,
497 &gEfiIsaIoProtocolGuid,
498 This->DriverBindingHandle,
499 Controller
500 );
501 }
502 }
503
504 return Status;
505 }
506
507 /**
508 Stop the device handled by this driver.
509
510 @param This The driver binding protocol.
511 @param Controller The controller to release.
512 @param NumberOfChildren The number of handles in ChildHandleBuffer.
513 @param ChildHandleBuffer The array of child handle.
514
515 @retval EFI_SUCCESS The device was stopped.
516 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
517 @retval Others Fail to uninstall protocols attached on the device.
518
519 **/
520 EFI_STATUS
521 EFIAPI
522 BiosKeyboardDriverBindingStop (
523 IN EFI_DRIVER_BINDING_PROTOCOL *This,
524 IN EFI_HANDLE Controller,
525 IN UINTN NumberOfChildren,
526 IN EFI_HANDLE *ChildHandleBuffer
527 )
528 {
529 EFI_STATUS Status;
530 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn;
531 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
532
533 //
534 // Disable Keyboard
535 //
536 Status = gBS->OpenProtocol (
537 Controller,
538 &gEfiSimpleTextInProtocolGuid,
539 (VOID **) &SimpleTextIn,
540 This->DriverBindingHandle,
541 Controller,
542 EFI_OPEN_PROTOCOL_GET_PROTOCOL
543 );
544 if (EFI_ERROR (Status)) {
545 return Status;
546 }
547
548 Status = gBS->OpenProtocol (
549 Controller,
550 &gEfiSimpleTextInputExProtocolGuid,
551 NULL,
552 This->DriverBindingHandle,
553 Controller,
554 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
555 );
556 if (EFI_ERROR (Status)) {
557 return Status;
558 }
559
560 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn);
561
562 Status = gBS->UninstallMultipleProtocolInterfaces (
563 Controller,
564 &gEfiSimpleTextInProtocolGuid,
565 &BiosKeyboardPrivate->SimpleTextIn,
566 &gEfiSimpleTextInputExProtocolGuid,
567 &BiosKeyboardPrivate->SimpleTextInputEx,
568 NULL
569 );
570 if (EFI_ERROR (Status)) {
571 return Status;
572 }
573 //
574 // Release the IsaIo protocol on the controller handle
575 //
576 gBS->CloseProtocol (
577 Controller,
578 &gEfiIsaIoProtocolGuid,
579 This->DriverBindingHandle,
580 Controller
581 );
582
583 //
584 // Free other resources
585 //
586 gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);
587 gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);
588 gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);
589 gBS->CloseEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);
590 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);
591
592 FreePool (BiosKeyboardPrivate);
593
594 return EFI_SUCCESS;
595 }
596
597 /**
598 Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.
599
600 @param BiosKeyboardPrivate Keyboard instance pointer.
601
602 @return The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.
603
604 **/
605 UINT8
606 KeyReadDataRegister (
607 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
608 )
609 {
610 UINT8 Data;
611
612 //
613 // Use IsaIo protocol to perform IO operations
614 //
615 BiosKeyboardPrivate->IsaIo->Io.Read (
616 BiosKeyboardPrivate->IsaIo,
617 EfiIsaIoWidthUint8,
618 BiosKeyboardPrivate->DataRegisterAddress,
619 1,
620 &Data
621 );
622
623 return Data;
624 }
625
626 /**
627 Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.
628
629 @param BiosKeyboardPrivate Keyboard instance pointer.
630
631 @return The status byte read from status register of Keyboard Controller from command port which often is port 64H.
632
633 **/
634 UINT8
635 KeyReadStatusRegister (
636 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
637 )
638 {
639 UINT8 Data;
640
641 //
642 // Use IsaIo protocol to perform IO operations
643 //
644 BiosKeyboardPrivate->IsaIo->Io.Read (
645 BiosKeyboardPrivate->IsaIo,
646 EfiIsaIoWidthUint8,
647 BiosKeyboardPrivate->StatusRegisterAddress,
648 1,
649 &Data
650 );
651
652 return Data;
653 }
654
655 /**
656 Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.
657
658 @param BiosKeyboardPrivate Keyboard instance pointer.
659 @param Data Data byte to write.
660
661 **/
662 VOID
663 KeyWriteCommandRegister (
664 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
665 IN UINT8 Data
666 )
667 {
668 //
669 // Use IsaIo protocol to perform IO operations
670 //
671 BiosKeyboardPrivate->IsaIo->Io.Write (
672 BiosKeyboardPrivate->IsaIo,
673 EfiIsaIoWidthUint8,
674 BiosKeyboardPrivate->CommandRegisterAddress,
675 1,
676 &Data
677 );
678 }
679
680 /**
681 Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.
682
683 @param BiosKeyboardPrivate Keyboard instance pointer.
684 @param Data Data byte to write.
685
686 **/
687 VOID
688 KeyWriteDataRegister (
689 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
690 IN UINT8 Data
691 )
692 {
693 //
694 // Use IsaIo protocol to perform IO operations
695 //
696 BiosKeyboardPrivate->IsaIo->Io.Write (
697 BiosKeyboardPrivate->IsaIo,
698 EfiIsaIoWidthUint8,
699 BiosKeyboardPrivate->DataRegisterAddress,
700 1,
701 &Data
702 );
703 }
704
705 /**
706 Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.
707
708 @param BiosKeyboardPrivate Keyboard instance pointer.
709 @param Data The pointer for data that being read out.
710
711 @retval EFI_SUCCESS The data byte read out successfully.
712 @retval EFI_TIMEOUT Timeout occurred during reading out data byte.
713
714 **/
715 EFI_STATUS
716 KeyboardRead (
717 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
718 OUT UINT8 *Data
719 )
720 {
721 UINT32 TimeOut;
722 UINT32 RegFilled;
723
724 TimeOut = 0;
725 RegFilled = 0;
726
727 //
728 // wait till output buffer full then perform the read
729 //
730 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
731 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {
732 RegFilled = 1;
733 *Data = KeyReadDataRegister (BiosKeyboardPrivate);
734 break;
735 }
736
737 gBS->Stall (30);
738 }
739
740 if (RegFilled == 0) {
741 return EFI_TIMEOUT;
742 }
743
744 return EFI_SUCCESS;
745 }
746
747 /**
748 Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.
749
750 @param BiosKeyboardPrivate Keyboard instance pointer.
751 @param Data Data byte to write.
752
753 @retval EFI_SUCCESS The data byte is written successfully.
754 @retval EFI_TIMEOUT Timeout occurred during writing.
755
756 **/
757 EFI_STATUS
758 KeyboardWrite (
759 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
760 IN UINT8 Data
761 )
762 {
763 UINT32 TimeOut;
764 UINT32 RegEmptied;
765
766 TimeOut = 0;
767 RegEmptied = 0;
768
769 //
770 // wait for input buffer empty
771 //
772 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
773 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
774 RegEmptied = 1;
775 break;
776 }
777
778 gBS->Stall (30);
779 }
780
781 if (RegEmptied == 0) {
782 return EFI_TIMEOUT;
783 }
784 //
785 // Write it
786 //
787 KeyWriteDataRegister (BiosKeyboardPrivate, Data);
788
789 return EFI_SUCCESS;
790 }
791
792 /**
793 Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.
794
795 @param BiosKeyboardPrivate Keyboard instance pointer.
796 @param Data Command byte to write.
797
798 @retval EFI_SUCCESS The command byte is written successfully.
799 @retval EFI_TIMEOUT Timeout occurred during writing.
800
801 **/
802 EFI_STATUS
803 KeyboardCommand (
804 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
805 IN UINT8 Data
806 )
807 {
808 UINT32 TimeOut;
809 UINT32 RegEmptied;
810
811 TimeOut = 0;
812 RegEmptied = 0;
813
814 //
815 // Wait For Input Buffer Empty
816 //
817 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
818 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
819 RegEmptied = 1;
820 break;
821 }
822
823 gBS->Stall (30);
824 }
825
826 if (RegEmptied == 0) {
827 return EFI_TIMEOUT;
828 }
829 //
830 // issue the command
831 //
832 KeyWriteCommandRegister (BiosKeyboardPrivate, Data);
833
834 //
835 // Wait For Input Buffer Empty again
836 //
837 RegEmptied = 0;
838 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
839 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
840 RegEmptied = 1;
841 break;
842 }
843
844 gBS->Stall (30);
845 }
846
847 if (RegEmptied == 0) {
848 return EFI_TIMEOUT;
849 }
850
851 return EFI_SUCCESS;
852 }
853
854 /**
855 Wait for a specific value to be presented in
856 Data register of Keyboard Controller by keyboard and then read it,
857 used in keyboard commands ack
858
859 @param BiosKeyboardPrivate Keyboard instance pointer.
860 @param Value The value to be waited for
861 @param WaitForValueTimeOut The limit of microseconds for timeout
862
863 @retval EFI_SUCCESS The command byte is written successfully.
864 @retval EFI_TIMEOUT Timeout occurred during writing.
865
866 **/
867 EFI_STATUS
868 KeyboardWaitForValue (
869 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
870 IN UINT8 Value,
871 IN UINTN WaitForValueTimeOut
872 )
873 {
874 UINT8 Data;
875 UINT32 TimeOut;
876 UINT32 SumTimeOut;
877 UINT32 GotIt;
878
879 GotIt = 0;
880 TimeOut = 0;
881 SumTimeOut = 0;
882
883 //
884 // Make sure the initial value of 'Data' is different from 'Value'
885 //
886 Data = 0;
887 if (Data == Value) {
888 Data = 1;
889 }
890 //
891 // Read from 8042 (multiple times if needed)
892 // until the expected value appears
893 // use SumTimeOut to control the iteration
894 //
895 while (1) {
896 //
897 // Perform a read
898 //
899 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
900 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {
901 Data = KeyReadDataRegister (BiosKeyboardPrivate);
902 break;
903 }
904
905 gBS->Stall (30);
906 }
907
908 SumTimeOut += TimeOut;
909
910 if (Data == Value) {
911 GotIt = 1;
912 break;
913 }
914
915 if (SumTimeOut >= WaitForValueTimeOut) {
916 break;
917 }
918 }
919 //
920 // Check results
921 //
922 if (GotIt != 0) {
923 return EFI_SUCCESS;
924 } else {
925 return EFI_TIMEOUT;
926 }
927
928 }
929
930 /**
931 Reads the next keystroke from the input device. The WaitForKey Event can
932 be used to test for existance of a keystroke via WaitForEvent () call.
933
934 @param BiosKeyboardPrivate Bioskeyboard driver private structure.
935 @param KeyData A pointer to a buffer that is filled in with the keystroke
936 state data for the key that was pressed.
937
938 @retval EFI_SUCCESS The keystroke information was returned.
939 @retval EFI_NOT_READY There was no keystroke data availiable.
940 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
941 hardware errors.
942 @retval EFI_INVALID_PARAMETER KeyData is NULL.
943
944 **/
945 EFI_STATUS
946 KeyboardReadKeyStrokeWorker (
947 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
948 OUT EFI_KEY_DATA *KeyData
949 )
950 {
951 EFI_STATUS Status;
952 EFI_TPL OldTpl;
953 if (KeyData == NULL) {
954 return EFI_INVALID_PARAMETER;
955 }
956
957 //
958 // Use TimerEvent callback function to check whether there's any key pressed
959 //
960
961 //
962 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
963 // Csm will be used to check whether there is a key pending, but the csm will disable all
964 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
965 // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
966 // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,
967 // e.g. usb keyboard driver.
968 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
969 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
970 //
971 gBS->Stall (1000);
972
973 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
974
975 BiosKeyboardTimerHandler (NULL, BiosKeyboardPrivate);
976 //
977 // If there's no key, just return
978 //
979 Status = CheckQueue (&BiosKeyboardPrivate->Queue);
980 if (EFI_ERROR (Status)) {
981 gBS->RestoreTPL (OldTpl);
982 return EFI_NOT_READY;
983 }
984
985 Status = Dequeue (&BiosKeyboardPrivate->Queue, KeyData);
986
987 gBS->RestoreTPL (OldTpl);
988
989 return EFI_SUCCESS;
990 }
991
992 //
993 // EFI Simple Text In Protocol Functions
994 //
995 /**
996 Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
997
998 @param This Pointer of simple text Protocol.
999 @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
1000
1001 @retval EFI_SUCCESS The command byte is written successfully.
1002 @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard.
1003
1004 **/
1005 EFI_STATUS
1006 EFIAPI
1007 BiosKeyboardReset (
1008 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
1009 IN BOOLEAN ExtendedVerification
1010 )
1011 {
1012 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
1013 EFI_STATUS Status;
1014 EFI_TPL OldTpl;
1015 UINT8 CommandByte;
1016 BOOLEAN MouseEnable;
1017 EFI_INPUT_KEY Key;
1018
1019 MouseEnable = FALSE;
1020 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
1021
1022 //
1023 // 1
1024 // Report reset progress code
1025 //
1026 REPORT_STATUS_CODE (
1027 EFI_PROGRESS_CODE,
1028 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET
1029 );
1030
1031 //
1032 // Report a Progress Code for clearing the keyboard buffer
1033 //
1034 REPORT_STATUS_CODE (
1035 EFI_PROGRESS_CODE,
1036 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER
1037 );
1038
1039 //
1040 // 2
1041 // Raise TPL to avoid mouse operation impact
1042 //
1043 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1044
1045 //
1046 //
1047 // Exhaust output buffer data
1048 //
1049 do {
1050 Status = BiosKeyboardReadKeyStroke (
1051 This,
1052 &Key
1053 );
1054 } while (!EFI_ERROR (Status));
1055 //
1056 // 3
1057 // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H
1058 // if not skip step 4&5 and jump to step 6 to selftest KBC and report this
1059 // else go step 4
1060 //
1061 if (!PcdGetBool (PcdFastPS2Detection)) {
1062 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) {
1063 //
1064 // 4
1065 // CheckMouseStatus to decide enable it later or not
1066 //
1067 //
1068 // Read the command byte of KBC
1069 //
1070 Status = KeyboardCommand (
1071 BiosKeyboardPrivate,
1072 KBC_CMDREG_VIA64_CMDBYTE_R
1073 );
1074
1075 if (EFI_ERROR (Status)) {
1076 Status = EFI_DEVICE_ERROR;
1077 goto Exit;
1078 }
1079
1080 Status = KeyboardRead (
1081 BiosKeyboardPrivate,
1082 &CommandByte
1083 );
1084
1085 if (EFI_ERROR (Status)) {
1086 Status = EFI_DEVICE_ERROR;
1087 goto Exit;
1088 }
1089 //
1090 // Check mouse enabled or not before
1091 //
1092 if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) {
1093 MouseEnable = FALSE;
1094 } else {
1095 MouseEnable = TRUE;
1096 }
1097 //
1098 // 5
1099 // disable mouse (via KBC) and Keyborad device
1100 //
1101 Status = KeyboardCommand (
1102 BiosKeyboardPrivate,
1103 KBC_CMDREG_VIA64_AUX_DISABLE
1104 );
1105
1106 if (EFI_ERROR (Status)) {
1107 Status = EFI_DEVICE_ERROR;
1108 goto Exit;
1109 }
1110
1111 Status = KeyboardCommand (
1112 BiosKeyboardPrivate,
1113 KBC_CMDREG_VIA64_KB_DISABLE
1114 );
1115
1116 if (EFI_ERROR (Status)) {
1117 Status = EFI_DEVICE_ERROR;
1118 goto Exit;
1119 }
1120 } else {
1121 //
1122 // 6
1123 // KBC Self Test
1124 //
1125 //
1126 // Report a Progress Code for performing a self test on the keyboard controller
1127 //
1128 REPORT_STATUS_CODE (
1129 EFI_PROGRESS_CODE,
1130 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST
1131 );
1132
1133 Status = KeyboardCommand (
1134 BiosKeyboardPrivate,
1135 KBC_CMDREG_VIA64_KBC_SLFTEST
1136 );
1137 if (EFI_ERROR (Status)) {
1138 Status = EFI_DEVICE_ERROR;
1139 goto Exit;
1140 }
1141
1142 Status = KeyboardWaitForValue (
1143 BiosKeyboardPrivate,
1144 KBC_CMDECHO_KBCSLFTEST_OK,
1145 KEYBOARD_WAITFORVALUE_TIMEOUT
1146 );
1147 if (EFI_ERROR (Status)) {
1148 Status = EFI_DEVICE_ERROR;
1149 goto Exit;
1150 }
1151 }
1152 }
1153 //
1154 // 7
1155 // Disable Mouse interface, enable Keyboard interface and declare selftest success
1156 //
1157 // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.
1158 //
1159 Status = KeyboardCommand (
1160 BiosKeyboardPrivate,
1161 KBC_CMDREG_VIA64_CMDBYTE_W
1162 );
1163
1164 if (EFI_ERROR (Status)) {
1165 Status = EFI_DEVICE_ERROR;
1166 goto Exit;
1167 }
1168
1169 //
1170 // Write 8042 Command Byte, set System Flag
1171 // While at the same time:
1172 // 1. disable mouse interface,
1173 // 2. enable kbd interface,
1174 // 3. enable PC/XT kbd translation mode
1175 // 4. enable mouse and kbd interrupts
1176 //
1177 //Command Byte bits:
1178 // 7: Reserved
1179 // 6: PC/XT translation mode
1180 // 5: Disable Auxiliary device interface
1181 // 4: Disable keyboard interface
1182 // 3: Reserved
1183 // 2: System Flag
1184 // 1: Enable Auxiliary device interrupt
1185 // 0: Enable Keyboard interrupt
1186 //
1187 CommandByte = 0;
1188 Status = KeyboardWrite (
1189 BiosKeyboardPrivate,
1190 (UINT8) ((CommandByte &
1191 (~KB_CMMBYTE_DISABLE_KB)) |
1192 KB_CMMBYTE_KSCAN2UNI_COV |
1193 KB_CMMBYTE_ENABLE_AUXINT |
1194 KB_CMMBYTE_ENABLE_KBINT |
1195 KB_CMMBYTE_SLFTEST_SUCC |
1196 KB_CMMBYTE_DISABLE_AUX)
1197 );
1198
1199 //
1200 // For resetting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
1201 // so we only do the real resetting for keyboard when user asks, and normally during booting an OS, it's skipped.
1202 // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,
1203 // Real reset will not do.
1204 //
1205 if (ExtendedVerification && CheckKeyboardConnect (BiosKeyboardPrivate)) {
1206 //
1207 // 8
1208 // Send keyboard reset command then read ACK
1209 //
1210 Status = KeyboardWrite (
1211 BiosKeyboardPrivate,
1212 KBC_INPBUF_VIA60_KBRESET
1213 );
1214
1215 if (EFI_ERROR (Status)) {
1216 Status = EFI_DEVICE_ERROR;
1217 goto Exit;
1218 }
1219
1220 Status = KeyboardWaitForValue (
1221 BiosKeyboardPrivate,
1222 KBC_CMDECHO_ACK,
1223 KEYBOARD_WAITFORVALUE_TIMEOUT
1224 );
1225
1226 if (EFI_ERROR (Status)) {
1227 Status = EFI_DEVICE_ERROR;
1228 goto Exit;
1229 }
1230 //
1231 // 9
1232 // Wait for keyboard return test OK.
1233 //
1234 Status = KeyboardWaitForValue (
1235 BiosKeyboardPrivate,
1236 KBC_CMDECHO_BATTEST_OK,
1237 KEYBOARD_WAITFORVALUE_TIMEOUT
1238 );
1239
1240 if (EFI_ERROR (Status)) {
1241 Status = EFI_DEVICE_ERROR;
1242 goto Exit;
1243 }
1244 //
1245 // 10
1246 // set keyboard scan code set = 02 (standard configuration)
1247 //
1248 Status = KeyboardWrite (
1249 BiosKeyboardPrivate,
1250 KBC_INPBUF_VIA60_KBSCODE
1251 );
1252 if (EFI_ERROR (Status)) {
1253 Status = EFI_DEVICE_ERROR;
1254 goto Exit;
1255 }
1256
1257 Status = KeyboardWaitForValue (
1258 BiosKeyboardPrivate,
1259 KBC_CMDECHO_ACK,
1260 KEYBOARD_WAITFORVALUE_TIMEOUT
1261 );
1262
1263 if (EFI_ERROR (Status)) {
1264 Status = EFI_DEVICE_ERROR;
1265 goto Exit;
1266 }
1267
1268 Status = KeyboardWrite (
1269 BiosKeyboardPrivate,
1270 KBC_INPBUF_VIA60_SCODESET2
1271 );
1272 if (EFI_ERROR (Status)) {
1273 Status = EFI_DEVICE_ERROR;
1274 goto Exit;
1275 }
1276
1277 Status = KeyboardWaitForValue (
1278 BiosKeyboardPrivate,
1279 KBC_CMDECHO_ACK,
1280 KEYBOARD_WAITFORVALUE_TIMEOUT
1281 );
1282
1283 if (EFI_ERROR (Status)) {
1284 Status = EFI_DEVICE_ERROR;
1285 goto Exit;
1286 }
1287 //
1288 // 11
1289 // enable keyboard itself (not via KBC) by writing CMD F4 via 60H
1290 //
1291 Status = KeyboardWrite (
1292 BiosKeyboardPrivate,
1293 KBC_INPBUF_VIA60_KBEN
1294 );
1295 if (EFI_ERROR (Status)) {
1296 Status = EFI_DEVICE_ERROR;
1297 goto Exit;
1298 }
1299
1300 Status = KeyboardWaitForValue (
1301 BiosKeyboardPrivate,
1302 KBC_CMDECHO_ACK,
1303 KEYBOARD_WAITFORVALUE_TIMEOUT
1304 );
1305
1306 if (EFI_ERROR (Status)) {
1307 Status = EFI_DEVICE_ERROR;
1308 goto Exit;
1309 }
1310 //
1311 // 12
1312 // Additional validation, do it as follow:
1313 // 1). check for status register of PARE && TIM via 64H
1314 // 2). perform KB checking by writing ABh via 64H
1315 //
1316 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & (KBC_STSREG_VIA64_PARE | KBC_STSREG_VIA64_TIM)) != 0) {
1317 Status = EFI_DEVICE_ERROR;
1318 goto Exit;
1319 }
1320
1321 Status = KeyboardCommand (
1322 BiosKeyboardPrivate,
1323 KBC_CMDREG_VIA64_KB_CKECK
1324 );
1325 if (EFI_ERROR (Status)) {
1326 Status = EFI_DEVICE_ERROR;
1327 goto Exit;
1328 }
1329
1330 Status = KeyboardWaitForValue (
1331 BiosKeyboardPrivate,
1332 KBC_CMDECHO_KBCHECK_OK,
1333 KEYBOARD_WAITFORVALUE_TIMEOUT
1334 );
1335
1336 if (EFI_ERROR (Status)) {
1337 Status = EFI_DEVICE_ERROR;
1338 goto Exit;
1339 }
1340 }
1341 //
1342 // 13
1343 // Done for validating keyboard. Enable keyboard (via KBC)
1344 // and recover the command byte to proper value
1345 //
1346 if (!PcdGetBool (PcdFastPS2Detection)) {
1347 Status = KeyboardCommand (
1348 BiosKeyboardPrivate,
1349 KBC_CMDREG_VIA64_KB_ENABLE
1350 );
1351
1352 if (EFI_ERROR (Status)) {
1353 Status = EFI_DEVICE_ERROR;
1354 goto Exit;
1355 }
1356 }
1357
1358 //
1359 // 14
1360 // conditionally enable mouse (via KBC)
1361 //
1362 if (MouseEnable) {
1363 Status = KeyboardCommand (
1364 BiosKeyboardPrivate,
1365 KBC_CMDREG_VIA64_AUX_ENABLE
1366 );
1367
1368 if (EFI_ERROR (Status)) {
1369 Status = EFI_DEVICE_ERROR;
1370
1371 }
1372 }
1373
1374 Exit:
1375 //
1376 // 15
1377 // resume priority of task level
1378 //
1379 gBS->RestoreTPL (OldTpl);
1380
1381 return Status;
1382
1383 }
1384
1385 /**
1386 Read out the scan code of the key that has just been stroked.
1387
1388 @param This Pointer of simple text Protocol.
1389 @param Key Pointer for store the key that read out.
1390
1391 @retval EFI_SUCCESS The key is read out successfully.
1392 @retval other The key reading failed.
1393
1394 **/
1395 EFI_STATUS
1396 EFIAPI
1397 BiosKeyboardReadKeyStroke (
1398 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
1399 OUT EFI_INPUT_KEY *Key
1400 )
1401 {
1402 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
1403 EFI_STATUS Status;
1404 EFI_KEY_DATA KeyData;
1405
1406 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
1407
1408 Status = KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, &KeyData);
1409 if (EFI_ERROR (Status)) {
1410 return Status;
1411 }
1412
1413 //
1414 // Convert the Ctrl+[a-z] to Ctrl+[1-26]
1415 //
1416 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
1417 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
1418 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
1419 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
1420 KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
1421 }
1422 }
1423
1424 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
1425
1426 return EFI_SUCCESS;
1427 }
1428
1429 /**
1430 Waiting on the keyboard event, if there's any key pressed by the user, signal the event
1431
1432 @param Event The event that be siganlled when any key has been stroked.
1433 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
1434
1435 **/
1436 VOID
1437 EFIAPI
1438 BiosKeyboardWaitForKey (
1439 IN EFI_EVENT Event,
1440 IN VOID *Context
1441 )
1442 {
1443 //
1444 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
1445 // Csm will be used to check whether there is a key pending, but the csm will disable all
1446 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
1447 // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
1448 // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,
1449 // e.g. usb keyboard driver.
1450 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
1451 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
1452 //
1453 gBS->Stall (1000);
1454 //
1455 // Use TimerEvent callback function to check whether there's any key pressed
1456 //
1457 BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));
1458
1459 if (!EFI_ERROR (BiosKeyboardCheckForKey (Context))) {
1460 gBS->SignalEvent (Event);
1461 }
1462 }
1463
1464 /**
1465 Check key buffer to get the key stroke status.
1466
1467 @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
1468
1469 @retval EFI_SUCCESS A key is being pressed now.
1470 @retval Other No key is now pressed.
1471
1472 **/
1473 EFI_STATUS
1474 EFIAPI
1475 BiosKeyboardCheckForKey (
1476 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
1477 )
1478 {
1479 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
1480
1481 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
1482
1483 return CheckQueue (&BiosKeyboardPrivate->Queue);
1484 }
1485 //
1486 // Private worker functions
1487 //
1488 #define TABLE_END 0x0
1489
1490 typedef struct _CONVERT_TABLE_ENTRY {
1491 UINT16 ScanCode;
1492 UINT16 EfiScanCode;
1493 } CONVERT_TABLE_ENTRY;
1494
1495 CONVERT_TABLE_ENTRY mConvertTable[] = {
1496 {
1497 0x47,
1498 SCAN_HOME
1499 },
1500 {
1501 0x48,
1502 SCAN_UP
1503 },
1504 {
1505 0x49,
1506 SCAN_PAGE_UP
1507 },
1508 {
1509 0x4b,
1510 SCAN_LEFT
1511 },
1512 {
1513 0x4d,
1514 SCAN_RIGHT
1515 },
1516 {
1517 0x4f,
1518 SCAN_END
1519 },
1520 {
1521 0x50,
1522 SCAN_DOWN
1523 },
1524 {
1525 0x51,
1526 SCAN_PAGE_DOWN
1527 },
1528 {
1529 0x52,
1530 SCAN_INSERT
1531 },
1532 {
1533 0x53,
1534 SCAN_DELETE
1535 },
1536 //
1537 // Function Keys are only valid if KeyChar == 0x00
1538 // This function does not require KeyChar to be 0x00
1539 //
1540 {
1541 0x3b,
1542 SCAN_F1
1543 },
1544 {
1545 0x3c,
1546 SCAN_F2
1547 },
1548 {
1549 0x3d,
1550 SCAN_F3
1551 },
1552 {
1553 0x3e,
1554 SCAN_F4
1555 },
1556 {
1557 0x3f,
1558 SCAN_F5
1559 },
1560 {
1561 0x40,
1562 SCAN_F6
1563 },
1564 {
1565 0x41,
1566 SCAN_F7
1567 },
1568 {
1569 0x42,
1570 SCAN_F8
1571 },
1572 {
1573 0x43,
1574 SCAN_F9
1575 },
1576 {
1577 0x44,
1578 SCAN_F10
1579 },
1580 {
1581 0x85,
1582 SCAN_F11
1583 },
1584 {
1585 0x86,
1586 SCAN_F12
1587 },
1588 //
1589 // Convert ALT + Fn keys
1590 //
1591 {
1592 0x68,
1593 SCAN_F1
1594 },
1595 {
1596 0x69,
1597 SCAN_F2
1598 },
1599 {
1600 0x6a,
1601 SCAN_F3
1602 },
1603 {
1604 0x6b,
1605 SCAN_F4
1606 },
1607 {
1608 0x6c,
1609 SCAN_F5
1610 },
1611 {
1612 0x6d,
1613 SCAN_F6
1614 },
1615 {
1616 0x6e,
1617 SCAN_F7
1618 },
1619 {
1620 0x6f,
1621 SCAN_F8
1622 },
1623 {
1624 0x70,
1625 SCAN_F9
1626 },
1627 {
1628 0x71,
1629 SCAN_F10
1630 },
1631 {
1632 TABLE_END,
1633 SCAN_NULL
1634 },
1635 };
1636
1637 /**
1638 Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.
1639
1640 @param KeyChar Unicode of key.
1641 @param ScanCode Scan code of key.
1642
1643 @return The value of EFI Scancode for the key.
1644 @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.
1645
1646 **/
1647 UINT16
1648 ConvertToEFIScanCode (
1649 IN CHAR16 KeyChar,
1650 IN UINT16 ScanCode
1651 )
1652 {
1653 UINT16 EfiScanCode;
1654 UINT16 Index;
1655
1656 if (KeyChar == CHAR_ESC) {
1657 EfiScanCode = SCAN_ESC;
1658 } else if (KeyChar == 0x00 || KeyChar == 0xe0) {
1659 //
1660 // Movement & Function Keys
1661 //
1662 for (Index = 0; (Index < sizeof (mConvertTable) / sizeof (CONVERT_TABLE_ENTRY)) && (mConvertTable[Index].ScanCode != TABLE_END); Index += 1) {
1663 if (ScanCode == mConvertTable[Index].ScanCode) {
1664 return mConvertTable[Index].EfiScanCode;
1665 }
1666 }
1667 //
1668 // Reach Table end, return default value
1669 //
1670 return SCAN_NULL;
1671 } else {
1672 return SCAN_NULL;
1673 }
1674
1675 return EfiScanCode;
1676 }
1677
1678 /**
1679 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
1680 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
1681 should not be in system.
1682
1683 @param BiosKeyboardPrivate Keyboard Private Data Struture
1684
1685 @retval TRUE Keyboard in System.
1686 @retval FALSE Keyboard not in System.
1687
1688 **/
1689 BOOLEAN
1690 CheckKeyboardConnect (
1691 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
1692 )
1693 {
1694 EFI_STATUS Status;
1695
1696 Status = EFI_SUCCESS;
1697 //
1698 // enable keyboard itself and wait for its ack
1699 // If can't receive ack, Keyboard should not be connected.
1700 //
1701 if (!PcdGetBool (PcdFastPS2Detection)) {
1702 Status = KeyboardWrite (
1703 BiosKeyboardPrivate,
1704 KBC_INPBUF_VIA60_KBEN
1705 );
1706 if (EFI_ERROR (Status)) {
1707 DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n"));
1708 REPORT_STATUS_CODE (
1709 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1710 EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR
1711 );
1712 return FALSE;
1713 }
1714
1715 Status = KeyboardWaitForValue (
1716 BiosKeyboardPrivate,
1717 KBC_CMDECHO_ACK,
1718 KEYBOARD_WAITFORVALUE_TIMEOUT
1719 );
1720
1721 if (EFI_ERROR (Status)) {
1722 DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Timeout!\n"));
1723 REPORT_STATUS_CODE (
1724 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1725 EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR
1726 );
1727 return FALSE;
1728 }
1729 return TRUE;
1730 } else {
1731 return TRUE;
1732 }
1733 }
1734
1735 /**
1736 Disable NULL pointer detection.
1737 **/
1738 VOID
1739 DisableNullDetection (
1740 VOID
1741 )
1742 {
1743 EFI_STATUS Status;
1744 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
1745
1746 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
1747 return;
1748 }
1749
1750 //
1751 // Check current capabilities and attributes
1752 //
1753 Status = gDS->GetMemorySpaceDescriptor (0, &Desc);
1754 ASSERT_EFI_ERROR (Status);
1755
1756 //
1757 // Try to add EFI_MEMORY_RP support if necessary
1758 //
1759 if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
1760 Desc.Capabilities |= EFI_MEMORY_RP;
1761 Status = gDS->SetMemorySpaceCapabilities (0, EFI_PAGES_TO_SIZE(1),
1762 Desc.Capabilities);
1763 ASSERT_EFI_ERROR (Status);
1764 if (EFI_ERROR (Status)) {
1765 return;
1766 }
1767 }
1768
1769 //
1770 // Don't bother if EFI_MEMORY_RP is already cleared.
1771 //
1772 if ((Desc.Attributes & EFI_MEMORY_RP) != 0) {
1773 Desc.Attributes &= ~EFI_MEMORY_RP;
1774 Status = gDS->SetMemorySpaceAttributes (0, EFI_PAGES_TO_SIZE(1),
1775 Desc.Attributes);
1776 ASSERT_EFI_ERROR (Status);
1777 } else {
1778 DEBUG ((DEBUG_WARN, "!!! Page 0 is supposed to be disabled !!!\r\n"));
1779 }
1780 }
1781
1782 /**
1783 Enable NULL pointer detection.
1784 **/
1785 VOID
1786 EnableNullDetection (
1787 VOID
1788 )
1789 {
1790 EFI_STATUS Status;
1791 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
1792
1793 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {
1794 return;
1795 }
1796
1797 //
1798 // Check current capabilities and attributes
1799 //
1800 Status = gDS->GetMemorySpaceDescriptor (0, &Desc);
1801 ASSERT_EFI_ERROR (Status);
1802
1803 //
1804 // Try to add EFI_MEMORY_RP support if necessary
1805 //
1806 if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
1807 Desc.Capabilities |= EFI_MEMORY_RP;
1808 Status = gDS->SetMemorySpaceCapabilities (0, EFI_PAGES_TO_SIZE(1),
1809 Desc.Capabilities);
1810 ASSERT_EFI_ERROR (Status);
1811 if (EFI_ERROR (Status)) {
1812 return;
1813 }
1814 }
1815
1816 //
1817 // Don't bother if EFI_MEMORY_RP is already set.
1818 //
1819 if ((Desc.Attributes & EFI_MEMORY_RP) == 0) {
1820 Desc.Attributes |= EFI_MEMORY_RP;
1821 Status = gDS->SetMemorySpaceAttributes (0, EFI_PAGES_TO_SIZE(1),
1822 Desc.Attributes);
1823 ASSERT_EFI_ERROR (Status);
1824 }
1825 }
1826
1827 /**
1828 Timer event handler: read a series of key stroke from 8042
1829 and put them into memory key buffer.
1830 It is registered as running under TPL_NOTIFY
1831
1832 @param Event The timer event
1833 @param Context A BIOS_KEYBOARD_DEV pointer
1834
1835 **/
1836 VOID
1837 EFIAPI
1838 BiosKeyboardTimerHandler (
1839 IN EFI_EVENT Event,
1840 IN VOID *Context
1841 )
1842 {
1843 EFI_TPL OldTpl;
1844 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
1845 EFI_IA32_REGISTER_SET Regs;
1846 UINT8 KbFlag1; // 0040h:0017h - KEYBOARD - STATUS FLAGS 1
1847 UINT8 KbFlag2; // 0040h:0018h - KEYBOARD - STATUS FLAGS 2
1848 EFI_KEY_DATA KeyData;
1849 LIST_ENTRY *Link;
1850 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
1851
1852 BiosKeyboardPrivate = Context;
1853
1854 //
1855 // Enter critical section
1856 //
1857 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1858
1859 //
1860 // if there is no key present, just return
1861 //
1862 if (BiosKeyboardPrivate->ExtendedKeyboard) {
1863 Regs.H.AH = 0x11;
1864 } else {
1865 Regs.H.AH = 0x01;
1866 }
1867
1868 BiosKeyboardPrivate->LegacyBios->Int86 (
1869 BiosKeyboardPrivate->LegacyBios,
1870 0x16,
1871 &Regs
1872 );
1873 if (Regs.X.Flags.ZF != 0) {
1874 gBS->RestoreTPL (OldTpl);
1875 return;
1876 }
1877
1878 //
1879 // Read the key
1880 //
1881 if (BiosKeyboardPrivate->ExtendedKeyboard) {
1882 Regs.H.AH = 0x10;
1883 } else {
1884 Regs.H.AH = 0x00;
1885 }
1886
1887 BiosKeyboardPrivate->LegacyBios->Int86 (
1888 BiosKeyboardPrivate->LegacyBios,
1889 0x16,
1890 &Regs
1891 );
1892
1893 KeyData.Key.ScanCode = (UINT16) Regs.H.AH;
1894 KeyData.Key.UnicodeChar = (UINT16) Regs.H.AL;
1895 DEBUG ((
1896 EFI_D_INFO,
1897 "[KBD]INT16 returns EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
1898 KeyData.Key.ScanCode,
1899 KeyData.Key.UnicodeChar
1900 ));
1901
1902 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
1903 KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
1904 //
1905 // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB buffer in BDA (BIOS DATE AREA), then
1906 // Int 16 depend KB buffer and some key bits in BDA to translate the scancode to ASCII code, and return both the scancode and ASCII
1907 // code to Int 16 caller. This translation process works well if the Int 9 could response user input in time. But in Tiano enviorment, the Int 9
1908 // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when
1909 // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit
1910 // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode
1911 // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other drivers
1912 // performance, like USB.
1913 //
1914 // 1. If CTRL or ALT release code is missed, all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In
1915 // this case, the KB input seems fail to work, and user input is blocked. To solve the problem, we can help to clear the CTRL or ALT flag in BDA
1916 // after every Int 16 finish. Thus persist to press CTRL or ALT has same effection as only press one time. It is Ok, since user not often use the
1917 // CTRL and ALT.
1918 //
1919 // 2. If SHIFT release code is missed, all later lowercase input will become capital. This is ugly, but not block user input. If user press the lost
1920 // SHIFT again, the lowercase will come back to normal. Since user often use the SHIFT, it is not reasonable to help to clear the SHIFT flag in BDA,
1921 // which will let persist to press SHIFT has same effection as only press one time.
1922 //
1923 //0040h:0017h - KEYBOARD - STATUS FLAGS 1
1924 // 7 INSert active
1925 // 6 Caps Lock active
1926 // 5 Num Lock active
1927 // 4 Scroll Lock active
1928 // 3 either Alt pressed
1929 // 2 either Ctrl pressed
1930 // 1 Left Shift pressed
1931 // 0 Right Shift pressed
1932
1933
1934 //
1935 // Disable NULL pointer detection temporarily
1936 //
1937 DisableNullDetection ();
1938
1939 //
1940 // Clear the CTRL and ALT BDA flag
1941 //
1942 KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1
1943 KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2
1944
1945 DEBUG_CODE (
1946 {
1947 if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {
1948 DEBUG ((EFI_D_INFO, "[KBD]Caps Lock Key is pressed.\n"));
1949 }
1950 if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {
1951 DEBUG ((EFI_D_INFO, "[KBD]Num Lock Key is pressed.\n"));
1952 }
1953 if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {
1954 DEBUG ((EFI_D_INFO, "[KBD]Scroll Lock Key is pressed.\n"));
1955 }
1956 if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {
1957 if ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) {
1958 DEBUG ((EFI_D_INFO, "[KBD]Left Alt Key is pressed.\n"));
1959 } else {
1960 DEBUG ((EFI_D_INFO, "[KBD]Right Alt Key is pressed.\n"));
1961 }
1962 }
1963 if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {
1964 if ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) {
1965 DEBUG ((EFI_D_INFO, "[KBD]Left Ctrl Key is pressed.\n"));
1966 } else {
1967 DEBUG ((EFI_D_INFO, "[KBD]Right Ctrl Key is pressed.\n"));
1968 }
1969 }
1970 if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {
1971 DEBUG ((EFI_D_INFO, "[KBD]Left Shift Key is pressed.\n"));
1972 }
1973 if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {
1974 DEBUG ((EFI_D_INFO, "[KBD]Right Shift Key is pressed.\n"));
1975 }
1976 }
1977 );
1978
1979 //
1980 // Record toggle state
1981 //
1982 if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {
1983 KeyData.KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
1984 }
1985 if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {
1986 KeyData.KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
1987 }
1988 if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {
1989 KeyData.KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
1990 }
1991 //
1992 // Record shift state
1993 // BUGBUG: Need add Menu key and Left/Right Logo key state in the future
1994 //
1995 if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {
1996 KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) ? EFI_LEFT_ALT_PRESSED : EFI_RIGHT_ALT_PRESSED;
1997 }
1998 if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {
1999 KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) ? EFI_LEFT_CONTROL_PRESSED : EFI_RIGHT_CONTROL_PRESSED;
2000 }
2001 if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {
2002 KeyData.KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
2003 }
2004 if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {
2005 KeyData.KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
2006 }
2007
2008 //
2009 // Clear left alt and left ctrl BDA flag
2010 //
2011 KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);
2012 *((UINT8 *) (UINTN) 0x418) = KbFlag2;
2013 KbFlag1 &= ~0x0C;
2014 *((UINT8 *) (UINTN) 0x417) = KbFlag1;
2015
2016 //
2017 // Restore NULL pointer detection
2018 //
2019 EnableNullDetection ();
2020
2021 //
2022 // Output EFI input key and shift/toggle state
2023 //
2024 if (KeyData.Key.UnicodeChar == CHAR_NULL || KeyData.Key.UnicodeChar == CHAR_SCANCODE || KeyData.Key.UnicodeChar == CHAR_ESC) {
2025 KeyData.Key.ScanCode = ConvertToEFIScanCode (KeyData.Key.UnicodeChar, KeyData.Key.ScanCode);
2026 KeyData.Key.UnicodeChar = CHAR_NULL;
2027 } else {
2028 KeyData.Key.ScanCode = SCAN_NULL;
2029 }
2030
2031 //
2032 // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.
2033 //
2034 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
2035 if (KeyData.Key.UnicodeChar >= 1 && KeyData.Key.UnicodeChar <= 26) {
2036 if (((KeyData.KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) ==
2037 ((KeyData.KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0)
2038 ) {
2039 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'a' - 1);
2040 } else {
2041 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'A' - 1);
2042 }
2043 }
2044 }
2045
2046 DEBUG ((
2047 EFI_D_INFO,
2048 "[KBD]Convert to EFI Scan Code, EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
2049 KeyData.Key.ScanCode,
2050 KeyData.Key.UnicodeChar
2051 ));
2052
2053 //
2054 // Need not return associated shift state if a class of printable characters that
2055 // are normally adjusted by shift modifiers.
2056 // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.
2057 //
2058 if ((KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') ||
2059 (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z')
2060 ) {
2061 DEBUG ((EFI_D_INFO, "[KBD]Shift key with a~z are pressed, remove shift state in EFI_KEY_STATE.\n"));
2062 KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
2063 }
2064
2065 //
2066 // Signal KeyNotify process event if this key pressed matches any key registered.
2067 //
2068 for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
2069 CurrentNotify = CR (
2070 Link,
2071 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
2072 NotifyEntry,
2073 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2074 );
2075 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
2076 //
2077 // The key notification function needs to run at TPL_CALLBACK
2078 // while current TPL is TPL_NOTIFY. It will be invoked in
2079 // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
2080 //
2081 Enqueue (&BiosKeyboardPrivate->QueueForNotify, &KeyData);
2082 gBS->SignalEvent (BiosKeyboardPrivate->KeyNotifyProcessEvent);
2083 }
2084 }
2085
2086 Enqueue (&BiosKeyboardPrivate->Queue, &KeyData);
2087 //
2088 // Leave critical section and return
2089 //
2090 gBS->RestoreTPL (OldTpl);
2091
2092 return ;
2093 }
2094
2095 /**
2096 Process key notify.
2097
2098 @param Event Indicates the event that invoke this function.
2099 @param Context Indicates the calling context.
2100 **/
2101 VOID
2102 EFIAPI
2103 KeyNotifyProcessHandler (
2104 IN EFI_EVENT Event,
2105 IN VOID *Context
2106 )
2107 {
2108 EFI_STATUS Status;
2109 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
2110 EFI_KEY_DATA KeyData;
2111 LIST_ENTRY *Link;
2112 LIST_ENTRY *NotifyList;
2113 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
2114 EFI_TPL OldTpl;
2115
2116 BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) Context;
2117
2118 //
2119 // Invoke notification functions.
2120 //
2121 NotifyList = &BiosKeyboardPrivate->NotifyList;
2122 while (TRUE) {
2123 //
2124 // Enter critical section
2125 //
2126 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2127 Status = Dequeue (&BiosKeyboardPrivate->QueueForNotify, &KeyData);
2128 //
2129 // Leave critical section
2130 //
2131 gBS->RestoreTPL (OldTpl);
2132 if (EFI_ERROR (Status)) {
2133 break;
2134 }
2135 for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
2136 CurrentNotify = CR (Link, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
2137 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
2138 CurrentNotify->KeyNotificationFn (&KeyData);
2139 }
2140 }
2141 }
2142 }
2143
2144 /**
2145 Free keyboard notify list.
2146
2147 @param ListHead The list head
2148
2149 @retval EFI_SUCCESS Free the notify list successfully
2150 @retval EFI_INVALID_PARAMETER ListHead is invalid.
2151
2152 **/
2153 EFI_STATUS
2154 BiosKeyboardFreeNotifyList (
2155 IN OUT LIST_ENTRY *ListHead
2156 )
2157 {
2158 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
2159
2160 if (ListHead == NULL) {
2161 return EFI_INVALID_PARAMETER;
2162 }
2163 while (!IsListEmpty (ListHead)) {
2164 NotifyNode = CR (
2165 ListHead->ForwardLink,
2166 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
2167 NotifyEntry,
2168 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2169 );
2170 RemoveEntryList (ListHead->ForwardLink);
2171 gBS->FreePool (NotifyNode);
2172 }
2173
2174 return EFI_SUCCESS;
2175 }
2176
2177 /**
2178 Check if key is registered.
2179
2180 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
2181 state data for the key that was registered.
2182 @param InputData A pointer to a buffer that is filled in with the keystroke
2183 state data for the key that was pressed.
2184
2185 @retval TRUE Key be pressed matches a registered key.
2186 @retval FLASE Match failed.
2187
2188 **/
2189 BOOLEAN
2190 IsKeyRegistered (
2191 IN EFI_KEY_DATA *RegsiteredData,
2192 IN EFI_KEY_DATA *InputData
2193 )
2194 {
2195 ASSERT (RegsiteredData != NULL && InputData != NULL);
2196
2197 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
2198 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
2199 return FALSE;
2200 }
2201
2202 //
2203 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
2204 //
2205 if (RegsiteredData->KeyState.KeyShiftState != 0 &&
2206 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
2207 return FALSE;
2208 }
2209 if (RegsiteredData->KeyState.KeyToggleState != 0 &&
2210 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
2211 return FALSE;
2212 }
2213
2214 return TRUE;
2215
2216 }
2217
2218 /**
2219 Waiting on the keyboard event, if there's any key pressed by the user, signal the event
2220
2221 @param Event The event that be siganlled when any key has been stroked.
2222 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
2223
2224 **/
2225 VOID
2226 EFIAPI
2227 BiosKeyboardWaitForKeyEx (
2228 IN EFI_EVENT Event,
2229 IN VOID *Context
2230 )
2231 {
2232 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
2233
2234 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context);
2235 BiosKeyboardWaitForKey (Event, &BiosKeyboardPrivate->SimpleTextIn);
2236
2237 }
2238
2239 /**
2240 Reset the input device and optionaly run diagnostics
2241
2242 @param This Protocol instance pointer.
2243 @param ExtendedVerification Driver may perform diagnostics on reset.
2244
2245 @retval EFI_SUCCESS The device was reset.
2246 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
2247 not be reset.
2248
2249 **/
2250 EFI_STATUS
2251 EFIAPI
2252 BiosKeyboardResetEx (
2253 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
2254 IN BOOLEAN ExtendedVerification
2255 )
2256 {
2257 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
2258 EFI_STATUS Status;
2259 EFI_TPL OldTpl;
2260
2261 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
2262
2263 Status = BiosKeyboardPrivate->SimpleTextIn.Reset (
2264 &BiosKeyboardPrivate->SimpleTextIn,
2265 ExtendedVerification
2266 );
2267 if (EFI_ERROR (Status)) {
2268 return EFI_DEVICE_ERROR;
2269 }
2270
2271 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2272
2273 gBS->RestoreTPL (OldTpl);
2274
2275 return EFI_SUCCESS;
2276
2277 }
2278
2279 /**
2280 Reads the next keystroke from the input device. The WaitForKey Event can
2281 be used to test for existance of a keystroke via WaitForEvent () call.
2282
2283 @param This Protocol instance pointer.
2284 @param KeyData A pointer to a buffer that is filled in with the keystroke
2285 state data for the key that was pressed.
2286
2287 @retval EFI_SUCCESS The keystroke information was returned.
2288 @retval EFI_NOT_READY There was no keystroke data availiable.
2289 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
2290 hardware errors.
2291 @retval EFI_INVALID_PARAMETER KeyData is NULL.
2292
2293 **/
2294 EFI_STATUS
2295 EFIAPI
2296 BiosKeyboardReadKeyStrokeEx (
2297 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
2298 OUT EFI_KEY_DATA *KeyData
2299 )
2300 {
2301 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
2302
2303 if (KeyData == NULL) {
2304 return EFI_INVALID_PARAMETER;
2305 }
2306
2307 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
2308
2309 return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, KeyData);
2310
2311 }
2312
2313 /**
2314 Set certain state for the input device.
2315
2316 @param This Protocol instance pointer.
2317 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
2318 state for the input device.
2319
2320 @retval EFI_SUCCESS The device state was set successfully.
2321 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
2322 not have the setting adjusted.
2323 @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
2324 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
2325
2326 **/
2327 EFI_STATUS
2328 EFIAPI
2329 BiosKeyboardSetState (
2330 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
2331 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
2332 )
2333 {
2334 EFI_STATUS Status;
2335 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
2336 EFI_TPL OldTpl;
2337 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
2338 UINT8 Command;
2339
2340 if (KeyToggleState == NULL) {
2341 return EFI_INVALID_PARAMETER;
2342 }
2343
2344 //
2345 // Thunk keyboard driver doesn't support partial keystroke.
2346 //
2347 if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID ||
2348 (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED
2349 ) {
2350 return EFI_UNSUPPORTED;
2351 }
2352
2353 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
2354 //
2355 // See if the Legacy BIOS Protocol is available
2356 //
2357 Status = gBS->LocateProtocol (
2358 &gEfiLegacyBiosProtocolGuid,
2359 NULL,
2360 (VOID **) &LegacyBios
2361 );
2362
2363 ASSERT_EFI_ERROR (Status);
2364 //
2365 // Enter critical section
2366 //
2367 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2368
2369 Command = 0;
2370 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
2371 Command |= 4;
2372 }
2373 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
2374 Command |= 2;
2375 }
2376 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
2377 Command |= 1;
2378 }
2379
2380 Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);
2381 if (EFI_ERROR (Status)) {
2382 Status = EFI_DEVICE_ERROR;
2383 goto Exit;
2384 }
2385 Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);
2386 if (EFI_ERROR (Status)) {
2387 Status = EFI_DEVICE_ERROR;
2388 goto Exit;
2389 }
2390 Status = KeyboardWrite (BiosKeyboardPrivate, Command);
2391 if (EFI_ERROR (Status)) {
2392 Status = EFI_DEVICE_ERROR;
2393 goto Exit;
2394 }
2395 //
2396 // Call Legacy BIOS Protocol to set whatever is necessary
2397 //
2398 LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);
2399
2400 Status = EFI_SUCCESS;
2401
2402 Exit:
2403 //
2404 // Leave critical section and return
2405 //
2406 gBS->RestoreTPL (OldTpl);
2407
2408 return Status;
2409
2410 }
2411
2412 /**
2413 Register a notification function for a particular keystroke for the input device.
2414
2415 @param This Protocol instance pointer.
2416 @param KeyData A pointer to a buffer that is filled in with the keystroke
2417 information data for the key that was pressed. If KeyData.Key,
2418 KeyData.KeyState.KeyToggleState and KeyData.KeyState.KeyShiftState
2419 are 0, then any incomplete keystroke will trigger a notification of
2420 the KeyNotificationFunction.
2421 @param KeyNotificationFunction Points to the function to be called when the key
2422 sequence is typed specified by KeyData. This notification function
2423 should be called at <=TPL_CALLBACK.
2424 @param NotifyHandle Points to the unique handle assigned to the registered notification.
2425
2426 @retval EFI_SUCCESS The notification function was registered successfully.
2427 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
2428 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
2429
2430 **/
2431 EFI_STATUS
2432 EFIAPI
2433 BiosKeyboardRegisterKeyNotify (
2434 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
2435 IN EFI_KEY_DATA *KeyData,
2436 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
2437 OUT VOID **NotifyHandle
2438 )
2439 {
2440 EFI_STATUS Status;
2441 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
2442 EFI_TPL OldTpl;
2443 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
2444 LIST_ENTRY *Link;
2445 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
2446
2447 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
2448 return EFI_INVALID_PARAMETER;
2449 }
2450
2451 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
2452
2453 //
2454 // Enter critical section
2455 //
2456 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2457
2458 //
2459 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
2460 //
2461 for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
2462 CurrentNotify = CR (
2463 Link,
2464 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
2465 NotifyEntry,
2466 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2467 );
2468 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
2469 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
2470 *NotifyHandle = CurrentNotify;
2471 Status = EFI_SUCCESS;
2472 goto Exit;
2473 }
2474 }
2475 }
2476
2477 //
2478 // Allocate resource to save the notification function
2479 //
2480
2481 NewNotify = (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY));
2482 if (NewNotify == NULL) {
2483 Status = EFI_OUT_OF_RESOURCES;
2484 goto Exit;
2485 }
2486
2487 NewNotify->Signature = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
2488 NewNotify->KeyNotificationFn = KeyNotificationFunction;
2489 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
2490 InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);
2491
2492 *NotifyHandle = NewNotify;
2493 Status = EFI_SUCCESS;
2494
2495 Exit:
2496 //
2497 // Leave critical section and return
2498 //
2499 gBS->RestoreTPL (OldTpl);
2500 return Status;
2501 }
2502
2503 /**
2504 Remove a registered notification function from a particular keystroke.
2505
2506 @param This Protocol instance pointer.
2507 @param NotificationHandle The handle of the notification function being unregistered.
2508
2509 @retval EFI_SUCCESS The notification function was unregistered successfully.
2510 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
2511
2512 **/
2513 EFI_STATUS
2514 EFIAPI
2515 BiosKeyboardUnregisterKeyNotify (
2516 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
2517 IN VOID *NotificationHandle
2518 )
2519 {
2520 EFI_STATUS Status;
2521 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
2522 EFI_TPL OldTpl;
2523 LIST_ENTRY *Link;
2524 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
2525
2526 //
2527 // Check incoming notification handle
2528 //
2529 if (NotificationHandle == NULL) {
2530 return EFI_INVALID_PARAMETER;
2531 }
2532
2533 if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
2534 return EFI_INVALID_PARAMETER;
2535 }
2536
2537 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
2538
2539 //
2540 // Enter critical section
2541 //
2542 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
2543
2544 for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
2545 CurrentNotify = CR (
2546 Link,
2547 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
2548 NotifyEntry,
2549 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
2550 );
2551 if (CurrentNotify == NotificationHandle) {
2552 //
2553 // Remove the notification function from NotifyList and free resources
2554 //
2555 RemoveEntryList (&CurrentNotify->NotifyEntry);
2556
2557 Status = EFI_SUCCESS;
2558 goto Exit;
2559 }
2560 }
2561
2562 //
2563 // Can not find the specified Notification Handle
2564 //
2565 Status = EFI_INVALID_PARAMETER;
2566
2567 Exit:
2568 //
2569 // Leave critical section and return
2570 //
2571 gBS->RestoreTPL (OldTpl);
2572 return Status;
2573 }
2574
2575 /**
2576 The user Entry Point for module BiosKeyboard. The user code starts with this function.
2577
2578 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2579 @param[in] SystemTable A pointer to the EFI System Table.
2580
2581 @retval EFI_SUCCESS The entry point is executed successfully.
2582 @retval other Some error occurs when executing this entry point.
2583
2584 **/
2585 EFI_STATUS
2586 EFIAPI
2587 InitializeBiosKeyboard(
2588 IN EFI_HANDLE ImageHandle,
2589 IN EFI_SYSTEM_TABLE *SystemTable
2590 )
2591 {
2592 EFI_STATUS Status;
2593
2594 //
2595 // Install driver model protocol(s).
2596 //
2597 Status = EfiLibInstallDriverBindingComponentName2 (
2598 ImageHandle,
2599 SystemTable,
2600 &gBiosKeyboardDriverBinding,
2601 ImageHandle,
2602 &gBiosKeyboardComponentName,
2603 &gBiosKeyboardComponentName2
2604 );
2605 ASSERT_EFI_ERROR (Status);
2606
2607 return Status;
2608 }