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