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