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