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