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