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