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