Drivers/Keyboard: add gpio keyboard driver

Simulate GPIO pins as keyboard. When the GPIO setting is expected,
send out a key value.

Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
diff --git a/Drivers/Keyboard/GpioKeyboardDxe/ComponentName.c b/Drivers/Keyboard/GpioKeyboardDxe/ComponentName.c
new file mode 100644
index 0000000..fd8313d
--- /dev/null
+++ b/Drivers/Keyboard/GpioKeyboardDxe/ComponentName.c
@@ -0,0 +1,184 @@
+/** @file

+

+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>

+Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>

+

+This program and the accompanying materials

+are licensed and made available under the terms and conditions

+of the BSD License which accompanies this distribution.  The

+full text of the license may be found at

+http://opensource.org/licenses/bsd-license.php

+

+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include "GpioKeyboard.h"

+

+//

+// EFI Component Name Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gGpioKeyboardComponentName = {

+  GpioKeyboardComponentNameGetDriverName,

+  GpioKeyboardComponentNameGetControllerName,

+  "eng"

+};

+

+//

+// EFI Component Name 2 Protocol

+//

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gGpioKeyboardComponentName2 = {

+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) GpioKeyboardComponentNameGetDriverName,

+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) GpioKeyboardComponentNameGetControllerName,

+  "en"

+};

+

+

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mGpioKeyboardDriverNameTable[] = {

+  {

+    "eng;en",

+    L"GPIO Keyboard Driver"

+  },

+  {

+    NULL,

+    NULL

+  }

+};

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  )

+{

+  return LookupUnicodeString2 (

+           Language,

+           This->SupportedLanguages,

+           mGpioKeyboardDriverNameTable,

+           DriverName,

+           (BOOLEAN)(This == &gGpioKeyboardComponentName)

+           );

+}

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  )

+{

+  return EFI_UNSUPPORTED;

+}

diff --git a/Drivers/Keyboard/GpioKeyboardDxe/ComponentName.h b/Drivers/Keyboard/GpioKeyboardDxe/ComponentName.h
new file mode 100644
index 0000000..842bda4
--- /dev/null
+++ b/Drivers/Keyboard/GpioKeyboardDxe/ComponentName.h
@@ -0,0 +1,154 @@
+/** @file

+

+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>

+Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>

+

+This program and the accompanying materials

+are licensed and made available under the terms and conditions

+of the BSD License which accompanies this distribution.  The

+full text of the license may be found at

+http://opensource.org/licenses/bsd-license.php

+

+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#ifndef _GPIO_KEYBOARD_COMPONENT_NAME_H_

+#define _GPIO_KEYBOARD_COMPONENT_NAME_H_

+

+

+extern EFI_COMPONENT_NAME_PROTOCOL   gGpioKeyboardComponentName;

+extern EFI_COMPONENT_NAME2_PROTOCOL  gGpioKeyboardComponentName2;

+

+//

+// EFI Component Name Functions

+//

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  );

+

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  );

+

+

+#endif

diff --git a/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboard.c b/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboard.c
new file mode 100644
index 0000000..d873201
--- /dev/null
+++ b/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboard.c
@@ -0,0 +1,1261 @@
+/** @file
+  GpioKeyboard driver
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution.  The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "GpioKeyboard.h"
+
+//
+// GPIO Keyboard Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gGpioKeyboardDriverBinding = {
+  GpioKeyboardDriverBindingSupported,
+  GpioKeyboardDriverBindingStart,
+  GpioKeyboardDriverBindingStop,
+  0x10,
+  NULL,
+  NULL
+};
+
+//
+// EFI Driver Binding Protocol Functions
+//
+
+/**
+  Check whether the driver supports this device.
+
+  @param  This                   The Udriver binding protocol.
+  @param  Controller             The controller handle to check.
+  @param  RemainingDevicePath    The remaining device path.
+
+  @retval EFI_SUCCESS            The driver supports this controller.
+  @retval other                  This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS                                Status;
+  EMBEDDED_GPIO                             *Gpio;
+  PLATFORM_GPIO_KBD_PROTOCOL                *PlatformGpio;
+
+  Status = gBS->LocateProtocol (
+                  &gPlatformGpioKeyboardProtocolGuid,
+                  NULL,
+                  (VOID **) &PlatformGpio
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEmbeddedGpioProtocolGuid,
+                  (VOID **) &Gpio,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEmbeddedGpioProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return Status;
+}
+
+/**
+  Starts the device with this driver.
+
+  @param  This                   The driver binding instance.
+  @param  Controller             Handle of device to bind driver to.
+  @param  RemainingDevicePath    Optional parameter use to pick a specific child
+                                 device to start.
+
+  @retval EFI_SUCCESS            The controller is controlled by the driver.
+  @retval Other                  This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS                                Status;
+  GPIO_KEYBOARD_DEV                         *GpioKeyboardPrivate;
+  EMBEDDED_GPIO                             *Gpio;
+  PLATFORM_GPIO_KBD_PROTOCOL                *PlatformGpio;
+  EFI_STATUS_CODE_VALUE                     StatusCode;
+
+  GpioKeyboardPrivate = NULL;
+  //StatusCode          = 0;
+
+  //
+  // Open the GPIO Interface
+  //
+  Status = gBS->LocateProtocol (
+                  &gPlatformGpioKeyboardProtocolGuid,
+                  NULL,
+                  (VOID **) &PlatformGpio
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEmbeddedGpioProtocolGuid,
+                  (VOID **) &Gpio,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Allocate the private device structure
+  //
+  GpioKeyboardPrivate = (GPIO_KEYBOARD_DEV *) AllocateZeroPool (sizeof (GPIO_KEYBOARD_DEV));
+  if (NULL == GpioKeyboardPrivate) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  //
+  // Initialize the private device structure
+  //
+  GpioKeyboardPrivate->Signature                  = GPIO_KEYBOARD_DEV_SIGNATURE;
+  GpioKeyboardPrivate->Handle                     = Controller;
+  GpioKeyboardPrivate->Gpio                       = Gpio;
+  GpioKeyboardPrivate->PlatformGpio               = PlatformGpio;
+  GpioKeyboardPrivate->Queue.Front                = 0;
+  GpioKeyboardPrivate->Queue.Rear                 = 0;
+  GpioKeyboardPrivate->QueueForNotify.Front       = 0;
+  GpioKeyboardPrivate->QueueForNotify.Rear        = 0;
+
+  GpioKeyboardPrivate->SimpleTextIn.Reset         = GpioKeyboardReset;
+  GpioKeyboardPrivate->SimpleTextIn.ReadKeyStroke = GpioKeyboardReadKeyStroke;
+
+  GpioKeyboardPrivate->SimpleTextInputEx.Reset               = GpioKeyboardResetEx;
+  GpioKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx     = GpioKeyboardReadKeyStrokeEx;
+  GpioKeyboardPrivate->SimpleTextInputEx.SetState            = GpioKeyboardSetState;
+
+  GpioKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify   = GpioKeyboardRegisterKeyNotify;
+  GpioKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = GpioKeyboardUnregisterKeyNotify;
+  InitializeListHead (&GpioKeyboardPrivate->NotifyList);
+
+  //
+  // Report that the keyboard is being enabled
+  //
+  REPORT_STATUS_CODE (
+    EFI_PROGRESS_CODE,
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE
+    );
+
+  //
+  // Setup the WaitForKey event
+  //
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_WAIT,
+                  TPL_NOTIFY,
+                  GpioKeyboardWaitForKey,
+                  &(GpioKeyboardPrivate->SimpleTextIn),
+                  &((GpioKeyboardPrivate->SimpleTextIn).WaitForKey)
+                  );
+  if (EFI_ERROR (Status)) {
+    (GpioKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;
+    goto Done;
+  }
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_WAIT,
+                  TPL_NOTIFY,
+                  GpioKeyboardWaitForKeyEx,
+                  &(GpioKeyboardPrivate->SimpleTextInputEx),
+                  &(GpioKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)
+                  );
+  if (EFI_ERROR (Status)) {
+    GpioKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;
+    goto Done;
+  }
+
+  //
+  // Setup a periodic timer, used for reading keystrokes at a fixed interval
+  //
+  Status = gBS->CreateEvent (
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  GpioKeyboardTimerHandler,
+                  GpioKeyboardPrivate,
+                  &GpioKeyboardPrivate->TimerEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    Status      = EFI_OUT_OF_RESOURCES;
+    StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+    goto Done;
+  }
+
+  Status = gBS->SetTimer (
+                  GpioKeyboardPrivate->TimerEvent,
+                  TimerPeriodic,
+                  KEYBOARD_TIMER_INTERVAL
+                  );
+  if (EFI_ERROR (Status)) {
+    Status      = EFI_OUT_OF_RESOURCES;
+    StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+    goto Done;
+  }
+
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  KeyNotifyProcessHandler,
+                  GpioKeyboardPrivate,
+                  &GpioKeyboardPrivate->KeyNotifyProcessEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    Status      = EFI_OUT_OF_RESOURCES;
+    StatusCode  = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+    goto Done;
+  }
+
+  //
+  // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system
+  //
+  REPORT_STATUS_CODE (
+    EFI_PROGRESS_CODE,
+    EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT
+    );
+
+  //
+  // Reset the keyboard device
+  //
+  Status = GpioKeyboardPrivate->SimpleTextInputEx.Reset (
+                                                    &GpioKeyboardPrivate->SimpleTextInputEx,
+                                                    FALSE
+                                                    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status));
+    StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
+    goto Done;
+  }
+#if 0
+  //
+  // Do platform specific policy like port swapping and keyboard light default
+  //
+  if (Ps2Policy != NULL) {
+
+    Ps2Policy->Ps2InitHardware (Controller);
+
+    Command = 0;
+    if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {
+      Command |= 4;
+    }
+
+    if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {
+      Command |= 2;
+    }
+
+    if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {
+      Command |= 1;
+    }
+
+    KeyboardWrite (GpioKeyboardPrivate, 0xed);
+    KeyboardWaitForValue (GpioKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);
+    KeyboardWrite (GpioKeyboardPrivate, Command);
+    //
+    // Call Legacy GPIO Protocol to set whatever is necessary
+    //
+    LegacyGpio->UpdateKeyboardLedStatus (LegacyGpio, Command);
+  }
+  //
+  // Get Configuration
+  //
+  Regs.H.AH = 0xc0;
+  CarryFlag = GpioKeyboardPrivate->LegacyGpio->Int86 (
+                                                 GpioKeyboardPrivate->LegacyGpio,
+                                                 0x15,
+                                                 &Regs
+                                                 );
+
+  if (!CarryFlag) {
+    //
+    // Check bit 6 of Feature Byte 2.
+    // If it is set, then Int 16 Func 09 is supported
+    //
+    if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {
+      //
+      // Get Keyboard Functionality
+      //
+      Regs.H.AH = 0x09;
+      CarryFlag = GpioKeyboardPrivate->LegacyGpio->Int86 (
+                                                     GpioKeyboardPrivate->LegacyGpio,
+                                                     0x16,
+                                                     &Regs
+                                                     );
+
+      if (!CarryFlag) {
+        //
+        // Check bit 5 of AH.
+        // If it is set, then INT 16 Finc 10-12 are supported.
+        //
+        if ((Regs.H.AL & 0x40) != 0) {
+          //
+          // Set the flag to use INT 16 Func 10-12
+          //
+          GpioKeyboardPrivate->ExtendedKeyboard = TRUE;
+        }
+      }
+    }
+  }
+  DEBUG ((EFI_D_INFO, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN)GpioKeyboardPrivate->ExtendedKeyboard));
+#endif
+  //
+  // Install protocol interfaces for the keyboard device.
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Controller,
+                  &gEfiSimpleTextInProtocolGuid,
+                  &GpioKeyboardPrivate->SimpleTextIn,
+                  &gEfiSimpleTextInputExProtocolGuid,
+                  &GpioKeyboardPrivate->SimpleTextInputEx,
+                  NULL
+                  );
+
+Done:
+  if (StatusCode != 0) {
+    //
+    // Report an Error Code for failing to start the keyboard device
+    //
+    REPORT_STATUS_CODE (
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,
+      StatusCode
+      );
+  }
+
+  if (EFI_ERROR (Status)) {
+
+    if (GpioKeyboardPrivate != NULL) {
+      if ((GpioKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {
+        gBS->CloseEvent ((GpioKeyboardPrivate->SimpleTextIn).WaitForKey);
+      }
+
+      if ((GpioKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {
+        gBS->CloseEvent ((GpioKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);
+      }
+
+      if (GpioKeyboardPrivate->KeyNotifyProcessEvent != NULL) {
+        gBS->CloseEvent (GpioKeyboardPrivate->KeyNotifyProcessEvent);
+      }
+
+      GpioKeyboardFreeNotifyList (&GpioKeyboardPrivate->NotifyList);
+
+      if (GpioKeyboardPrivate->TimerEvent != NULL) {
+        gBS->CloseEvent (GpioKeyboardPrivate->TimerEvent);
+      }
+      FreePool (GpioKeyboardPrivate);
+    }
+
+Exit:
+    gBS->CloseProtocol (
+           Controller,
+           &gEmbeddedGpioProtocolGuid,
+           This->DriverBindingHandle,
+           Controller
+           );
+  }
+
+  return Status;
+}
+
+/**
+  Stop the device handled by this driver.
+
+  @param  This                   The driver binding protocol.
+  @param  Controller             The controller to release.
+  @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
+  @param  ChildHandleBuffer      The array of child handle.
+
+  @retval EFI_SUCCESS            The device was stopped.
+  @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.
+  @retval Others                 Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Controller,
+  IN  UINTN                        NumberOfChildren,
+  IN  EFI_HANDLE                   *ChildHandleBuffer
+  )
+{
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Enqueue the key.
+
+  @param  Queue                 The queue to be enqueued.
+  @param  KeyData               The key data to be enqueued.
+
+  @retval EFI_NOT_READY         The queue is full.
+  @retval EFI_SUCCESS           Successfully enqueued the key data.
+
+**/
+EFI_STATUS
+Enqueue (
+  IN SIMPLE_QUEUE         *Queue,
+  IN EFI_KEY_DATA         *KeyData
+  )
+{
+  if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {
+    return EFI_NOT_READY;
+  }
+
+  CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
+  Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Dequeue the key.
+
+  @param  Queue                 The queue to be dequeued.
+  @param  KeyData               The key data to be dequeued.
+
+  @retval EFI_NOT_READY         The queue is empty.
+  @retval EFI_SUCCESS           Successfully dequeued the key data.
+
+**/
+EFI_STATUS
+Dequeue (
+  IN SIMPLE_QUEUE         *Queue,
+  IN EFI_KEY_DATA         *KeyData
+  )
+{
+  if (Queue->Front == Queue->Rear) {
+    return EFI_NOT_READY;
+  }
+
+  CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));
+  Queue->Front  = (Queue->Front + 1) % QUEUE_MAX_COUNT;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Check whether the queue is empty.
+
+  @param  Queue                 The queue to be checked.
+
+  @retval EFI_NOT_READY         The queue is empty.
+  @retval EFI_SUCCESS           The queue is not empty.
+
+**/
+EFI_STATUS
+CheckQueue (
+  IN SIMPLE_QUEUE         *Queue
+  )
+{
+  if (Queue->Front == Queue->Rear) {
+    return EFI_NOT_READY;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Check key buffer to get the key stroke status.
+
+  @param  This         Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
+
+  @retval EFI_SUCCESS  A key is being pressed now.
+  @retval Other        No key is now pressed.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardCheckForKey (
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This
+  )
+{
+  GPIO_KEYBOARD_DEV     *GpioKeyboardPrivate;
+
+  GpioKeyboardPrivate = GPIO_KEYBOARD_DEV_FROM_THIS (This);
+
+  return CheckQueue (&GpioKeyboardPrivate->Queue);
+}
+
+/**
+  Free keyboard notify list.
+
+  @param  ListHead   The list head
+
+  @retval EFI_SUCCESS           Free the notify list successfully
+  @retval EFI_INVALID_PARAMETER ListHead is invalid.
+
+**/
+EFI_STATUS
+GpioKeyboardFreeNotifyList (
+  IN OUT LIST_ENTRY           *ListHead
+  )
+{
+  GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
+
+  if (ListHead == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  while (!IsListEmpty (ListHead)) {
+    NotifyNode = CR (
+                   ListHead->ForwardLink,
+                   GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+                   NotifyEntry,
+                   GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+                   );
+    RemoveEntryList (ListHead->ForwardLink);
+    gBS->FreePool (NotifyNode);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Judge whether is a registed key
+
+  @param RegsiteredData       A pointer to a buffer that is filled in with the keystroke
+                              state data for the key that was registered.
+  @param InputData            A pointer to a buffer that is filled in with the keystroke
+                              state data for the key that was pressed.
+
+  @retval TRUE                Key be pressed matches a registered key.
+  @retval FLASE               Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+  IN EFI_KEY_DATA  *RegsiteredData,
+  IN EFI_KEY_DATA  *InputData
+  )
+
+{
+  ASSERT (RegsiteredData != NULL && InputData != NULL);
+
+  if ((RegsiteredData->Key.ScanCode    != InputData->Key.ScanCode) ||
+      (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
+    return FALSE;
+  }
+
+  //
+  // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
+  //
+  if (RegsiteredData->KeyState.KeyShiftState != 0 &&
+      RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
+    return FALSE;
+  }
+  if (RegsiteredData->KeyState.KeyToggleState != 0 &&
+      RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
+    return FALSE;
+  }
+
+  return TRUE;
+
+}
+
+/**
+  Event notification function for SIMPLE_TEXT_IN.WaitForKey event
+  Signal the event if there is key available
+
+  @param Event    the event object
+  @param Context  waitting context
+
+**/
+VOID
+EFIAPI
+GpioKeyboardWaitForKey (
+  IN  EFI_EVENT               Event,
+  IN  VOID                    *Context
+  )
+{
+  //
+  // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
+  // Csm will be used to check whether there is a key pending, but the csm will disable all
+  // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
+  // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
+  // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,
+  // e.g. usb keyboard driver.
+  // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
+  // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
+  //
+  gBS->Stall (1000);
+  //
+  // Use TimerEvent callback function to check whether there's any key pressed
+  //
+  GpioKeyboardTimerHandler (NULL, GPIO_KEYBOARD_DEV_FROM_THIS (Context));
+
+  if (!EFI_ERROR (GpioKeyboardCheckForKey (Context))) {
+    gBS->SignalEvent (Event);
+  }
+}
+
+/**
+  Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
+  Signal the event if there is key available
+
+  @param Event    event object
+  @param Context  waiting context
+
+**/
+VOID
+EFIAPI
+GpioKeyboardWaitForKeyEx (
+  IN  EFI_EVENT               Event,
+  IN  VOID                    *Context
+  )
+
+{
+  GPIO_KEYBOARD_DEV                     *GpioKeyboardPrivate;
+
+  GpioKeyboardPrivate = TEXT_INPUT_EX_GPIO_KEYBOARD_DEV_FROM_THIS (Context);
+  GpioKeyboardWaitForKey (Event, &GpioKeyboardPrivate->SimpleTextIn);
+
+}
+
+//
+// EFI Simple Text In Protocol Functions
+//
+/**
+  Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
+
+  @param  This                  Pointer of simple text Protocol.
+  @param  ExtendedVerification  Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
+
+  @retval EFI_SUCCESS           The command byte is written successfully.
+  @retval EFI_DEVICE_ERROR      Errors occurred during resetting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardReset (
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
+  IN  BOOLEAN                         ExtendedVerification
+  )
+{
+  GPIO_KEYBOARD_DEV *GpioKeyboardPrivate;
+  EFI_STATUS        Status;
+  EFI_TPL           OldTpl;
+  GPIO_KBD_KEY      GpioKeyFirst, *GpioKey = NULL;
+  LIST_ENTRY        *Next = NULL;
+
+  GpioKeyboardPrivate = GPIO_KEYBOARD_DEV_FROM_THIS (This);
+
+  //
+  // Raise TPL to avoid mouse operation impact
+  //
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+  if (GpioKeyboardPrivate->PlatformGpio && GpioKeyboardPrivate->PlatformGpio->Register) {
+    Status = GpioKeyboardPrivate->PlatformGpio->Register (&GpioKeyFirst);
+    if (Status == EFI_SUCCESS) {
+      GpioKey = &GpioKeyFirst;
+      do {
+        Status = GpioKeyboardPrivate->Gpio->Set (GpioKeyboardPrivate->Gpio, GpioKey->Pin, GPIO_MODE_INPUT);
+        ASSERT_EFI_ERROR (Status);
+        Next = &GpioKey->Next;
+        GpioKey = CR (Next, GPIO_KBD_KEY, Next, GPIO_KBD_KEY_NEXT_SIGNATURE);
+      } while (&GpioKeyFirst != GpioKey);
+    }
+  } else {
+    Status = EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // resume priority of task level
+  //
+  gBS->RestoreTPL (OldTpl);
+
+  return Status;
+
+}
+
+/**
+  Reset the input device and optionaly run diagnostics
+
+  @param  This                  Protocol instance pointer.
+  @param  ExtendedVerification  Driver may perform diagnostics on reset.
+
+  @retval EFI_SUCCESS           The device was reset.
+  @retval EFI_DEVICE_ERROR      The device is not functioning properly and could-
+                                not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardResetEx (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
+  IN BOOLEAN                            ExtendedVerification
+  )
+{
+  GPIO_KEYBOARD_DEV                     *GpioKeyboardPrivate;
+  EFI_STATUS                            Status;
+  EFI_TPL                               OldTpl;
+
+  GpioKeyboardPrivate = TEXT_INPUT_EX_GPIO_KEYBOARD_DEV_FROM_THIS (This);
+
+  Status = GpioKeyboardPrivate->SimpleTextIn.Reset (
+                                               &GpioKeyboardPrivate->SimpleTextIn,
+                                               ExtendedVerification
+                                               );
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+  gBS->RestoreTPL (OldTpl);
+
+  return EFI_SUCCESS;
+
+}
+
+/**
+  Reads the next keystroke from the input device. The WaitForKey Event can
+  be used to test for existance of a keystroke via WaitForEvent () call.
+
+  @param  GpioKeyboardPrivate   Gpiokeyboard driver private structure.
+  @param  KeyData               A pointer to a buffer that is filled in with the keystroke
+                                state data for the key that was pressed.
+
+  @retval EFI_SUCCESS           The keystroke information was returned.
+  @retval EFI_NOT_READY         There was no keystroke data availiable.
+  @retval EFI_DEVICE_ERROR      The keystroke information was not returned due to
+                                hardware errors.
+  @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+KeyboardReadKeyStrokeWorker (
+  IN GPIO_KEYBOARD_DEV  *GpioKeyboardPrivate,
+  OUT EFI_KEY_DATA      *KeyData
+  )
+{
+  EFI_STATUS                            Status;
+  EFI_TPL                               OldTpl;
+  if (KeyData == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Use TimerEvent callback function to check whether there's any key pressed
+  //
+
+  //
+  // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
+  // Csm will be used to check whether there is a key pending, but the csm will disable all
+  // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
+  // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
+  // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,
+  // e.g. usb keyboard driver.
+  // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
+  // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
+  //
+  gBS->Stall (1000);
+
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+  GpioKeyboardTimerHandler (NULL, GpioKeyboardPrivate);
+  //
+  // If there's no key, just return
+  //
+  Status = CheckQueue (&GpioKeyboardPrivate->Queue);
+  if (EFI_ERROR (Status)) {
+    gBS->RestoreTPL (OldTpl);
+    return EFI_NOT_READY;
+  }
+
+  Status = Dequeue (&GpioKeyboardPrivate->Queue, KeyData);
+
+  gBS->RestoreTPL (OldTpl);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Read out the scan code of the key that has just been stroked.
+
+  @param  This        Pointer of simple text Protocol.
+  @param  Key         Pointer for store the key that read out.
+
+  @retval EFI_SUCCESS The key is read out successfully.
+  @retval other       The key reading failed.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardReadKeyStroke (
+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,
+  OUT EFI_INPUT_KEY                   *Key
+  )
+{
+  GPIO_KEYBOARD_DEV     *GpioKeyboardPrivate;
+  EFI_STATUS            Status;
+  EFI_KEY_DATA          KeyData;
+
+  GpioKeyboardPrivate = GPIO_KEYBOARD_DEV_FROM_THIS (This);
+
+  Status = KeyboardReadKeyStrokeWorker (GpioKeyboardPrivate, &KeyData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Convert the Ctrl+[a-z] to Ctrl+[1-26]
+  //
+  if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
+    if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
+      KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
+    } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
+      KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
+    }
+  }
+
+  CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Reads the next keystroke from the input device. The WaitForKey Event can
+  be used to test for existance of a keystroke via WaitForEvent () call.
+
+  @param  This         Protocol instance pointer.
+  @param  KeyData      A pointer to a buffer that is filled in with the keystroke
+                       state data for the key that was pressed.
+
+  @retval  EFI_SUCCESS           The keystroke information was returned.
+  @retval  EFI_NOT_READY         There was no keystroke data availiable.
+  @retval  EFI_DEVICE_ERROR      The keystroke information was not returned due to
+                                 hardware errors.
+  @retval  EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardReadKeyStrokeEx (
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  OUT EFI_KEY_DATA                      *KeyData
+  )
+{
+  GPIO_KEYBOARD_DEV                     *GpioKeyboardPrivate;
+
+  if (KeyData == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  GpioKeyboardPrivate = TEXT_INPUT_EX_GPIO_KEYBOARD_DEV_FROM_THIS (This);
+
+  return KeyboardReadKeyStrokeWorker (GpioKeyboardPrivate, KeyData);
+
+}
+
+/**
+  Set certain state for the input device.
+
+  @param  This              Protocol instance pointer.
+  @param  KeyToggleState    A pointer to the EFI_KEY_TOGGLE_STATE to set the-
+                            state for the input device.
+
+  @retval EFI_SUCCESS           The device state was set successfully.
+  @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could-
+                                not have the setting adjusted.
+  @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.
+  @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardSetState (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
+  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState
+  )
+{
+  if (KeyToggleState == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Thunk keyboard driver doesn't support partial keystroke.
+  //
+  if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID ||
+      (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED
+      ) {
+    return EFI_UNSUPPORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Register a notification function for a particular keystroke for the input device.
+
+  @param  This                    Protocol instance pointer.
+  @param  KeyData                 A pointer to a buffer that is filled in with the keystroke
+                                  information data for the key that was pressed.
+  @param  KeyNotificationFunction Points to the function to be called when the key
+                                  sequence is typed specified by KeyData.
+  @param  NotifyHandle            Points to the unique handle assigned to the registered notification.
+
+
+  @retval EFI_SUCCESS             The notification function was registered successfully.
+  @retval EFI_OUT_OF_RESOURCES    Unable to allocate resources for necesssary data structures.
+  @retval EFI_INVALID_PARAMETER   KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardRegisterKeyNotify (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
+  IN EFI_KEY_DATA                       *KeyData,
+  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,
+  OUT VOID                              **NotifyHandle
+  )
+{
+  EFI_STATUS                            Status;
+  GPIO_KEYBOARD_DEV                     *GpioKeyboardPrivate;
+  EFI_TPL                               OldTpl;
+  GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *NewNotify;
+  LIST_ENTRY                            *Link;
+  GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;
+
+  if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  GpioKeyboardPrivate = TEXT_INPUT_EX_GPIO_KEYBOARD_DEV_FROM_THIS (This);
+
+  //
+  // Enter critical section
+  //
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+  //
+  // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
+  //
+  for (Link = GpioKeyboardPrivate->NotifyList.ForwardLink; Link != &GpioKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
+    CurrentNotify = CR (
+                      Link,
+                      GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+                      NotifyEntry,
+                      GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+                      );
+    if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+      if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+        *NotifyHandle = CurrentNotify;
+        Status = EFI_SUCCESS;
+        goto Exit;
+      }
+    }
+  }
+
+  //
+  // Allocate resource to save the notification function
+  //
+
+  NewNotify = (GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY));
+  if (NewNotify == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  NewNotify->Signature         = GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
+  NewNotify->KeyNotificationFn = KeyNotificationFunction;
+  CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+  InsertTailList (&GpioKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);
+
+  *NotifyHandle                = NewNotify;
+  Status                       = EFI_SUCCESS;
+
+Exit:
+  //
+  // Leave critical section and return
+  //
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+
+}
+
+/**
+  Remove a registered notification function from a particular keystroke.
+
+  @param  This                 Protocol instance pointer.
+  @param  NotificationHandle   The handle of the notification function being unregistered.
+
+  @retval EFI_SUCCESS             The notification function was unregistered successfully.
+  @retval EFI_INVALID_PARAMETER   The NotificationHandle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+GpioKeyboardUnregisterKeyNotify (
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
+  IN VOID                               *NotificationHandle
+  )
+{
+  EFI_STATUS                            Status;
+  GPIO_KEYBOARD_DEV                     *GpioKeyboardPrivate;
+  EFI_TPL                               OldTpl;
+  LIST_ENTRY                            *Link;
+  GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;
+
+  //
+  // Check incoming notification handle
+  //
+  if (NotificationHandle == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (((GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  GpioKeyboardPrivate = TEXT_INPUT_EX_GPIO_KEYBOARD_DEV_FROM_THIS (This);
+
+  //
+  // Enter critical section
+  //
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+  for (Link = GpioKeyboardPrivate->NotifyList.ForwardLink; Link != &GpioKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
+    CurrentNotify = CR (
+                      Link,
+                      GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+                      NotifyEntry,
+                      GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+                      );
+    if (CurrentNotify == NotificationHandle) {
+      //
+      // Remove the notification function from NotifyList and free resources
+      //
+      RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+      Status = EFI_SUCCESS;
+      goto Exit;
+    }
+  }
+
+  //
+  // Can not find the specified Notification Handle
+  //
+  Status = EFI_INVALID_PARAMETER;
+
+Exit:
+  //
+  // Leave critical section and return
+  //
+  gBS->RestoreTPL (OldTpl);
+  return Status;
+}
+
+/**
+  Timer event handler: read a series of scancodes from 8042
+  and put them into memory scancode buffer.
+  it read as much scancodes to either fill
+  the memory buffer or empty the keyboard buffer.
+  It is registered as running under TPL_NOTIFY
+
+  @param Event       The timer event
+  @param Context     A KEYBOARD_CONSOLE_IN_DEV pointer
+
+**/
+VOID
+EFIAPI
+GpioKeyboardTimerHandler (
+  IN EFI_EVENT    Event,
+  IN VOID         *Context
+  )
+{
+  EFI_STATUS                         Status;
+  EFI_TPL                            OldTpl;
+  LIST_ENTRY                         *Link;
+  EFI_KEY_DATA                       KeyData;
+  GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+  GPIO_KEYBOARD_DEV                  *GpioKeyboardPrivate;
+  UINTN                              Value;
+  GPIO_KBD_KEY                       GpioKeyFirst, *GpioKey = NULL;
+  LIST_ENTRY                         *Next;
+
+  GpioKeyboardPrivate = Context;
+
+  //
+  // Enter critical section
+  //
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+  if (GpioKeyboardPrivate->PlatformGpio && GpioKeyboardPrivate->PlatformGpio->Register) {
+    Status = GpioKeyboardPrivate->PlatformGpio->Register (&GpioKeyFirst);
+    if (Status == EFI_SUCCESS) {
+      GpioKey = &GpioKeyFirst;
+      do {
+        Status = GpioKeyboardPrivate->Gpio->Get (GpioKeyboardPrivate->Gpio, GpioKey->Pin, &Value);
+        if (EFI_ERROR (Status)) {
+          goto Exit;
+        }
+        if (Value == GpioKey->Value) {
+          KeyData.Key.ScanCode = GpioKey->Key.ScanCode;
+          KeyData.Key.UnicodeChar = GpioKey->Key.UnicodeChar;
+          KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID;
+          KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
+          break;
+        }
+        Next = &GpioKey->Next;
+        GpioKey = CR (Next, GPIO_KBD_KEY, Next, GPIO_KBD_KEY_NEXT_SIGNATURE);
+      } while (&GpioKeyFirst != GpioKey);
+    }
+  } else {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  //
+  // Signal KeyNotify process event if this key pressed matches any key registered.
+  //
+  for (Link = GpioKeyboardPrivate->NotifyList.ForwardLink; Link != &GpioKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
+    CurrentNotify = CR (
+                      Link,
+                      GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+                      NotifyEntry,
+                      GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+                      );
+    if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+      //
+      // The key notification function needs to run at TPL_CALLBACK
+      // while current TPL is TPL_NOTIFY. It will be invoked in
+      // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
+      //
+      Enqueue (&GpioKeyboardPrivate->QueueForNotify, &KeyData);
+      gBS->SignalEvent (GpioKeyboardPrivate->KeyNotifyProcessEvent);
+    }
+  }
+
+  Enqueue (&GpioKeyboardPrivate->Queue, &KeyData);
+
+Exit:
+  //
+  // Leave critical section and return
+  //
+  gBS->RestoreTPL (OldTpl);
+}
+
+/**
+  Process key notify.
+
+  @param  Event                 Indicates the event that invoke this function.
+  @param  Context               Indicates the calling context.
+**/
+VOID
+EFIAPI
+KeyNotifyProcessHandler (
+  IN  EFI_EVENT                 Event,
+  IN  VOID                      *Context
+  )
+{
+  EFI_STATUS                            Status;
+  GPIO_KEYBOARD_DEV                     *GpioKeyboardPrivate;
+  EFI_KEY_DATA                          KeyData;
+  LIST_ENTRY                            *Link;
+  LIST_ENTRY                            *NotifyList;
+  GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY    *CurrentNotify;
+  EFI_TPL                               OldTpl;
+
+  GpioKeyboardPrivate = (GPIO_KEYBOARD_DEV *) Context;
+
+  //
+  // Invoke notification functions.
+  //
+  NotifyList = &GpioKeyboardPrivate->NotifyList;
+  while (TRUE) {
+    //
+    // Enter critical section
+    //
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+    Status = Dequeue (&GpioKeyboardPrivate->QueueForNotify, &KeyData);
+    //
+    // Leave critical section
+    //
+    gBS->RestoreTPL (OldTpl);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+    for (Link = GetFirstNode (NotifyList); !IsNull (NotifyList, Link); Link = GetNextNode (NotifyList, Link)) {
+      CurrentNotify = CR (Link, GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY, NotifyEntry, GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE);
+      if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+        CurrentNotify->KeyNotificationFn (&KeyData);
+      }
+    }
+  }
+}
+
+/**
+  The user Entry Point for module GpioKeyboard. The user code starts with this function.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       The entry point is executed successfully.
+  @retval other             Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeGpioKeyboard(
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  EFI_STATUS              Status;
+
+  //
+  // Install driver model protocol(s).
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gGpioKeyboardDriverBinding,
+             ImageHandle,
+             &gGpioKeyboardComponentName,
+             &gGpioKeyboardComponentName2
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboard.h b/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboard.h
new file mode 100644
index 0000000..3a69e10
--- /dev/null
+++ b/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboard.h
@@ -0,0 +1,638 @@
+/** @file

+

+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>

+Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>

+

+This program and the accompanying materials

+are licensed and made available under the terms and conditions

+of the BSD License which accompanies this distribution.  The

+full text of the license may be found at

+http://opensource.org/licenses/bsd-license.php

+

+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#ifndef _GPIO_KEYBOARD_H_

+#define _GPIO_KEYBOARD_H_

+

+

+#include <Guid/StatusCodeDataTypeId.h>

+#include <Protocol/DevicePath.h>

+#include <Protocol/EmbeddedGpio.h>

+#include <Protocol/PlatformGpioKeyboard.h>

+#include <Protocol/SimpleTextIn.h>

+#include <Protocol/SimpleTextInEx.h>

+

+#include <Library/BaseLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DebugLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/IoLib.h>

+#include <Library/PcdLib.h>

+#include <Library/ReportStatusCodeLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiDriverEntryPoint.h>

+#include <Library/UefiLib.h>

+

+//#include <IndustryStandard/Pci.h>

+

+//

+// Driver Binding Externs

+//

+extern EFI_DRIVER_BINDING_PROTOCOL  gGpioKeyboardDriverBinding;

+extern EFI_COMPONENT_NAME_PROTOCOL  gGpioKeyboardComponentName;

+extern EFI_COMPONENT_NAME2_PROTOCOL gGpioKeyboardComponentName2;

+

+

+//

+// GPIO Keyboard Defines

+//

+#define CHAR_SCANCODE                   0xe0

+#define CHAR_ESC                        0x1b

+

+#define KEYBOARD_TIMEOUT                65536   // 0.07s

+#define KEYBOARD_WAITFORVALUE_TIMEOUT   1000000 // 1s

+#define KEYBOARD_BAT_TIMEOUT            4000000 // 4s

+#define KEYBOARD_TIMER_INTERVAL         500000  // 0.5s

+

+#define QUEUE_MAX_COUNT                 32

+

+//

+// GPIO Keyboard Device Structure

+//

+#define GPIO_KEYBOARD_DEV_SIGNATURE SIGNATURE_32 ('G', 'K', 'B', 'D')

+#define GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('g', 'k', 'c', 'n')

+

+typedef struct _GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY {

+  UINTN                                      Signature;

+  EFI_KEY_DATA                               KeyData;

+  EFI_KEY_NOTIFY_FUNCTION                    KeyNotificationFn;

+  LIST_ENTRY                                 NotifyEntry;

+} GPIO_KEYBOARD_CONSOLE_IN_EX_NOTIFY;

+

+typedef struct {

+  UINTN             Front;

+  UINTN             Rear;

+  EFI_KEY_DATA      Buffer[QUEUE_MAX_COUNT];

+} SIMPLE_QUEUE;

+

+#define KEYBOARD_SCAN_CODE_MAX_COUNT  32

+typedef struct {

+  UINT8                               Buffer[KEYBOARD_SCAN_CODE_MAX_COUNT];

+  UINTN                               Head;

+  UINTN                               Tail;

+} SCAN_CODE_QUEUE;

+

+typedef struct {

+  UINTN                                       Signature;

+  EFI_HANDLE                                  Handle;

+  EMBEDDED_GPIO                               *Gpio;

+  PLATFORM_GPIO_KBD_PROTOCOL                  *PlatformGpio;

+  EFI_SIMPLE_TEXT_INPUT_PROTOCOL              SimpleTextIn;

+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL           SimpleTextInputEx;

+  UINT16                                      DataRegisterAddress;

+  UINT16                                      StatusRegisterAddress;

+  UINT16                                      CommandRegisterAddress;

+  BOOLEAN                                     ExtendedKeyboard;

+

+  //

+  // Buffer storing EFI_KEY_DATA

+  //

+  SIMPLE_QUEUE                                Queue;

+  SIMPLE_QUEUE                                QueueForNotify;

+

+  //

+  // Notification Function List

+  //

+  LIST_ENTRY                                  NotifyList;

+  EFI_EVENT                                   KeyNotifyProcessEvent;

+  EFI_EVENT                                   TimerEvent;

+

+} GPIO_KEYBOARD_DEV;

+

+#define GPIO_KEYBOARD_DEV_FROM_THIS(a)  CR (a, GPIO_KEYBOARD_DEV, SimpleTextIn, GPIO_KEYBOARD_DEV_SIGNATURE)

+#define TEXT_INPUT_EX_GPIO_KEYBOARD_DEV_FROM_THIS(a) \

+  CR (a, \

+      GPIO_KEYBOARD_DEV, \

+      SimpleTextInputEx, \

+      GPIO_KEYBOARD_DEV_SIGNATURE \

+      )

+

+//

+// Global Variables

+//

+extern EFI_DRIVER_BINDING_PROTOCOL   gGpioKeyboardDriverBinding;

+

+//

+// Driver Binding Protocol functions

+//

+

+/**

+  Check whether the driver supports this device.

+

+  @param  This                   The Udriver binding protocol.

+  @param  Controller             The controller handle to check.

+  @param  RemainingDevicePath    The remaining device path.

+

+  @retval EFI_SUCCESS            The driver supports this controller.

+  @retval other                  This device isn't supported.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardDriverBindingSupported (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+/**

+  Starts the device with this driver.

+

+  @param  This                   The driver binding instance.

+  @param  Controller             Handle of device to bind driver to.

+  @param  RemainingDevicePath    Optional parameter use to pick a specific child

+                                 device to start.

+

+  @retval EFI_SUCCESS            The controller is controlled by the driver.

+  @retval Other                  This controller cannot be started.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardDriverBindingStart (

+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN EFI_HANDLE                   Controller,

+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath

+  );

+

+/**

+  Stop the device handled by this driver.

+

+  @param  This                   The driver binding protocol.

+  @param  Controller             The controller to release.

+  @param  NumberOfChildren       The number of handles in ChildHandleBuffer.

+  @param  ChildHandleBuffer      The array of child handle.

+

+  @retval EFI_SUCCESS            The device was stopped.

+  @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.

+  @retval Others                 Fail to uninstall protocols attached on the device.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardDriverBindingStop (

+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,

+  IN  EFI_HANDLE                   Controller,

+  IN  UINTN                        NumberOfChildren,

+  IN  EFI_HANDLE                   *ChildHandleBuffer

+  );

+

+/**

+  Retrieves a Unicode string that is the user readable name of the driver.

+

+  This function retrieves the user readable name of a driver in the form of a

+  Unicode string. If the driver specified by This has a user readable name in

+  the language specified by Language, then a pointer to the driver name is

+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified

+  by This does not support the language specified by Language,

+  then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language. This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified

+                                in RFC 4646 or ISO 639-2 language code format.

+

+  @param  DriverName[out]       A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                driver specified by This in the language

+                                specified by Language.

+

+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by

+                                This and the language specified by Language was

+                                returned in DriverName.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER DriverName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardComponentNameGetDriverName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,

+  IN  CHAR8                        *Language,

+  OUT CHAR16                       **DriverName

+  );

+

+

+/**

+  Retrieves a Unicode string that is the user readable name of the controller

+  that is being managed by a driver.

+

+  This function retrieves the user readable name of the controller specified by

+  ControllerHandle and ChildHandle in the form of a Unicode string. If the

+  driver specified by This has a user readable name in the language specified by

+  Language, then a pointer to the controller name is returned in ControllerName,

+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently

+  managing the controller specified by ControllerHandle and ChildHandle,

+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not

+  support the language specified by Language, then EFI_UNSUPPORTED is returned.

+

+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or

+                                EFI_COMPONENT_NAME_PROTOCOL instance.

+

+  @param  ControllerHandle[in]  The handle of a controller that the driver

+                                specified by This is managing.  This handle

+                                specifies the controller whose name is to be

+                                returned.

+

+  @param  ChildHandle[in]       The handle of the child controller to retrieve

+                                the name of.  This is an optional parameter that

+                                may be NULL.  It will be NULL for device

+                                drivers.  It will also be NULL for a bus drivers

+                                that wish to retrieve the name of the bus

+                                controller.  It will not be NULL for a bus

+                                driver that wishes to retrieve the name of a

+                                child controller.

+

+  @param  Language[in]          A pointer to a Null-terminated ASCII string

+                                array indicating the language.  This is the

+                                language of the driver name that the caller is

+                                requesting, and it must match one of the

+                                languages specified in SupportedLanguages. The

+                                number of languages supported by a driver is up

+                                to the driver writer. Language is specified in

+                                RFC 4646 or ISO 639-2 language code format.

+

+  @param  ControllerName[out]   A pointer to the Unicode string to return.

+                                This Unicode string is the name of the

+                                controller specified by ControllerHandle and

+                                ChildHandle in the language specified by

+                                Language from the point of view of the driver

+                                specified by This.

+

+  @retval EFI_SUCCESS           The Unicode string for the user readable name in

+                                the language specified by Language for the

+                                driver specified by This was returned in

+                                DriverName.

+

+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.

+

+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid

+                                EFI_HANDLE.

+

+  @retval EFI_INVALID_PARAMETER Language is NULL.

+

+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently

+                                managing the controller specified by

+                                ControllerHandle and ChildHandle.

+

+  @retval EFI_UNSUPPORTED       The driver specified by This does not support

+                                the language specified by Language.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardComponentNameGetControllerName (

+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,

+  IN  EFI_HANDLE                                      ControllerHandle,

+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,

+  IN  CHAR8                                           *Language,

+  OUT CHAR16                                          **ControllerName

+  );

+

+

+//

+// Simple Text Input Protocol functions

+//

+/**

+  Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.

+

+  @param  This                  Pointer of simple text Protocol.

+  @param  ExtendedVerification  Whether perform the extra validation of keyboard. True: perform; FALSE: skip.

+

+  @retval EFI_SUCCESS           The command byte is written successfully.

+  @retval EFI_DEVICE_ERROR      Errors occurred during resetting keyboard.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardReset (

+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,

+  IN  BOOLEAN                         ExtendedVerification

+  );

+

+/**

+  Reset the input device and optionaly run diagnostics

+

+  @param  This                  Protocol instance pointer.

+  @param  ExtendedVerification  Driver may perform diagnostics on reset.

+

+  @retval EFI_SUCCESS           The device was reset.

+  @retval EFI_DEVICE_ERROR      The device is not functioning properly and could 

+                                not be reset.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardResetEx (

+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,

+  IN BOOLEAN                            ExtendedVerification

+  );

+

+/**

+  Set certain state for the input device.

+

+  @param  This              Protocol instance pointer.

+  @param  KeyToggleState    A pointer to the EFI_KEY_TOGGLE_STATE to set the

+                            state for the input device.

+

+  @retval EFI_SUCCESS           The device state was set successfully.

+  @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could

+                                not have the setting adjusted.

+  @retval EFI_UNSUPPORTED       The device does not have the ability to set its state.

+  @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardSetState (

+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,

+  IN EFI_KEY_TOGGLE_STATE               *KeyToggleState

+  );

+

+/**

+  Register a notification function for a particular keystroke for the input device.

+

+  @param  This                    Protocol instance pointer.

+  @param  KeyData                 A pointer to a buffer that is filled in with the keystroke

+                                  information data for the key that was pressed.

+  @param  KeyNotificationFunction Points to the function to be called when the key

+                                  sequence is typed specified by KeyData.

+  @param  NotifyHandle            Points to the unique handle assigned to the registered notification.

+

+

+  @retval EFI_SUCCESS             The notification function was registered successfully.

+  @retval EFI_OUT_OF_RESOURCES    Unable to allocate resources for necesssary data structures.

+  @retval EFI_INVALID_PARAMETER   KeyData or NotifyHandle is NULL.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardRegisterKeyNotify (

+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,

+  IN EFI_KEY_DATA                       *KeyData,

+  IN EFI_KEY_NOTIFY_FUNCTION            KeyNotificationFunction,

+  OUT VOID                              **NotifyHandle

+  );

+

+/**

+  Remove a registered notification function from a particular keystroke.

+

+  @param  This                 Protocol instance pointer.

+  @param  NotificationHandle   The handle of the notification function being unregistered.

+

+  @retval EFI_SUCCESS             The notification function was unregistered successfully.

+  @retval EFI_INVALID_PARAMETER   The NotificationHandle is invalid.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardUnregisterKeyNotify (

+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,

+  IN VOID                               *NotificationHandle

+  );

+

+//

+// Private worker functions

+//

+/**

+  Free keyboard notify list.

+

+  @param  ListHead   The list head

+

+  @retval EFI_SUCCESS           Free the notify list successfully

+  @retval EFI_INVALID_PARAMETER ListHead is invalid.

+

+**/

+EFI_STATUS

+GpioKeyboardFreeNotifyList (

+  IN OUT LIST_ENTRY           *ListHead

+  );

+

+/**

+  Check if key is registered.

+

+  @param  RegsiteredData    A pointer to a buffer that is filled in with the keystroke

+                            state data for the key that was registered.

+  @param  InputData         A pointer to a buffer that is filled in with the keystroke

+                            state data for the key that was pressed.

+

+  @retval TRUE              Key be pressed matches a registered key.

+  @retval FLASE             Match failed.

+

+**/

+BOOLEAN

+IsKeyRegistered (

+  IN EFI_KEY_DATA  *RegsiteredData,

+  IN EFI_KEY_DATA  *InputData

+  );

+

+/**

+  Waiting on the keyboard event, if there's any key pressed by the user, signal the event

+

+  @param  Event       The event that be siganlled when any key has been stroked.

+  @param  Context     Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.

+

+**/

+VOID

+EFIAPI

+GpioKeyboardWaitForKey (

+  IN  EFI_EVENT  Event,

+  IN  VOID       *Context

+  );

+

+/**

+  Waiting on the keyboard event, if there's any key pressed by the user, signal the event

+

+  @param  Event    The event that be siganlled when any key has been stroked.

+  @param  Context  Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.

+

+**/

+VOID

+EFIAPI

+GpioKeyboardWaitForKeyEx (

+  IN  EFI_EVENT  Event,

+  IN  VOID       *Context

+  );

+

+/**

+  Timer event handler: read a series of key stroke from 8042

+  and put them into memory key buffer.

+  It is registered as running under TPL_NOTIFY

+

+  @param  Event   The timer event

+  @param  Context A GPIO_KEYBOARD_DEV pointer

+

+**/

+VOID

+EFIAPI

+GpioKeyboardTimerHandler (

+  IN EFI_EVENT    Event,

+  IN VOID         *Context

+  );

+

+/**

+  Process key notify.

+

+  @param  Event                 Indicates the event that invoke this function.

+  @param  Context               Indicates the calling context.

+**/

+VOID

+EFIAPI

+KeyNotifyProcessHandler (

+  IN  EFI_EVENT                 Event,

+  IN  VOID                      *Context

+  );

+

+/**

+  Read out the scan code of the key that has just been stroked.

+

+  @param  This        Pointer of simple text Protocol.

+  @param  Key         Pointer for store the key that read out.

+

+  @retval EFI_SUCCESS The key is read out successfully.

+  @retval other       The key reading failed.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardReadKeyStroke (

+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This,

+  OUT EFI_INPUT_KEY                   *Key

+  );

+

+/**

+  Reads the next keystroke from the input device. The WaitForKey Event can

+  be used to test for existance of a keystroke via WaitForEvent () call.

+

+  @param  This         Protocol instance pointer.

+  @param  KeyData      A pointer to a buffer that is filled in with the keystroke

+                       state data for the key that was pressed.

+

+  @retval  EFI_SUCCESS           The keystroke information was returned.

+  @retval  EFI_NOT_READY         There was no keystroke data availiable.

+  @retval  EFI_DEVICE_ERROR      The keystroke information was not returned due to

+                                 hardware errors.

+  @retval  EFI_INVALID_PARAMETER KeyData is NULL.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardReadKeyStrokeEx (

+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,

+  OUT EFI_KEY_DATA                      *KeyData

+  );

+

+#if 0

+/**

+  Check key buffer to get the key stroke status.

+

+  @param  This         Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.

+

+  @retval EFI_SUCCESS  A key is being pressed now.

+  @retval Other        No key is now pressed.

+

+**/

+EFI_STATUS

+EFIAPI

+GpioKeyboardCheckForKey (

+  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *This

+  );

+

+/**

+  Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.

+

+  @param  KeyChar      Unicode of key.

+  @param  ScanCode     Scan code of key.

+

+  @return The value of EFI Scancode for the key.

+  @retval SCAN_NULL   No corresponding value in the EFI convert table is found for the key.

+

+**/

+UINT16

+ConvertToEFIScanCode (

+  IN  CHAR16  KeyChar,

+  IN  UINT16  ScanCode

+  );

+

+/**

+  Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command

+  If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device

+  should not be in system.

+

+  @param  GpioKeyboardPrivate  Keyboard Private Data Struture

+

+  @retval TRUE  Keyboard in System.

+  @retval FALSE Keyboard not in System.

+

+**/

+BOOLEAN

+CheckKeyboardConnect (

+  IN  GPIO_KEYBOARD_DEV     *GpioKeyboardPrivate

+  );

+

+/**

+  Wait for a specific value to be presented in

+  Data register of Keyboard Controller by keyboard and then read it,

+  used in keyboard commands ack

+

+  @param   GpioKeyboardPrivate  Keyboard instance pointer.

+  @param   Value                The value to be waited for

+  @param   WaitForValueTimeOut  The limit of microseconds for timeout

+

+  @retval  EFI_SUCCESS          The command byte is written successfully.

+  @retval  EFI_TIMEOUT          Timeout occurred during writing.

+

+**/

+EFI_STATUS

+KeyboardWaitForValue (

+  IN GPIO_KEYBOARD_DEV  *GpioKeyboardPrivate,

+  IN UINT8              Value,

+  IN UINTN              WaitForValueTimeOut

+  );

+

+/**

+  Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.

+

+  @param   GpioKeyboardPrivate  Keyboard instance pointer.

+  @param   Data                 Data byte to write.

+

+  @retval  EFI_SUCCESS          The data byte is written successfully.

+  @retval  EFI_TIMEOUT          Timeout occurred during writing.

+

+**/

+EFI_STATUS

+KeyboardWrite (

+  IN GPIO_KEYBOARD_DEV  *GpioKeyboardPrivate,

+  IN UINT8              Data

+  );

+

+#endif

+

+#endif /* _GPIO_KEYBOARD_H_ */

diff --git a/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboardDxe.dec b/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboardDxe.dec
new file mode 100644
index 0000000..9e8d047
--- /dev/null
+++ b/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboardDxe.dec
@@ -0,0 +1,39 @@
+#/** @file
+# Framework Module Development Environment Industry Standards
+#
+# This Package provides headers and libraries that conform to EFI/PI Industry standards.
+# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2017, Linaro. All rights reserved.<BR>
+#
+#    This program and the accompanying materials are licensed and made available under
+#    the terms and conditions of the BSD License which accompanies this distribution.
+#    The full text of the license may be found at
+#    http://opensource.org/licenses/bsd-license.php
+#
+#    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+  DEC_SPECIFICATION              = 0x00010019
+  PACKAGE_NAME                   = GpioKeyboardDxePkg
+  PACKAGE_GUID                   = 45acb94c-bc65-45a1-885e-47307ddd89b3
+  PACKAGE_VERSION                = 0.1
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+#                   Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+#  BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+#
+################################################################################
+
+[Guids.common]
+  gGpioKeyboardDxeTokenSpaceGuid    = { 0x0d5afb45, 0x569e, 0x418d, { 0xb9, 0xf8, 0x9c, 0x09, 0x97, 0xf0, 0x1f, 0x25 }}
+
+[Protocols.common]
+  gPlatformGpioKeyboardProtocolGuid = { 0x9b6be5c6, 0x93d1, 0x4a30, { 0x84, 0xdf, 0x97, 0xa5, 0x63, 0x46, 0x5b, 0x14 }}
diff --git a/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboardDxe.inf b/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboardDxe.inf
new file mode 100644
index 0000000..77db007
--- /dev/null
+++ b/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboardDxe.inf
@@ -0,0 +1,62 @@
+## @file
+# Gpio Keyboard driver.
+#
+# Copyright (c) 2017, Linaro Ltd. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution.  The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010019
+  BASE_NAME                      = GpioKeyboardDxe
+  FILE_GUID                      = d1927a35-11fa-44d0-9d91-dace09225d8d
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeGpioKeyboard
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = AARCH64
+#
+#  DRIVER_BINDING                = gGpioKeyboardDriverBinding
+#  COMPONENT_NAME                = gGpioKeyboardComponentName
+#
+
+[Sources.common]
+  ComponentName.c
+  GpioKeyboard.c
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  OpenPlatformPkg/Drivers/Keyboard/GpioKeyboardDxe/GpioKeyboardDxe.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  IoLib
+  ReportStatusCodeLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  UefiLib
+
+[Protocols]
+  gEfiDriverBindingProtocolGuid
+  gEfiSimpleTextInProtocolGuid
+  gEfiSimpleTextInputExProtocolGuid
+  gEmbeddedGpioProtocolGuid
+  gPlatformGpioKeyboardProtocolGuid
+
+[Depex]
+  TRUE
diff --git a/Include/Protocol/PlatformGpioKeyboard.h b/Include/Protocol/PlatformGpioKeyboard.h
new file mode 100644
index 0000000..a6c0de1
--- /dev/null
+++ b/Include/Protocol/PlatformGpioKeyboard.h
@@ -0,0 +1,49 @@
+/** @file
+
+  Copyright (c) 2017, Linaro. All rights reserved.
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PLATFORM_GPIO_KEYBOARD_H__
+#define __PLATFORM_GPIO_KEYBOARD_H__
+
+#include <Protocol/EmbeddedGpio.h>
+
+//
+// Protocol interface structure
+//
+typedef struct _PLATFORM_GPIO_KBD_PROTOCOL  PLATFORM_GPIO_KBD_PROTOCOL;
+
+typedef struct _GPIO_KBD_KEY                GPIO_KBD_KEY;
+
+#define GPIO_KBD_KEY_NEXT_SIGNATURE SIGNATURE_32 ('g', 'k', 'b', 'd')
+
+struct _GPIO_KBD_KEY {
+  UINTN                                     Signature;
+  EMBEDDED_GPIO_PIN                         Pin;
+  UINT32                                    Value;
+  EFI_INPUT_KEY                             Key;
+  LIST_ENTRY                                Next;
+};
+
+typedef
+EFI_STATUS
+(EFIAPI *PLATFORM_GPIO_KBD_REGISTER) (
+  IN OUT GPIO_KBD_KEY                       *GpioKey
+  );
+
+struct _PLATFORM_GPIO_KBD_PROTOCOL {
+  PLATFORM_GPIO_KBD_REGISTER                Register;
+};
+
+extern EFI_GUID gPlatformGpioKeyboardProtocolGuid;
+
+#endif /* __PLATFORM_GPIO_KEYBOARD_H__ */