public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips
       [not found] ` <20190819133200.14577-2-andy.hayes@displaylink.com>
@ 2019-08-30 15:27   ` Leif Lindholm
  2019-09-09  8:06     ` [External] " Andy Hayes
                       ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Leif Lindholm @ 2019-08-30 15:27 UTC (permalink / raw)
  To: Andy Hayes; +Cc: devel, Michael D Kinney, Ni, Ray

Hi Andy,

This looks fine to me - all my feedback has been addressed.
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>

Ray - did you have any comments on this, or can I go ahead and commit?

Best Regards,

Leif

On Mon, Aug 19, 2019 at 02:32:00PM +0100, Andy Hayes wrote:
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Signed-off-by: Andy Hayes <andy.hayes@displaylink.com>
> ---
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c |  137 +++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c        |  235 +++++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf  |   65 ++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c                 |  598 +++++++++++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h                 |  129 +++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c                  |  578 +++++++++++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c       |  145 +++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h       |  109 ++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c       | 1082 ++++++++++++++++++++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h       |  278 +++++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c          |  180 ++++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c           |  254 +++++
>  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc                    |   61 ++
>  Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md                             |   77 ++
>  Maintainers.txt                                                          |    5 +
>  15 files changed, 3933 insertions(+)
> 
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> new file mode 100644
> index 000000000000..4bfadd770b81
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> @@ -0,0 +1,137 @@
> +/** @file CapabilityDescriptor.c
> + * @brief Definitions for reading USB capability descriptor DisplayLink dock
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +#include "UsbDescriptors.h"
> +
> +/**
> + * Check that the Capability Descriptor is valid and hasn't been tampered with.
> + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> + * @param Length
> + * @param out
> + * @return
> + */
> +STATIC EFI_STATUS
> +ValidateHeader (
> +    CONST IN VOID* Data,
> +    IN UINTN Length,
> +    OUT CONST VendorDescriptorGeneric** Out
> +    )
> +{
> +  if (Length < sizeof (VendorDescriptorGeneric)) {
> +    DEBUG ((DEBUG_ERROR, "Data too short (%d bytes) for capability descriptor header section\n", Length));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  CONST VendorDescriptorGeneric* Desc = (VendorDescriptorGeneric*)Data;
> +  if (Desc->Length > Length) {
> +    DEBUG ((DEBUG_ERROR, "Capability descriptor: Descriptor (%d bytes) exceeds buffer (%d bytes)\n",
> +          Length, Desc->Length));
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +  if (Desc->Type != DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY) {
> +    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid type (0x%08x)\n", Desc->Type));
> +    return EFI_UNSUPPORTED;
> +  }
> +  if (Desc->CapabilityVersion != 1) {
> +    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid version (%d)\n", Desc->CapabilityVersion));
> +    return EFI_INCOMPATIBLE_VERSION;
> +  }
> +  // Capability length must fit within remaining space
> +  if (Desc->CapabilityLength > (Desc->Length - (sizeof (Desc->Length) + sizeof (Desc->Type)))) {
> +    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid CapabilityLength (%d)\n", Desc->CapabilityLength));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  *Out = Desc;
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> + * Check that the connected DisplayLink device supports the functionality that this driver requires, e.g. video formats
> + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> + * @param Length
> + * @param Output
> + * @return
> + */
> +EFI_STATUS
> +UsbDisplayLinkParseCapabilitiesDescriptor (
> +    CONST IN VOID* Data,
> +    IN UINTN Length,
> +    OUT VendorDescriptor* Output
> +    )
> +{
> +  CONST VendorDescriptorGeneric* Desc;
> +  EFI_STATUS Status;
> +
> +  Desc = NULL;
> +  Status = ValidateHeader (Data, Length, &Desc);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  // Default capabilities
> +  Output->Capabilities1 = 0;
> +
> +  CONST UINTN CapsHeaderLength = sizeof (Desc->CapabilityVersion) + sizeof (Desc->CapabilityLength);
> +  ASSERT (CapsHeaderLength < MAX_UINT8);
> +
> +  UINTN DataRemaining;
> +  UINTN Offset;
> +
> +  DataRemaining = Desc->CapabilityLength - CapsHeaderLength;
> +  Offset = 0;
> +
> +  while (DataRemaining >= sizeof (DescriptorKLV)) {
> +    CONST DescriptorKLV* KeyHeader = (CONST DescriptorKLV*)(Desc->Klv + Offset);
> +    CONST UINTN KeyValueSize = sizeof (DescriptorKLV) + KeyHeader->Length;
> +    if (KeyValueSize > DataRemaining) {
> +      DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid value Length (%d)\n", Desc->CapabilityLength));
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    switch (KeyHeader->Key) {
> +      case CAPABILITIES1_KEY: {
> +        if (KeyHeader->Length != CAPABILITIES1_LENGTH) {
> +          DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid length (%d) for Capabilities 1\n", KeyHeader->Length));
> +          return EFI_INVALID_PARAMETER;
> +        }
> +        Output->Capabilities1 = *(UINT32*)KeyHeader->Value;
> +        break;
> +      default:
> +        // Ignore unknown types
> +        break;
> +      }
> +    }
> +    DataRemaining -= KeyValueSize;
> +    Offset += KeyValueSize;
> +  }
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> + * Check that the DisplayLink device supports the basic level of functionality to display GOP pixels.
> + * @param Descriptor The USB descriptor received from the DisplayLink device
> + * @return True we can bind, False we can't
> + */
> +BOOLEAN
> +UsbDisplayLinkCapabilitiesSufficientToBind (
> +    CONST IN VendorDescriptor* Descriptor
> +    )
> +{
> +  BOOLEAN Sufficient;
> +  Sufficient = (BOOLEAN)(Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL);
> +
> +  if (Sufficient == FALSE) {
> +    DEBUG ((DEBUG_ERROR, "DisplayLink device does not report support for base capabilites - reports x%x, required x%x\n", Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL));
> +  }
> +  return Sufficient;
> +}
> +
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> new file mode 100644
> index 000000000000..74498f339eb7
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> @@ -0,0 +1,235 @@
> +/**
> + * @file ComponentName.c
> + * @brief UEFI Component Name protocol implementation for USB DisplayLink driver.
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +);
> +
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> +  IN  EFI_HANDLE                                      ControllerHandle,
> +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> +  IN  CHAR8                                           *Language,
> +  OUT CHAR16                                          **ControllerName
> +);
> +
> +
> +//
> +// EFI Component Name Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  mUsbDisplayLinkComponentName = {
> +  UsbDisplayLinkComponentNameGetDriverName,
> +  UsbDisplayLinkComponentNameGetControllerName,
> +  "eng"
> +};
> +
> +//
> +// EFI Component Name 2 Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplayLinkComponentName2 = {
> +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbDisplayLinkComponentNameGetDriverName,
> +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbDisplayLinkComponentNameGetControllerName,
> +  "en"
> +};
> +
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbDisplayLinkDriverNameTable[] = {
> +  { (CHAR8*)"eng;en", (CHAR16*)L"DisplayLink USB GOP Driver" },
> +  { (CHAR8*)NULL , (CHAR16*)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                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param  Language              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            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
> +UsbDisplayLinkComponentNameGetDriverName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> +  IN  CHAR8                        *Language,
> +  OUT CHAR16                       **DriverName
> +  )
> +{
> +  return LookupUnicodeString2 (
> +           Language,
> +           This->SupportedLanguages,
> +           mUsbDisplayLinkDriverNameTable,
> +           DriverName,
> +           (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> +}
> +
> +/**
> +  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                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> +  @param  ControllerHandle      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           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              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        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 not a valid EFI_HANDLE.
> +  @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
> +UsbDisplayLinkComponentNameGetControllerName (
> +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> +  IN  EFI_HANDLE                                      ControllerHandle,
> +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> +  IN  CHAR8                                           *Language,
> +  OUT CHAR16                                          **ControllerName
> +  )
> +{
> +  EFI_STATUS                   Status;
> +  USB_DISPLAYLINK_DEV          *UsbDisplayLinkDev;
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
> +  EFI_USB_IO_PROTOCOL          *UsbIoProtocol;
> +
> +  //
> +  // This is a device driver, so ChildHandle must be NULL.
> +  //
> +  if (ChildHandle != NULL) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Check Controller's handle
> +  //
> +  Status = gBS->OpenProtocol  (
> +                  ControllerHandle,
> +                  &gEfiUsbIoProtocolGuid,
> +                  (VOID **) &UsbIoProtocol,
> +                  gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER);
> +
> +  if (!EFI_ERROR (Status)) {
> +    gBS->CloseProtocol  (
> +           ControllerHandle,
> +           &gEfiUsbIoProtocolGuid,
> +           gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> +           ControllerHandle);
> +
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (Status != EFI_ALREADY_STARTED) {
> +    return EFI_UNSUPPORTED;
> +  }
> +  //
> +  // Get the device context
> +  //
> +  Status = gBS->OpenProtocol (
> +                  ControllerHandle,
> +                  &gEfiGraphicsOutputProtocolGuid,
> +                  (VOID**)&GraphicsOutputProtocol,
> +                  gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> +                  ControllerHandle,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> +
> +  return LookupUnicodeString2 (
> +           Language,
> +           This->SupportedLanguages,
> +           UsbDisplayLinkDev->ControllerNameTable,
> +           ControllerName,
> +           (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> +}
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> new file mode 100644
> index 000000000000..0f458fedcc88
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> @@ -0,0 +1,65 @@
> +#/** @file
> +# USB DisplayLink driver that implements blt and EDID commands
> +#
> +# USB DisplayLink driver consumes I/O Protocol and Device Path Protocol, and produces
> +# Graphics Output Protocol on DisplayLink devices.
> +# 1. DisplayLink reference
> +# 2. UEFI Specification, v2.1
> +#
> +#  Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = DisplayLinkGop
> +  FILE_GUID                      = 2D2E62AA-9ECF-43b7-8219-94E7FC713DFF
> +  MODULE_TYPE                    = UEFI_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = UsbDisplayLinkDriverBindingEntryPoint
> +  UNLOAD_IMAGE                   = UsbDisplayLinkDriverCombinedGopUnload
> +  INF_DRIVER_VERSION             = 0x00000001
> +
> +[Sources]
> +  CapabilityDescriptor.c
> +  ComponentName.c
> +  Edid.c
> +  Edid.h
> +  Gop.c
> +  UsbDescriptors.c
> +  UsbDescriptors.h
> +  UsbDisplayLink.c
> +  UsbDisplayLink.h
> +  UsbTransfer.c
> +  VideoModes.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +  ReportStatusCodeLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiLib
> +  UefiUsbLib
> +
> +[Protocols]
> +  gEfiUsbIoProtocolGuid                         ## TO_START
> +  gEfiEdidActiveProtocolGuid                    # PROTOCOL BY_START
> +  gEfiEdidDiscoveredProtocolGuid                # PROTOCOL BY_START
> +  gEfiEdidOverrideProtocolGuid                  # PROTOCOL TO_START
> +  gEfiHiiDatabaseProtocolGuid
> +  gEfiHiiFontProtocolGuid
> +
> +[Guids]
> +  gEfiEventExitBootServicesGuid
> +  gEfiGlobalVariableGuid
> +
> +[Pcd]
> +  gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize     ## CONSUMES
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> new file mode 100644
> index 000000000000..21f4b7d9c736
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> @@ -0,0 +1,598 @@
> +/** @file Edid.c
> + * @brief Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +#include "Edid.h"
> +
> +CONST UINT8 ExpectedEdidHeader[EDID_HEADER_SIZE] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
> +
> +//
> +// Standard timing defined by VESA EDID
> +//
> +CONST EDID_TIMING EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES][8] = {
> +  //
> +  // Established Timing I
> +  //
> +  {
> +    { 800, 600, 60 },
> +    { 800, 600, 56 },
> +    { 640, 480, 75 },
> +    { 640, 480, 72 },
> +    { 640, 480, 67 },
> +    { 640, 480, 60 },
> +    { 720, 400, 88 },
> +    { 720, 400, 70 },
> +  },
> +  {
> +    //
> +    // Established Timing II
> +    //
> +    { 1280, 1024, 75 },
> +    { 1024,  768, 75 },
> +    { 1024,  768, 70 },
> +    { 1024,  768, 60 },
> +    { 1024,  768, 87 },
> +    { 832,   624, 75 },
> +    { 800,   600, 75 },
> +    { 800,   600, 72 },
> +  },
> +  //
> +  // Established Timing III
> +  //
> +  {
> +    { 1152, 870, 75 },
> +    { 0, 0, 0 },
> +    { 0, 0, 0 },
> +    { 0, 0, 0 },
> +    { 0, 0, 0 },
> +    { 0, 0, 0 },
> +    { 0, 0, 0 },
> +    { 0, 0, 0 },
> +  }
> +};
> +
> +/**
> + * Requests the monitor EDID data from the connected DisplayLink device
> + * @param UsbDisplayLinkDev
> + * @param EdidDataBlock
> + * @param EdidSize
> + * @retval EFI_DEVICE_ERROR - No EDID received, or EDID is corrupted
> + * @retval EFI_OUT_OF_RESOURCES - Cannot allocate memory
> + * @retval EFI_SUCCESS
> + *
> + */
> +STATIC EFI_STATUS
> +ReadEdidData (
> +  IN USB_DISPLAYLINK_DEV      *UsbDisplayLinkDev,
> +  OUT UINT8                    **EdidDataBlock,
> +  OUT UINTN                    *EdidSize
> +)
> +{
> +  EFI_STATUS Status;
> +
> +  UINT8 EdidDataRead[EDID_BLOCK_SIZE];
> +  UINT8 *EdidData = EdidDataRead;
> +  UINT8* ValidEdid;
> +
> +  Status = DlUsbSendControlReadMessage (UsbDisplayLinkDev, GET_OUTPUT_EDID, 0, EdidDataRead, sizeof (EdidDataRead));
> +
> +  if (EFI_ERROR (Status) || (EdidData[0] != 0)) {
> +    DEBUG ((DEBUG_ERROR, "No monitor EDID received from DisplayLink device - System error %r, EDID error %d. Monitor connected correctly?\n", Status, EdidData[0]));
> +    return EFI_DEVICE_ERROR;
> +  } else {
> +    //
> +    // Search for the EDID signature
> +    //
> +    ValidEdid = &EdidData[0];
> +    CONST UINT64 Signature = 0x00ffffffffffff00ull;
> +    if (CompareMem (ValidEdid, &Signature, 8) != 0) {
> +      //
> +      // No EDID signature found
> +      //
> +      DEBUG ((DEBUG_ERROR, "Monitor EDID received from DisplayLink device did not have a valid signature - corrupted?\n"));
> +      Status = EFI_DEVICE_ERROR;
> +      return Status;
> +    }
> +  }
> +
> +  *EdidDataBlock = (UINT8*)AllocateCopyPool (
> +    EDID_BLOCK_SIZE,
> +    ValidEdid);
> +
> +  if (*EdidDataBlock == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Currently only support EDID 1.x
> +  //
> +  *EdidSize = EDID_BLOCK_SIZE;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +Calculates the mod256 checksum of the EDID and compares it with the one supplied at the end of the EDID
> +@param  EDID        Pointer to the 128-byte EDID
> +@retval TRUE        The EDID checksum is correct
> +**/
> +BOOLEAN
> +IsEdidChecksumCorrect (
> +    CONST VOID *EDID
> +    )
> +{
> +  CONST UINT8 EdidChecksum = ((UINT8 *)EDID)[EDID_BLOCK_SIZE - 1];
> +  UINT8 CalculatedChecksum;
> +
> +  CalculatedChecksum = 0;
> +
> +  UINTN i;
> +  for (i = 0; i < EDID_BLOCK_SIZE - 1; i++) {
> +    CalculatedChecksum += ((UINT8 *)EDID)[i];
> +  }
> +  CalculatedChecksum = 0 - CalculatedChecksum;
> +
> +  return (CalculatedChecksum == EdidChecksum);
> +}
> +
> +/**
> +Check if a particular video mode is in the Established Timings section of the EDID.
> +
> +@param  EDID        Pointer to the 128-byte EDID
> +@param  hRes        Horizontal resolution
> +@param  vRes        Vertical resolution
> +@param  refresh     Refresh rate
> +@retval TRUE        The requested mode is present in the Established Timings section
> +
> +**/
> +STATIC BOOLEAN
> +IsModeInEstablishedTimings (
> +    IN CONST VOID *EDID,
> +    IN UINT16 HRes,
> +    IN UINT16 VRes,
> +    IN UINT16 Refresh
> +    )
> +{
> +  CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> +  BOOLEAN ModeSupported;
> +
> +  ModeSupported = FALSE;
> +
> +  int EstByteNum;
> +  int BitNum;
> +  for (EstByteNum = 0; EstByteNum < EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES; EstByteNum++) {
> +    for (BitNum = 0; BitNum < 8; BitNum++) {
> +      if (pEDID->EstablishedTimings[EstByteNum] & (1 << BitNum)) { // The bit is set in the established timings of the EDID
> +
> +        if ((EstablishedTimings[EstByteNum][BitNum].HRes == HRes) && // The passed-in resolution matches the resolution represented by the set bit
> +          (EstablishedTimings[EstByteNum][BitNum].VRes == VRes) &&
> +          (EstablishedTimings[EstByteNum][BitNum].Refresh == Refresh)) {
> +
> +          ModeSupported = TRUE;
> +          break;
> +        }
> +      }
> +    }
> +    if (ModeSupported == TRUE) {
> +      break;
> +    }
> +  }
> +  return ModeSupported;
> +}
> +
> +/**
> +Extract the resolutions and refresh rate from one of the entries in the Standard Timings section of the EDID.
> +
> +@param  EDID          Pointer to the 128-byte EDID
> +@param  timingNumber  The entry that we want to extract
> +@param  hRes          Output - Horizontal resolution
> +@param  vRes          Output - Vertical resolution
> +@param  refresh       Output - Refresh rate
> +@retval TRUE          The requested Standard Timings entry contains valid data
> +
> +**/
> +STATIC BOOLEAN ReadStandardTiming (
> +  CONST VOID *EDID,
> +  IN UINT8 TimingNumber,
> +  OUT UINT16 *HRes,
> +  OUT UINT16 *VRes,
> +  OUT UINT8 *Refresh)
> +{
> +  CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> +
> +  // See section 3.9.1 of the VESA EDID spec
> +
> +  if (((pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels) == 0x01) &&
> +    (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh) == 0x01) {
> +    *HRes = 0;
> +    *VRes = 0;
> +    *Refresh = 0;
> +    return FALSE;
> +  }
> +  *HRes = (pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels + 31) * 8;
> +
> +  UINT8 AspectRatio;
> +  AspectRatio = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh >> 6) & 0x3;
> +
> +  switch (AspectRatio) {
> +  case 0: *VRes = (*HRes * 10) / 16;
> +    break;
> +  case 1: *VRes = (*HRes * 3) / 4;
> +    break;
> +  case 2: *VRes = (*HRes * 4) / 5;
> +    break;
> +  case 3: *VRes = (*HRes * 9) / 16;
> +    break;
> +  default: break;
> +  }
> +
> +  // WORKAROUND - 1360x768 is not a perfect aspect ratio
> +  if ((*HRes == 1360) && (*VRes == 765)) {
> +    *VRes = 768;
> +  }
> +
> +  *Refresh = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh & 0x1F) + 60;
> +
> +  return TRUE;
> +}
> +
> +/**
> +Extract the resolutions and refresh rate from one of the entries in the Detailed Timings section of the EDID.
> +
> +@param  EDID          Pointer to the 128-byte EDID
> +@param  timingNumber  The entry that we want to extract
> +@param  videoMode     Output - Filled in with details from the detailed timing
> +@retval TRUE          The requested Detailed Timings entry contains valid data
> +
> +**/
> +STATIC BOOLEAN
> +ReadDetailedTiming (
> +  IN CONST VOID *EDID,
> +  IN UINT8 TimingNumber,
> +  OUT struct VideoMode *VideoMode
> +  )
> +{
> +  if (TimingNumber >= EDID_NUMBER_OF_DETAILED_TIMINGS) {
> +    return FALSE;
> +  }
> +
> +  UINT16 NumValidDetailedTimingsFound;
> +  NumValidDetailedTimingsFound = 0;
> +
> +  // Spin through the detailed timings until we find a valid one - then check if this has the index that we want
> +  int BlockNumber;
> +  for (BlockNumber = 0; BlockNumber < EDID_NUMBER_OF_DETAILED_TIMINGS; BlockNumber++) {
> +    CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> +    CONST struct DetailedTimingIdentification *pTiming = &pEDID->detailedTimingDescriptions[BlockNumber];
> +
> +    if (((BlockNumber == 0) && (pTiming->PixelClock == EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK)) ||
> +      (pTiming->PixelClock == 0)) {
> +      // This is not a valid detailed timing descriptor
> +      continue;
> +    }
> +
> +    if ((pTiming->Features & EdidDetailedTimingsFeaturesSyncSchemeMask) != EdidDetailedTimingsFeaturesSyncSchemeMask) {
> +      DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported sync scheme found - not processing.\n"));
> +      continue;
> +    }
> +
> +    if ((pTiming->Features & EdidDetailedTimingsFeaturesStereoModeMask) != 0) {
> +      DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported stereo mode found - not processing.\n"));
> +      continue;
> +    }
> +
> +    // We've found a supported detailed timing - now see if this is the requested one
> +    if (TimingNumber != NumValidDetailedTimingsFound) {
> +      NumValidDetailedTimingsFound++;
> +      continue;
> +    }
> +
> +    ZeroMem ((VOID *)VideoMode, sizeof (struct VideoMode));
> +
> +    // Bit manipulations copied from host software class EDIDTimingDescriptor
> +
> +    VideoMode->PixelClock = (UINT16)pTiming->PixelClock;
> +    VideoMode->HActive = pTiming->HActiveLo + ((pTiming->HActiveHiBlankingHi & 0xF0) << 4);
> +    VideoMode->VActive = pTiming->VActiveLo + ((pTiming->VActiveHiBlankingHi & 0xF0) << 4);
> +
> +    VideoMode->HBlanking = pTiming->HBlankingLo + ((pTiming->HActiveHiBlankingHi & 0x0F) << 8);
> +    VideoMode->VBlanking = pTiming->VBlankingLo + ((pTiming->VActiveHiBlankingHi & 0x0F) << 8);
> +
> +    VideoMode->HSyncOffset = pTiming->HSyncOffsetLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0xC0) << 2);  // Horizontal Front Porch
> +    VideoMode->HSyncWidth = pTiming->HSyncWidthLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x30) << 4);
> +
> +    VideoMode->VSyncOffset = ((pTiming->VSyncOffsetLoSyncWidthLo & 0xF0) >> 4) + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x0C) << 2); // Vertical Front Porch
> +    VideoMode->VSyncWidth = (pTiming->VSyncOffsetLoSyncWidthLo & 0x0F) + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x03) << 4);
> +
> +    VideoMode->Reserved2 = 2;
> +    VideoMode->Accumulate = 1;
> +
> +    // Horizontal and vertical sync inversions - positive if bit set in descriptor (EDID spec)
> +    // In the VideoMode, they are negative if the bit is set (NR-110497-TC 4.3.3 0x22 Set Video Mode)
> +
> +    // Horizontal sync
> +    if ((pTiming->Features & EdidDetailedTimingsFeaturesHorizontalSyncPositive) == 0) {
> +      VideoMode->Flags |= VideoModeFlagsHorizontalSyncInverted;
> +    }
> +    // Vertical sync
> +    if ((pTiming->Features & EdidDetailedTimingsFeaturesVerticalSyncPositive) == 0) {
> +      VideoMode->Flags |= VideoModeFlagsVerticalSyncInverted;
> +    }
> +    // Interlace
> +    if ((pTiming->Features & EdidDetailedTimingsFeaturesInterlaced) == EdidDetailedTimingsFeaturesInterlaced) {
> +      VideoMode->Flags |= VideoModeFlagsInterlaced;
> +    }
> +
> +    DEBUG ((DEBUG_INFO, "Read mode %dx%d from detailed timings\n", VideoMode->HActive, VideoMode->VActive));
> +    return TRUE;
> +  }
> +  return FALSE;
> +}
> +
> +/**
> +Check if a particular video mode is in either the Established or Standard Timings section of the EDID.
> +
> +@param  EDID        Pointer to the 128-byte EDID
> +@param  hRes        Horizontal resolution
> +@param  vRes        Vertical resolution
> +@param  refresh     Refresh rate
> +@retval TRUE        The requested mode is present in the EDID
> +
> +**/
> +STATIC BOOLEAN
> +IsModeInEdid (
> +    IN CONST VOID *EDID,
> +    IN UINT16 HRes,
> +    IN UINT16 VRes,
> +    IN UINT16 Refresh
> +    )
> +{
> +  UINT16 EdidHRes;
> +  UINT16 EdidVRes;
> +  UINT8 EdidRefresh;
> +  BOOLEAN ModeSupported;
> +
> +  ModeSupported = IsModeInEstablishedTimings (EDID, HRes, VRes, Refresh);
> +
> +  if (ModeSupported == FALSE) {
> +    // Check if the mode is in the Standard Timings section of the EDID
> +    UINT8 i;
> +    for (i = 0; i < EDID_NUMBER_OF_STANDARD_TIMINGS; i++) {
> +      if (TRUE == ReadStandardTiming (EDID, i, &EdidHRes, &EdidVRes, &EdidRefresh)) {
> +        if ((HRes == EdidHRes) && (VRes == EdidVRes) && (Refresh == EdidRefresh)) {
> +          ModeSupported = TRUE;
> +          break;
> +        }
> +      }
> +    }
> +  }
> +  return ModeSupported;
> +}
> +
> +/**
> +Returns the (index)'th entry from the list of pre-calculated video timings that is also present in the EDID,
> +or, video mode data corresponding to any detailed timings present in the EDID.
> +
> +Like QueryVideoMode, finds the number (and contents) of video modes available by repeatedly calling this function
> +with an increasing index value, until it returns FALSE
> +@param  index       The caller wants the _index_'th video mode
> +@param  EDID        Pointer to the 128-byte EDID
> +@param  edidSize    Size in bytes of the EDID
> +@param  videoMode   Video timings extracted from the modeData structure
> +@retval EFI_SUCCESS The requested mode is present in the EDID
> +@retval EFI_INVALID_PARAMETER The requested mode is not present in the EDID
> +**/
> +EFI_STATUS
> +DlEdidGetSupportedVideoMode (
> +    IN UINT32 Index,
> +    IN CONST VOID *EDID,
> +    IN UINT32 EdidSize,
> +    OUT CONST struct VideoMode **VideoMode
> +    )
> +{
> +  UINTN SupportedVideoModesFoundInEdid;
> +  EFI_STATUS Status;
> +
> +  SupportedVideoModesFoundInEdid = 0;
> +  Status = EFI_INVALID_PARAMETER;
> +
> +  // If we didn't manage to find an EDID earlier, just use one of the hard-coded video modes
> +  if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> +    if (Index >= DlVideoModeGetNumSupportedVideoModes ()) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +    else {
> +      *VideoMode = DlVideoModeGetSupportedVideoMode (Index);
> +      DEBUG ((DEBUG_WARN, "No monitor EDID loaded - returning mode from default list (%dx%d)\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
> +      return EFI_SUCCESS;
> +    }
> +  }
> +
> +  UINT16 ModeNumber;
> +  for (ModeNumber = 0; ModeNumber < DlVideoModeGetNumSupportedVideoModes (); ModeNumber++) {
> +
> +    CONST struct VideoMode *SupportedVideoMode = DlVideoModeGetSupportedVideoMode (ModeNumber);
> +    ASSERT (SupportedVideoMode);
> +
> +    if (IsModeInEdid (EDID, SupportedVideoMode->HActive, SupportedVideoMode->VActive, DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE)) {
> +      if (Index == SupportedVideoModesFoundInEdid) {
> +        *VideoMode = SupportedVideoMode;
> +        Status = EFI_SUCCESS;
> +        break;
> +      }
> +      SupportedVideoModesFoundInEdid++;
> +    }
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    // Have a look in the detailed timings
> +    UINTN DetailedTimingNumber;
> +    STATIC struct VideoMode TmpVideoMode;
> +    DetailedTimingNumber = Index - SupportedVideoModesFoundInEdid;
> +
> +    if (DetailedTimingNumber < EDID_NUMBER_OF_DETAILED_TIMINGS) {
> +      if (ReadDetailedTiming (EDID, (UINT8)DetailedTimingNumber, &TmpVideoMode)) {
> +        *VideoMode = &TmpVideoMode;
> +        Status = EFI_SUCCESS;
> +      }
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> + * Like GetSupportedEdidVideoMode, but will return a fallback fixed mode of 640x480@60Hz
> + * for index 0 if no suitable modes found in EDID.
> + * @param index
> + * @param EDID
> + * @param edidSize
> + * @param videoMode
> + * @return EFI_SUCCESS
> + */
> +EFI_STATUS
> +DlEdidGetSupportedVideoModeWithFallback (
> +    IN UINT32 Index,
> +    IN CONST VOID *EDID,
> +    IN UINT32 EdidSize,
> +    OUT CONST struct VideoMode **VideoMode
> +    )
> +{
> +  EFI_STATUS Status;
> +  Status = DlEdidGetSupportedVideoMode (Index, EDID, EdidSize, VideoMode);
> +
> +  if (EFI_ERROR (Status)) {
> +    // Special case - if we didn't find any matching video modes in the EDID, fall back to 640x480@60Hz
> +    if (Index == 0) {
> +      *VideoMode = DlVideoModeGetSupportedVideoMode (0);
> +      DEBUG ((DEBUG_WARN, "No video modes supported by driver found in monitor EDID received from DL device - falling back to %dx%d\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
> +      Status = EFI_SUCCESS;
> +    }
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +Count the number of video modes that we have timing information for that are present in the EDID
> +@param  EDID        Pointer to the 128-byte EDID
> +@param  edidSize
> +@retval             The number of modes in the EDID
> +
> +**/
> +UINT32
> +DlEdidGetNumSupportedModesInEdid (
> +    IN CONST VOID *EDID,
> +    IN UINT32 EdidSize
> +    )
> +{
> +  UINT32 MaxMode;
> +
> +  if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> +    return DlVideoModeGetNumSupportedVideoModes ();
> +  }
> +
> +  for (MaxMode = 0; ; MaxMode++) {
> +    CONST struct VideoMode *videoMode;
> +    if (EFI_ERROR (DlEdidGetSupportedVideoMode (MaxMode, EDID, EdidSize, &videoMode))) {
> +      break;
> +    }
> +  }
> +  DEBUG ((DEBUG_INFO, "Found %d video modes supported by driver in monitor EDID.\n", MaxMode));
> +  return MaxMode;
> +}
> +
> +
> +
> +/**
> + * Read the EDID from the connected monitor, store it in the local data structure
> + * @param UsbDisplayLinkDev
> + * @retval EFI_OUT_OF_RESOURCES - Could not allocate memory
> + * @retval EFI_SUCCESS
> + */
> +EFI_STATUS
> +DlReadEdid (
> +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> +    )
> +{
> +  EFI_STATUS Status;
> +  BOOLEAN EdidFound;
> +  EFI_EDID_OVERRIDE_PROTOCOL* EdidOverride;
> +
> +  //
> +  // setup EDID information
> +  //
> +  UsbDisplayLinkDev->EdidDiscovered.Edid = (UINT8 *)NULL;
> +  UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = 0;
> +
> +  EdidFound = FALSE;
> +
> +  //
> +  // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
> +  //
> +  Status = gBS->LocateProtocol (&gEfiEdidOverrideProtocolGuid, NULL, (VOID**)&EdidOverride);
> +
> +  if (!EFI_ERROR (Status)) {
> +    UINT32 EdidAttributes = 0xff;
> +    UINTN EdidDataSize = 0;
> +    UINT8* EdidDataBlock = (UINT8*)NULL;
> +
> +    // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
> +    EdidDataBlock = (UINT8*)AllocatePool (EDID_BLOCK_SIZE * 2);
> +
> +    if (NULL == EdidDataBlock) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    Status = EdidOverride->GetEdid (
> +      EdidOverride,
> +      &UsbDisplayLinkDev->Handle,
> +      &EdidAttributes,
> +      &EdidDataSize,
> +      &EdidDataBlock);
> +
> +    if (!EFI_ERROR (Status) && EdidAttributes == 0 && EdidDataSize != 0) {
> +      UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> +      UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> +      EdidFound = TRUE;
> +    }
> +    else {
> +      FreePool (EdidDataBlock);
> +      EdidDataBlock = NULL;
> +    }
> +  }
> +
> +  if (EdidFound != TRUE) {
> +    UINTN EdidDataSize = 0;
> +    UINT8* EdidDataBlock = (UINT8*)NULL;
> +
> +    if (ReadEdidData (UsbDisplayLinkDev, &EdidDataBlock, &EdidDataSize) == EFI_SUCCESS) {
> +
> +      if (IsEdidChecksumCorrect (EdidDataBlock)) {
> +        UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> +        UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> +        EdidFound = TRUE;
> +      } else {
> +        DEBUG ((DEBUG_WARN, "Monitor EDID received from DisplayLink device had an invalid checksum. Corrupted?\n"));
> +      }
> +    }
> +  }
> +
> +  if (EdidFound == FALSE) {
> +    DEBUG ((DEBUG_WARN, "No valid monitor EDID received from DisplayLink device. Cannot detect resolutions supported by monitor.\n"));
> +  }
> +
> +  // Set the EDID active.
> +  // In an error case this will be set 0/NULL, which flags to the parsing code that there is no EDID.
> +  UsbDisplayLinkDev->EdidActive.SizeOfEdid = UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid;
> +  UsbDisplayLinkDev->EdidActive.Edid = UsbDisplayLinkDev->EdidDiscovered.Edid;
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> new file mode 100644
> index 000000000000..a1b8a0512d1a
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> @@ -0,0 +1,129 @@
> +/** @file Edid.h
> + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> + * Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#ifndef EDID_H
> +#define EDID_H
> +
> +#include "UsbDisplayLink.h"
> +
> +#define EDID_HEADER_SIZE                          ((UINTN)8)
> +#define EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES  ((UINTN)3)
> +#define EDID_NUMBER_OF_STANDARD_TIMINGS           ((UINTN)8)
> +#define EDID_NUMBER_OF_DETAILED_TIMINGS           ((UINTN)4)
> +
> +
> +typedef struct {
> +  UINT16  HRes;
> +  UINT16  VRes;
> +  UINT16  Refresh;
> +} EDID_TIMING;
> +
> +
> +EFI_STATUS
> +DlEdidGetSupportedVideoMode (
> +    UINT32 ModeNumber,
> +    CONST VOID *EDID,
> +    UINT32 EdidSize,
> +    CONST struct VideoMode **VideoMode
> +    );
> +
> +EFI_STATUS
> +DlEdidGetSupportedVideoModeWithFallback (
> +    UINT32 ModeNumber,
> +    CONST VOID *EDID,
> +    UINT32 EdidSize,
> +    CONST struct VideoMode **VideoMode
> +    );
> +
> +UINT32
> +DlEdidGetNumSupportedModesInEdid (
> +    CONST VOID *EDID,
> +    UINT32 EdidSize
> +    );
> +
> +EFI_STATUS
> +DlReadEdid (
> +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> +);
> +
> +// EDID Detailed timings section - Features
> +enum EdidDetailedTimingsFeatures {
> +  EdidDetailedTimingsFeaturesInterlaced              = 0x80,
> +  EdidDetailedTimingsFeaturesStereoModeMask          = 0x60,
> +  EdidDetailedTimingsFeaturesSyncSchemeMask          = 0x18,
> +  EdidDetailedTimingsFeaturesHorizontalSyncPositive  = 0x02,
> +  EdidDetailedTimingsFeaturesVerticalSyncPositive    = 0x04,
> +};
> +
> +// NR-110497-TC-7ZM Section 4.3.3 0x22 Set Video Mode - Flags
> +enum VideoModeFlags {
> +  VideoModeFlagsInterlaced             = 0x0001,
> +  VideoModeFlagsHorizontalSyncInverted = 0x0100,
> +  VideoModeFlagsVerticalSyncInverted   = 0x0200,
> +};
> +
> +struct StandardTimingIdentification {
> +  UINT8 HorizontalActivePixels;           // X resolution, from 256->2288 in increments of 8 pixels
> +  UINT8 ImageAspectRatioAndrefresh;   // Bits 7,6 Aspect ratio - 0=16:10 1=4:3 2=5:4 3=16:9
> +                                          // Bits 5,0 Refresh rate Range 60->1213Hz
> +};
> +
> +struct DetailedTimingIdentification {
> +  UINT16 PixelClock;                  // wPixelClock in VideoMode struct
> +  UINT8  HActiveLo;                   // wHActive
> +  UINT8  HBlankingLo;                 // wHBlanking
> +  UINT8  HActiveHiBlankingHi;
> +  UINT8  VActiveLo;                   // wVActive
> +  UINT8  VBlankingLo;                 // wVBlanking
> +  UINT8  VActiveHiBlankingHi;
> +  UINT8  HSyncOffsetLo;               // wHSyncOffset, front porch
> +  UINT8  HSyncWidthLo;                // wHSyncWidth
> +  UINT8  VSyncOffsetLoSyncWidthLo;
> +  UINT8  HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi;
> +  UINT8  HImageSizeHi;
> +  UINT8  VImageSizeHi;
> +  UINT8  HImageSizeLoVImageSizeLo;
> +  UINT8  HBorder;
> +  UINT8  VBorder;
> +  UINT8  Features;
> +};
> +
> +struct Edid {
> +  UINT8  Header[EDID_HEADER_SIZE];           //EDID header "00 FF FF FF FF FF FF 00"
> +  UINT16 ManufactureName;                  //EISA 3-character ID
> +  UINT16 ProductCode;                      //Vendor assigned code
> +  UINT32 SerialNumber;                     //32-bit serial number
> +  UINT8  WeekOfManufacture;                //Week number
> +  UINT8  YearOfManufacture;                //Year
> +  UINT8  EdidVersion;                      //EDID Structure Version
> +  UINT8  EdidRevision;                     //EDID Structure Revision
> +  UINT8  VideoInputDefinition;
> +  UINT8  MaxHorizontalImageSize;           //cm
> +  UINT8  MaxVerticalImageSize;             //cm
> +  UINT8  DisplayTransferCharacteristic;
> +  UINT8  FeatureSupport;
> +  UINT8  RedGreenLowBits;                  //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
> +  UINT8  BlueWhiteLowBits;                 //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
> +  UINT8  RedX;                             //Red-x Bits 9 - 2
> +  UINT8  RedY;                             //Red-y Bits 9 - 2
> +  UINT8  GreenX;                           //Green-x Bits 9 - 2
> +  UINT8  GreenY;                           //Green-y Bits 9 - 2
> +  UINT8  BlueX;                            //Blue-x Bits 9 - 2
> +  UINT8  BlueY;                            //Blue-y Bits 9 - 2
> +  UINT8  WhiteX;                           //White-x Bits 9 - 2
> +  UINT8  WhiteY;                           //White-x Bits 9 - 2
> +  UINT8  EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES];
> +  struct StandardTimingIdentification  standardTimingIdentifications[EDID_NUMBER_OF_STANDARD_TIMINGS];
> +  struct DetailedTimingIdentification  detailedTimingDescriptions[EDID_NUMBER_OF_DETAILED_TIMINGS];
> +  UINT8  ExtensionFlag;                    //Number of (optional) 128-byte EDID extension blocks to follow
> +  UINT8  Checksum;
> +};
> +
> +#endif // EDID_H
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> new file mode 100644
> index 000000000000..3e483afdba72
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> @@ -0,0 +1,578 @@
> +/**
> + * @file Gop.c
> + * @brief UEFI GOP protocol API implementation for USB DisplayLink driver.
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +#include "Edid.h"
> +
> +
> +/**
> + *
> + * @param This            Pointer to the instance of the GOP protocol
> + * @param BltOperation
> + * @param SourceX
> + * @param SourceY
> + * @param Width
> + * @param Height
> + * @param DestinationX
> + * @param DestinationY
> + * @return
> + */
> +STATIC EFI_STATUS
> +CheckBounds (
> +    IN EFI_GRAPHICS_OUTPUT_PROTOCOL* This,
> +    IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> +    IN UINTN SourceX,
> +    IN UINTN SourceY,
> +    IN UINTN Width,
> +    IN UINTN Height,
> +    IN UINTN DestinationX,
> +    IN UINTN DestinationY
> +    )
> +{
> +  USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> +
> +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> +  Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> +
> +  CONST EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* ScreenMode = Gop->Mode->Info;
> +
> +  if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
> +    if (SourceY + Height > ScreenMode->VerticalResolution) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    if (SourceX + Width > ScreenMode->HorizontalResolution) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +  }
> +
> +  if (BltOperation == EfiBltBufferToVideo
> +    || BltOperation == EfiBltVideoToVideo
> +    || BltOperation == EfiBltVideoFill) {
> +    if (DestinationY + Height > ScreenMode->VerticalResolution) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +
> +    if (DestinationX + Width > ScreenMode->HorizontalResolution) {
> +      return EFI_INVALID_PARAMETER;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> + * Update the local copy of the Frame Buffer. This local copy is periodically transmitted to the
> + * DisplayLink device (via DlGopSendScreenUpdate)
> + * @param UsbDisplayLinkDev
> + * @param BltBuffer
> + * @param BltOperation
> + * @param SourceX
> + * @param SourceY
> + * @param DestinationX
> + * @param DestinationY
> + * @param Width
> + * @param Height
> + * @param BltBufferStride
> + * @param PixelsPerScanLine
> + */
> +STATIC VOID
> +BuildBackBuffer (
> +  IN  USB_DISPLAYLINK_DEV                     *UsbDisplayLinkDev,
> +  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer, OPTIONAL
> +  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
> +  IN  UINTN                                   SourceX,
> +  IN  UINTN                                   SourceY,
> +  IN  UINTN                                   DestinationX,
> +  IN  UINTN                                   DestinationY,
> +  IN  UINTN                                   Width,
> +  IN  UINTN                                   Height,
> +  IN  UINTN                                   BltBufferStride,
> +  IN  UINTN                                   PixelsPerScanLine
> +)
> +{
> +  UINTN H;
> +  UINTN W;
> +  switch (BltOperation) {
> +  case EfiBltVideoToBltBuffer:
> +  {
> +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> +    Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)((UINT8 *)BltBuffer + (DestinationY * BltBufferStride) + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> +    SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> +
> +    for (H = 0; H < Height; H++) {
> +      for (W = 0; W < Width; W++) {
> +        Blt[W] = *SrcB++;
> +      }
> +      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> +      SrcB += PixelsPerScanLine - Width;
> +    }
> +  }
> +  break;
> +
> +  case EfiBltBufferToVideo:
> +  {
> +    // Update the store of the area of the screen that is "dirty" - that we need to send in the next screen update.
> +    if (DestinationY < UsbDisplayLinkDev->LastY1) {
> +      UsbDisplayLinkDev->LastY1 = DestinationY;
> +    }
> +    if ((DestinationY + Height) > UsbDisplayLinkDev->LastY2) {
> +      UsbDisplayLinkDev->LastY2 = DestinationY + Height;
> +    }
> +
> +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> +    Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)(((UINT8 *)BltBuffer) + (SourceY * BltBufferStride) + SourceX * sizeof *Blt);
> +    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> +
> +    for (H = 0; H < Height; H++) {
> +      for (W = 0; W < Width; W++) {
> +        *DstB++ = Blt[W];
> +      }
> +      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> +      DstB += PixelsPerScanLine - Width;
> +    }
> +  }
> +  break;
> +
> +  case EfiBltVideoToVideo:
> +  {
> +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> +    SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> +    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> +
> +    for (H = 0; H < Height; H++) {
> +      for (W = 0; W < Width; W++) {
> +        *DstB++ = *SrcB++;
> +      }
> +      SrcB += PixelsPerScanLine - Width;
> +      DstB += PixelsPerScanLine - Width;
> +    }
> +  }
> +  break;
> +
> +  case EfiBltVideoFill:
> +  {
> +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> +    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> +    for (H = 0; H < Height; H++) {
> +      for (W = 0; W < Width; W++) {
> +        *DstB++ = *BltBuffer;
> +      }
> +      DstB += PixelsPerScanLine - Width;
> +    }
> +  }
> +  break;
> +  default: break;
> +  }
> +}
> +
> +/**
> + * Display a colour bar pattern on the DisplayLink device.
> + * @param UsbDisplayLinkDev
> + * @param PatternNumber
> + * @return
> + */
> +EFI_STATUS
> +DlGopSendTestPattern (
> +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> +    IN UINTN PatternNumber)
> +{
> +  EFI_STATUS Status;
> +  UINTN DataLen;
> +  UINT8 *DstBuf;
> +  UINT32 USBStatus;
> +
> +  Status = EFI_SUCCESS;
> +  DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per pixel
> +  DstBuf = AllocateZeroPool (DataLen);
> +
> +  if (DstBuf == NULL) {
> +    DEBUG ((DEBUG_ERROR, "SendTestPattern Failed to allocate memory\n"));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //DEBUG ((DEBUG_ERROR, "Called DlGopSendTestPattern %d\n", PatternNumber));
> +
> +  CONST UINT8 RedPixel[3] = { 0xFF, 0x00, 0x00 };
> +  CONST UINT8 GreenPixel[3] = { 0x00, 0xFF, 0x00 };
> +  CONST UINT8 BluePixel[3] = { 0x00, 0x00, 0xFF };
> +  CONST UINT8 YellowPixel[3] = { 0xFF, 0xFF, 0x00 };
> +  CONST UINT8 MagentaPixel[3] = { 0xFF, 0x00, 0xFF };
> +  CONST UINT8 CyanPixel[3] = { 0x00, 0xFF, 0xFF };
> +
> +  UINTN Row;
> +  UINTN Column;
> +  for (Row = 0; Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution; Row++) {
> +    for (Column = 0; Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution; Column++) {
> +
> +      if (0 == PatternNumber) {
> +        if (Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution / 3) {
> +          CopyMem (&DstBuf[Column * 3], RedPixel, sizeof (RedPixel));
> +        }
> +        else if (Row < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution * 2) / 3)
> +        {
> +          CopyMem (&DstBuf[Column * 3], GreenPixel, sizeof (GreenPixel));
> +        }
> +        else {
> +          CopyMem (&DstBuf[Column * 3], BluePixel, sizeof (BluePixel));
> +        }
> +      }
> +      else {
> +        if (Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution / 3) {
> +          CopyMem (&DstBuf[Column * 3], YellowPixel, sizeof (RedPixel));
> +        }
> +        else if (Column < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 2) / 3)
> +        {
> +          CopyMem (&DstBuf[Column * 3], MagentaPixel, sizeof (GreenPixel));
> +        }
> +        else {
> +          CopyMem (&DstBuf[Column * 3], CyanPixel, sizeof (BluePixel));
> +        }
> +      }
> +    }
> +    DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, DataLen, &USBStatus);
> +  }
> +  // Payload with length of 1 to terminate the frame
> +  DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, 1, &USBStatus);
> +  FreePool (DstBuf);
> +
> +  return Status;
> +}
> +
> +
> +/**
> + * Transfer the latest copy of the Blt buffer over USB to the DisplayLink device
> + * @param UsbDisplayLinkDev
> + * @return
> + */
> +EFI_STATUS
> +DlGopSendScreenUpdate (
> +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> +    )
> +{
> +  EFI_STATUS Status;
> +  UINT32 USBStatus;
> +  Status = EFI_SUCCESS;
> +
> +  // If it has been a while since we sent an update, send a full screen.
> +  // This allows us to update a hot-plugged monitor quickly.
> +  if (UsbDisplayLinkDev->TimeSinceLastScreenUpdate > DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD) {
> +    UsbDisplayLinkDev->LastY1 = 0;
> +    UsbDisplayLinkDev->LastY2 = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution - 1;
> +  }
> +
> +  // If there has been no BLT since the last update/poll, drop out quietly.
> +  if (UsbDisplayLinkDev->LastY2 < UsbDisplayLinkDev->LastY1) {
> +    UsbDisplayLinkDev->TimeSinceLastScreenUpdate += (DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 1000);  // Convert us to ms
> +    return EFI_SUCCESS;
> +  }
> +
> +  UsbDisplayLinkDev->TimeSinceLastScreenUpdate = 0;
> +
> +  EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> +
> +  UINTN DataLen;
> +  UINTN Width;
> +  UINTN Height;
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcPtr;
> +  UINT8* DstPtr;
> +  UINT8 DstBuffer[1920 * 3]; // Get rid of the magic numbers at some point
> +                             // Could also use a buffer allocated at runtime to store the line, stored in the USB_DISPLAYLINK_DEV structure.
> +  UINTN H;
> +
> +  DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per pixel
> +  Width = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution;
> +  Height = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution;
> +  SrcPtr = UsbDisplayLinkDev->Screen;
> +  DstPtr = DstBuffer;
> +
> +  for (H = 0; H < Height; H++) {
> +    DstPtr = DstBuffer;
> +
> +    UINTN W;
> +    for (W = 0; W < Width; W++) {
> +      // Need to swap round the RGB values
> +      DstPtr[0] = ((UINT8 *)SrcPtr)[2];
> +      DstPtr[1] = ((UINT8 *)SrcPtr)[1];
> +      DstPtr[2] = ((UINT8 *)SrcPtr)[0];
> +      SrcPtr++;
> +      DstPtr += 3;
> +    }
> +
> +    Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, DataLen, &USBStatus);
> +
> +    // USBStatus values defined in usbio.h, e.g. EFI_USB_ERR_TIMEOUT 0x40
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB status x%x\n", H, DataLen, Status, USBStatus));
> +      break;
> +    }
> +    // Need an extra DlUsbBulkWrite if the data length is divisible by USB MaxPacketSize. This spare data will just get written into the (invisible) stride area.
> +    // Note that the API doesn't let us do a bulk write of 0.
> +    if ((DataLen & (UsbDisplayLinkDev->BulkOutEndpointDescriptor.MaxPacketSize - 1)) == 0) {
> +      Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 2, &USBStatus);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB status x%x\n", H, DataLen, Status, USBStatus));
> +        break;
> +      }
> +    }
> +  }
> +
> +  if (!EFI_ERROR (Status)) {
> +    // If we've successfully transmitted the frame, reset the values that store which area of the screen has been BLTted to.
> +    // If we haven't succeeded, this will mean we'll try to resend it after the next poll period.
> +    UsbDisplayLinkDev->LastY2 = 0;
> +    UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> +  }
> +
> +  // Payload with length of 1 to terminate the frame
> +  // We need to do this even if we had an error, to indicate to the DL device that it should now expect a new frame.
> +  DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 1, &USBStatus);
> +
> +  gBS->RestoreTPL (OriginalTPL);
> +
> +  return Status;
> +}
> +
> +/**
> + * Calculate the video refresh rate from the video timing parameters (pixel clock etc)
> + * @param videoMode
> + * @return
> + */
> +#ifndef MDEPKG_NDEBUG
> +STATIC inline UINT16
> +CalculateRefreshRate (
> +    IN CONST struct VideoMode *VideoMode)
> +{
> +  UINT16 RefreshRate;
> +  UINT16 Rmod;
> +  UINT16 Rate10Hz;
> +
> +  RefreshRate = (VideoMode->PixelClock * 10000) / ((VideoMode->HActive + VideoMode->HBlanking) * (VideoMode->VActive + VideoMode->VBlanking));
> +  Rmod = RefreshRate % 10;
> +  Rate10Hz = RefreshRate - Rmod;
> +
> +  if (Rmod >= 5) {
> +    Rate10Hz += 10;
> +  }
> +  return Rate10Hz;
> +}
> +#endif // MDEPKG_NDEBUG
> +/* ***************************************************************************************************** */
> +/* ***************************************************************************************************** */
> +/* ******************        START OF FUNCTIONS WHICH IMPLEMENT GOP INTERFACE         ****************** */
> +/* ***************************************************************************************************** */
> +/* ***************************************************************************************************** */
> +
> +
> +/**
> + *
> + * @param Gop          Pointer to the instance of the GOP protocol
> + * @param ModeNumber
> + * @param SizeOfInfo
> + * @param Info
> + * @return
> + */
> +EFI_STATUS
> +EFIAPI
> +DisplayLinkQueryMode (
> +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *Gop,
> +  IN  UINT32                                ModeNumber,
> +  OUT UINTN                                 *SizeOfInfo,
> +  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
> +)
> +{
> +  USB_DISPLAYLINK_DEV *Dev;
> +  CONST struct VideoMode *VideoMode;
> +  EFI_STATUS Status;
> +
> +  Dev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> +  Status = EFI_INVALID_PARAMETER;
> +
> +  if ((SizeOfInfo == NULL) || (Info == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Get a video mode from the EDID
> +  Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, Dev->EdidActive.Edid, Dev->EdidActive.SizeOfEdid, &VideoMode);
> +
> +  if (!EFI_ERROR (Status)) {
> +
> +    *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> +    if (*Info == NULL) {
> +      return EFI_OUT_OF_RESOURCES;
> +    }
> +
> +    DEBUG ((DEBUG_INFO, "BIOS querying mode number %d - returning %dx%d @ %dHz\n", ModeNumber, VideoMode->HActive, VideoMode->VActive, CalculateRefreshRate (VideoMode)));
> +
> +    *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> +
> +    (*Info)->Version = 0;
> +    (*Info)->HorizontalResolution = VideoMode->HActive;
> +    (*Info)->VerticalResolution = VideoMode->VActive;
> +    (*Info)->PixelFormat = PixelBltOnly;
> +    (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;
> +    (*Info)->PixelInformation.RedMask = 0;
> +    (*Info)->PixelInformation.GreenMask = 0;
> +    (*Info)->PixelInformation.BlueMask = 0;
> +    (*Info)->PixelInformation.ReservedMask = 0;
> +  }
> +  return Status;
> +}
> +
> +/**
> + *
> + * @param Gop         Pointer to the instance of the GOP protocol
> + * @param ModeNumber
> + * @return
> + */
> +EFI_STATUS
> +EFIAPI
> +DisplayLinkSetMode (
> +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *Gop,
> +  IN  UINT32                        ModeNumber
> +)
> +{
> +  USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> +  EFI_STATUS Status;
> +  CONST struct VideoMode *VideoMode;
> +
> +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> +
> +  // Prevent the DisplayLinkPeriodicTimer from interrupting us (bug 28877).
> +  // When the driver is manually loaded, the TPL is TPL_NOTIFY (16) which prevents the interrupt from the timer.
> +  // When the GOP driver is sideloaded, the TPL of this call is TPL_APPLICATION (4) and the timer can interrupt us.
> +  Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> +
> +  // Get a video mode from the EDID
> +  Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, UsbDisplayLinkDev->EdidActive.Edid, UsbDisplayLinkDev->EdidActive.SizeOfEdid, &VideoMode);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Gop->Mode->Info->Version = 0;
> +  Gop->Mode->Info->HorizontalResolution = VideoMode->HActive;
> +  Gop->Mode->Info->VerticalResolution = VideoMode->VActive;
> +  Gop->Mode->Info->PixelFormat = PixelBltOnly;
> +  Gop->Mode->Info->PixelsPerScanLine = Gop->Mode->Info->HorizontalResolution;
> +  Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> +  Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> +  Gop->Mode->FrameBufferSize = 0;
> +
> +  //
> +  // Allocate the back buffer
> +  //
> +  if (UsbDisplayLinkDev->Screen != NULL) {
> +    FreePool (UsbDisplayLinkDev->Screen);
> +  }
> +
> +  UsbDisplayLinkDev->Screen = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)AllocateZeroPool (
> +    Gop->Mode->Info->HorizontalResolution *
> +    Gop->Mode->Info->VerticalResolution *
> +    sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> +
> +  if (UsbDisplayLinkDev->Screen == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Video mode %d selected by BIOS - %d x %d.\n", ModeNumber, VideoMode->HActive, VideoMode->VActive));
> +  // Wait until we are sure that we can set the video mode before we tell the firmware
> +  Status = DlUsbSendControlWriteMessage (UsbDisplayLinkDev, SET_VIDEO_MODE, 0, VideoMode, sizeof (struct VideoMode));
> +
> +  if (Status != EFI_SUCCESS) {
> +    // Flag up that we haven't set the video mode correctly yet.
> +    DEBUG ((DEBUG_ERROR, "Failed to send USB message to DisplayLink device to set monitor video mode. Monitor connected correctly?\n"));
> +    Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> +    FreePool (UsbDisplayLinkDev->Screen);
> +    UsbDisplayLinkDev->Screen = NULL;
> +  } else {
> +    BuildBackBuffer (
> +      UsbDisplayLinkDev,
> +      UsbDisplayLinkDev->Screen,
> +      EfiBltBufferToVideo,
> +      0, 0,
> +      0, 0,
> +      Gop->Mode->Info->HorizontalResolution,
> +      Gop->Mode->Info->VerticalResolution,
> +      Gop->Mode->Info->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
> +      Gop->Mode->Info->HorizontalResolution);
> +    // unlock the DisplayLinkPeriodicTimer
> +    Gop->Mode->Mode = ModeNumber;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> + * Implementation of the GOP protocol Blt API function
> + * @param This            Pointer to the instance of the GOP protocol
> + * @param BltBuffer
> + * @param BltOperation
> + * @param SourceX
> + * @param SourceY
> + * @param DestinationX
> + * @param DestinationY
> + * @param Width
> + * @param Height
> + * @param Delta
> + * @return
> + */
> +EFI_STATUS
> +EFIAPI
> +DisplayLinkBlt (
> +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
> +  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer, OPTIONAL
> +  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
> +  IN  UINTN                                   SourceX,
> +  IN  UINTN                                   SourceY,
> +  IN  UINTN                                   DestinationX,
> +  IN  UINTN                                   DestinationY,
> +  IN  UINTN                                   Width,
> +  IN  UINTN                                   Height,
> +  IN  UINTN                                   Delta         OPTIONAL
> +)
> +{
> +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> +
> +  // Drop out if we haven't set the video mode up yet
> +  if (This->Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Width == 0 || Height == 0) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Lock so we make an atomic write the frame buffer.
> +  // We would not want a timer based event (Cursor, ...) to come in while we are doing this operation.
> +  EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> +
> +  CONST UINTN BltBufferStride = (Delta == 0) ? Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) : Delta;
> +  CONST EFI_STATUS boundsCheckStatus = CheckBounds (This, BltOperation, SourceX, SourceY, Width, Height, DestinationX, DestinationY);
> +  if (EFI_ERROR (boundsCheckStatus)) {
> +    gBS->RestoreTPL (OriginalTPL);
> +    return boundsCheckStatus;
> +  }
> +
> +  BuildBackBuffer (UsbDisplayLinkDev, BltBuffer, BltOperation, SourceX, SourceY, DestinationX, DestinationY, Width, Height, BltBufferStride, This->Mode->Info->PixelsPerScanLine);
> +
> +  gBS->RestoreTPL (OriginalTPL);
> +  return EFI_SUCCESS;
> +}
> +
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> new file mode 100644
> index 000000000000..c12a80a6e1ab
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> @@ -0,0 +1,145 @@
> +/**
> + * @file UsbDescriptors.c
> + * @brief Functions to read USB Interface and Capabilities descriptors
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +#include "UsbDescriptors.h"
> +
> +/**
> + *
> + * @param UsbIo
> + * @param descriptorType
> + * @param index
> + * @param Buffer
> + * @param Length
> + * @param UsbStatus
> + * @return
> + */
> +STATIC EFI_STATUS
> +ReadDescriptor (
> +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> +    UINT8 DescriptorType,
> +    UINT8 Index,
> +    VOID* Buffer,
> +    UINT16 Length,
> +    UINT32* UsbStatus)
> +{
> +  EFI_STATUS Status;
> +
> +  UINT8 Header[2];
> +  ZeroMem (Header, sizeof (Header));
> +
> +  EFI_USB_DEVICE_REQUEST Request;
> +  ZeroMem (&Request, sizeof (Request));
> +  Request.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_STANDARD | USB_TARGET_DEVICE;
> +  Request.Request = USB_REQ_GET_DESCRIPTOR;
> +  Request.Index = 0;
> +  Request.Value = DescriptorType << 8 | Index;
> +  Request.Length = sizeof (Header);
> +
> +  // Read the descriptor header to see how many bytes it contains
> +  Status = UsbIo->UsbControlTransfer (
> +      UsbIo,
> +      &Request,
> +      EfiUsbDataIn,
> +      DISPLAYLINK_USB_CTRL_TIMEOUT,
> +      Header,
> +      sizeof (Header),
> +      UsbStatus);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to read length of descriptor type x%x, index %u (code %r, USB status x%x)\n",
> +          DescriptorType, Index, Status, *UsbStatus));
> +    return Status;
> +  }
> +  CONST UINT16 TotalLength = Header[0];
> +
> +  // Now we know the size of it, we can read the entire descriptor
> +  Request.Length = TotalLength;
> +
> +  Status = UsbIo->UsbControlTransfer (
> +      UsbIo,
> +      &Request,
> +      EfiUsbDataIn,
> +      DISPLAYLINK_USB_CTRL_TIMEOUT,
> +      Buffer,
> +      TotalLength,
> +      UsbStatus);
> +
> +  return Status;
> +}
> +
> +/**
> +  Perform a USB control transfer to read the DisplayLink vendor descriptor.
> +
> +  @param UsbIo   Pointer to the instance of the USBIO protocol
> +  @param Buffer  Pointer to the buffer where descriptor should be written
> +  @param Length  Length of buffer (and the maximum amount of descriptor data that shall be read)
> +
> +  @retval EFI_SUCCESS  The descriptor has been copied into Buffer
> +  @retval Other        The descriptor could not be read
> +**/
> +EFI_STATUS
> +ReadCapabilitiesDescriptor (
> +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> +    OUT VOID* Buffer,
> +    IN UINT16 Length)
> +{
> +  UINT32 UsbStatus;
> +  EFI_STATUS Status;
> +
> +  Status = ReadDescriptor (
> +      UsbIo,
> +      DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY,
> +      0,
> +      Buffer,
> +      Length,
> +      &UsbStatus);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Could not read capabilities descriptor from DL device (code %r, USB status x%x). Unrecognised firmware version?\n", Status, UsbStatus));
> +  }
> +
> +  return Status;
> +}
> +
> +
> +/**
> + An alternative to the UBSIO protocol function EFI_USB_IO_GET_INTERFACE_DESCRIPTOR.
> + This version allows you to specify an index.
> + * @param UsbIo                 Pointer to the instance of the USBIO protocol
> + * @param interfaceDescriptor   Where the descriptor should be written
> + * @param index                 The index of the descriptor required (the standard USBIO function doesn't let you do this)
> + * @return
> + */
> +EFI_STATUS
> +UsbDisplayLinkGetInterfaceDescriptor (
> +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> +    OUT EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> +    UINT8 Index
> +    )
> +{
> +  UINT32 UsbStatus;
> +  EFI_STATUS Status;
> +
> +  Status = ReadDescriptor (
> +      UsbIo,
> +      USB_DESC_TYPE_INTERFACE,
> +      Index,
> +      InterfaceDescriptor,
> +      sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
> +      &UsbStatus);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "USB control transfer failed while reading interface descriptor (code %r, USB status x%x)\n", Status, UsbStatus));
> +  }
> +
> +  return Status;
> +}
> +
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> new file mode 100644
> index 000000000000..cdc01aad193a
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> @@ -0,0 +1,109 @@
> +/**
> + * @file UsbDescriptors.h
> + * @brief Functions to read USB Interface and Capabilities descriptors
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#ifndef USB_DESCRIPTORS_H_
> +#define USB_DESCRIPTORS_H_
> +
> +  /**
> +  Type of the Direct Framebuffer capability descriptor.
> +  This is a vendor specific USB descriptor for DisplayLink.
> +  @see NR-140082 Section 3.5
> +  **/
> +#define DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY 0x5e
> +
> +  /**
> +  Identifiers for capabllity keys
> +  @see NR-140082 Section 3.2
> +  **/
> +
> +  /**
> +  Key for Capabilities 1 - See section 3.2.1
> +  **/
> +#define CAPABILITIES1_KEY 0x0
> +
> +  /**
> +  Lengths for capabllity fields
> +  **/
> +#define CAPABILITIES1_LENGTH 0x4
> +
> +  /**
> +  Bits for the capability bitmask Capabilities1
> +  **/
> +
> +  /**
> +  This is the first capability defined for the protocol.
> +  It represents the mode of operation as of initial release.
> +  If a device ever breaks compatibility with this initial release,
> +  it will cease
> +  to support CapabilityBaseProtocol.
> +  **/
> +#define CAPABILITIES1_BASE_PROTOCOL (1 << 0)
> +
> +  /**
> +  Idealised VendorDescriptor which is the result
> +  of parsing vendor descriptor from device.
> +  **/
> +  typedef struct {
> +    UINT32 Capabilities1;
> +  } VendorDescriptor;
> +
> +#pragma pack(push, 1)
> +  typedef struct {
> +    UINT16 Key; /** Really of type enum DescrptorKeys */
> +    UINT8 Length;
> +    UINT8 Value[];
> +  } DescriptorKLV;
> +
> +  typedef struct {
> +    UINT8 Length;
> +    UINT8 Type;
> +    UINT16 CapabilityVersion;
> +    UINT8 CapabilityLength;
> +    UINT8 Klv[];
> +  } VendorDescriptorGeneric;
> +#pragma pack(pop)
> +
> +
> +EFI_STATUS UsbDisplayLinkGetInterfaceDescriptor (
> +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> +    EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> +    UINT8 index
> +    );
> +
> +EFI_STATUS ReadCapabilitiesDescriptor (IN EFI_USB_IO_PROTOCOL *UsbIo, VOID* Buffer, UINT16 Length);
> +
> +/**
> +Parse data in buffer to a VendorDescriptor, if possible.
> +
> +@param Data      Buffer
> +@param Length    Length of buffer
> +
> +@retval EFI_SUCCESS      The descriptor was parsed successfully
> +@retval EFI_UNSUPPORTED  Simple Pointer Protocol is not installed on Controller.
> +**/
> +EFI_STATUS
> +UsbDisplayLinkParseCapabilitiesDescriptor (
> +  CONST IN VOID* Data,
> +  IN UINTN Length,
> +  OUT VendorDescriptor* Descriptor
> +);
> +
> +/**
> +Decide if binding may proceed, given capabilities
> +
> +@retval TRUE   Binding may proceed
> +@retval FALSE  Binding is not possible
> +**/
> +BOOLEAN
> +UsbDisplayLinkCapabilitiesSufficientToBind (
> +  CONST IN VendorDescriptor* Descriptor
> +);
> +
> +#endif // USB_DESCRIPTORS_H_
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> new file mode 100644
> index 000000000000..997a3e307f38
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> @@ -0,0 +1,1082 @@
> +/**
> + * @file UsbDisplayLink.c
> + * @brief USB DisplayLink Driver that manages USB DisplayLink device and produces Graphics Output Protocol
> + * This file implements the functions of the Driver Binding / Start / Stop / Unload interface
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/PrintLib.h>
> +#include <Protocol/HiiFont.h>
> +
> +#include "Edid.h"
> +#include "UsbDescriptors.h"
> +
> +//
> +// Functions of Driver Binding Protocol
> +//
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> +  IN EFI_HANDLE                     Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> +);
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> +  IN EFI_HANDLE                     Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> +);
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingStop (
> +  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
> +  IN  EFI_HANDLE                    Controller,
> +  IN  UINTN                         NumberOfChildren,
> +  IN  EFI_HANDLE                    *ChildHandleBuffer
> +);
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingEntryPoint (
> +  IN EFI_HANDLE           ImageHandle,
> +  IN EFI_SYSTEM_TABLE     *SystemTable
> +);
> +
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> +  IN EFI_HANDLE           ImageHandle,
> +  IN EFI_SYSTEM_TABLE     *SystemTable,
> +  IN EFI_HANDLE           DriverBindingHandle
> +);
> +
> +
> +// Generated with https://www.guidgen.com/ - "B70E5A79-C6D6-4267-B02E-9108C989E287"
> +EFI_GUID gEfiDlGopVariableGuid = { 0xB70E5A79, 0xC6D6, 0x4267,{ 0xB0, 0x2E, 0x91, 0x08, 0xC9, 0x89, 0xE2, 0x87 } };
> +
> +
> +EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding = {
> +  UsbDisplayLinkDriverBindingSupported,
> +  UsbDisplayLinkDriverBindingStart,
> +  UsbDisplayLinkDriverBindingStop,
> +  INF_DRIVER_VERSION,
> +  NULL,
> +  NULL
> +};
> +
> +
> +/**
> + * Reads integer environment variable with default fallback.
> + * @param variableName   variable name to read
> + * @param defaultValue   default value to return if requested not found
> + */
> +STATIC UINT32
> +ReadEnvironmentInt (
> +    CHAR16 *VariableName,
> +    UINT32 DefaultValue
> +    )
> +{
> +  UINT32 Result;
> +  UINTN DataSize;
> +  DataSize = sizeof (Result);
> +  CONST EFI_STATUS Status = gRT->GetVariable (VariableName, &gEfiDlGopVariableGuid, (UINT32*)NULL, &DataSize, &Result);
> +  if (!EFI_ERROR (Status) && (sizeof (Result) == DataSize)) {
> +    return Result;
> +  }
> +  return DefaultValue;
> +}
> +
> +/**
> +* Reads boolean environment variable with default fallback.
> +* @param variableName   variable name to read
> +* @param defaultValue   default value to return if requested not found
> +*/
> +STATIC BOOLEAN
> +ReadEnvironmentBool (
> +    CHAR16 *VariableName,
> +    BOOLEAN DefaultValue
> +    )
> +{
> +  return ReadEnvironmentInt (VariableName, DefaultValue ? 1 : 0) == 1;
> +}
> +
> +
> +/**
> +*
> +* @param UsbDisplayLinkDev
> +* @return
> +*/
> +STATIC EFI_STATUS
> +InitializeUsbDisplayLinkDevice (
> +  IN OUT USB_DISPLAYLINK_DEV *UsbDisplayLinkDev
> +)
> +{
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> +  Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> +  Gop->QueryMode = DisplayLinkQueryMode;
> +  Gop->SetMode = DisplayLinkSetMode;
> +  Gop->Blt = DisplayLinkBlt;
> +
> +  //
> +  // Allocate buffer for Graphics Output Protocol mode information
> +  //
> +  Gop->Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
> +  if (Gop->Mode == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +  Gop->Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> +  if (Gop->Mode->Info == NULL) {
> +    FreePool (Gop->Mode);
> +    Gop->Mode = NULL;
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  Gop->Mode->MaxMode = MAX(1, DlEdidGetNumSupportedModesInEdid (UsbDisplayLinkDev->EdidActive.Edid, UsbDisplayLinkDev->EdidActive.SizeOfEdid));
> +
> +  Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> +  Gop->Mode->Info->Version = 0;
> +  // Initialising the horizontal resolution prevents certain BIOSs from hanging on boot, but
> +  // it is not yet clear why. See bug 28194.
> +  Gop->Mode->Info->HorizontalResolution = DlVideoModeGetSupportedVideoMode (0)->HActive;
> +  Gop->Mode->Info->VerticalResolution = 0;
> +  Gop->Mode->Info->PixelFormat = PixelBltOnly;
> +  Gop->Mode->Info->PixelsPerScanLine = 0;
> +  Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> +  Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> +  Gop->Mode->FrameBufferSize = 0;
> +
> +  // Prevent DlGopSendScreenUpdate from running until we are sure that the video mode is set
> +  UsbDisplayLinkDev->LastY2 = 0;
> +  UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Look for alternate settings for the UsbIo handle's interface
> +  which offer protocol DL_PROTOCOL_DIRECT_FB.
> +
> +  @retval -1                     Not found
> +  @retval Other                  The alternate setting
> +**/
> +STATIC INTN
> +GetDirectFbAltSetting (
> +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> +    IN UINT8 ParentInterfaceNumber
> +    )
> +{
> +  EFI_STATUS Status;
> +  INTN AltSettingIndex;
> +  UINT16 InterfaceIndex;
> +
> +  AltSettingIndex = -1;
> +
> +  for (InterfaceIndex = 0; InterfaceIndex <= 0xFF; InterfaceIndex++) {
> +    EFI_USB_INTERFACE_DESCRIPTOR interfaceDescriptor;
> +    Status = UsbDisplayLinkGetInterfaceDescriptor (UsbIo, &interfaceDescriptor, (UINT8)InterfaceIndex);
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> +
> +    if (interfaceDescriptor.InterfaceNumber == ParentInterfaceNumber &&
> +       (interfaceDescriptor.InterfaceClass == CLASS_VENDOR) &&
> +        interfaceDescriptor.InterfaceProtocol == INTERFACE_PROTOCOL_DIRECT_FB) {
> +      AltSettingIndex = interfaceDescriptor.AlternateSetting;
> +      break;
> +    }
> +  }
> +  return AltSettingIndex;
> +}
> +
> +/**
> + *
> + * @param UsbIo
> + * @param altSettingIndex
> + * @return
> + */
> +STATIC EFI_STATUS
> +SelectAltSetting (
> +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> +    IN UINTN AltSettingIndex)
> +{
> +  // Set alternate setting 1 on the interface
> +  EFI_STATUS Status;
> +  UINT32 UsbStatus;
> +  EFI_USB_DEVICE_REQUEST Request;
> +  ZeroMem (&Request, sizeof (Request));
> +  Request.RequestType = USB_REQ_TYPE_STANDARD | USB_TARGET_INTERFACE;
> +  Request.Request = USB_REQ_SET_INTERFACE;
> +  Request.Index = DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO;
> +  Request.Value = (UINT16)AltSettingIndex;
> +
> +  Status = UsbIo->UsbControlTransfer (
> +    UsbIo,
> +    &Request,
> +    EfiUsbNoData,
> +    DISPLAYLINK_USB_CTRL_TIMEOUT,
> +    NULL,
> +    0,
> +    &UsbStatus);
> +
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_UNSUPPORTED;
> +    DEBUG ((DEBUG_ERROR, "USB control transfer failed while attempting to select alt setting %d on interface (code %r, USB status x%x). DisplayLink device has unsupported firmware version?\n", AltSettingIndex, Status, UsbStatus));
> +  }
> +  return Status;
> +}
> +
> +
> +/**
> +  Report whether the driver can support the device attached via UsbIo
> +  by seeing what if any capabilities it reports.
> +
> +  @retval TRUE     Device has sufficient capabilities for this driver.
> +  @retval FALSE    Device lacks sufficient capabilities.
> +**/
> +STATIC BOOLEAN
> +CapabilitiesSupported (
> +    IN EFI_USB_IO_PROTOCOL *UsbIo
> +    )
> +{
> +  UINT8 Buffer[256];
> +  EFI_STATUS Status;
> +
> +  Status = ReadCapabilitiesDescriptor (UsbIo, Buffer, sizeof (Buffer));
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  VendorDescriptor descriptor;
> +  Status = UsbDisplayLinkParseCapabilitiesDescriptor (Buffer, sizeof (Buffer), &descriptor);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to parse capabilities descriptor (code %r)\n", Status));
> +    return FALSE;
> +  }
> +
> +  return UsbDisplayLinkCapabilitiesSufficientToBind (&descriptor);
> +}
> +
> +
> +/**
> + *
> + * @param UsbIo
> + * @param InterfaceDescriptor
> + * @param altSettingIndex
> + * @return
> + */
> +STATIC BOOLEAN
> +IsDLDirectFbCapableInterface (
> +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> +    IN EFI_USB_INTERFACE_DESCRIPTOR  *InterfaceDescriptor,
> +    IN INTN *AltSettingIndex)
> +{
> +  EFI_STATUS Status;
> +  EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
> +
> +  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DeviceDescriptor);
> +
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  if (DeviceDescriptor.IdVendor != VENDOR_DISPLAYLINK) {
> +    return FALSE;
> +  }
> +
> +  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, InterfaceDescriptor);
> +  if (EFI_ERROR (Status)) {
> +    return FALSE;
> +  }
> +
> +  // We can assume that the interface that we want to talk to - the NIVO interface - is number 0
> +  if (InterfaceDescriptor->InterfaceNumber != DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO) {
> +    return FALSE;
> +  }
> +
> +  // Check if we have an interface (alt setting) descriptor with the correct interface protocol
> +  *AltSettingIndex = GetDirectFbAltSetting (UsbIo, InterfaceDescriptor->InterfaceNumber);
> +
> +  if (*AltSettingIndex == -1) {
> +    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to find setting on device which supports GOP functionality. Check firmware / device version?\n"));
> +    return FALSE;
> +  }
> +
> +  // Now check that the capabilities that we need are properly supported
> +  if (CapabilitiesSupported (UsbIo) == FALSE) {
> +    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: DL device detected, but it doesn't support the required GOP features. Check firmware / device version?\n"));
> +    return FALSE;
> +  }
> +
> +  return TRUE;
> +}
> +
> +
> +/**
> + * Prints a block of text in the framebuffer (helper function).
> + * @param X   x coordinate
> + * @param Y   y coordinate
> + */
> +STATIC VOID
> +DisplayLinkPrintTextToScreenInternal (
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> +  UINTN X,
> +  UINTN Y,
> +  IN CHAR16 *Buffer
> +  )
> +{
> +  EFI_STATUS Status;
> +  EFI_HII_FONT_PROTOCOL *HiiFont;
> +  EFI_IMAGE_OUTPUT *Blt;
> +  EFI_FONT_DISPLAY_INFO FontInfo;
> +  EFI_HII_OUT_FLAGS Flags;
> +
> +  Blt = (EFI_IMAGE_OUTPUT*)NULL;
> +
> +  Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **)&HiiFont);
> +  if (!EFI_ERROR (Status)) {
> +    Blt = (EFI_IMAGE_OUTPUT*)AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
> +    Blt->Width = (UINT16)GraphicsOutput->Mode->Info->HorizontalResolution;
> +    Blt->Height = (UINT16)GraphicsOutput->Mode->Info->VerticalResolution;
> +    Blt->Image.Screen = GraphicsOutput;
> +
> +    ZeroMem (&FontInfo, sizeof (EFI_FONT_DISPLAY_INFO));
> +    FontInfo.ForegroundColor.Red = 0;
> +    FontInfo.ForegroundColor.Green = 0;
> +    FontInfo.ForegroundColor.Blue = 0;
> +    FontInfo.BackgroundColor.Red = 0xff;
> +    FontInfo.BackgroundColor.Green = 0xff;
> +    FontInfo.BackgroundColor.Blue = 0xff;
> +
> +    Flags = EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_OUT_FLAG_CLIP |
> +            EFI_HII_OUT_FLAG_CLIP_CLEAN_X | EFI_HII_OUT_FLAG_CLIP_CLEAN_Y |
> +            EFI_HII_IGNORE_LINE_BREAK | EFI_HII_DIRECT_TO_SCREEN;
> +
> +    Status = HiiFont->StringToImage (
> +                           HiiFont,
> +                           Flags,
> +                           Buffer,
> +                           &FontInfo,
> +                           &Blt,
> +                           X,
> +                           Y,
> +                           (EFI_HII_ROW_INFO**)NULL,
> +                           (UINTN*)NULL,
> +                           (UINTN*)NULL);
> +  }
> +
> +  if (Blt != NULL) {
> +    FreePool (Blt);
> +  }
> +}
> +
> +
> +/**
> +* Prints a block of text in the framebuffer.
> +* @param X       x coordinate
> +* @param Y       y coordinate
> +* @param Format  string format similar to stdlib's vsnprintf
> +* @param ...     arguments
> +*/
> +VOID
> +EFIAPI
> +DlGopPrintTextToScreen (
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> +  UINTN X,
> +  UINTN Y,
> +  IN CONST CHAR16 *Format,
> +  ...
> +  )
> +{
> +  VA_LIST Marker;
> +  CHAR16 *Buffer;
> +  UINTN BufferSize;
> +
> +  ASSERT (Format != NULL);
> +  ASSERT (((UINTN) Format & BIT0) == 0);
> +
> +  VA_START(Marker, Format);
> +
> +  BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);
> +
> +  Buffer = (CHAR16*)AllocatePool (BufferSize);
> +  ASSERT (Buffer != NULL);
> +
> +  UnicodeVSPrint (Buffer, BufferSize, Format, Marker);
> +
> +  VA_END(Marker);
> +
> +  DisplayLinkPrintTextToScreenInternal (GraphicsOutput, X, Y, Buffer);
> +
> +  FreePool (Buffer);
> +}
> +
> +
> +/**
> + * Sometimes platforms only write to the first GOP device that they find. Enabling this function allows us to copy the pixels from this device.
> + * @param UsbDisplayLinkDev
> + */
> +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> +STATIC VOID
> +DisplayLinkCopyFromPrimaryGopDevice (
> +  IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> +  )
> +{
> +  UINTN HandleCount;
> +  EFI_HANDLE *HandleBuffer;
> +  UINTN HandleIndex;
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
> +
> +  gBS->LocateHandleBuffer (
> +    ByProtocol,
> +    &gEfiGraphicsOutputProtocolGuid,
> +    NULL,
> +    &HandleCount,
> +    &HandleBuffer);
> +
> +  for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
> +    gBS->HandleProtocol (HandleBuffer[HandleIndex], &gEfiGraphicsOutputProtocolGuid, (VOID**)&Gop);
> +    if (Gop != &UsbDisplayLinkDev->GraphicsOutputProtocol && Gop->Mode->FrameBufferBase != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
> +
> +    // See if we need to do a screen update - calculate a really noddy hash to see if any screen updates have happened.
> +    STATIC UINT32 prevframeBufferHash = 0; // 4 bytes per pixel
> +    UINT32 currFrameBufferHash = 0;
> +    UINTN i;
> +    for (i = 0; i < (Gop->Mode->Info->HorizontalResolution * Gop->Mode->Info->VerticalResolution); i++) {
> +      currFrameBufferHash += ((UINT32*)(UINTN)Gop->Mode->FrameBufferBase)[i];
> +    }
> +
> +    if (currFrameBufferHash != prevframeBufferHash) {
> +      prevframeBufferHash = currFrameBufferHash;
> +
> +      DisplayLinkBlt (
> +        &UsbDisplayLinkDev->GraphicsOutputProtocol,
> +        (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(UINTN)Gop->Mode->FrameBufferBase,
> +        EfiBltBufferToVideo,
> +        0,
> +        0,
> +        0,
> +        0,
> +        Gop->Mode->Info->HorizontalResolution,
> +        Gop->Mode->Info->VerticalResolution,
> +        0);
> +      }
> +      break;
> +    }
> +  }
> +
> +  FreePool (HandleBuffer);
> +}
> +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> +
> +
> +/**
> + * Exit from boot services: signal handler.
> + */
> +STATIC VOID
> +EFIAPI
> +DisplayLinkDriverExitBootServices (
> +  IN EFI_EVENT  Event,
> +  IN VOID       *Context
> +  )
> +{
> +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> +  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> +
> +  gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> +}
> +
> +/**
> + * Periodic screen update: timer callback.
> + */
> +VOID
> +EFIAPI
> +DisplayLinkPeriodicTimer (
> +    IN EFI_EVENT Event,
> +    IN VOID* Context
> +    )
> +{
> +  EFI_STATUS Status;
> +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> +
> +  Status = EFI_SUCCESS;
> +  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> +
> +  // Drop out if we haven't set the video mode up yet
> +  if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> +    // Restart the one-shot timer to poll the status again.
> +    Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> +    }
> +    return;
> +  }
> +
> +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> +  DisplayLinkCopyFromPrimaryGopDevice (UsbDisplayLinkDev);
> +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> +
> +  if (UsbDisplayLinkDev->ShowBandwidth) {
> +    STATIC UINTN Count = 0;
> +
> +    if (Count++ % 50 == 0) {
> +      DlGopPrintTextToScreen (&UsbDisplayLinkDev->GraphicsOutputProtocol, 32, 48, (CONST CHAR16*)L"  Bandwidth: %d MB/s    ", UsbDisplayLinkDev->DataSent * 10000000 / DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 50 / 1024 / 1024);
> +      UsbDisplayLinkDev->DataSent = 0;
> +    }
> +  }
> +
> +  if (UsbDisplayLinkDev->ShowTestPattern)
> +  {
> +    if (UsbDisplayLinkDev->ShowTestPattern == 5) {
> +      DlGopSendTestPattern (UsbDisplayLinkDev, 0);
> +    } else if (UsbDisplayLinkDev->ShowTestPattern >= 10) {
> +      DlGopSendTestPattern (UsbDisplayLinkDev, 1);
> +      UsbDisplayLinkDev->ShowTestPattern = 0;
> +    }
> +    UsbDisplayLinkDev->ShowTestPattern++;
> +
> +  }
> +
> +  // Send the latest version of the frame buffer to the DL device over USB
> +  DlGopSendScreenUpdate (UsbDisplayLinkDev);
> +
> +  // Restart the timer now we've finished
> +  Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> +  }
> +}
> +
> +/* ****************************************************************************************************** */
> +/* ****************************************************************************************************** */
> +/* ******************   START OF FUNCTIONS WHICH IMPLEMENT DRIVER BINDING INTERFACE    ****************** */
> +/* ****************************************************************************************************** */
> +/* ****************************************************************************************************** */
> +
> +/**
> +  Check whether USB DisplayLink driver supports this device.
> +
> +  @param  This                   The USB DisplayLink driver 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
> +UsbDisplayLinkDriverBindingSupported (
> +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> +  IN EFI_HANDLE                     Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> +  )
> +{
> +  EFI_STATUS          Status;
> +  EFI_USB_IO_PROTOCOL *UsbIo;
> +
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiUsbIoProtocolGuid,
> +                  (VOID **) &UsbIo,
> +                  This->DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_BY_DRIVER);
> +
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  //
> +  // Use the USB I/O Protocol interface to check whether Controller is
> +  // a DisplayLink device that can be managed by this driver.
> +  //
> +  Status = EFI_UNSUPPORTED;
> +  EFI_USB_INTERFACE_DESCRIPTOR DummyInterfaceDescriptor;
> +  INTN DummyAltSettingIndex;
> +
> +  if (IsDLDirectFbCapableInterface (UsbIo, &DummyInterfaceDescriptor, &DummyAltSettingIndex)){
> +    Status = EFI_SUCCESS;
> +  }
> +
> +  gBS->CloseProtocol (
> +        Controller,
> +        &gEfiUsbIoProtocolGuid,
> +        This->DriverBindingHandle,
> +        Controller);
> +
> +  return Status;
> +}
> +
> +
> +/**
> +  Starts the DisplayLink device with this driver.
> +
> +  This function consumes USB I/O Protocol, intializes USB DisplayLink device,
> +  installs Graphics Output Protocol
> +  Transfer to manage the USB DisplayLink device.
> +
> +  @param  This                  The USB DisplayLink 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           This driver supports this device.
> +  @retval EFI_UNSUPPORTED       This driver does not support this device.
> +  @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
> +  @retval EFI_OUT_OF_RESOURCES  Can't allocate memory resources.
> +  @retval EFI_ALREADY_STARTED   This driver has been started.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingStart (
> +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> +  IN EFI_HANDLE                   Controller,
> +  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  USB_DISPLAYLINK_DEV             *UsbDisplayLinkDev;
> +  UINT8                           EndpointNumber;
> +  EFI_USB_ENDPOINT_DESCRIPTOR     EndpointDescriptor;
> +  UINT8                           Index;
> +  BOOLEAN                         FoundOut;
> +  BOOLEAN                         FoundIn;
> +  EFI_TPL                         OriginalTPL;
> +  INTN                            altSettingIndex;
> +
> +  OriginalTPL = gBS->RaiseTPL (TPL_CALLBACK);
> +
> +  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)AllocateZeroPool (sizeof (USB_DISPLAYLINK_DEV));
> +  if (UsbDisplayLinkDev == NULL) {
> +    DEBUG ((DEBUG_ERROR, "Device initialialisation - Failed to allocate memory for device.\n"));
> +    gBS->RestoreTPL (OriginalTPL);
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  UsbDisplayLinkDev->Signature = USB_DISPLAYLINK_DEV_SIGNATURE;
> +
> +  UsbDisplayLinkDev->ShowBandwidth = ReadEnvironmentBool (L"DisplayLinkShowBandwidth", FALSE);
> +  UsbDisplayLinkDev->ShowTestPattern = ReadEnvironmentBool (L"DisplayLinkShowTestPatterns", FALSE);
> +
> +  //
> +  // Open USB I/O Protocol
> +  //
> +  Status = gBS->OpenProtocol (
> +      Controller,
> +      &gEfiUsbIoProtocolGuid,
> +      (VOID **) &UsbDisplayLinkDev->UsbIo,
> +      This->DriverBindingHandle,
> +      Controller,
> +      EFI_OPEN_PROTOCOL_BY_DRIVER);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to open usbio protocol. Is USB correctly supported on this platform?.\n"));
> +    Status = EFI_UNSUPPORTED;
> +    goto ErrorExit2;
> +  }
> +
> +  if (!IsDLDirectFbCapableInterface (UsbDisplayLinkDev->UsbIo, &UsbDisplayLinkDev->InterfaceDescriptor, &altSettingIndex)) {
> +    Status = EFI_UNSUPPORTED;
> +    goto ErrorExit4;
> +  }
> +
> +  Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, altSettingIndex);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to select alternate setting.\n"));
> +    Status = EFI_UNSUPPORTED;
> +    goto ErrorExit4;
> +  }
> +
> +  //
> +  // Parse endpoint descriptor
> +  //
> +  EndpointNumber = UsbDisplayLinkDev->InterfaceDescriptor.NumEndpoints;
> +
> +  //
> +  // Traverse endpoints to find bulk endpoint
> +  //
> +  FoundOut = FALSE;
> +  FoundIn = FALSE;
> +  for (Index = 0; Index < EndpointNumber; Index++) {
> +    UsbDisplayLinkDev->UsbIo->UsbGetEndpointDescriptor (
> +             UsbDisplayLinkDev->UsbIo,
> +             Index,
> +             &EndpointDescriptor);
> +
> +    if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_BULK) {
> +      if (!FoundOut && (EndpointDescriptor.EndpointAddress & BIT7) == 0) {
> +        CopyMem (&UsbDisplayLinkDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> +        FoundOut = TRUE;
> +      } else if (!FoundIn && (EndpointDescriptor.EndpointAddress & BIT7) == BIT7) {
> +        CopyMem (&UsbDisplayLinkDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> +        FoundIn = TRUE;
> +      }
> +    }
> +  }
> +
> +  if (FoundOut == FALSE) {
> +    Status = EFI_UNSUPPORTED;
> +    DEBUG ((DEBUG_ERROR, "No endpoints found.  Num endpoints searched = %d.\n", EndpointNumber));
> +    goto ErrorExit4;
> +  }
> +
> +  Status = DlReadEdid (UsbDisplayLinkDev);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to read monitor EDID from DisplayLink device (code %r)\n", Status));
> +    goto ErrorExit7;
> +  }
> +
> +  Status = InitializeUsbDisplayLinkDevice (UsbDisplayLinkDev);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to initialise DisplayLink device (code %r)\n", Status));
> +    goto ErrorExit7;
> +  }
> +
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +      &Controller,
> +      &gEfiGraphicsOutputProtocolGuid,
> +      &UsbDisplayLinkDev->GraphicsOutputProtocol,
> +      &gEfiEdidDiscoveredProtocolGuid,
> +      &UsbDisplayLinkDev->EdidDiscovered,
> +      &gEfiEdidActiveProtocolGuid,
> +      &UsbDisplayLinkDev->EdidActive,
> +      NULL);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to install Graphics Output and EDID protocol interfaces - driver not installed correctly - %r\n", Status));
> +    goto ErrorExit8;
> +  }
> +
> +  UsbDisplayLinkDev->ControllerNameTable = (EFI_UNICODE_STRING_TABLE*)NULL;
> +
> +  AddUnicodeString2 (
> +    "eng",
> +    mUsbDisplayLinkComponentName.SupportedLanguages,
> +    &UsbDisplayLinkDev->ControllerNameTable,
> +    (CONST CHAR16*)L"Generic Usb DisplayLink",
> +    TRUE);
> +
> +  AddUnicodeString2 (
> +    "en",
> +    mUsbDisplayLinkComponentName2.SupportedLanguages,
> +    &UsbDisplayLinkDev->ControllerNameTable,
> +    (CONST CHAR16*)L"Generic Usb DisplayLink",
> +    FALSE);
> +
> +  //
> +  // Setup a periodic timer
> +  //
> +  Status = gBS->CreateEvent (
> +                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
> +                  TPL_CALLBACK,
> +                  DisplayLinkPeriodicTimer,
> +                  UsbDisplayLinkDev,
> +                  &UsbDisplayLinkDev->TimerEvent);
> +
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    DEBUG ((DEBUG_ERROR, "Failed to create screeen update polling event.\n"));
> +    goto ErrorExit8;
> +  }
> +
> +  // Start one-shot timer. The rendering operations can take quite a long time, so we
> +  // don't want another timer event to happen until we have finished; so we'll restart
> +  // the timer from DisplayLinkPeriodicTimer, the event handler function.
> +  Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    DEBUG ((DEBUG_ERROR, "Failed to create screen update polling timer.\n"));
> +    goto ErrorExit8;
> +  }
> +
> +  Status = gBS->CreateEventEx (
> +                  EVT_NOTIFY_SIGNAL,
> +                  TPL_NOTIFY,
> +                  DisplayLinkDriverExitBootServices,
> +                  UsbDisplayLinkDev,
> +                  &gEfiEventExitBootServicesGuid,
> +                  &UsbDisplayLinkDev->DriverExitBootServicesEvent);
> +
> +  if (EFI_ERROR (Status)) {
> +    Status = EFI_OUT_OF_RESOURCES;
> +    DEBUG ((DEBUG_ERROR, "Failed to create event for bootexit.\n"));
> +    goto ErrorExit8;
> +  }
> +
> +  gBS->RestoreTPL (OriginalTPL);
> +
> +  DEBUG ((DEBUG_INFO, "DisplayLink GOP driver successfully bound to device.\n"));
> +
> +  return EFI_SUCCESS;
> +
> +  //
> +  // Error handler
> +  //
> + ErrorExit8:
> + ErrorExit7:
> + ErrorExit4:
> +  gBS->CloseProtocol (
> +   Controller,
> +   &gEfiUsbIoProtocolGuid,
> +   This->DriverBindingHandle,
> +   Controller);
> +
> + ErrorExit2:
> +  if (UsbDisplayLinkDev != NULL) {
> +    FreePool (UsbDisplayLinkDev);
> +    UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)NULL;
> +  }
> +
> +  DEBUG ((DEBUG_ERROR, "Exiting - Failed to initialise driver.\n"));
> +
> +  gBS->RestoreTPL (OriginalTPL);
> +  return Status;
> +}
> +
> +/**
> +Entrypoint of USB DisplayLink Driver.
> +
> +This function is the entrypoint of a combined USB DisplayLink GOP Driver. It installs Driver Binding
> +Protocols together with Component Name Protocols.
> +
> +@param  ImageHandle       The firmware allocated handle for the EFI image.
> +@param  SystemTable       A pointer to the EFI System Table.
> +@param  DriverBindingHandle  The Driver binding handle
> +
> +@retval EFI_SUCCESS       The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> +  IN EFI_HANDLE           ImageHandle,
> +  IN EFI_SYSTEM_TABLE     *SystemTable,
> +  IN EFI_HANDLE           DriverBindingHandle
> +)
> +{
> +  EFI_STATUS Status;
> +
> +  Status = EfiLibInstallDriverBindingComponentName2 (
> +    ImageHandle,
> +    SystemTable,
> +    &gUsbDisplayLinkDriverBinding,
> +    DriverBindingHandle,
> +    &mUsbDisplayLinkComponentName,
> +    &mUsbDisplayLinkComponentName2);
> +
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +Entrypoint of USB DisplayLink Driver.
> +
> +This function is the entrypoint of USB DisplayLink Driver. It installs Driver Binding
> +Protocols together with Component Name Protocols.
> +
> +@param  ImageHandle       The firmware allocated handle for the EFI image.
> +@param  SystemTable       A pointer to the EFI System Table.
> +
> +@retval EFI_SUCCESS       The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingEntryPoint (
> +  IN EFI_HANDLE           ImageHandle,
> +  IN EFI_SYSTEM_TABLE     *SystemTable
> +)
> +{
> +  return UsbDisplayLinkDriverCombinedGopBindingEntryPoint (ImageHandle, SystemTable, ImageHandle);
> +}
> +
> +
> +/**
> +Unloads an image.
> +@param  ImageHandle           Handle that identifies the image to be unloaded.
> +@retval EFI_SUCCESS           The image has been unloaded.
> +@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverCombinedGopUnload (
> +  IN EFI_HANDLE  ImageHandle
> +)
> +{
> +  EFI_STATUS  Status = EFI_SUCCESS;
> +  EFI_STATUS  handleDisconnectStatus;
> +  EFI_HANDLE  *HandleBuffer;
> +  UINTN       HandleCount;
> +  UINTN       Index;
> +
> +  //
> +  // Retrieve array of all handles in the handle database
> +  //
> +  handleDisconnectStatus = gBS->LocateHandleBuffer (
> +    AllHandles,
> +    NULL,
> +    NULL,
> +    &HandleCount,
> +    &HandleBuffer
> +  );
> +  if (! EFI_ERROR (handleDisconnectStatus)) {
> +    //
> +    // Disconnect the current driver from handles in the handle database
> +    //
> +    for (Index = 0; Index < HandleCount; Index++) {
> +      Status = gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
> +    }
> +    //
> +    // Free the array of handles
> +    //
> +    if (HandleBuffer != NULL)
> +    {
> +      FreePool (HandleBuffer);
> +    }
> +  }
> +
> +  // Even if we didn't manage to disconnect the handles, try to uninstall the protocols
> +  //
> +  // Uninstall protocols installed in the driver entry point
> +  //
> +  Status = gBS->UninstallMultipleProtocolInterfaces (
> +    ImageHandle,
> +    &gEfiDriverBindingProtocolGuid,
> +    &gUsbDisplayLinkDriverBinding,
> +    &gEfiComponentNameProtocolGuid,
> +    &mUsbDisplayLinkComponentName,
> +    &gEfiComponentName2ProtocolGuid,
> +    &mUsbDisplayLinkComponentName2,
> +    NULL
> +  );
> +
> +  if (EFI_ERROR (handleDisconnectStatus))
> +  {
> +    return handleDisconnectStatus;
> +  }
> +  return Status;
> +}
> +
> +
> +/**
> +  Stop the USB DisplayLink device handled by this driver.
> +
> +  @param  This                   The USB DisplayLink 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_UNSUPPORTED        Simple Pointer Protocol is not installed on Controller.
> +  @retval Others                 Fail to uninstall protocols attached on the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingStop (
> +  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
> +  IN  EFI_HANDLE                    Controller,
> +  IN  UINTN                         NumberOfChildren,
> +  IN  EFI_HANDLE                    *ChildHandleBuffer
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  USB_DISPLAYLINK_DEV               *UsbDisplayLinkDev;
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL      *GraphicsOutputProtocol;
> +
> +  Status = gBS->OpenProtocol (
> +                  Controller,
> +                  &gEfiGraphicsOutputProtocolGuid,
> +                  (VOID **) &GraphicsOutputProtocol,
> +                  This->DriverBindingHandle,
> +                  Controller,
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +
> +  if (EFI_ERROR (Status)) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> +
> +  // Reset the video mode to clear the display. Don't drop out if there is a problem, just press on.
> +  // Note that this will also clear the frame buffer, as the screen buffer will be re-allocated with AllocateZeroPool.
> +  if ((GraphicsOutputProtocol->Mode != NULL) &&
> +      (GraphicsOutputProtocol->Mode->Mode != GRAPHICS_OUTPUT_INVALID_MODE_NUMBER)) {
> +    Status = DisplayLinkSetMode (GraphicsOutputProtocol, GraphicsOutputProtocol->Mode->Mode);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_WARN, "Driver stop - Problem resetting video mode - %r.\n", Status));
> +    }
> +  }
> +
> +  // Reset the alt setting on the interface (to the DL3 alt setting)
> +  Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, 0);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_WARN, "Error resetting USB interface alternate setting - %r.\n", Status));
> +  }
> +
> +  Status = gBS->UninstallMultipleProtocolInterfaces (
> +                  Controller,
> +                  &gEfiGraphicsOutputProtocolGuid,
> +                  &UsbDisplayLinkDev->GraphicsOutputProtocol,
> +                  &gEfiEdidDiscoveredProtocolGuid,
> +                  &UsbDisplayLinkDev->EdidDiscovered,
> +                  &gEfiEdidActiveProtocolGuid,
> +                  &UsbDisplayLinkDev->EdidActive,
> +                  NULL);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_WARN, "Error uninstalling Graphics Output and EDID protocol interfaces - %r.\n", Status));
> +    return Status;
> +  }
> +
> +  gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> +
> +  gBS->CloseProtocol (
> +         Controller,
> +         &gEfiUsbIoProtocolGuid,
> +         This->DriverBindingHandle,
> +         Controller);
> +
> +  //
> +  // Free all resources.
> +  //
> +  if (UsbDisplayLinkDev->ControllerNameTable != NULL) {
> +    FreeUnicodeStringTable (UsbDisplayLinkDev->ControllerNameTable);
> +  }
> +
> +  if (UsbDisplayLinkDev->Screen != NULL) {
> +    FreePool (UsbDisplayLinkDev->Screen);
> +    UsbDisplayLinkDev->Screen = NULL;
> +  }
> +
> +  if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode) {
> +    if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info) {
> +      FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info);
> +      UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info = NULL;
> +    }
> +    FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode);
> +    UsbDisplayLinkDev->GraphicsOutputProtocol.Mode = NULL;
> +  }
> +
> +  FreePool (UsbDisplayLinkDev);
> +
> +  return EFI_SUCCESS;
> +
> +}
> +
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> new file mode 100644
> index 000000000000..497a2621bc2c
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> @@ -0,0 +1,278 @@
> +/**
> + * @file UsbDisplayLink.h
> + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#ifndef _EFI_USB_DISPLAYLINK_H_
> +#define _EFI_USB_DISPLAYLINK_H_
> +
> +#include <Uefi/UefiBaseType.h>
> +#include <Uefi/UefiSpec.h>
> +
> +#include <Protocol/EdidActive.h>
> +#include <Protocol/EdidDiscovered.h>
> +#include <Protocol/EdidOverride.h>
> +#include <Protocol/GraphicsOutput.h>
> +#include <Protocol/UsbIo.h>
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/ReportStatusCodeLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +
> +#define VENDOR_DISPLAYLINK      0x17e9
> +#define CLASS_VENDOR            0xFF
> +
> +#define DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO ((UINTN)0)
> +
> +#define INTERFACE_PROTOCOL_DIRECT_FB    4
> +
> +#define USB_TRANSFER_LENGTH           (64 * 1024)
> +#define DISPLAYLINK_MODE_DATA_LENGTH  (146)
> +#define DISPLAYLINK_USB_CTRL_TIMEOUT  (1000)
> +#define DISPLAYLINK_USB_BULK_TIMEOUT  (1)
> +
> +#define DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD  ((UINTN)1000000) // 0.1s in us
> +#define DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD   ((UINTN)30000) // 3s in ticks
> +
> +#define DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE ((UINT16)60)
> +
> +// Requests to read values from the firmware
> +#define EDID_BLOCK_SIZE 128
> +#define EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK ((UINT16)(0x64))
> +
> +/** Structures ported from firmware - protocol.h */
> +enum ID {
> +  // VideoCommands
> +  GET_OUTPUT_EDID = 0,
> +  SET_VIDEO_MODE = 1
> +};
> +
> +typedef struct {
> +  UINT32                     HorizontalResolution;
> +  UINT32                     VerticalResolution;
> +  UINT32                     ColorDepth;
> +  UINT32                     RefreshRate;
> +  UINT8                      Commands[DISPLAYLINK_MODE_DATA_LENGTH];
> +} DISPLAYLINK_MODE_DATA;
> +
> +#define GRAPHICS_OUTPUT_INVALID_MODE_NUMBER 0xffff
> +
> +/**
> + *  Device instance of USB display.
> + */
> +typedef struct {
> +  UINT64                        Signature;
> +  EFI_HANDLE                    Handle;
> +  EFI_USB_IO_PROTOCOL           *UsbIo;
> +  EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
> +  EFI_USB_ENDPOINT_DESCRIPTOR   BulkOutEndpointDescriptor;
> +  EFI_USB_ENDPOINT_DESCRIPTOR   BulkInEndpointDescriptor;
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL  GraphicsOutputProtocol;
> +  EFI_EDID_DISCOVERED_PROTOCOL  EdidDiscovered;
> +  EFI_EDID_ACTIVE_PROTOCOL      EdidActive;
> +  EFI_UNICODE_STRING_TABLE      *ControllerNameTable;
> +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Screen;
> +  UINTN                         DataSent;                       /** Debug - used to track the bandwidth */
> +  EFI_EVENT                     TimerEvent;
> +  EFI_EVENT                     DriverExitBootServicesEvent;
> +  BOOLEAN                       ShowBandwidth;                 /** Debugging - show the bandwidth on the screen */
> +  BOOLEAN                       ShowTestPattern;               /** Show a colourbar pattern instead of the BLTd contents of the framebuffer */
> +  UINTN                         LastY1;                        /** Used to track if we can do a partial screen update */
> +  UINTN                         LastY2;
> +  UINTN                         LastWidth;
> +  UINTN                         TimeSinceLastScreenUpdate;     /** Do a full screen update every (x) seconds */
> +} USB_DISPLAYLINK_DEV;
> +
> +#define USB_DISPLAYLINK_DEV_SIGNATURE SIGNATURE_32 ('d', 'l', 'i', 'n')
> +
> +struct VideoMode {
> +  UINT8  Reserved1;          /* Reserved - must be 0. */
> +  UINT8  Reserved2;          /* Reserved - must be 2. */
> +
> +  // Values matching the EDID Detailed Timing Descriptor spec
> +  UINT16 PixelClock;
> +  UINT16 HActive;
> +  UINT16 HBlanking;
> +  UINT16 HSyncOffset;  // Horizontal Front Porch
> +  UINT16 HSyncWidth;
> +  UINT16 VActive;
> +  UINT16 VBlanking;
> +  UINT16 VSyncOffset;  // Vertical Front Porch
> +  UINT16 VSyncWidth;
> +  // End of Edid Detailed Timing Descriptor
> +
> +  UINT16 Flags               /*ModeFlags*/;
> +  UINT16 Accumulate;
> +  UINT16 Reserved3;         /* Reserved - must be 0. */
> +  UINT16 Reserved4;         /* Reserved - must be 0. */
> +  UINT16 InsetLeft;
> +  UINT16 InsetTop;
> +  UINT16 InsetRight;
> +  UINT16 InsetBottom;
> +  UINT32 FillValue;
> +  UINT32 Reserved5;        /* Reserved - must be 0. */
> +  UINT8  Vic;
> +  UINT8  ActiveFormat;
> +  UINT16 Reserved6;
> +};
> +
> +#define USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(a) \
> +  CR(a, USB_DISPLAYLINK_DEV, GraphicsOutputProtocol, USB_DISPLAYLINK_DEV_SIGNATURE)
> +
> +//
> +// Global Variables
> +//
> +extern EFI_DRIVER_BINDING_PROTOCOL   gUsbDisplayLinkDriverBinding;
> +extern EFI_COMPONENT_NAME_PROTOCOL   mUsbDisplayLinkComponentName;
> +extern EFI_COMPONENT_NAME2_PROTOCOL  mUsbDisplayLinkComponentName2;
> +
> +
> +/* ******************************************* */
> +/* ********  GOP interface functions  ******** */
> +/* ******************************************* */
> +
> +/**
> + * Implementation of the GOP protocol QueryMode API function
> + * @param This         Instance of the GOP protocol
> + * @param ModeNumber
> + * @param SizeOfInfo
> + * @param Info
> + * @return
> + */
> +EFI_STATUS
> +  EFIAPI
> +  DisplayLinkQueryMode (
> +    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
> +    IN  UINT32                                ModeNumber,
> +    OUT UINTN                                 *SizeOfInfo,
> +    OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
> +  );
> +
> +
> +/**
> + * Implementation of the GOP protocol SetMode API function
> + * @param This
> + * @param ModeNumber
> + * @return
> + */
> +EFI_STATUS
> +  EFIAPI
> +  DisplayLinkSetMode (
> +    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *This,
> +    IN  UINT32                        ModeNumber
> +  );
> +
> +/**
> + * Implementation of the GOP protocol Blt API function
> + * @param This
> + * @param BltBuffer
> + * @param BltOperation
> + * @param SourceX
> + * @param SourceY
> + * @param DestinationX
> + * @param DestinationY
> + * @param Width
> + * @param Height
> + * @param Delta
> + * @return
> + */
> +EFI_STATUS
> +  EFIAPI
> +  DisplayLinkBlt (
> +    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
> +    IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer, OPTIONAL
> +    IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
> +    IN  UINTN                                   SourceX,
> +    IN  UINTN                                   SourceY,
> +    IN  UINTN                                   DestinationX,
> +    IN  UINTN                                   DestinationY,
> +    IN  UINTN                                   Width,
> +    IN  UINTN                                   Height,
> +    IN  UINTN                                   Delta         OPTIONAL
> +  );
> +
> +/* *************************** */
> +/* **  GOP helper functions ** */
> +/* *************************** */
> +
> +VOID
> +EFIAPI
> +DlGopPrintTextToScreen (
> +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> +  UINTN X,
> +  UINTN Y,
> +  IN CONST CHAR16 *Format,
> +  ...
> +);
> +
> +EFI_STATUS
> +DlGopSendTestPattern (
> +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> +  UINTN PatternNumber
> +);
> +
> +EFI_STATUS
> +DlGopSendScreenUpdate (
> +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> +);
> +
> +
> +/* ******************************************* */
> +/* ********  USB interface functions  ******** */
> +/* ******************************************* */
> +
> +EFI_STATUS
> +DlUsbSendControlWriteMessage (
> +  IN USB_DISPLAYLINK_DEV *Device,
> +  IN UINT8 Request,
> +  IN UINT16 Value,
> +  IN CONST VOID *ControlMsg,
> +  IN UINT16 ControlMsgLen
> +);
> +
> +EFI_STATUS
> +DlUsbSendControlReadMessage (
> +  IN USB_DISPLAYLINK_DEV *Device,
> +  IN UINT8 Request,
> +  IN UINT16 Value,
> +  OUT VOID *ControlMsg,
> +  IN UINT16 ControlMsgLen
> +);
> +
> +EFI_STATUS
> +DlUsbBulkWrite (
> +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> +  CONST UINT8* Buffer,
> +  UINTN DataLen,
> +  UINT32 *USBStatus
> +);
> +
> +UINTN
> +DlUsbBulkRead (
> +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> +  UINT8* Buffer,
> +  UINTN BufferLen
> +);
> +
> +/* ******************************************* */
> +/* ********   Video Mode functions    ******** */
> +/* ******************************************* */
> +
> +// Pre-calculated video modes
> +UINT32
> +DlVideoModeGetNumSupportedVideoModes ();
> +
> +CONST struct VideoMode *
> +DlVideoModeGetSupportedVideoMode (
> +  UINT32 index
> +);
> +
> +#endif
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> new file mode 100644
> index 000000000000..252293da39d4
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> @@ -0,0 +1,180 @@
> +/**
> + * @file UsbTransfer.c
> + * @brief Wrapper of UEFI USB bulk and control transfer interface for USB DisplayLink driver.
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +
> +/**
> + * Write the data to the DisplayLink device using the USBIO protocol.
> + * @param UsbDisplayLinkDev
> + * @param Buffer
> + * @param DataLen
> + * @param USBStatus
> + * @return
> +  * EFI_SUCCESS   The bulk transfer has been successfully executed.
> +  * EFI_INVALID_PARAMETER   If DeviceEndpoint is not valid.
> +  * EFI_INVALID_PARAMETER   Data is NULL.
> +  * EFI_INVALID_PARAMETER   DataLength is NULL.
> +  * EFI_INVALID_PARAMETER   Status is NULL.
> +  * EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
> +  * EFI_TIMEOUT   The bulk transfer cannot be completed within Timeout timeframe.
> +  * EFI_DEVICE_ERROR  The transfer failed other than timeout, and the transfer status is returned in Status.
> + */
> +EFI_STATUS
> +DlUsbBulkWrite (
> +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> +    IN CONST UINT8* Buffer,
> +    IN UINTN DataLen,
> +    OUT UINT32 *USBStatus
> +    )
> +{
> +  EFI_STATUS Status;
> +  Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> +    UsbDisplayLinkDev->UsbIo,
> +    UsbDisplayLinkDev->BulkOutEndpointDescriptor.EndpointAddress,
> +    (VOID*)Buffer,
> +    &DataLen,
> +    DISPLAYLINK_USB_BULK_TIMEOUT,
> +    USBStatus);
> +
> +  return Status;
> +}
> +
> +/**
> +* Read data from the DisplayLink device using the USBIO protocol.
> +* @param UsbDisplayLinkDev
> +* @param Buffer
> +* @param BufferLen
> +* @return 0 if an error occurred or 0 bytes were read, otherwise the number of bytes read
> + */
> +UINTN
> +DlUsbBulkRead (
> +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> +    IN UINT8* Buffer,
> +    IN UINTN BufferLen
> +    )
> +{
> +  UINT32 Result;
> +  UINTN ReadLen;
> +  EFI_STATUS Status;
> +
> +  ReadLen = BufferLen;
> +
> +  Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> +    UsbDisplayLinkDev->UsbIo,
> +    UsbDisplayLinkDev->BulkInEndpointDescriptor.EndpointAddress,
> +    Buffer,
> +    &ReadLen,
> +    DISPLAYLINK_USB_BULK_TIMEOUT,
> +    &Result);
> +
> +  if (EFI_ERROR (Status)) {
> +    return 0;
> +  }
> +
> +  return ReadLen;
> +}
> +
> +
> +/**
> +Send a control message (e.g set video mode) message to the DisplayLink device.
> +
> +@param  Device                   USB device handle.
> +@param  request                  Request type, e.g. SET_VIDEO_MODE
> +@param  value
> +@param  controlMsg               Pointer to the message to send.
> +@param  controlMsgLen            Length of the message.
> +
> +@retval EFI_SUCCESS            Successfully sent message.
> +
> +**/
> +EFI_STATUS
> +DlUsbSendControlWriteMessage (
> +  IN USB_DISPLAYLINK_DEV *Device,
> +  IN UINT8 Request,
> +  IN UINT16 Value,
> +  IN CONST VOID *ControlMsg,
> +  IN UINT16 ControlMsgLen
> +  )
> +{
> +  EFI_STATUS             Status;
> +  UINT32                 UsbStatus;
> +  EFI_USB_DEVICE_REQUEST UsbRequest;
> +
> +  ZeroMem (&Request, sizeof (Request));
> +  UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE;
> +  UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> +  UsbRequest.Request = Request;
> +  UsbRequest.Value = Value;
> +  UsbRequest.Length = ControlMsgLen;
> +
> +  Status = Device->UsbIo->UsbControlTransfer (
> +    Device->UsbIo,
> +    &UsbRequest,
> +    EfiUsbDataOut,
> +    DISPLAYLINK_USB_CTRL_TIMEOUT,
> +    (VOID *)ControlMsg,
> +    ControlMsgLen,
> +    &UsbStatus);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "USB write control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> +    Status = EFI_DEVICE_ERROR;
> +  }
> +  return Status;
> +}
> +
> +
> +/**
> +Request data from the DisplayLink device (e.g. the monitor EDID)
> +
> +@param  Device                   USB device handle.
> +@param  request                  Request type, e.g. GET_OUTPUT_EDID
> +@param  value
> +@param  controlMsg               Pointer to the message to send.
> +@param  controlMsgLen            Length of the message.
> +
> +@retval EFI_SUCCESS            Successfully sent message.
> +
> +**/
> +EFI_STATUS
> +DlUsbSendControlReadMessage (
> +  IN USB_DISPLAYLINK_DEV *Device,
> +  IN UINT8 Request,
> +  IN UINT16 Value,
> +  OUT VOID *ControlMsg,
> +  IN UINT16 ControlMsgLen
> +  )
> +{
> +  EFI_STATUS             Status;
> +  UINT32                 UsbStatus;
> +  EFI_USB_DEVICE_REQUEST UsbRequest;
> +
> +  ZeroMem (&UsbRequest, sizeof (UsbRequest));
> +  UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE | USB_ENDPOINT_DIR_IN;
> +  UsbRequest.Request = Request;
> +  UsbRequest.Value = Value;
> +  UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> +  UsbRequest.Length = ControlMsgLen;
> +
> +  Status = Device->UsbIo->UsbControlTransfer (
> +    Device->UsbIo,
> +    &UsbRequest,
> +    EfiUsbDataIn,
> +    DISPLAYLINK_USB_CTRL_TIMEOUT,
> +    (VOID *)ControlMsg,
> +    ControlMsgLen,
> +    &UsbStatus);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "USB read control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> +    Status = EFI_DEVICE_ERROR;
> +  }
> +  return Status;
> +}
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> new file mode 100644
> index 000000000000..6218c093147c
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> @@ -0,0 +1,254 @@
> +/**
> + * @file VideoModes.c
> + * @brief Pre-calculated video timings sent to the DisplayLink device when a video mode is selected
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +
> +
> +// Supported video modes - must be in order of pixel count (i.e. hres x vres)
> +
> +STATIC CONST struct VideoMode ModeData[] = {
> +  {
> +     // 640 x 480 @ 60Hz
> +    .Reserved2 = 2,
> +    .PixelClock = 2517,
> +    .HActive = 640,
> +    .HBlanking = 160,
> +    .HSyncOffset = 16,
> +    .HSyncWidth = 96,
> +    .VActive = 480,
> +    .VBlanking = 45,
> +    .VSyncOffset = 10,
> +    .VSyncWidth = 2,
> +    .Flags = 0x00000300,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  },
> +  {
> +    // 800 x 600 @ 60Hz
> +    .Reserved2 = 2,
> +    .PixelClock = 4000,
> +    .HActive = 800,
> +    .HBlanking = 256,
> +    .HSyncOffset = 40,
> +    .HSyncWidth = 128,
> +    .VActive = 600,
> +    .VBlanking = 28,
> +    .VSyncOffset = 1,
> +    .VSyncWidth = 3,
> +    .Flags = 0x00000000,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  },
> +  {
> +    // 1024x768 @ 60Hz
> +    .Reserved1 = 0,
> +    .Reserved2 = 2,
> +    .PixelClock = 6500,
> +    .HActive = 1024,
> +    .HBlanking = 320,
> +    .HSyncOffset = 24,
> +    .HSyncWidth = 136,
> +    .VActive = 768,
> +    .VBlanking = 38,
> +    .VSyncOffset = 3,
> +    .VSyncWidth = 6,
> +    .Flags = 0x00000300,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  },
> +  {
> +    // 1360x768 @ 60Hz
> +    .Reserved1 = 0,
> +    .Reserved2 = 2,
> +    .PixelClock = 8550,
> +    .HActive = 1360,
> +    .HBlanking = 432,
> +    .HSyncOffset = 64,
> +    .HSyncWidth = 112,
> +    .VActive = 768,
> +    .VBlanking = 27,
> +    .VSyncOffset = 3,
> +    .VSyncWidth = 6,
> +    .Flags = 0x00000000,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  },
> +  {
> +    // 1280x960 @ 60Hz
> +    .Reserved1 = 0,
> +    .Reserved2 = 2,
> +    .PixelClock = 10800,
> +    .HActive = 1280,
> +    .HBlanking = 520,
> +    .HSyncOffset = 96,
> +    .HSyncWidth = 112,
> +    .VActive = 960,
> +    .VBlanking = 40,
> +    .VSyncOffset = 1,
> +    .VSyncWidth = 3,
> +    .Flags = 0x00000000,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  },
> +  {
> +    // 1280x1024 @ 60Hz
> +    .Reserved1 = 0,
> +    .Reserved2 = 2,
> +    .PixelClock = 10800,
> +    .HActive = 1280,
> +    .HBlanking = 408,
> +    .HSyncOffset = 48,
> +    .HSyncWidth = 112,
> +    .VActive = 1024,
> +    .VBlanking = 42,
> +    .VSyncOffset = 1,
> +    .VSyncWidth = 3,
> +    .Flags = 0x00000000,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  },
> +  {
> +    // 1600x900 @ 60Hz
> +    .Reserved2 = 2,
> +    .PixelClock = 11825,
> +    .HActive = 1600,
> +    .HBlanking = 512,
> +    .HSyncOffset = 88,
> +    .HSyncWidth = 168,
> +    .VActive = 900,
> +    .VBlanking = 34,
> +    .VSyncOffset = 3,
> +    .VSyncWidth = 5,
> +    .Flags = 0x00000500,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  },
> +  {
> +    // 1400x1050 @ 60Hz
> +    .Reserved1 = 0,
> +    .Reserved2 = 2,
> +    .PixelClock = 12175,
> +    .HActive = 1400,
> +    .HBlanking = 464,
> +    .HSyncOffset = 88,
> +    .HSyncWidth = 144,
> +    .VActive = 1050,
> +    .VBlanking = 39,
> +    .VSyncOffset = 3,
> +    .VSyncWidth = 4,
> +    .Flags = 0x00000100,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  },
> +  {
> +    // 1600x1200 @ 60Hz
> +    .Reserved1 = 0,
> +    .Reserved2 = 2,
> +    .PixelClock = 16200,
> +    .HActive = 1600,
> +    .HBlanking = 560,
> +    .HSyncOffset = 64,
> +    .HSyncWidth = 192,
> +    .VActive = 1200,
> +    .VBlanking = 50,
> +    .VSyncOffset = 1,
> +    .VSyncWidth = 3,
> +    .Flags = 0x00000000,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  },
> +  {
> +    // 1920 x 1080
> +    .Reserved2 = 2,
> +    .PixelClock = 14850,
> +    .HActive = 1920,
> +    .HBlanking = 280,
> +    .HSyncOffset = 88,
> +    .HSyncWidth = 44,
> +    .VActive = 1080,
> +    .VBlanking = 45,
> +    .VSyncOffset = 4,
> +    .VSyncWidth = 5,
> +    .Flags = 0x00000000,
> +    .Accumulate = 1,
> +    .Reserved3 = 0,
> +    .Reserved4 = 0,
> +    .Reserved5 = 0x00000000,
> +    .Vic = 0,
> +    .ActiveFormat = 0,
> +  }
> +};
> +
> +STATIC CONST UINT32 NumSupportedVideoModes = (sizeof (ModeData) / sizeof (struct VideoMode));
> +
> +/**
> +Find the number of pre-calculated video modes that we support.
> +
> +@retval Number of modes.
> +
> +**/
> +UINT32 DlVideoModeGetNumSupportedVideoModes ()
> +{
> +  return NumSupportedVideoModes;
> +}
> +
> +/**
> +Get one of the pre-calculated video modes
> +
> +@param  index      The video mode that we want.
> +
> +@retval NULL       The index was out of range.
> +
> +**/
> +CONST struct VideoMode *DlVideoModeGetSupportedVideoMode (
> +    UINT32 Index
> +    )
> +{
> +  if (Index >= NumSupportedVideoModes) {
> +    return NULL;
> +  }
> +  return &ModeData[Index];
> +}
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> new file mode 100644
> index 000000000000..955331ba6076
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> @@ -0,0 +1,61 @@
> +#/** @file
> +#
> +#  Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +[Defines]
> +  PLATFORM_NAME                  = DisplayLinkPkg
> +  PLATFORM_GUID                  = ad3b37b0-f798-4f97-9b3f-0c6f43d7c993
> +  PLATFORM_VERSION               = 0.1
> +  DSC_SPECIFICATION              = 0x0001001C
> +  OUTPUT_DIRECTORY               = Build/DisplayLink
> +  SUPPORTED_ARCHITECTURES        = X64|IA32|AARCH64|ARM
> +  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
> +  SKUID_IDENTIFIER               = DEFAULT
> +
> +[LibraryClasses]
> +  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
> +  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> +  DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
> +  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
> +  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> +  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> +  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
> +  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
> +  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
> +  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
> +  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
> +  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
> +  UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
> +
> +[LibraryClasses.common.UEFI_DRIVER]
> +  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
> +
> +[LibraryClasses.AARCH64]
> +  NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> +  NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> +
> +[LibraryClasses.ARM]
> +  NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> +  NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> +
> +[PcdsFixedAtBuild]
> +!ifdef $(DEBUG_ENABLE_OUTPUT)
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x3f
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80080043  # Flags to control amount of debug output - see https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging
> +  gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x07
> +!endif
> +
> +[Components]
> +  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> +
> +[BuildOptions]
> +  *_*_*_CC_FLAGS               = -D DISABLE_NEW_DEPRECATED_INTERFACES -D INF_DRIVER_VERSION=$(INF_DRIVER_VERSION)
> +  GCC:RELEASE_*_*_CC_FLAGS     = -DMDEPKG_NDEBUG
> +  MSFT:RELEASE_*_*_CC_FLAGS    = /D MDEPKG_NDEBUG
> +!ifdef $(COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE)
> +  *_*_*_CC_FLAGS = -D COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> +!endif
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> new file mode 100644
> index 000000000000..40061f1eb46d
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> @@ -0,0 +1,77 @@
> +# DISPLAYLINK DRIVERS
> +This package contains a GOP driver for Universal USB-connected docks containing the
> +DisplayLink DL-6xxx chip or newer.
> +
> +[DisplayLink Website](http://www.displaylink.com)
> +
> +[Products](https://www.displaylink.com/products/universal-docking-stations)
> +
> +# INDEX
> +
> +* [Resolutions Supported](#resolutions-supported)
> +* [Frame rates](#frame-rates)
> +* [Multiple monitor outputs](#multiple-monitor-outputs)
> +* [Multiple DisplayLink devices](#multiple-displaylink-devices)
> +* [Behaviour with no monitor connected](#behaviour-with-no-monitor-connected)
> +
> +# Resolutions supported
> +
> +The driver supports the following resolutions:
> +
> +640 x 480 @ 60Hz
> +
> +800 x 600 @ 60Hz
> +
> +1024x768 @ 60Hz
> +
> +1360x768 @ 60Hz
> +
> +1280x960 @ 60Hz
> +
> +1280x1024 @ 60Hz
> +
> +1600x900 @ 60Hz
> +
> +1400x1050 @ 60Hz
> +
> +1600x1200 @ 60Hz
> +
> +1920x1080 @ 60Hz
> +
> +
> +Note that the list of resolutions advertised by the driver may be smaller than
> +this if a connected monitor does not support a particular resolution. The driver
> +interrogates connected monitors to see which modes can be supported.It is the
> +responsibility of the BIOS to select the video mode from this list which most
> +closely matches its requirements. In some cases this may lead to the BIOS
> +scaling its display.
> +
> +# Frame rates
> +
> +The driver is limited to a maximum of ten frames per second. Some slower systems
> +at higher screen resolutions may perform at a lower rate than this.
> +
> +# Multiple monitor outputs
> +
> +If multiple monitors are connected to the DisplayLinkdevice, the display will be
> +duplicated (cloned) across all outputs at the same resolution. The resolution
> +used will be limited by the capability of the monitor with the
> +lowest specification.
> +
> +# Multiple DisplayLink devices
> +
> +The driver will support the connection of multiple DisplayLink devices. The
> +exact behaviourof the system with multiple devices connected is defined by the
> +rest of the BIOS; usually, the BIOS causes the displays to be duplicated
> +(cloned) across all devices. Note that the system performance and frame rate
> +will be affected by the number of DisplayLink devices connected.
> +
> +# Behaviour with no monitor connected
> +
> +The driver uses the EDID (Extended Display Identification Data) protocol to
> +detect the list of resolutions that a monitor will support.In some monitors this
> +may take some time, and occasionally no EDID information will be returned at
> +all. In this case the driver will not be able to detect that there is a monitor
> +connected. To improve the user experience in these cases, the driver will behave
> +as if there is a monitor connected, and will fall back to presenting the full
> +range of supported resolutions to the BIOS.
> diff --git a/Maintainers.txt b/Maintainers.txt
> index 876ae5612ad8..47aac133abb1 100644
> --- a/Maintainers.txt
> +++ b/Maintainers.txt
> @@ -47,6 +47,11 @@ Drivers/OptionRomPkg
>  W: https://github.com/tianocore/tianocore.github.io/wiki/OptionRomPkg
>  M: Ray Ni <ray.ni@intel.com>
>  
> +Drivers/DisplayLink
> +M: Leif Lindholm <leif.lindholm@linaro.org>
> +M: Ard Bieshuevel <ard.bieshuevel@linaro.org>
> +R: Andy Hayes <andy.hayes@displaylink.com>
> +
>  Platform
>  M: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>  M: Leif Lindholm <leif.lindholm@linaro.org>
> -- 
> 2.20.1
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [External] Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips
  2019-08-30 15:27   ` [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips Leif Lindholm
@ 2019-09-09  8:06     ` Andy Hayes
  2019-09-09 11:00       ` Leif Lindholm
  2019-09-13  7:57     ` Ni, Ray
  2019-10-04 19:54     ` [edk2-devel] " Laszlo Ersek
  2 siblings, 1 reply; 6+ messages in thread
From: Andy Hayes @ 2019-09-09  8:06 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: devel@edk2.groups.io, Michael D Kinney, Ni, Ray

[-- Attachment #1: Type: text/plain, Size: 131881 bytes --]

Hi,

Is it OK to commit this now? Does anyone else have any comments on it?

Best Regards,

Andy Hayes

From: Leif Lindholm <leif.lindholm@linaro.org>
Sent: 30 August 2019 16:27
To: Andy Hayes <andy.hayes@displaylink.com>
Cc: devel@edk2.groups.io; Michael D Kinney <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>
Subject: [External] Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips

Hi Andy,

This looks fine to me - all my feedback has been addressed.
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org<mailto:leif.lindholm@linaro.org>>

Ray - did you have any comments on this, or can I go ahead and commit?

Best Regards,

Leif

On Mon, Aug 19, 2019 at 02:32:00PM +0100, Andy Hayes wrote:
> Cc: Leif Lindholm <leif.lindholm@linaro.org<mailto:leif.lindholm@linaro.org>>
> Cc: Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
> Signed-off-by: Andy Hayes <andy.hayes@displaylink.com<mailto:andy.hayes@displaylink.com>>
> ---
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c | 137 +++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c | 235 +++++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf | 65 ++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c | 598 +++++++++++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h | 129 +++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c | 578 +++++++++++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c | 145 +++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h | 109 ++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c | 1082 ++++++++++++++++++++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h | 278 +++++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c | 180 ++++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c | 254 +++++
> Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc | 61 ++
> Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md | 77 ++
> Maintainers.txt | 5 +
> 15 files changed, 3933 insertions(+)
>
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> new file mode 100644
> index 000000000000..4bfadd770b81
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> @@ -0,0 +1,137 @@
> +/** @file CapabilityDescriptor.c
> + * @brief Definitions for reading USB capability descriptor DisplayLink dock
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +#include "UsbDescriptors.h"
> +
> +/**
> + * Check that the Capability Descriptor is valid and hasn't been tampered with.
> + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> + * @param Length
> + * @param out
> + * @return
> + */
> +STATIC EFI_STATUS
> +ValidateHeader (
> + CONST IN VOID* Data,
> + IN UINTN Length,
> + OUT CONST VendorDescriptorGeneric** Out
> + )
> +{
> + if (Length < sizeof (VendorDescriptorGeneric)) {
> + DEBUG ((DEBUG_ERROR, "Data too short (%d bytes) for capability descriptor header section\n", Length));
> + return EFI_INVALID_PARAMETER;
> + }
> + CONST VendorDescriptorGeneric* Desc = (VendorDescriptorGeneric*)Data;
> + if (Desc->Length > Length) {
> + DEBUG ((DEBUG_ERROR, "Capability descriptor: Descriptor (%d bytes) exceeds buffer (%d bytes)\n",
> + Length, Desc->Length));
> + return EFI_BUFFER_TOO_SMALL;
> + }
> + if (Desc->Type != DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY) {
> + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid type (0x%08x)\n", Desc->Type));
> + return EFI_UNSUPPORTED;
> + }
> + if (Desc->CapabilityVersion != 1) {
> + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid version (%d)\n", Desc->CapabilityVersion));
> + return EFI_INCOMPATIBLE_VERSION;
> + }
> + // Capability length must fit within remaining space
> + if (Desc->CapabilityLength > (Desc->Length - (sizeof (Desc->Length) + sizeof (Desc->Type)))) {
> + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid CapabilityLength (%d)\n", Desc->CapabilityLength));
> + return EFI_INVALID_PARAMETER;
> + }
> + *Out = Desc;
> + return EFI_SUCCESS;
> +}
> +
> +
> +/**
> + * Check that the connected DisplayLink device supports the functionality that this driver requires, e.g. video formats
> + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> + * @param Length
> + * @param Output
> + * @return
> + */
> +EFI_STATUS
> +UsbDisplayLinkParseCapabilitiesDescriptor (
> + CONST IN VOID* Data,
> + IN UINTN Length,
> + OUT VendorDescriptor* Output
> + )
> +{
> + CONST VendorDescriptorGeneric* Desc;
> + EFI_STATUS Status;
> +
> + Desc = NULL;
> + Status = ValidateHeader (Data, Length, &Desc);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + // Default capabilities
> + Output->Capabilities1 = 0;
> +
> + CONST UINTN CapsHeaderLength = sizeof (Desc->CapabilityVersion) + sizeof (Desc->CapabilityLength);
> + ASSERT (CapsHeaderLength < MAX_UINT8);
> +
> + UINTN DataRemaining;
> + UINTN Offset;
> +
> + DataRemaining = Desc->CapabilityLength - CapsHeaderLength;
> + Offset = 0;
> +
> + while (DataRemaining >= sizeof (DescriptorKLV)) {
> + CONST DescriptorKLV* KeyHeader = (CONST DescriptorKLV*)(Desc->Klv + Offset);
> + CONST UINTN KeyValueSize = sizeof (DescriptorKLV) + KeyHeader->Length;
> + if (KeyValueSize > DataRemaining) {
> + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid value Length (%d)\n", Desc->CapabilityLength));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + switch (KeyHeader->Key) {
> + case CAPABILITIES1_KEY: {
> + if (KeyHeader->Length != CAPABILITIES1_LENGTH) {
> + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid length (%d) for Capabilities 1\n", KeyHeader->Length));
> + return EFI_INVALID_PARAMETER;
> + }
> + Output->Capabilities1 = *(UINT32*)KeyHeader->Value;
> + break;
> + default:
> + // Ignore unknown types
> + break;
> + }
> + }
> + DataRemaining -= KeyValueSize;
> + Offset += KeyValueSize;
> + }
> + return EFI_SUCCESS;
> +}
> +
> +
> +/**
> + * Check that the DisplayLink device supports the basic level of functionality to display GOP pixels.
> + * @param Descriptor The USB descriptor received from the DisplayLink device
> + * @return True we can bind, False we can't
> + */
> +BOOLEAN
> +UsbDisplayLinkCapabilitiesSufficientToBind (
> + CONST IN VendorDescriptor* Descriptor
> + )
> +{
> + BOOLEAN Sufficient;
> + Sufficient = (BOOLEAN)(Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL);
> +
> + if (Sufficient == FALSE) {
> + DEBUG ((DEBUG_ERROR, "DisplayLink device does not report support for base capabilites - reports x%x, required x%x\n", Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL));
> + }
> + return Sufficient;
> +}
> +
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> new file mode 100644
> index 000000000000..74498f339eb7
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> @@ -0,0 +1,235 @@
> +/**
> + * @file ComponentName.c
> + * @brief UEFI Component Name protocol implementation for USB DisplayLink driver.
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> +);
> +
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> +);
> +
> +
> +//
> +// EFI Component Name Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL mUsbDisplayLinkComponentName = {
> + UsbDisplayLinkComponentNameGetDriverName,
> + UsbDisplayLinkComponentNameGetControllerName,
> + "eng"
> +};
> +
> +//
> +// EFI Component Name 2 Protocol
> +//
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplayLinkComponentName2 = {
> + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbDisplayLinkComponentNameGetDriverName,
> + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbDisplayLinkComponentNameGetControllerName,
> + "en"
> +};
> +
> +
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbDisplayLinkDriverNameTable[] = {
> + { (CHAR8*)"eng;en", (CHAR16*)L"DisplayLink USB GOP Driver" },
> + { (CHAR8*)NULL , (CHAR16*)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 A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param Language 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 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
> +UsbDisplayLinkComponentNameGetDriverName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN CHAR8 *Language,
> + OUT CHAR16 **DriverName
> + )
> +{
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + mUsbDisplayLinkDriverNameTable,
> + DriverName,
> + (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> +}
> +
> +/**
> + 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 A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> + EFI_COMPONENT_NAME_PROTOCOL instance.
> + @param ControllerHandle 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 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 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 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 not a valid EFI_HANDLE.
> + @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
> +UsbDisplayLinkComponentNameGetControllerName (
> + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> + IN EFI_HANDLE ControllerHandle,
> + IN EFI_HANDLE ChildHandle OPTIONAL,
> + IN CHAR8 *Language,
> + OUT CHAR16 **ControllerName
> + )
> +{
> + EFI_STATUS Status;
> + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
> + EFI_USB_IO_PROTOCOL *UsbIoProtocol;
> +
> + //
> + // This is a device driver, so ChildHandle must be NULL.
> + //
> + if (ChildHandle != NULL) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + //
> + // Check Controller's handle
> + //
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **) &UsbIoProtocol,
> + gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_BY_DRIVER);
> +
> + if (!EFI_ERROR (Status)) {
> + gBS->CloseProtocol (
> + ControllerHandle,
> + &gEfiUsbIoProtocolGuid,
> + gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> + ControllerHandle);
> +
> + return EFI_UNSUPPORTED;
> + }
> +
> + if (Status != EFI_ALREADY_STARTED) {
> + return EFI_UNSUPPORTED;
> + }
> + //
> + // Get the device context
> + //
> + Status = gBS->OpenProtocol (
> + ControllerHandle,
> + &gEfiGraphicsOutputProtocolGuid,
> + (VOID**)&GraphicsOutputProtocol,
> + gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> + ControllerHandle,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> +
> + return LookupUnicodeString2 (
> + Language,
> + This->SupportedLanguages,
> + UsbDisplayLinkDev->ControllerNameTable,
> + ControllerName,
> + (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> +}
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> new file mode 100644
> index 000000000000..0f458fedcc88
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> @@ -0,0 +1,65 @@
> +#/** @file
> +# USB DisplayLink driver that implements blt and EDID commands
> +#
> +# USB DisplayLink driver consumes I/O Protocol and Device Path Protocol, and produces
> +# Graphics Output Protocol on DisplayLink devices.
> +# 1. DisplayLink reference
> +# 2. UEFI Specification, v2.1
> +#
> +# Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +
> +[Defines]
> + INF_VERSION = 0x0001001B
> + BASE_NAME = DisplayLinkGop
> + FILE_GUID = 2D2E62AA-9ECF-43b7-8219-94E7FC713DFF
> + MODULE_TYPE = UEFI_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = UsbDisplayLinkDriverBindingEntryPoint
> + UNLOAD_IMAGE = UsbDisplayLinkDriverCombinedGopUnload
> + INF_DRIVER_VERSION = 0x00000001
> +
> +[Sources]
> + CapabilityDescriptor.c
> + ComponentName.c
> + Edid.c
> + Edid.h
> + Gop.c
> + UsbDescriptors.c
> + UsbDescriptors.h
> + UsbDisplayLink.c
> + UsbDisplayLink.h
> + UsbTransfer.c
> + VideoModes.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> + BaseMemoryLib
> + DebugLib
> + MemoryAllocationLib
> + ReportStatusCodeLib
> + UefiBootServicesTableLib
> + UefiDriverEntryPoint
> + UefiLib
> + UefiUsbLib
> +
> +[Protocols]
> + gEfiUsbIoProtocolGuid ## TO_START
> + gEfiEdidActiveProtocolGuid # PROTOCOL BY_START
> + gEfiEdidDiscoveredProtocolGuid # PROTOCOL BY_START
> + gEfiEdidOverrideProtocolGuid # PROTOCOL TO_START
> + gEfiHiiDatabaseProtocolGuid
> + gEfiHiiFontProtocolGuid
> +
> +[Guids]
> + gEfiEventExitBootServicesGuid
> + gEfiGlobalVariableGuid
> +
> +[Pcd]
> + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize ## CONSUMES
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> new file mode 100644
> index 000000000000..21f4b7d9c736
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> @@ -0,0 +1,598 @@
> +/** @file Edid.c
> + * @brief Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +#include "Edid.h"
> +
> +CONST UINT8 ExpectedEdidHeader[EDID_HEADER_SIZE] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
> +
> +//
> +// Standard timing defined by VESA EDID
> +//
> +CONST EDID_TIMING EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES][8] = {
> + //
> + // Established Timing I
> + //
> + {
> + { 800, 600, 60 },
> + { 800, 600, 56 },
> + { 640, 480, 75 },
> + { 640, 480, 72 },
> + { 640, 480, 67 },
> + { 640, 480, 60 },
> + { 720, 400, 88 },
> + { 720, 400, 70 },
> + },
> + {
> + //
> + // Established Timing II
> + //
> + { 1280, 1024, 75 },
> + { 1024, 768, 75 },
> + { 1024, 768, 70 },
> + { 1024, 768, 60 },
> + { 1024, 768, 87 },
> + { 832, 624, 75 },
> + { 800, 600, 75 },
> + { 800, 600, 72 },
> + },
> + //
> + // Established Timing III
> + //
> + {
> + { 1152, 870, 75 },
> + { 0, 0, 0 },
> + { 0, 0, 0 },
> + { 0, 0, 0 },
> + { 0, 0, 0 },
> + { 0, 0, 0 },
> + { 0, 0, 0 },
> + { 0, 0, 0 },
> + }
> +};
> +
> +/**
> + * Requests the monitor EDID data from the connected DisplayLink device
> + * @param UsbDisplayLinkDev
> + * @param EdidDataBlock
> + * @param EdidSize
> + * @retval EFI_DEVICE_ERROR - No EDID received, or EDID is corrupted
> + * @retval EFI_OUT_OF_RESOURCES - Cannot allocate memory
> + * @retval EFI_SUCCESS
> + *
> + */
> +STATIC EFI_STATUS
> +ReadEdidData (
> + IN USB_DISPLAYLINK_DEV *UsbDisplayLinkDev,
> + OUT UINT8 **EdidDataBlock,
> + OUT UINTN *EdidSize
> +)
> +{
> + EFI_STATUS Status;
> +
> + UINT8 EdidDataRead[EDID_BLOCK_SIZE];
> + UINT8 *EdidData = EdidDataRead;
> + UINT8* ValidEdid;
> +
> + Status = DlUsbSendControlReadMessage (UsbDisplayLinkDev, GET_OUTPUT_EDID, 0, EdidDataRead, sizeof (EdidDataRead));
> +
> + if (EFI_ERROR (Status) || (EdidData[0] != 0)) {
> + DEBUG ((DEBUG_ERROR, "No monitor EDID received from DisplayLink device - System error %r, EDID error %d. Monitor connected correctly?\n", Status, EdidData[0]));
> + return EFI_DEVICE_ERROR;
> + } else {
> + //
> + // Search for the EDID signature
> + //
> + ValidEdid = &EdidData[0];
> + CONST UINT64 Signature = 0x00ffffffffffff00ull;
> + if (CompareMem (ValidEdid, &Signature, 8) != 0) {
> + //
> + // No EDID signature found
> + //
> + DEBUG ((DEBUG_ERROR, "Monitor EDID received from DisplayLink device did not have a valid signature - corrupted?\n"));
> + Status = EFI_DEVICE_ERROR;
> + return Status;
> + }
> + }
> +
> + *EdidDataBlock = (UINT8*)AllocateCopyPool (
> + EDID_BLOCK_SIZE,
> + ValidEdid);
> +
> + if (*EdidDataBlock == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + //
> + // Currently only support EDID 1.x
> + //
> + *EdidSize = EDID_BLOCK_SIZE;
> +
> + return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +Calculates the mod256 checksum of the EDID and compares it with the one supplied at the end of the EDID
> +@param EDID Pointer to the 128-byte EDID
> +@retval TRUE The EDID checksum is correct
> +**/
> +BOOLEAN
> +IsEdidChecksumCorrect (
> + CONST VOID *EDID
> + )
> +{
> + CONST UINT8 EdidChecksum = ((UINT8 *)EDID)[EDID_BLOCK_SIZE - 1];
> + UINT8 CalculatedChecksum;
> +
> + CalculatedChecksum = 0;
> +
> + UINTN i;
> + for (i = 0; i < EDID_BLOCK_SIZE - 1; i++) {
> + CalculatedChecksum += ((UINT8 *)EDID)[i];
> + }
> + CalculatedChecksum = 0 - CalculatedChecksum;
> +
> + return (CalculatedChecksum == EdidChecksum);
> +}
> +
> +/**
> +Check if a particular video mode is in the Established Timings section of the EDID.
> +
> +@param EDID Pointer to the 128-byte EDID
> +@param hRes Horizontal resolution
> +@param vRes Vertical resolution
> +@param refresh Refresh rate
> +@retval TRUE The requested mode is present in the Established Timings section
> +
> +**/
> +STATIC BOOLEAN
> +IsModeInEstablishedTimings (
> + IN CONST VOID *EDID,
> + IN UINT16 HRes,
> + IN UINT16 VRes,
> + IN UINT16 Refresh
> + )
> +{
> + CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> + BOOLEAN ModeSupported;
> +
> + ModeSupported = FALSE;
> +
> + int EstByteNum;
> + int BitNum;
> + for (EstByteNum = 0; EstByteNum < EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES; EstByteNum++) {
> + for (BitNum = 0; BitNum < 8; BitNum++) {
> + if (pEDID->EstablishedTimings[EstByteNum] & (1 << BitNum)) { // The bit is set in the established timings of the EDID
> +
> + if ((EstablishedTimings[EstByteNum][BitNum].HRes == HRes) && // The passed-in resolution matches the resolution represented by the set bit
> + (EstablishedTimings[EstByteNum][BitNum].VRes == VRes) &&
> + (EstablishedTimings[EstByteNum][BitNum].Refresh == Refresh)) {
> +
> + ModeSupported = TRUE;
> + break;
> + }
> + }
> + }
> + if (ModeSupported == TRUE) {
> + break;
> + }
> + }
> + return ModeSupported;
> +}
> +
> +/**
> +Extract the resolutions and refresh rate from one of the entries in the Standard Timings section of the EDID.
> +
> +@param EDID Pointer to the 128-byte EDID
> +@param timingNumber The entry that we want to extract
> +@param hRes Output - Horizontal resolution
> +@param vRes Output - Vertical resolution
> +@param refresh Output - Refresh rate
> +@retval TRUE The requested Standard Timings entry contains valid data
> +
> +**/
> +STATIC BOOLEAN ReadStandardTiming (
> + CONST VOID *EDID,
> + IN UINT8 TimingNumber,
> + OUT UINT16 *HRes,
> + OUT UINT16 *VRes,
> + OUT UINT8 *Refresh)
> +{
> + CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> +
> + // See section 3.9.1 of the VESA EDID spec
> +
> + if (((pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels) == 0x01) &&
> + (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh) == 0x01) {
> + *HRes = 0;
> + *VRes = 0;
> + *Refresh = 0;
> + return FALSE;
> + }
> + *HRes = (pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels + 31) * 8;
> +
> + UINT8 AspectRatio;
> + AspectRatio = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh >> 6) & 0x3;
> +
> + switch (AspectRatio) {
> + case 0: *VRes = (*HRes * 10) / 16;
> + break;
> + case 1: *VRes = (*HRes * 3) / 4;
> + break;
> + case 2: *VRes = (*HRes * 4) / 5;
> + break;
> + case 3: *VRes = (*HRes * 9) / 16;
> + break;
> + default: break;
> + }
> +
> + // WORKAROUND - 1360x768 is not a perfect aspect ratio
> + if ((*HRes == 1360) && (*VRes == 765)) {
> + *VRes = 768;
> + }
> +
> + *Refresh = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh & 0x1F) + 60;
> +
> + return TRUE;
> +}
> +
> +/**
> +Extract the resolutions and refresh rate from one of the entries in the Detailed Timings section of the EDID.
> +
> +@param EDID Pointer to the 128-byte EDID
> +@param timingNumber The entry that we want to extract
> +@param videoMode Output - Filled in with details from the detailed timing
> +@retval TRUE The requested Detailed Timings entry contains valid data
> +
> +**/
> +STATIC BOOLEAN
> +ReadDetailedTiming (
> + IN CONST VOID *EDID,
> + IN UINT8 TimingNumber,
> + OUT struct VideoMode *VideoMode
> + )
> +{
> + if (TimingNumber >= EDID_NUMBER_OF_DETAILED_TIMINGS) {
> + return FALSE;
> + }
> +
> + UINT16 NumValidDetailedTimingsFound;
> + NumValidDetailedTimingsFound = 0;
> +
> + // Spin through the detailed timings until we find a valid one - then check if this has the index that we want
> + int BlockNumber;
> + for (BlockNumber = 0; BlockNumber < EDID_NUMBER_OF_DETAILED_TIMINGS; BlockNumber++) {
> + CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> + CONST struct DetailedTimingIdentification *pTiming = &pEDID->detailedTimingDescriptions[BlockNumber];
> +
> + if (((BlockNumber == 0) && (pTiming->PixelClock == EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK)) ||
> + (pTiming->PixelClock == 0)) {
> + // This is not a valid detailed timing descriptor
> + continue;
> + }
> +
> + if ((pTiming->Features & EdidDetailedTimingsFeaturesSyncSchemeMask) != EdidDetailedTimingsFeaturesSyncSchemeMask) {
> + DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported sync scheme found - not processing.\n"));
> + continue;
> + }
> +
> + if ((pTiming->Features & EdidDetailedTimingsFeaturesStereoModeMask) != 0) {
> + DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported stereo mode found - not processing.\n"));
> + continue;
> + }
> +
> + // We've found a supported detailed timing - now see if this is the requested one
> + if (TimingNumber != NumValidDetailedTimingsFound) {
> + NumValidDetailedTimingsFound++;
> + continue;
> + }
> +
> + ZeroMem ((VOID *)VideoMode, sizeof (struct VideoMode));
> +
> + // Bit manipulations copied from host software class EDIDTimingDescriptor
> +
> + VideoMode->PixelClock = (UINT16)pTiming->PixelClock;
> + VideoMode->HActive = pTiming->HActiveLo + ((pTiming->HActiveHiBlankingHi & 0xF0) << 4);
> + VideoMode->VActive = pTiming->VActiveLo + ((pTiming->VActiveHiBlankingHi & 0xF0) << 4);
> +
> + VideoMode->HBlanking = pTiming->HBlankingLo + ((pTiming->HActiveHiBlankingHi & 0x0F) << 8);
> + VideoMode->VBlanking = pTiming->VBlankingLo + ((pTiming->VActiveHiBlankingHi & 0x0F) << 8);
> +
> + VideoMode->HSyncOffset = pTiming->HSyncOffsetLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0xC0) << 2); // Horizontal Front Porch
> + VideoMode->HSyncWidth = pTiming->HSyncWidthLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x30) << 4);
> +
> + VideoMode->VSyncOffset = ((pTiming->VSyncOffsetLoSyncWidthLo & 0xF0) >> 4) + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x0C) << 2); // Vertical Front Porch
> + VideoMode->VSyncWidth = (pTiming->VSyncOffsetLoSyncWidthLo & 0x0F) + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x03) << 4);
> +
> + VideoMode->Reserved2 = 2;
> + VideoMode->Accumulate = 1;
> +
> + // Horizontal and vertical sync inversions - positive if bit set in descriptor (EDID spec)
> + // In the VideoMode, they are negative if the bit is set (NR-110497-TC 4.3.3 0x22 Set Video Mode)
> +
> + // Horizontal sync
> + if ((pTiming->Features & EdidDetailedTimingsFeaturesHorizontalSyncPositive) == 0) {
> + VideoMode->Flags |= VideoModeFlagsHorizontalSyncInverted;
> + }
> + // Vertical sync
> + if ((pTiming->Features & EdidDetailedTimingsFeaturesVerticalSyncPositive) == 0) {
> + VideoMode->Flags |= VideoModeFlagsVerticalSyncInverted;
> + }
> + // Interlace
> + if ((pTiming->Features & EdidDetailedTimingsFeaturesInterlaced) == EdidDetailedTimingsFeaturesInterlaced) {
> + VideoMode->Flags |= VideoModeFlagsInterlaced;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Read mode %dx%d from detailed timings\n", VideoMode->HActive, VideoMode->VActive));
> + return TRUE;
> + }
> + return FALSE;
> +}
> +
> +/**
> +Check if a particular video mode is in either the Established or Standard Timings section of the EDID.
> +
> +@param EDID Pointer to the 128-byte EDID
> +@param hRes Horizontal resolution
> +@param vRes Vertical resolution
> +@param refresh Refresh rate
> +@retval TRUE The requested mode is present in the EDID
> +
> +**/
> +STATIC BOOLEAN
> +IsModeInEdid (
> + IN CONST VOID *EDID,
> + IN UINT16 HRes,
> + IN UINT16 VRes,
> + IN UINT16 Refresh
> + )
> +{
> + UINT16 EdidHRes;
> + UINT16 EdidVRes;
> + UINT8 EdidRefresh;
> + BOOLEAN ModeSupported;
> +
> + ModeSupported = IsModeInEstablishedTimings (EDID, HRes, VRes, Refresh);
> +
> + if (ModeSupported == FALSE) {
> + // Check if the mode is in the Standard Timings section of the EDID
> + UINT8 i;
> + for (i = 0; i < EDID_NUMBER_OF_STANDARD_TIMINGS; i++) {
> + if (TRUE == ReadStandardTiming (EDID, i, &EdidHRes, &EdidVRes, &EdidRefresh)) {
> + if ((HRes == EdidHRes) && (VRes == EdidVRes) && (Refresh == EdidRefresh)) {
> + ModeSupported = TRUE;
> + break;
> + }
> + }
> + }
> + }
> + return ModeSupported;
> +}
> +
> +/**
> +Returns the (index)'th entry from the list of pre-calculated video timings that is also present in the EDID,
> +or, video mode data corresponding to any detailed timings present in the EDID.
> +
> +Like QueryVideoMode, finds the number (and contents) of video modes available by repeatedly calling this function
> +with an increasing index value, until it returns FALSE
> +@param index The caller wants the _index_'th video mode
> +@param EDID Pointer to the 128-byte EDID
> +@param edidSize Size in bytes of the EDID
> +@param videoMode Video timings extracted from the modeData structure
> +@retval EFI_SUCCESS The requested mode is present in the EDID
> +@retval EFI_INVALID_PARAMETER The requested mode is not present in the EDID
> +**/
> +EFI_STATUS
> +DlEdidGetSupportedVideoMode (
> + IN UINT32 Index,
> + IN CONST VOID *EDID,
> + IN UINT32 EdidSize,
> + OUT CONST struct VideoMode **VideoMode
> + )
> +{
> + UINTN SupportedVideoModesFoundInEdid;
> + EFI_STATUS Status;
> +
> + SupportedVideoModesFoundInEdid = 0;
> + Status = EFI_INVALID_PARAMETER;
> +
> + // If we didn't manage to find an EDID earlier, just use one of the hard-coded video modes
> + if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> + if (Index >= DlVideoModeGetNumSupportedVideoModes ()) {
> + return EFI_INVALID_PARAMETER;
> + }
> + else {
> + *VideoMode = DlVideoModeGetSupportedVideoMode (Index);
> + DEBUG ((DEBUG_WARN, "No monitor EDID loaded - returning mode from default list (%dx%d)\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
> + return EFI_SUCCESS;
> + }
> + }
> +
> + UINT16 ModeNumber;
> + for (ModeNumber = 0; ModeNumber < DlVideoModeGetNumSupportedVideoModes (); ModeNumber++) {
> +
> + CONST struct VideoMode *SupportedVideoMode = DlVideoModeGetSupportedVideoMode (ModeNumber);
> + ASSERT (SupportedVideoMode);
> +
> + if (IsModeInEdid (EDID, SupportedVideoMode->HActive, SupportedVideoMode->VActive, DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE)) {
> + if (Index == SupportedVideoModesFoundInEdid) {
> + *VideoMode = SupportedVideoMode;
> + Status = EFI_SUCCESS;
> + break;
> + }
> + SupportedVideoModesFoundInEdid++;
> + }
> + }
> +
> + if (EFI_ERROR (Status)) {
> + // Have a look in the detailed timings
> + UINTN DetailedTimingNumber;
> + STATIC struct VideoMode TmpVideoMode;
> + DetailedTimingNumber = Index - SupportedVideoModesFoundInEdid;
> +
> + if (DetailedTimingNumber < EDID_NUMBER_OF_DETAILED_TIMINGS) {
> + if (ReadDetailedTiming (EDID, (UINT8)DetailedTimingNumber, &TmpVideoMode)) {
> + *VideoMode = &TmpVideoMode;
> + Status = EFI_SUCCESS;
> + }
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> + * Like GetSupportedEdidVideoMode, but will return a fallback fixed mode of 640x480@60Hz
> + * for index 0 if no suitable modes found in EDID.
> + * @param index
> + * @param EDID
> + * @param edidSize
> + * @param videoMode
> + * @return EFI_SUCCESS
> + */
> +EFI_STATUS
> +DlEdidGetSupportedVideoModeWithFallback (
> + IN UINT32 Index,
> + IN CONST VOID *EDID,
> + IN UINT32 EdidSize,
> + OUT CONST struct VideoMode **VideoMode
> + )
> +{
> + EFI_STATUS Status;
> + Status = DlEdidGetSupportedVideoMode (Index, EDID, EdidSize, VideoMode);
> +
> + if (EFI_ERROR (Status)) {
> + // Special case - if we didn't find any matching video modes in the EDID, fall back to 640x480@60Hz
> + if (Index == 0) {
> + *VideoMode = DlVideoModeGetSupportedVideoMode (0);
> + DEBUG ((DEBUG_WARN, "No video modes supported by driver found in monitor EDID received from DL device - falling back to %dx%d\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
> + Status = EFI_SUCCESS;
> + }
> + }
> +
> + return Status;
> +}
> +
> +/**
> +Count the number of video modes that we have timing information for that are present in the EDID
> +@param EDID Pointer to the 128-byte EDID
> +@param edidSize
> +@retval The number of modes in the EDID
> +
> +**/
> +UINT32
> +DlEdidGetNumSupportedModesInEdid (
> + IN CONST VOID *EDID,
> + IN UINT32 EdidSize
> + )
> +{
> + UINT32 MaxMode;
> +
> + if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> + return DlVideoModeGetNumSupportedVideoModes ();
> + }
> +
> + for (MaxMode = 0; ; MaxMode++) {
> + CONST struct VideoMode *videoMode;
> + if (EFI_ERROR (DlEdidGetSupportedVideoMode (MaxMode, EDID, EdidSize, &videoMode))) {
> + break;
> + }
> + }
> + DEBUG ((DEBUG_INFO, "Found %d video modes supported by driver in monitor EDID.\n", MaxMode));
> + return MaxMode;
> +}
> +
> +
> +
> +/**
> + * Read the EDID from the connected monitor, store it in the local data structure
> + * @param UsbDisplayLinkDev
> + * @retval EFI_OUT_OF_RESOURCES - Could not allocate memory
> + * @retval EFI_SUCCESS
> + */
> +EFI_STATUS
> +DlReadEdid (
> + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> + )
> +{
> + EFI_STATUS Status;
> + BOOLEAN EdidFound;
> + EFI_EDID_OVERRIDE_PROTOCOL* EdidOverride;
> +
> + //
> + // setup EDID information
> + //
> + UsbDisplayLinkDev->EdidDiscovered.Edid = (UINT8 *)NULL;
> + UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = 0;
> +
> + EdidFound = FALSE;
> +
> + //
> + // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
> + //
> + Status = gBS->LocateProtocol (&gEfiEdidOverrideProtocolGuid, NULL, (VOID**)&EdidOverride);
> +
> + if (!EFI_ERROR (Status)) {
> + UINT32 EdidAttributes = 0xff;
> + UINTN EdidDataSize = 0;
> + UINT8* EdidDataBlock = (UINT8*)NULL;
> +
> + // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
> + EdidDataBlock = (UINT8*)AllocatePool (EDID_BLOCK_SIZE * 2);
> +
> + if (NULL == EdidDataBlock) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Status = EdidOverride->GetEdid (
> + EdidOverride,
> + &UsbDisplayLinkDev->Handle,
> + &EdidAttributes,
> + &EdidDataSize,
> + &EdidDataBlock);
> +
> + if (!EFI_ERROR (Status) && EdidAttributes == 0 && EdidDataSize != 0) {
> + UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> + UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> + EdidFound = TRUE;
> + }
> + else {
> + FreePool (EdidDataBlock);
> + EdidDataBlock = NULL;
> + }
> + }
> +
> + if (EdidFound != TRUE) {
> + UINTN EdidDataSize = 0;
> + UINT8* EdidDataBlock = (UINT8*)NULL;
> +
> + if (ReadEdidData (UsbDisplayLinkDev, &EdidDataBlock, &EdidDataSize) == EFI_SUCCESS) {
> +
> + if (IsEdidChecksumCorrect (EdidDataBlock)) {
> + UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> + UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> + EdidFound = TRUE;
> + } else {
> + DEBUG ((DEBUG_WARN, "Monitor EDID received from DisplayLink device had an invalid checksum. Corrupted?\n"));
> + }
> + }
> + }
> +
> + if (EdidFound == FALSE) {
> + DEBUG ((DEBUG_WARN, "No valid monitor EDID received from DisplayLink device. Cannot detect resolutions supported by monitor.\n"));
> + }
> +
> + // Set the EDID active.
> + // In an error case this will be set 0/NULL, which flags to the parsing code that there is no EDID.
> + UsbDisplayLinkDev->EdidActive.SizeOfEdid = UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid;
> + UsbDisplayLinkDev->EdidActive.Edid = UsbDisplayLinkDev->EdidDiscovered.Edid;
> +
> + return EFI_SUCCESS;
> +}
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> new file mode 100644
> index 000000000000..a1b8a0512d1a
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> @@ -0,0 +1,129 @@
> +/** @file Edid.h
> + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> + * Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#ifndef EDID_H
> +#define EDID_H
> +
> +#include "UsbDisplayLink.h"
> +
> +#define EDID_HEADER_SIZE ((UINTN)8)
> +#define EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES ((UINTN)3)
> +#define EDID_NUMBER_OF_STANDARD_TIMINGS ((UINTN)8)
> +#define EDID_NUMBER_OF_DETAILED_TIMINGS ((UINTN)4)
> +
> +
> +typedef struct {
> + UINT16 HRes;
> + UINT16 VRes;
> + UINT16 Refresh;
> +} EDID_TIMING;
> +
> +
> +EFI_STATUS
> +DlEdidGetSupportedVideoMode (
> + UINT32 ModeNumber,
> + CONST VOID *EDID,
> + UINT32 EdidSize,
> + CONST struct VideoMode **VideoMode
> + );
> +
> +EFI_STATUS
> +DlEdidGetSupportedVideoModeWithFallback (
> + UINT32 ModeNumber,
> + CONST VOID *EDID,
> + UINT32 EdidSize,
> + CONST struct VideoMode **VideoMode
> + );
> +
> +UINT32
> +DlEdidGetNumSupportedModesInEdid (
> + CONST VOID *EDID,
> + UINT32 EdidSize
> + );
> +
> +EFI_STATUS
> +DlReadEdid (
> + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> +);
> +
> +// EDID Detailed timings section - Features
> +enum EdidDetailedTimingsFeatures {
> + EdidDetailedTimingsFeaturesInterlaced = 0x80,
> + EdidDetailedTimingsFeaturesStereoModeMask = 0x60,
> + EdidDetailedTimingsFeaturesSyncSchemeMask = 0x18,
> + EdidDetailedTimingsFeaturesHorizontalSyncPositive = 0x02,
> + EdidDetailedTimingsFeaturesVerticalSyncPositive = 0x04,
> +};
> +
> +// NR-110497-TC-7ZM Section 4.3.3 0x22 Set Video Mode - Flags
> +enum VideoModeFlags {
> + VideoModeFlagsInterlaced = 0x0001,
> + VideoModeFlagsHorizontalSyncInverted = 0x0100,
> + VideoModeFlagsVerticalSyncInverted = 0x0200,
> +};
> +
> +struct StandardTimingIdentification {
> + UINT8 HorizontalActivePixels; // X resolution, from 256->2288 in increments of 8 pixels
> + UINT8 ImageAspectRatioAndrefresh; // Bits 7,6 Aspect ratio - 0=16:10 1=4:3 2=5:4 3=16:9
> + // Bits 5,0 Refresh rate Range 60->1213Hz
> +};
> +
> +struct DetailedTimingIdentification {
> + UINT16 PixelClock; // wPixelClock in VideoMode struct
> + UINT8 HActiveLo; // wHActive
> + UINT8 HBlankingLo; // wHBlanking
> + UINT8 HActiveHiBlankingHi;
> + UINT8 VActiveLo; // wVActive
> + UINT8 VBlankingLo; // wVBlanking
> + UINT8 VActiveHiBlankingHi;
> + UINT8 HSyncOffsetLo; // wHSyncOffset, front porch
> + UINT8 HSyncWidthLo; // wHSyncWidth
> + UINT8 VSyncOffsetLoSyncWidthLo;
> + UINT8 HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi;
> + UINT8 HImageSizeHi;
> + UINT8 VImageSizeHi;
> + UINT8 HImageSizeLoVImageSizeLo;
> + UINT8 HBorder;
> + UINT8 VBorder;
> + UINT8 Features;
> +};
> +
> +struct Edid {
> + UINT8 Header[EDID_HEADER_SIZE]; //EDID header "00 FF FF FF FF FF FF 00"
> + UINT16 ManufactureName; //EISA 3-character ID
> + UINT16 ProductCode; //Vendor assigned code
> + UINT32 SerialNumber; //32-bit serial number
> + UINT8 WeekOfManufacture; //Week number
> + UINT8 YearOfManufacture; //Year
> + UINT8 EdidVersion; //EDID Structure Version
> + UINT8 EdidRevision; //EDID Structure Revision
> + UINT8 VideoInputDefinition;
> + UINT8 MaxHorizontalImageSize; //cm
> + UINT8 MaxVerticalImageSize; //cm
> + UINT8 DisplayTransferCharacteristic;
> + UINT8 FeatureSupport;
> + UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
> + UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
> + UINT8 RedX; //Red-x Bits 9 - 2
> + UINT8 RedY; //Red-y Bits 9 - 2
> + UINT8 GreenX; //Green-x Bits 9 - 2
> + UINT8 GreenY; //Green-y Bits 9 - 2
> + UINT8 BlueX; //Blue-x Bits 9 - 2
> + UINT8 BlueY; //Blue-y Bits 9 - 2
> + UINT8 WhiteX; //White-x Bits 9 - 2
> + UINT8 WhiteY; //White-x Bits 9 - 2
> + UINT8 EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES];
> + struct StandardTimingIdentification standardTimingIdentifications[EDID_NUMBER_OF_STANDARD_TIMINGS];
> + struct DetailedTimingIdentification detailedTimingDescriptions[EDID_NUMBER_OF_DETAILED_TIMINGS];
> + UINT8 ExtensionFlag; //Number of (optional) 128-byte EDID extension blocks to follow
> + UINT8 Checksum;
> +};
> +
> +#endif // EDID_H
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> new file mode 100644
> index 000000000000..3e483afdba72
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> @@ -0,0 +1,578 @@
> +/**
> + * @file Gop.c
> + * @brief UEFI GOP protocol API implementation for USB DisplayLink driver.
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +#include "Edid.h"
> +
> +
> +/**
> + *
> + * @param This Pointer to the instance of the GOP protocol
> + * @param BltOperation
> + * @param SourceX
> + * @param SourceY
> + * @param Width
> + * @param Height
> + * @param DestinationX
> + * @param DestinationY
> + * @return
> + */
> +STATIC EFI_STATUS
> +CheckBounds (
> + IN EFI_GRAPHICS_OUTPUT_PROTOCOL* This,
> + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> + IN UINTN SourceX,
> + IN UINTN SourceY,
> + IN UINTN Width,
> + IN UINTN Height,
> + IN UINTN DestinationX,
> + IN UINTN DestinationY
> + )
> +{
> + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> + EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> +
> + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> + Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> +
> + CONST EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* ScreenMode = Gop->Mode->Info;
> +
> + if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
> + if (SourceY + Height > ScreenMode->VerticalResolution) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (SourceX + Width > ScreenMode->HorizontalResolution) {
> + return EFI_INVALID_PARAMETER;
> + }
> + }
> +
> + if (BltOperation == EfiBltBufferToVideo
> + || BltOperation == EfiBltVideoToVideo
> + || BltOperation == EfiBltVideoFill) {
> + if (DestinationY + Height > ScreenMode->VerticalResolution) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (DestinationX + Width > ScreenMode->HorizontalResolution) {
> + return EFI_INVALID_PARAMETER;
> + }
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + * Update the local copy of the Frame Buffer. This local copy is periodically transmitted to the
> + * DisplayLink device (via DlGopSendScreenUpdate)
> + * @param UsbDisplayLinkDev
> + * @param BltBuffer
> + * @param BltOperation
> + * @param SourceX
> + * @param SourceY
> + * @param DestinationX
> + * @param DestinationY
> + * @param Width
> + * @param Height
> + * @param BltBufferStride
> + * @param PixelsPerScanLine
> + */
> +STATIC VOID
> +BuildBackBuffer (
> + IN USB_DISPLAYLINK_DEV *UsbDisplayLinkDev,
> + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
> + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> + IN UINTN SourceX,
> + IN UINTN SourceY,
> + IN UINTN DestinationX,
> + IN UINTN DestinationY,
> + IN UINTN Width,
> + IN UINTN Height,
> + IN UINTN BltBufferStride,
> + IN UINTN PixelsPerScanLine
> +)
> +{
> + UINTN H;
> + UINTN W;
> + switch (BltOperation) {
> + case EfiBltVideoToBltBuffer:
> + {
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)((UINT8 *)BltBuffer + (DestinationY * BltBufferStride) + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> + SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> +
> + for (H = 0; H < Height; H++) {
> + for (W = 0; W < Width; W++) {
> + Blt[W] = *SrcB++;
> + }
> + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> + SrcB += PixelsPerScanLine - Width;
> + }
> + }
> + break;
> +
> + case EfiBltBufferToVideo:
> + {
> + // Update the store of the area of the screen that is "dirty" - that we need to send in the next screen update.
> + if (DestinationY < UsbDisplayLinkDev->LastY1) {
> + UsbDisplayLinkDev->LastY1 = DestinationY;
> + }
> + if ((DestinationY + Height) > UsbDisplayLinkDev->LastY2) {
> + UsbDisplayLinkDev->LastY2 = DestinationY + Height;
> + }
> +
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)(((UINT8 *)BltBuffer) + (SourceY * BltBufferStride) + SourceX * sizeof *Blt);
> + DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> +
> + for (H = 0; H < Height; H++) {
> + for (W = 0; W < Width; W++) {
> + *DstB++ = Blt[W];
> + }
> + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> + DstB += PixelsPerScanLine - Width;
> + }
> + }
> + break;
> +
> + case EfiBltVideoToVideo:
> + {
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> + SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> + DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> +
> + for (H = 0; H < Height; H++) {
> + for (W = 0; W < Width; W++) {
> + *DstB++ = *SrcB++;
> + }
> + SrcB += PixelsPerScanLine - Width;
> + DstB += PixelsPerScanLine - Width;
> + }
> + }
> + break;
> +
> + case EfiBltVideoFill:
> + {
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> + DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> + for (H = 0; H < Height; H++) {
> + for (W = 0; W < Width; W++) {
> + *DstB++ = *BltBuffer;
> + }
> + DstB += PixelsPerScanLine - Width;
> + }
> + }
> + break;
> + default: break;
> + }
> +}
> +
> +/**
> + * Display a colour bar pattern on the DisplayLink device.
> + * @param UsbDisplayLinkDev
> + * @param PatternNumber
> + * @return
> + */
> +EFI_STATUS
> +DlGopSendTestPattern (
> + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> + IN UINTN PatternNumber)
> +{
> + EFI_STATUS Status;
> + UINTN DataLen;
> + UINT8 *DstBuf;
> + UINT32 USBStatus;
> +
> + Status = EFI_SUCCESS;
> + DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per pixel
> + DstBuf = AllocateZeroPool (DataLen);
> +
> + if (DstBuf == NULL) {
> + DEBUG ((DEBUG_ERROR, "SendTestPattern Failed to allocate memory\n"));
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + //DEBUG ((DEBUG_ERROR, "Called DlGopSendTestPattern %d\n", PatternNumber));
> +
> + CONST UINT8 RedPixel[3] = { 0xFF, 0x00, 0x00 };
> + CONST UINT8 GreenPixel[3] = { 0x00, 0xFF, 0x00 };
> + CONST UINT8 BluePixel[3] = { 0x00, 0x00, 0xFF };
> + CONST UINT8 YellowPixel[3] = { 0xFF, 0xFF, 0x00 };
> + CONST UINT8 MagentaPixel[3] = { 0xFF, 0x00, 0xFF };
> + CONST UINT8 CyanPixel[3] = { 0x00, 0xFF, 0xFF };
> +
> + UINTN Row;
> + UINTN Column;
> + for (Row = 0; Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution; Row++) {
> + for (Column = 0; Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution; Column++) {
> +
> + if (0 == PatternNumber) {
> + if (Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution / 3) {
> + CopyMem (&DstBuf[Column * 3], RedPixel, sizeof (RedPixel));
> + }
> + else if (Row < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution * 2) / 3)
> + {
> + CopyMem (&DstBuf[Column * 3], GreenPixel, sizeof (GreenPixel));
> + }
> + else {
> + CopyMem (&DstBuf[Column * 3], BluePixel, sizeof (BluePixel));
> + }
> + }
> + else {
> + if (Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution / 3) {
> + CopyMem (&DstBuf[Column * 3], YellowPixel, sizeof (RedPixel));
> + }
> + else if (Column < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 2) / 3)
> + {
> + CopyMem (&DstBuf[Column * 3], MagentaPixel, sizeof (GreenPixel));
> + }
> + else {
> + CopyMem (&DstBuf[Column * 3], CyanPixel, sizeof (BluePixel));
> + }
> + }
> + }
> + DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, DataLen, &USBStatus);
> + }
> + // Payload with length of 1 to terminate the frame
> + DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, 1, &USBStatus);
> + FreePool (DstBuf);
> +
> + return Status;
> +}
> +
> +
> +/**
> + * Transfer the latest copy of the Blt buffer over USB to the DisplayLink device
> + * @param UsbDisplayLinkDev
> + * @return
> + */
> +EFI_STATUS
> +DlGopSendScreenUpdate (
> + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 USBStatus;
> + Status = EFI_SUCCESS;
> +
> + // If it has been a while since we sent an update, send a full screen.
> + // This allows us to update a hot-plugged monitor quickly.
> + if (UsbDisplayLinkDev->TimeSinceLastScreenUpdate > DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD) {
> + UsbDisplayLinkDev->LastY1 = 0;
> + UsbDisplayLinkDev->LastY2 = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution - 1;
> + }
> +
> + // If there has been no BLT since the last update/poll, drop out quietly.
> + if (UsbDisplayLinkDev->LastY2 < UsbDisplayLinkDev->LastY1) {
> + UsbDisplayLinkDev->TimeSinceLastScreenUpdate += (DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 1000); // Convert us to ms
> + return EFI_SUCCESS;
> + }
> +
> + UsbDisplayLinkDev->TimeSinceLastScreenUpdate = 0;
> +
> + EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> +
> + UINTN DataLen;
> + UINTN Width;
> + UINTN Height;
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcPtr;
> + UINT8* DstPtr;
> + UINT8 DstBuffer[1920 * 3]; // Get rid of the magic numbers at some point
> + // Could also use a buffer allocated at runtime to store the line, stored in the USB_DISPLAYLINK_DEV structure.
> + UINTN H;
> +
> + DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per pixel
> + Width = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution;
> + Height = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution;
> + SrcPtr = UsbDisplayLinkDev->Screen;
> + DstPtr = DstBuffer;
> +
> + for (H = 0; H < Height; H++) {
> + DstPtr = DstBuffer;
> +
> + UINTN W;
> + for (W = 0; W < Width; W++) {
> + // Need to swap round the RGB values
> + DstPtr[0] = ((UINT8 *)SrcPtr)[2];
> + DstPtr[1] = ((UINT8 *)SrcPtr)[1];
> + DstPtr[2] = ((UINT8 *)SrcPtr)[0];
> + SrcPtr++;
> + DstPtr += 3;
> + }
> +
> + Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, DataLen, &USBStatus);
> +
> + // USBStatus values defined in usbio.h, e.g. EFI_USB_ERR_TIMEOUT 0x40
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB status x%x\n", H, DataLen, Status, USBStatus));
> + break;
> + }
> + // Need an extra DlUsbBulkWrite if the data length is divisible by USB MaxPacketSize. This spare data will just get written into the (invisible) stride area.
> + // Note that the API doesn't let us do a bulk write of 0.
> + if ((DataLen & (UsbDisplayLinkDev->BulkOutEndpointDescriptor.MaxPacketSize - 1)) == 0) {
> + Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 2, &USBStatus);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB status x%x\n", H, DataLen, Status, USBStatus));
> + break;
> + }
> + }
> + }
> +
> + if (!EFI_ERROR (Status)) {
> + // If we've successfully transmitted the frame, reset the values that store which area of the screen has been BLTted to.
> + // If we haven't succeeded, this will mean we'll try to resend it after the next poll period.
> + UsbDisplayLinkDev->LastY2 = 0;
> + UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> + }
> +
> + // Payload with length of 1 to terminate the frame
> + // We need to do this even if we had an error, to indicate to the DL device that it should now expect a new frame.
> + DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 1, &USBStatus);
> +
> + gBS->RestoreTPL (OriginalTPL);
> +
> + return Status;
> +}
> +
> +/**
> + * Calculate the video refresh rate from the video timing parameters (pixel clock etc)
> + * @param videoMode
> + * @return
> + */
> +#ifndef MDEPKG_NDEBUG
> +STATIC inline UINT16
> +CalculateRefreshRate (
> + IN CONST struct VideoMode *VideoMode)
> +{
> + UINT16 RefreshRate;
> + UINT16 Rmod;
> + UINT16 Rate10Hz;
> +
> + RefreshRate = (VideoMode->PixelClock * 10000) / ((VideoMode->HActive + VideoMode->HBlanking) * (VideoMode->VActive + VideoMode->VBlanking));
> + Rmod = RefreshRate % 10;
> + Rate10Hz = RefreshRate - Rmod;
> +
> + if (Rmod >= 5) {
> + Rate10Hz += 10;
> + }
> + return Rate10Hz;
> +}
> +#endif // MDEPKG_NDEBUG
> +/* ***************************************************************************************************** */
> +/* ***************************************************************************************************** */
> +/* ****************** START OF FUNCTIONS WHICH IMPLEMENT GOP INTERFACE ****************** */
> +/* ***************************************************************************************************** */
> +/* ***************************************************************************************************** */
> +
> +
> +/**
> + *
> + * @param Gop Pointer to the instance of the GOP protocol
> + * @param ModeNumber
> + * @param SizeOfInfo
> + * @param Info
> + * @return
> + */
> +EFI_STATUS
> +EFIAPI
> +DisplayLinkQueryMode (
> + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,
> + IN UINT32 ModeNumber,
> + OUT UINTN *SizeOfInfo,
> + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
> +)
> +{
> + USB_DISPLAYLINK_DEV *Dev;
> + CONST struct VideoMode *VideoMode;
> + EFI_STATUS Status;
> +
> + Dev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> + Status = EFI_INVALID_PARAMETER;
> +
> + if ((SizeOfInfo == NULL) || (Info == NULL)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // Get a video mode from the EDID
> + Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, Dev->EdidActive.Edid, Dev->EdidActive.SizeOfEdid, &VideoMode);
> +
> + if (!EFI_ERROR (Status)) {
> +
> + *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> + if (*Info == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + DEBUG ((DEBUG_INFO, "BIOS querying mode number %d - returning %dx%d @ %dHz\n", ModeNumber, VideoMode->HActive, VideoMode->VActive, CalculateRefreshRate (VideoMode)));
> +
> + *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> +
> + (*Info)->Version = 0;
> + (*Info)->HorizontalResolution = VideoMode->HActive;
> + (*Info)->VerticalResolution = VideoMode->VActive;
> + (*Info)->PixelFormat = PixelBltOnly;
> + (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;
> + (*Info)->PixelInformation.RedMask = 0;
> + (*Info)->PixelInformation.GreenMask = 0;
> + (*Info)->PixelInformation.BlueMask = 0;
> + (*Info)->PixelInformation.ReservedMask = 0;
> + }
> + return Status;
> +}
> +
> +/**
> + *
> + * @param Gop Pointer to the instance of the GOP protocol
> + * @param ModeNumber
> + * @return
> + */
> +EFI_STATUS
> +EFIAPI
> +DisplayLinkSetMode (
> + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,
> + IN UINT32 ModeNumber
> +)
> +{
> + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> + EFI_STATUS Status;
> + CONST struct VideoMode *VideoMode;
> +
> + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> +
> + // Prevent the DisplayLinkPeriodicTimer from interrupting us (bug 28877).
> + // When the driver is manually loaded, the TPL is TPL_NOTIFY (16) which prevents the interrupt from the timer.
> + // When the GOP driver is sideloaded, the TPL of this call is TPL_APPLICATION (4) and the timer can interrupt us.
> + Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> +
> + // Get a video mode from the EDID
> + Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, UsbDisplayLinkDev->EdidActive.Edid, UsbDisplayLinkDev->EdidActive.SizeOfEdid, &VideoMode);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Gop->Mode->Info->Version = 0;
> + Gop->Mode->Info->HorizontalResolution = VideoMode->HActive;
> + Gop->Mode->Info->VerticalResolution = VideoMode->VActive;
> + Gop->Mode->Info->PixelFormat = PixelBltOnly;
> + Gop->Mode->Info->PixelsPerScanLine = Gop->Mode->Info->HorizontalResolution;
> + Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> + Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> + Gop->Mode->FrameBufferSize = 0;
> +
> + //
> + // Allocate the back buffer
> + //
> + if (UsbDisplayLinkDev->Screen != NULL) {
> + FreePool (UsbDisplayLinkDev->Screen);
> + }
> +
> + UsbDisplayLinkDev->Screen = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)AllocateZeroPool (
> + Gop->Mode->Info->HorizontalResolution *
> + Gop->Mode->Info->VerticalResolution *
> + sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> +
> + if (UsbDisplayLinkDev->Screen == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + DEBUG ((DEBUG_INFO, "Video mode %d selected by BIOS - %d x %d.\n", ModeNumber, VideoMode->HActive, VideoMode->VActive));
> + // Wait until we are sure that we can set the video mode before we tell the firmware
> + Status = DlUsbSendControlWriteMessage (UsbDisplayLinkDev, SET_VIDEO_MODE, 0, VideoMode, sizeof (struct VideoMode));
> +
> + if (Status != EFI_SUCCESS) {
> + // Flag up that we haven't set the video mode correctly yet.
> + DEBUG ((DEBUG_ERROR, "Failed to send USB message to DisplayLink device to set monitor video mode. Monitor connected correctly?\n"));
> + Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> + FreePool (UsbDisplayLinkDev->Screen);
> + UsbDisplayLinkDev->Screen = NULL;
> + } else {
> + BuildBackBuffer (
> + UsbDisplayLinkDev,
> + UsbDisplayLinkDev->Screen,
> + EfiBltBufferToVideo,
> + 0, 0,
> + 0, 0,
> + Gop->Mode->Info->HorizontalResolution,
> + Gop->Mode->Info->VerticalResolution,
> + Gop->Mode->Info->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
> + Gop->Mode->Info->HorizontalResolution);
> + // unlock the DisplayLinkPeriodicTimer
> + Gop->Mode->Mode = ModeNumber;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + * Implementation of the GOP protocol Blt API function
> + * @param This Pointer to the instance of the GOP protocol
> + * @param BltBuffer
> + * @param BltOperation
> + * @param SourceX
> + * @param SourceY
> + * @param DestinationX
> + * @param DestinationY
> + * @param Width
> + * @param Height
> + * @param Delta
> + * @return
> + */
> +EFI_STATUS
> +EFIAPI
> +DisplayLinkBlt (
> + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
> + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> + IN UINTN SourceX,
> + IN UINTN SourceY,
> + IN UINTN DestinationX,
> + IN UINTN DestinationY,
> + IN UINTN Width,
> + IN UINTN Height,
> + IN UINTN Delta OPTIONAL
> +)
> +{
> + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> +
> + // Drop out if we haven't set the video mode up yet
> + if (This->Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> + return EFI_SUCCESS;
> + }
> +
> + if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (Width == 0 || Height == 0) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + // Lock so we make an atomic write the frame buffer.
> + // We would not want a timer based event (Cursor, ...) to come in while we are doing this operation.
> + EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> +
> + CONST UINTN BltBufferStride = (Delta == 0) ? Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) : Delta;
> + CONST EFI_STATUS boundsCheckStatus = CheckBounds (This, BltOperation, SourceX, SourceY, Width, Height, DestinationX, DestinationY);
> + if (EFI_ERROR (boundsCheckStatus)) {
> + gBS->RestoreTPL (OriginalTPL);
> + return boundsCheckStatus;
> + }
> +
> + BuildBackBuffer (UsbDisplayLinkDev, BltBuffer, BltOperation, SourceX, SourceY, DestinationX, DestinationY, Width, Height, BltBufferStride, This->Mode->Info->PixelsPerScanLine);
> +
> + gBS->RestoreTPL (OriginalTPL);
> + return EFI_SUCCESS;
> +}
> +
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> new file mode 100644
> index 000000000000..c12a80a6e1ab
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> @@ -0,0 +1,145 @@
> +/**
> + * @file UsbDescriptors.c
> + * @brief Functions to read USB Interface and Capabilities descriptors
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +#include "UsbDescriptors.h"
> +
> +/**
> + *
> + * @param UsbIo
> + * @param descriptorType
> + * @param index
> + * @param Buffer
> + * @param Length
> + * @param UsbStatus
> + * @return
> + */
> +STATIC EFI_STATUS
> +ReadDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + UINT8 DescriptorType,
> + UINT8 Index,
> + VOID* Buffer,
> + UINT16 Length,
> + UINT32* UsbStatus)
> +{
> + EFI_STATUS Status;
> +
> + UINT8 Header[2];
> + ZeroMem (Header, sizeof (Header));
> +
> + EFI_USB_DEVICE_REQUEST Request;
> + ZeroMem (&Request, sizeof (Request));
> + Request.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_STANDARD | USB_TARGET_DEVICE;
> + Request.Request = USB_REQ_GET_DESCRIPTOR;
> + Request.Index = 0;
> + Request.Value = DescriptorType << 8 | Index;
> + Request.Length = sizeof (Header);
> +
> + // Read the descriptor header to see how many bytes it contains
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &Request,
> + EfiUsbDataIn,
> + DISPLAYLINK_USB_CTRL_TIMEOUT,
> + Header,
> + sizeof (Header),
> + UsbStatus);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to read length of descriptor type x%x, index %u (code %r, USB status x%x)\n",
> + DescriptorType, Index, Status, *UsbStatus));
> + return Status;
> + }
> + CONST UINT16 TotalLength = Header[0];
> +
> + // Now we know the size of it, we can read the entire descriptor
> + Request.Length = TotalLength;
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &Request,
> + EfiUsbDataIn,
> + DISPLAYLINK_USB_CTRL_TIMEOUT,
> + Buffer,
> + TotalLength,
> + UsbStatus);
> +
> + return Status;
> +}
> +
> +/**
> + Perform a USB control transfer to read the DisplayLink vendor descriptor.
> +
> + @param UsbIo Pointer to the instance of the USBIO protocol
> + @param Buffer Pointer to the buffer where descriptor should be written
> + @param Length Length of buffer (and the maximum amount of descriptor data that shall be read)
> +
> + @retval EFI_SUCCESS The descriptor has been copied into Buffer
> + @retval Other The descriptor could not be read
> +**/
> +EFI_STATUS
> +ReadCapabilitiesDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT VOID* Buffer,
> + IN UINT16 Length)
> +{
> + UINT32 UsbStatus;
> + EFI_STATUS Status;
> +
> + Status = ReadDescriptor (
> + UsbIo,
> + DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY,
> + 0,
> + Buffer,
> + Length,
> + &UsbStatus);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Could not read capabilities descriptor from DL device (code %r, USB status x%x). Unrecognised firmware version?\n", Status, UsbStatus));
> + }
> +
> + return Status;
> +}
> +
> +
> +/**
> + An alternative to the UBSIO protocol function EFI_USB_IO_GET_INTERFACE_DESCRIPTOR.
> + This version allows you to specify an index.
> + * @param UsbIo Pointer to the instance of the USBIO protocol
> + * @param interfaceDescriptor Where the descriptor should be written
> + * @param index The index of the descriptor required (the standard USBIO function doesn't let you do this)
> + * @return
> + */
> +EFI_STATUS
> +UsbDisplayLinkGetInterfaceDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + OUT EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> + UINT8 Index
> + )
> +{
> + UINT32 UsbStatus;
> + EFI_STATUS Status;
> +
> + Status = ReadDescriptor (
> + UsbIo,
> + USB_DESC_TYPE_INTERFACE,
> + Index,
> + InterfaceDescriptor,
> + sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
> + &UsbStatus);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "USB control transfer failed while reading interface descriptor (code %r, USB status x%x)\n", Status, UsbStatus));
> + }
> +
> + return Status;
> +}
> +
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> new file mode 100644
> index 000000000000..cdc01aad193a
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> @@ -0,0 +1,109 @@
> +/**
> + * @file UsbDescriptors.h
> + * @brief Functions to read USB Interface and Capabilities descriptors
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#ifndef USB_DESCRIPTORS_H_
> +#define USB_DESCRIPTORS_H_
> +
> + /**
> + Type of the Direct Framebuffer capability descriptor.
> + This is a vendor specific USB descriptor for DisplayLink.
> + @see NR-140082 Section 3.5
> + **/
> +#define DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY 0x5e
> +
> + /**
> + Identifiers for capabllity keys
> + @see NR-140082 Section 3.2
> + **/
> +
> + /**
> + Key for Capabilities 1 - See section 3.2.1
> + **/
> +#define CAPABILITIES1_KEY 0x0
> +
> + /**
> + Lengths for capabllity fields
> + **/
> +#define CAPABILITIES1_LENGTH 0x4
> +
> + /**
> + Bits for the capability bitmask Capabilities1
> + **/
> +
> + /**
> + This is the first capability defined for the protocol.
> + It represents the mode of operation as of initial release.
> + If a device ever breaks compatibility with this initial release,
> + it will cease
> + to support CapabilityBaseProtocol.
> + **/
> +#define CAPABILITIES1_BASE_PROTOCOL (1 << 0)
> +
> + /**
> + Idealised VendorDescriptor which is the result
> + of parsing vendor descriptor from device.
> + **/
> + typedef struct {
> + UINT32 Capabilities1;
> + } VendorDescriptor;
> +
> +#pragma pack(push, 1)
> + typedef struct {
> + UINT16 Key; /** Really of type enum DescrptorKeys */
> + UINT8 Length;
> + UINT8 Value[];
> + } DescriptorKLV;
> +
> + typedef struct {
> + UINT8 Length;
> + UINT8 Type;
> + UINT16 CapabilityVersion;
> + UINT8 CapabilityLength;
> + UINT8 Klv[];
> + } VendorDescriptorGeneric;
> +#pragma pack(pop)
> +
> +
> +EFI_STATUS UsbDisplayLinkGetInterfaceDescriptor (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> + UINT8 index
> + );
> +
> +EFI_STATUS ReadCapabilitiesDescriptor (IN EFI_USB_IO_PROTOCOL *UsbIo, VOID* Buffer, UINT16 Length);
> +
> +/**
> +Parse data in buffer to a VendorDescriptor, if possible.
> +
> +@param Data Buffer
> +@param Length Length of buffer
> +
> +@retval EFI_SUCCESS The descriptor was parsed successfully
> +@retval EFI_UNSUPPORTED Simple Pointer Protocol is not installed on Controller.
> +**/
> +EFI_STATUS
> +UsbDisplayLinkParseCapabilitiesDescriptor (
> + CONST IN VOID* Data,
> + IN UINTN Length,
> + OUT VendorDescriptor* Descriptor
> +);
> +
> +/**
> +Decide if binding may proceed, given capabilities
> +
> +@retval TRUE Binding may proceed
> +@retval FALSE Binding is not possible
> +**/
> +BOOLEAN
> +UsbDisplayLinkCapabilitiesSufficientToBind (
> + CONST IN VendorDescriptor* Descriptor
> +);
> +
> +#endif // USB_DESCRIPTORS_H_
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> new file mode 100644
> index 000000000000..997a3e307f38
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> @@ -0,0 +1,1082 @@
> +/**
> + * @file UsbDisplayLink.c
> + * @brief USB DisplayLink Driver that manages USB DisplayLink device and produces Graphics Output Protocol
> + * This file implements the functions of the Driver Binding / Start / Stop / Unload interface
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/PrintLib.h>
> +#include <Protocol/HiiFont.h>
> +
> +#include "Edid.h"
> +#include "UsbDescriptors.h"
> +
> +//
> +// Functions of Driver Binding Protocol
> +//
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> +);
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> +);
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> +);
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingEntryPoint (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> +);
> +
> +
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable,
> + IN EFI_HANDLE DriverBindingHandle
> +);
> +
> +
> +// Generated with https://www.guidgen.com/<https://www.guidgen.com/> - "B70E5A79-C6D6-4267-B02E-9108C989E287"
> +EFI_GUID gEfiDlGopVariableGuid = { 0xB70E5A79, 0xC6D6, 0x4267,{ 0xB0, 0x2E, 0x91, 0x08, 0xC9, 0x89, 0xE2, 0x87 } };
> +
> +
> +EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding = {
> + UsbDisplayLinkDriverBindingSupported,
> + UsbDisplayLinkDriverBindingStart,
> + UsbDisplayLinkDriverBindingStop,
> + INF_DRIVER_VERSION,
> + NULL,
> + NULL
> +};
> +
> +
> +/**
> + * Reads integer environment variable with default fallback.
> + * @param variableName variable name to read
> + * @param defaultValue default value to return if requested not found
> + */
> +STATIC UINT32
> +ReadEnvironmentInt (
> + CHAR16 *VariableName,
> + UINT32 DefaultValue
> + )
> +{
> + UINT32 Result;
> + UINTN DataSize;
> + DataSize = sizeof (Result);
> + CONST EFI_STATUS Status = gRT->GetVariable (VariableName, &gEfiDlGopVariableGuid, (UINT32*)NULL, &DataSize, &Result);
> + if (!EFI_ERROR (Status) && (sizeof (Result) == DataSize)) {
> + return Result;
> + }
> + return DefaultValue;
> +}
> +
> +/**
> +* Reads boolean environment variable with default fallback.
> +* @param variableName variable name to read
> +* @param defaultValue default value to return if requested not found
> +*/
> +STATIC BOOLEAN
> +ReadEnvironmentBool (
> + CHAR16 *VariableName,
> + BOOLEAN DefaultValue
> + )
> +{
> + return ReadEnvironmentInt (VariableName, DefaultValue ? 1 : 0) == 1;
> +}
> +
> +
> +/**
> +*
> +* @param UsbDisplayLinkDev
> +* @return
> +*/
> +STATIC EFI_STATUS
> +InitializeUsbDisplayLinkDevice (
> + IN OUT USB_DISPLAYLINK_DEV *UsbDisplayLinkDev
> +)
> +{
> + EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> + Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> + Gop->QueryMode = DisplayLinkQueryMode;
> + Gop->SetMode = DisplayLinkSetMode;
> + Gop->Blt = DisplayLinkBlt;
> +
> + //
> + // Allocate buffer for Graphics Output Protocol mode information
> + //
> + Gop->Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
> + if (Gop->Mode == NULL) {
> + return EFI_OUT_OF_RESOURCES;
> + }
> + Gop->Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> + if (Gop->Mode->Info == NULL) {
> + FreePool (Gop->Mode);
> + Gop->Mode = NULL;
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + Gop->Mode->MaxMode = MAX(1, DlEdidGetNumSupportedModesInEdid (UsbDisplayLinkDev->EdidActive.Edid, UsbDisplayLinkDev->EdidActive.SizeOfEdid));
> +
> + Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> + Gop->Mode->Info->Version = 0;
> + // Initialising the horizontal resolution prevents certain BIOSs from hanging on boot, but
> + // it is not yet clear why. See bug 28194.
> + Gop->Mode->Info->HorizontalResolution = DlVideoModeGetSupportedVideoMode (0)->HActive;
> + Gop->Mode->Info->VerticalResolution = 0;
> + Gop->Mode->Info->PixelFormat = PixelBltOnly;
> + Gop->Mode->Info->PixelsPerScanLine = 0;
> + Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> + Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> + Gop->Mode->FrameBufferSize = 0;
> +
> + // Prevent DlGopSendScreenUpdate from running until we are sure that the video mode is set
> + UsbDisplayLinkDev->LastY2 = 0;
> + UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Look for alternate settings for the UsbIo handle's interface
> + which offer protocol DL_PROTOCOL_DIRECT_FB.
> +
> + @retval -1 Not found
> + @retval Other The alternate setting
> +**/
> +STATIC INTN
> +GetDirectFbAltSetting (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN UINT8 ParentInterfaceNumber
> + )
> +{
> + EFI_STATUS Status;
> + INTN AltSettingIndex;
> + UINT16 InterfaceIndex;
> +
> + AltSettingIndex = -1;
> +
> + for (InterfaceIndex = 0; InterfaceIndex <= 0xFF; InterfaceIndex++) {
> + EFI_USB_INTERFACE_DESCRIPTOR interfaceDescriptor;
> + Status = UsbDisplayLinkGetInterfaceDescriptor (UsbIo, &interfaceDescriptor, (UINT8)InterfaceIndex);
> + if (EFI_ERROR (Status)) {
> + break;
> + }
> +
> + if (interfaceDescriptor.InterfaceNumber == ParentInterfaceNumber &&
> + (interfaceDescriptor.InterfaceClass == CLASS_VENDOR) &&
> + interfaceDescriptor.InterfaceProtocol == INTERFACE_PROTOCOL_DIRECT_FB) {
> + AltSettingIndex = interfaceDescriptor.AlternateSetting;
> + break;
> + }
> + }
> + return AltSettingIndex;
> +}
> +
> +/**
> + *
> + * @param UsbIo
> + * @param altSettingIndex
> + * @return
> + */
> +STATIC EFI_STATUS
> +SelectAltSetting (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN UINTN AltSettingIndex)
> +{
> + // Set alternate setting 1 on the interface
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> + EFI_USB_DEVICE_REQUEST Request;
> + ZeroMem (&Request, sizeof (Request));
> + Request.RequestType = USB_REQ_TYPE_STANDARD | USB_TARGET_INTERFACE;
> + Request.Request = USB_REQ_SET_INTERFACE;
> + Request.Index = DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO;
> + Request.Value = (UINT16)AltSettingIndex;
> +
> + Status = UsbIo->UsbControlTransfer (
> + UsbIo,
> + &Request,
> + EfiUsbNoData,
> + DISPLAYLINK_USB_CTRL_TIMEOUT,
> + NULL,
> + 0,
> + &UsbStatus);
> +
> + if (EFI_ERROR (Status)) {
> + Status = EFI_UNSUPPORTED;
> + DEBUG ((DEBUG_ERROR, "USB control transfer failed while attempting to select alt setting %d on interface (code %r, USB status x%x). DisplayLink device has unsupported firmware version?\n", AltSettingIndex, Status, UsbStatus));
> + }
> + return Status;
> +}
> +
> +
> +/**
> + Report whether the driver can support the device attached via UsbIo
> + by seeing what if any capabilities it reports.
> +
> + @retval TRUE Device has sufficient capabilities for this driver.
> + @retval FALSE Device lacks sufficient capabilities.
> +**/
> +STATIC BOOLEAN
> +CapabilitiesSupported (
> + IN EFI_USB_IO_PROTOCOL *UsbIo
> + )
> +{
> + UINT8 Buffer[256];
> + EFI_STATUS Status;
> +
> + Status = ReadCapabilitiesDescriptor (UsbIo, Buffer, sizeof (Buffer));
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + VendorDescriptor descriptor;
> + Status = UsbDisplayLinkParseCapabilitiesDescriptor (Buffer, sizeof (Buffer), &descriptor);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to parse capabilities descriptor (code %r)\n", Status));
> + return FALSE;
> + }
> +
> + return UsbDisplayLinkCapabilitiesSufficientToBind (&descriptor);
> +}
> +
> +
> +/**
> + *
> + * @param UsbIo
> + * @param InterfaceDescriptor
> + * @param altSettingIndex
> + * @return
> + */
> +STATIC BOOLEAN
> +IsDLDirectFbCapableInterface (
> + IN EFI_USB_IO_PROTOCOL *UsbIo,
> + IN EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor,
> + IN INTN *AltSettingIndex)
> +{
> + EFI_STATUS Status;
> + EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
> +
> + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DeviceDescriptor);
> +
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + if (DeviceDescriptor.IdVendor != VENDOR_DISPLAYLINK) {
> + return FALSE;
> + }
> +
> + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, InterfaceDescriptor);
> + if (EFI_ERROR (Status)) {
> + return FALSE;
> + }
> +
> + // We can assume that the interface that we want to talk to - the NIVO interface - is number 0
> + if (InterfaceDescriptor->InterfaceNumber != DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO) {
> + return FALSE;
> + }
> +
> + // Check if we have an interface (alt setting) descriptor with the correct interface protocol
> + *AltSettingIndex = GetDirectFbAltSetting (UsbIo, InterfaceDescriptor->InterfaceNumber);
> +
> + if (*AltSettingIndex == -1) {
> + DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to find setting on device which supports GOP functionality. Check firmware / device version?\n"));
> + return FALSE;
> + }
> +
> + // Now check that the capabilities that we need are properly supported
> + if (CapabilitiesSupported (UsbIo) == FALSE) {
> + DEBUG ((DEBUG_ERROR, "DisplayLink GOP: DL device detected, but it doesn't support the required GOP features. Check firmware / device version?\n"));
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +
> +/**
> + * Prints a block of text in the framebuffer (helper function).
> + * @param X x coordinate
> + * @param Y y coordinate
> + */
> +STATIC VOID
> +DisplayLinkPrintTextToScreenInternal (
> + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> + UINTN X,
> + UINTN Y,
> + IN CHAR16 *Buffer
> + )
> +{
> + EFI_STATUS Status;
> + EFI_HII_FONT_PROTOCOL *HiiFont;
> + EFI_IMAGE_OUTPUT *Blt;
> + EFI_FONT_DISPLAY_INFO FontInfo;
> + EFI_HII_OUT_FLAGS Flags;
> +
> + Blt = (EFI_IMAGE_OUTPUT*)NULL;
> +
> + Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **)&HiiFont);
> + if (!EFI_ERROR (Status)) {
> + Blt = (EFI_IMAGE_OUTPUT*)AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
> + Blt->Width = (UINT16)GraphicsOutput->Mode->Info->HorizontalResolution;
> + Blt->Height = (UINT16)GraphicsOutput->Mode->Info->VerticalResolution;
> + Blt->Image.Screen = GraphicsOutput;
> +
> + ZeroMem (&FontInfo, sizeof (EFI_FONT_DISPLAY_INFO));
> + FontInfo.ForegroundColor.Red<http://FontInfo.ForegroundColor.Red> = 0;
> + FontInfo.ForegroundColor.Green<http://FontInfo.ForegroundColor.Green> = 0;
> + FontInfo.ForegroundColor.Blue<http://FontInfo.ForegroundColor.Blue> = 0;
> + FontInfo.BackgroundColor.Red<http://FontInfo.BackgroundColor.Red> = 0xff;
> + FontInfo.BackgroundColor.Green<http://FontInfo.BackgroundColor.Green> = 0xff;
> + FontInfo.BackgroundColor.Blue<http://FontInfo.BackgroundColor.Blue> = 0xff;
> +
> + Flags = EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_OUT_FLAG_CLIP |
> + EFI_HII_OUT_FLAG_CLIP_CLEAN_X | EFI_HII_OUT_FLAG_CLIP_CLEAN_Y |
> + EFI_HII_IGNORE_LINE_BREAK | EFI_HII_DIRECT_TO_SCREEN;
> +
> + Status = HiiFont->StringToImage (
> + HiiFont,
> + Flags,
> + Buffer,
> + &FontInfo,
> + &Blt,
> + X,
> + Y,
> + (EFI_HII_ROW_INFO**)NULL,
> + (UINTN*)NULL,
> + (UINTN*)NULL);
> + }
> +
> + if (Blt != NULL) {
> + FreePool (Blt);
> + }
> +}
> +
> +
> +/**
> +* Prints a block of text in the framebuffer.
> +* @param X x coordinate
> +* @param Y y coordinate
> +* @param Format string format similar to stdlib's vsnprintf
> +* @param ... arguments
> +*/
> +VOID
> +EFIAPI
> +DlGopPrintTextToScreen (
> + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> + UINTN X,
> + UINTN Y,
> + IN CONST CHAR16 *Format,
> + ...
> + )
> +{
> + VA_LIST Marker;
> + CHAR16 *Buffer;
> + UINTN BufferSize;
> +
> + ASSERT (Format != NULL);
> + ASSERT (((UINTN) Format & BIT0) == 0);
> +
> + VA_START(Marker, Format);
> +
> + BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);
> +
> + Buffer = (CHAR16*)AllocatePool (BufferSize);
> + ASSERT (Buffer != NULL);
> +
> + UnicodeVSPrint (Buffer, BufferSize, Format, Marker);
> +
> + VA_END(Marker);
> +
> + DisplayLinkPrintTextToScreenInternal (GraphicsOutput, X, Y, Buffer);
> +
> + FreePool (Buffer);
> +}
> +
> +
> +/**
> + * Sometimes platforms only write to the first GOP device that they find. Enabling this function allows us to copy the pixels from this device.
> + * @param UsbDisplayLinkDev
> + */
> +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> +STATIC VOID
> +DisplayLinkCopyFromPrimaryGopDevice (
> + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> + )
> +{
> + UINTN HandleCount;
> + EFI_HANDLE *HandleBuffer;
> + UINTN HandleIndex;
> + EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
> +
> + gBS->LocateHandleBuffer (
> + ByProtocol,
> + &gEfiGraphicsOutputProtocolGuid,
> + NULL,
> + &HandleCount,
> + &HandleBuffer);
> +
> + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
> + gBS->HandleProtocol (HandleBuffer[HandleIndex], &gEfiGraphicsOutputProtocolGuid, (VOID**)&Gop);
> + if (Gop != &UsbDisplayLinkDev->GraphicsOutputProtocol && Gop->Mode->FrameBufferBase != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
> +
> + // See if we need to do a screen update - calculate a really noddy hash to see if any screen updates have happened.
> + STATIC UINT32 prevframeBufferHash = 0; // 4 bytes per pixel
> + UINT32 currFrameBufferHash = 0;
> + UINTN i;
> + for (i = 0; i < (Gop->Mode->Info->HorizontalResolution * Gop->Mode->Info->VerticalResolution); i++) {
> + currFrameBufferHash += ((UINT32*)(UINTN)Gop->Mode->FrameBufferBase)[i];
> + }
> +
> + if (currFrameBufferHash != prevframeBufferHash) {
> + prevframeBufferHash = currFrameBufferHash;
> +
> + DisplayLinkBlt (
> + &UsbDisplayLinkDev->GraphicsOutputProtocol,
> + (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(UINTN)Gop->Mode->FrameBufferBase,
> + EfiBltBufferToVideo,
> + 0,
> + 0,
> + 0,
> + 0,
> + Gop->Mode->Info->HorizontalResolution,
> + Gop->Mode->Info->VerticalResolution,
> + 0);
> + }
> + break;
> + }
> + }
> +
> + FreePool (HandleBuffer);
> +}
> +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> +
> +
> +/**
> + * Exit from boot services: signal handler.
> + */
> +STATIC VOID
> +EFIAPI
> +DisplayLinkDriverExitBootServices (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> + UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> +
> + gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> +}
> +
> +/**
> + * Periodic screen update: timer callback.
> + */
> +VOID
> +EFIAPI
> +DisplayLinkPeriodicTimer (
> + IN EFI_EVENT Event,
> + IN VOID* Context
> + )
> +{
> + EFI_STATUS Status;
> + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> +
> + Status = EFI_SUCCESS;
> + UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> +
> + // Drop out if we haven't set the video mode up yet
> + if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> + // Restart the one-shot timer to poll the status again.
> + Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> + }
> + return;
> + }
> +
> +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> + DisplayLinkCopyFromPrimaryGopDevice (UsbDisplayLinkDev);
> +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> +
> + if (UsbDisplayLinkDev->ShowBandwidth) {
> + STATIC UINTN Count = 0;
> +
> + if (Count++ % 50 == 0) {
> + DlGopPrintTextToScreen (&UsbDisplayLinkDev->GraphicsOutputProtocol, 32, 48, (CONST CHAR16*)L" Bandwidth: %d MB/s ", UsbDisplayLinkDev->DataSent * 10000000 / DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 50 / 1024 / 1024);
> + UsbDisplayLinkDev->DataSent = 0;
> + }
> + }
> +
> + if (UsbDisplayLinkDev->ShowTestPattern)
> + {
> + if (UsbDisplayLinkDev->ShowTestPattern == 5) {
> + DlGopSendTestPattern (UsbDisplayLinkDev, 0);
> + } else if (UsbDisplayLinkDev->ShowTestPattern >= 10) {
> + DlGopSendTestPattern (UsbDisplayLinkDev, 1);
> + UsbDisplayLinkDev->ShowTestPattern = 0;
> + }
> + UsbDisplayLinkDev->ShowTestPattern++;
> +
> + }
> +
> + // Send the latest version of the frame buffer to the DL device over USB
> + DlGopSendScreenUpdate (UsbDisplayLinkDev);
> +
> + // Restart the timer now we've finished
> + Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> + }
> +}
> +
> +/* ****************************************************************************************************** */
> +/* ****************************************************************************************************** */
> +/* ****************** START OF FUNCTIONS WHICH IMPLEMENT DRIVER BINDING INTERFACE ****************** */
> +/* ****************************************************************************************************** */
> +/* ****************************************************************************************************** */
> +
> +/**
> + Check whether USB DisplayLink driver supports this device.
> +
> + @param This The USB DisplayLink driver 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
> +UsbDisplayLinkDriverBindingSupported (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> +
> + Status = gBS->OpenProtocol (
> + Controller,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **) &UsbIo,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_BY_DRIVER);
> +
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // Use the USB I/O Protocol interface to check whether Controller is
> + // a DisplayLink device that can be managed by this driver.
> + //
> + Status = EFI_UNSUPPORTED;
> + EFI_USB_INTERFACE_DESCRIPTOR DummyInterfaceDescriptor;
> + INTN DummyAltSettingIndex;
> +
> + if (IsDLDirectFbCapableInterface (UsbIo, &DummyInterfaceDescriptor, &DummyAltSettingIndex)){
> + Status = EFI_SUCCESS;
> + }
> +
> + gBS->CloseProtocol (
> + Controller,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + Controller);
> +
> + return Status;
> +}
> +
> +
> +/**
> + Starts the DisplayLink device with this driver.
> +
> + This function consumes USB I/O Protocol, intializes USB DisplayLink device,
> + installs Graphics Output Protocol
> + Transfer to manage the USB DisplayLink device.
> +
> + @param This The USB DisplayLink 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 This driver supports this device.
> + @retval EFI_UNSUPPORTED This driver does not support this device.
> + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
> + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
> + @retval EFI_ALREADY_STARTED This driver has been started.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingStart (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> + )
> +{
> + EFI_STATUS Status;
> + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> + UINT8 EndpointNumber;
> + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
> + UINT8 Index;
> + BOOLEAN FoundOut;
> + BOOLEAN FoundIn;
> + EFI_TPL OriginalTPL;
> + INTN altSettingIndex;
> +
> + OriginalTPL = gBS->RaiseTPL (TPL_CALLBACK);
> +
> + UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)AllocateZeroPool (sizeof (USB_DISPLAYLINK_DEV));
> + if (UsbDisplayLinkDev == NULL) {
> + DEBUG ((DEBUG_ERROR, "Device initialialisation - Failed to allocate memory for device.\n"));
> + gBS->RestoreTPL (OriginalTPL);
> + return EFI_OUT_OF_RESOURCES;
> + }
> +
> + UsbDisplayLinkDev->Signature = USB_DISPLAYLINK_DEV_SIGNATURE;
> +
> + UsbDisplayLinkDev->ShowBandwidth = ReadEnvironmentBool (L"DisplayLinkShowBandwidth", FALSE);
> + UsbDisplayLinkDev->ShowTestPattern = ReadEnvironmentBool (L"DisplayLinkShowTestPatterns", FALSE);
> +
> + //
> + // Open USB I/O Protocol
> + //
> + Status = gBS->OpenProtocol (
> + Controller,
> + &gEfiUsbIoProtocolGuid,
> + (VOID **) &UsbDisplayLinkDev->UsbIo,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_BY_DRIVER);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to open usbio protocol. Is USB correctly supported on this platform?.\n"));
> + Status = EFI_UNSUPPORTED;
> + goto ErrorExit2;
> + }
> +
> + if (!IsDLDirectFbCapableInterface (UsbDisplayLinkDev->UsbIo, &UsbDisplayLinkDev->InterfaceDescriptor, &altSettingIndex)) {
> + Status = EFI_UNSUPPORTED;
> + goto ErrorExit4;
> + }
> +
> + Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, altSettingIndex);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to select alternate setting.\n"));
> + Status = EFI_UNSUPPORTED;
> + goto ErrorExit4;
> + }
> +
> + //
> + // Parse endpoint descriptor
> + //
> + EndpointNumber = UsbDisplayLinkDev->InterfaceDescriptor.NumEndpoints;
> +
> + //
> + // Traverse endpoints to find bulk endpoint
> + //
> + FoundOut = FALSE;
> + FoundIn = FALSE;
> + for (Index = 0; Index < EndpointNumber; Index++) {
> + UsbDisplayLinkDev->UsbIo->UsbGetEndpointDescriptor (
> + UsbDisplayLinkDev->UsbIo,
> + Index,
> + &EndpointDescriptor);
> +
> + if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_BULK) {
> + if (!FoundOut && (EndpointDescriptor.EndpointAddress & BIT7) == 0) {
> + CopyMem (&UsbDisplayLinkDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> + FoundOut = TRUE;
> + } else if (!FoundIn && (EndpointDescriptor.EndpointAddress & BIT7) == BIT7) {
> + CopyMem (&UsbDisplayLinkDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> + FoundIn = TRUE;
> + }
> + }
> + }
> +
> + if (FoundOut == FALSE) {
> + Status = EFI_UNSUPPORTED;
> + DEBUG ((DEBUG_ERROR, "No endpoints found. Num endpoints searched = %d.\n", EndpointNumber));
> + goto ErrorExit4;
> + }
> +
> + Status = DlReadEdid (UsbDisplayLinkDev);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to read monitor EDID from DisplayLink device (code %r)\n", Status));
> + goto ErrorExit7;
> + }
> +
> + Status = InitializeUsbDisplayLinkDevice (UsbDisplayLinkDev);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to initialise DisplayLink device (code %r)\n", Status));
> + goto ErrorExit7;
> + }
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &Controller,
> + &gEfiGraphicsOutputProtocolGuid,
> + &UsbDisplayLinkDev->GraphicsOutputProtocol,
> + &gEfiEdidDiscoveredProtocolGuid,
> + &UsbDisplayLinkDev->EdidDiscovered,
> + &gEfiEdidActiveProtocolGuid,
> + &UsbDisplayLinkDev->EdidActive,
> + NULL);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to install Graphics Output and EDID protocol interfaces - driver not installed correctly - %r\n", Status));
> + goto ErrorExit8;
> + }
> +
> + UsbDisplayLinkDev->ControllerNameTable = (EFI_UNICODE_STRING_TABLE*)NULL;
> +
> + AddUnicodeString2 (
> + "eng",
> + mUsbDisplayLinkComponentName.SupportedLanguages,
> + &UsbDisplayLinkDev->ControllerNameTable,
> + (CONST CHAR16*)L"Generic Usb DisplayLink",
> + TRUE);
> +
> + AddUnicodeString2 (
> + "en",
> + mUsbDisplayLinkComponentName2.SupportedLanguages,
> + &UsbDisplayLinkDev->ControllerNameTable,
> + (CONST CHAR16*)L"Generic Usb DisplayLink",
> + FALSE);
> +
> + //
> + // Setup a periodic timer
> + //
> + Status = gBS->CreateEvent (
> + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> + TPL_CALLBACK,
> + DisplayLinkPeriodicTimer,
> + UsbDisplayLinkDev,
> + &UsbDisplayLinkDev->TimerEvent);
> +
> + if (EFI_ERROR (Status)) {
> + Status = EFI_OUT_OF_RESOURCES;
> + DEBUG ((DEBUG_ERROR, "Failed to create screeen update polling event.\n"));
> + goto ErrorExit8;
> + }
> +
> + // Start one-shot timer. The rendering operations can take quite a long time, so we
> + // don't want another timer event to happen until we have finished; so we'll restart
> + // the timer from DisplayLinkPeriodicTimer, the event handler function.
> + Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> + if (EFI_ERROR (Status)) {
> + Status = EFI_OUT_OF_RESOURCES;
> + DEBUG ((DEBUG_ERROR, "Failed to create screen update polling timer.\n"));
> + goto ErrorExit8;
> + }
> +
> + Status = gBS->CreateEventEx (
> + EVT_NOTIFY_SIGNAL,
> + TPL_NOTIFY,
> + DisplayLinkDriverExitBootServices,
> + UsbDisplayLinkDev,
> + &gEfiEventExitBootServicesGuid,
> + &UsbDisplayLinkDev->DriverExitBootServicesEvent);
> +
> + if (EFI_ERROR (Status)) {
> + Status = EFI_OUT_OF_RESOURCES;
> + DEBUG ((DEBUG_ERROR, "Failed to create event for bootexit.\n"));
> + goto ErrorExit8;
> + }
> +
> + gBS->RestoreTPL (OriginalTPL);
> +
> + DEBUG ((DEBUG_INFO, "DisplayLink GOP driver successfully bound to device.\n"));
> +
> + return EFI_SUCCESS;
> +
> + //
> + // Error handler
> + //
> + ErrorExit8:
> + ErrorExit7:
> + ErrorExit4:
> + gBS->CloseProtocol (
> + Controller,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + Controller);
> +
> + ErrorExit2:
> + if (UsbDisplayLinkDev != NULL) {
> + FreePool (UsbDisplayLinkDev);
> + UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)NULL;
> + }
> +
> + DEBUG ((DEBUG_ERROR, "Exiting - Failed to initialise driver.\n"));
> +
> + gBS->RestoreTPL (OriginalTPL);
> + return Status;
> +}
> +
> +/**
> +Entrypoint of USB DisplayLink Driver.
> +
> +This function is the entrypoint of a combined USB DisplayLink GOP Driver. It installs Driver Binding
> +Protocols together with Component Name Protocols.
> +
> +@param ImageHandle The firmware allocated handle for the EFI image.
> +@param SystemTable A pointer to the EFI System Table.
> +@param DriverBindingHandle The Driver binding handle
> +
> +@retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable,
> + IN EFI_HANDLE DriverBindingHandle
> +)
> +{
> + EFI_STATUS Status;
> +
> + Status = EfiLibInstallDriverBindingComponentName2 (
> + ImageHandle,
> + SystemTable,
> + &gUsbDisplayLinkDriverBinding,
> + DriverBindingHandle,
> + &mUsbDisplayLinkComponentName,
> + &mUsbDisplayLinkComponentName2);
> +
> + ASSERT_EFI_ERROR (Status);
> +
> + return EFI_SUCCESS;
> +}
> +
> +
> +/**
> +Entrypoint of USB DisplayLink Driver.
> +
> +This function is the entrypoint of USB DisplayLink Driver. It installs Driver Binding
> +Protocols together with Component Name Protocols.
> +
> +@param ImageHandle The firmware allocated handle for the EFI image.
> +@param SystemTable A pointer to the EFI System Table.
> +
> +@retval EFI_SUCCESS The entry point is executed successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingEntryPoint (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> +)
> +{
> + return UsbDisplayLinkDriverCombinedGopBindingEntryPoint (ImageHandle, SystemTable, ImageHandle);
> +}
> +
> +
> +/**
> +Unloads an image.
> +@param ImageHandle Handle that identifies the image to be unloaded.
> +@retval EFI_SUCCESS The image has been unloaded.
> +@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverCombinedGopUnload (
> + IN EFI_HANDLE ImageHandle
> +)
> +{
> + EFI_STATUS Status = EFI_SUCCESS;
> + EFI_STATUS handleDisconnectStatus;
> + EFI_HANDLE *HandleBuffer;
> + UINTN HandleCount;
> + UINTN Index;
> +
> + //
> + // Retrieve array of all handles in the handle database
> + //
> + handleDisconnectStatus = gBS->LocateHandleBuffer (
> + AllHandles,
> + NULL,
> + NULL,
> + &HandleCount,
> + &HandleBuffer
> + );
> + if (! EFI_ERROR (handleDisconnectStatus)) {
> + //
> + // Disconnect the current driver from handles in the handle database
> + //
> + for (Index = 0; Index < HandleCount; Index++) {
> + Status = gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
> + }
> + //
> + // Free the array of handles
> + //
> + if (HandleBuffer != NULL)
> + {
> + FreePool (HandleBuffer);
> + }
> + }
> +
> + // Even if we didn't manage to disconnect the handles, try to uninstall the protocols
> + //
> + // Uninstall protocols installed in the driver entry point
> + //
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + ImageHandle,
> + &gEfiDriverBindingProtocolGuid,
> + &gUsbDisplayLinkDriverBinding,
> + &gEfiComponentNameProtocolGuid,
> + &mUsbDisplayLinkComponentName,
> + &gEfiComponentName2ProtocolGuid,
> + &mUsbDisplayLinkComponentName2,
> + NULL
> + );
> +
> + if (EFI_ERROR (handleDisconnectStatus))
> + {
> + return handleDisconnectStatus;
> + }
> + return Status;
> +}
> +
> +
> +/**
> + Stop the USB DisplayLink device handled by this driver.
> +
> + @param This The USB DisplayLink 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_UNSUPPORTED Simple Pointer Protocol is not installed on Controller.
> + @retval Others Fail to uninstall protocols attached on the device.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UsbDisplayLinkDriverBindingStop (
> + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> + IN EFI_HANDLE Controller,
> + IN UINTN NumberOfChildren,
> + IN EFI_HANDLE *ChildHandleBuffer
> + )
> +{
> + EFI_STATUS Status;
> + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
> +
> + Status = gBS->OpenProtocol (
> + Controller,
> + &gEfiGraphicsOutputProtocolGuid,
> + (VOID **) &GraphicsOutputProtocol,
> + This->DriverBindingHandle,
> + Controller,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> +
> + if (EFI_ERROR (Status)) {
> + return EFI_UNSUPPORTED;
> + }
> +
> + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> +
> + // Reset the video mode to clear the display. Don't drop out if there is a problem, just press on.
> + // Note that this will also clear the frame buffer, as the screen buffer will be re-allocated with AllocateZeroPool.
> + if ((GraphicsOutputProtocol->Mode != NULL) &&
> + (GraphicsOutputProtocol->Mode->Mode != GRAPHICS_OUTPUT_INVALID_MODE_NUMBER)) {
> + Status = DisplayLinkSetMode (GraphicsOutputProtocol, GraphicsOutputProtocol->Mode->Mode);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_WARN, "Driver stop - Problem resetting video mode - %r.\n", Status));
> + }
> + }
> +
> + // Reset the alt setting on the interface (to the DL3 alt setting)
> + Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, 0);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_WARN, "Error resetting USB interface alternate setting - %r.\n", Status));
> + }
> +
> + Status = gBS->UninstallMultipleProtocolInterfaces (
> + Controller,
> + &gEfiGraphicsOutputProtocolGuid,
> + &UsbDisplayLinkDev->GraphicsOutputProtocol,
> + &gEfiEdidDiscoveredProtocolGuid,
> + &UsbDisplayLinkDev->EdidDiscovered,
> + &gEfiEdidActiveProtocolGuid,
> + &UsbDisplayLinkDev->EdidActive,
> + NULL);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_WARN, "Error uninstalling Graphics Output and EDID protocol interfaces - %r.\n", Status));
> + return Status;
> + }
> +
> + gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> +
> + gBS->CloseProtocol (
> + Controller,
> + &gEfiUsbIoProtocolGuid,
> + This->DriverBindingHandle,
> + Controller);
> +
> + //
> + // Free all resources.
> + //
> + if (UsbDisplayLinkDev->ControllerNameTable != NULL) {
> + FreeUnicodeStringTable (UsbDisplayLinkDev->ControllerNameTable);
> + }
> +
> + if (UsbDisplayLinkDev->Screen != NULL) {
> + FreePool (UsbDisplayLinkDev->Screen);
> + UsbDisplayLinkDev->Screen = NULL;
> + }
> +
> + if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode) {
> + if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info) {
> + FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info);
> + UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info = NULL;
> + }
> + FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode);
> + UsbDisplayLinkDev->GraphicsOutputProtocol.Mode = NULL;
> + }
> +
> + FreePool (UsbDisplayLinkDev);
> +
> + return EFI_SUCCESS;
> +
> +}
> +
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> new file mode 100644
> index 000000000000..497a2621bc2c
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> @@ -0,0 +1,278 @@
> +/**
> + * @file UsbDisplayLink.h
> + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#ifndef _EFI_USB_DISPLAYLINK_H_
> +#define _EFI_USB_DISPLAYLINK_H_
> +
> +#include <Uefi/UefiBaseType.h>
> +#include <Uefi/UefiSpec.h>
> +
> +#include <Protocol/EdidActive.h>
> +#include <Protocol/EdidDiscovered.h>
> +#include <Protocol/EdidOverride.h>
> +#include <Protocol/GraphicsOutput.h>
> +#include <Protocol/UsbIo.h>
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/ReportStatusCodeLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +
> +#define VENDOR_DISPLAYLINK 0x17e9
> +#define CLASS_VENDOR 0xFF
> +
> +#define DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO ((UINTN)0)
> +
> +#define INTERFACE_PROTOCOL_DIRECT_FB 4
> +
> +#define USB_TRANSFER_LENGTH (64 * 1024)
> +#define DISPLAYLINK_MODE_DATA_LENGTH (146)
> +#define DISPLAYLINK_USB_CTRL_TIMEOUT (1000)
> +#define DISPLAYLINK_USB_BULK_TIMEOUT (1)
> +
> +#define DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD ((UINTN)1000000) // 0.1s in us
> +#define DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD ((UINTN)30000) // 3s in ticks
> +
> +#define DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE ((UINT16)60)
> +
> +// Requests to read values from the firmware
> +#define EDID_BLOCK_SIZE 128
> +#define EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK ((UINT16)(0x64))
> +
> +/** Structures ported from firmware - protocol.h */
> +enum ID {
> + // VideoCommands
> + GET_OUTPUT_EDID = 0,
> + SET_VIDEO_MODE = 1
> +};
> +
> +typedef struct {
> + UINT32 HorizontalResolution;
> + UINT32 VerticalResolution;
> + UINT32 ColorDepth;
> + UINT32 RefreshRate;
> + UINT8 Commands[DISPLAYLINK_MODE_DATA_LENGTH];
> +} DISPLAYLINK_MODE_DATA;
> +
> +#define GRAPHICS_OUTPUT_INVALID_MODE_NUMBER 0xffff
> +
> +/**
> + * Device instance of USB display.
> + */
> +typedef struct {
> + UINT64 Signature;
> + EFI_HANDLE Handle;
> + EFI_USB_IO_PROTOCOL *UsbIo;
> + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> + EFI_USB_ENDPOINT_DESCRIPTOR BulkOutEndpointDescriptor;
> + EFI_USB_ENDPOINT_DESCRIPTOR BulkInEndpointDescriptor;
> + EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutputProtocol;
> + EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered;
> + EFI_EDID_ACTIVE_PROTOCOL EdidActive;
> + EFI_UNICODE_STRING_TABLE *ControllerNameTable;
> + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Screen;
> + UINTN DataSent; /** Debug - used to track the bandwidth */
> + EFI_EVENT TimerEvent;
> + EFI_EVENT DriverExitBootServicesEvent;
> + BOOLEAN ShowBandwidth; /** Debugging - show the bandwidth on the screen */
> + BOOLEAN ShowTestPattern; /** Show a colourbar pattern instead of the BLTd contents of the framebuffer */
> + UINTN LastY1; /** Used to track if we can do a partial screen update */
> + UINTN LastY2;
> + UINTN LastWidth;
> + UINTN TimeSinceLastScreenUpdate; /** Do a full screen update every (x) seconds */
> +} USB_DISPLAYLINK_DEV;
> +
> +#define USB_DISPLAYLINK_DEV_SIGNATURE SIGNATURE_32 ('d', 'l', 'i', 'n')
> +
> +struct VideoMode {
> + UINT8 Reserved1; /* Reserved - must be 0. */
> + UINT8 Reserved2; /* Reserved - must be 2. */
> +
> + // Values matching the EDID Detailed Timing Descriptor spec
> + UINT16 PixelClock;
> + UINT16 HActive;
> + UINT16 HBlanking;
> + UINT16 HSyncOffset; // Horizontal Front Porch
> + UINT16 HSyncWidth;
> + UINT16 VActive;
> + UINT16 VBlanking;
> + UINT16 VSyncOffset; // Vertical Front Porch
> + UINT16 VSyncWidth;
> + // End of Edid Detailed Timing Descriptor
> +
> + UINT16 Flags /*ModeFlags*/;
> + UINT16 Accumulate;
> + UINT16 Reserved3; /* Reserved - must be 0. */
> + UINT16 Reserved4; /* Reserved - must be 0. */
> + UINT16 InsetLeft;
> + UINT16 InsetTop;
> + UINT16 InsetRight;
> + UINT16 InsetBottom;
> + UINT32 FillValue;
> + UINT32 Reserved5; /* Reserved - must be 0. */
> + UINT8 Vic;
> + UINT8 ActiveFormat;
> + UINT16 Reserved6;
> +};
> +
> +#define USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(a) \
> + CR(a, USB_DISPLAYLINK_DEV, GraphicsOutputProtocol, USB_DISPLAYLINK_DEV_SIGNATURE)
> +
> +//
> +// Global Variables
> +//
> +extern EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding;
> +extern EFI_COMPONENT_NAME_PROTOCOL mUsbDisplayLinkComponentName;
> +extern EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplayLinkComponentName2;
> +
> +
> +/* ******************************************* */
> +/* ******** GOP interface functions ******** */
> +/* ******************************************* */
> +
> +/**
> + * Implementation of the GOP protocol QueryMode API function
> + * @param This Instance of the GOP protocol
> + * @param ModeNumber
> + * @param SizeOfInfo
> + * @param Info
> + * @return
> + */
> +EFI_STATUS
> + EFIAPI
> + DisplayLinkQueryMode (
> + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> + IN UINT32 ModeNumber,
> + OUT UINTN *SizeOfInfo,
> + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
> + );
> +
> +
> +/**
> + * Implementation of the GOP protocol SetMode API function
> + * @param This
> + * @param ModeNumber
> + * @return
> + */
> +EFI_STATUS
> + EFIAPI
> + DisplayLinkSetMode (
> + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> + IN UINT32 ModeNumber
> + );
> +
> +/**
> + * Implementation of the GOP protocol Blt API function
> + * @param This
> + * @param BltBuffer
> + * @param BltOperation
> + * @param SourceX
> + * @param SourceY
> + * @param DestinationX
> + * @param DestinationY
> + * @param Width
> + * @param Height
> + * @param Delta
> + * @return
> + */
> +EFI_STATUS
> + EFIAPI
> + DisplayLinkBlt (
> + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
> + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> + IN UINTN SourceX,
> + IN UINTN SourceY,
> + IN UINTN DestinationX,
> + IN UINTN DestinationY,
> + IN UINTN Width,
> + IN UINTN Height,
> + IN UINTN Delta OPTIONAL
> + );
> +
> +/* *************************** */
> +/* ** GOP helper functions ** */
> +/* *************************** */
> +
> +VOID
> +EFIAPI
> +DlGopPrintTextToScreen (
> + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> + UINTN X,
> + UINTN Y,
> + IN CONST CHAR16 *Format,
> + ...
> +);
> +
> +EFI_STATUS
> +DlGopSendTestPattern (
> + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> + UINTN PatternNumber
> +);
> +
> +EFI_STATUS
> +DlGopSendScreenUpdate (
> + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> +);
> +
> +
> +/* ******************************************* */
> +/* ******** USB interface functions ******** */
> +/* ******************************************* */
> +
> +EFI_STATUS
> +DlUsbSendControlWriteMessage (
> + IN USB_DISPLAYLINK_DEV *Device,
> + IN UINT8 Request,
> + IN UINT16 Value,
> + IN CONST VOID *ControlMsg,
> + IN UINT16 ControlMsgLen
> +);
> +
> +EFI_STATUS
> +DlUsbSendControlReadMessage (
> + IN USB_DISPLAYLINK_DEV *Device,
> + IN UINT8 Request,
> + IN UINT16 Value,
> + OUT VOID *ControlMsg,
> + IN UINT16 ControlMsgLen
> +);
> +
> +EFI_STATUS
> +DlUsbBulkWrite (
> + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> + CONST UINT8* Buffer,
> + UINTN DataLen,
> + UINT32 *USBStatus
> +);
> +
> +UINTN
> +DlUsbBulkRead (
> + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> + UINT8* Buffer,
> + UINTN BufferLen
> +);
> +
> +/* ******************************************* */
> +/* ******** Video Mode functions ******** */
> +/* ******************************************* */
> +
> +// Pre-calculated video modes
> +UINT32
> +DlVideoModeGetNumSupportedVideoModes ();
> +
> +CONST struct VideoMode *
> +DlVideoModeGetSupportedVideoMode (
> + UINT32 index
> +);
> +
> +#endif
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> new file mode 100644
> index 000000000000..252293da39d4
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> @@ -0,0 +1,180 @@
> +/**
> + * @file UsbTransfer.c
> + * @brief Wrapper of UEFI USB bulk and control transfer interface for USB DisplayLink driver.
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +
> +/**
> + * Write the data to the DisplayLink device using the USBIO protocol.
> + * @param UsbDisplayLinkDev
> + * @param Buffer
> + * @param DataLen
> + * @param USBStatus
> + * @return
> + * EFI_SUCCESS The bulk transfer has been successfully executed.
> + * EFI_INVALID_PARAMETER If DeviceEndpoint is not valid.
> + * EFI_INVALID_PARAMETER Data is NULL.
> + * EFI_INVALID_PARAMETER DataLength is NULL.
> + * EFI_INVALID_PARAMETER Status is NULL.
> + * EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
> + * EFI_TIMEOUT The bulk transfer cannot be completed within Timeout timeframe.
> + * EFI_DEVICE_ERROR The transfer failed other than timeout, and the transfer status is returned in Status.
> + */
> +EFI_STATUS
> +DlUsbBulkWrite (
> + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> + IN CONST UINT8* Buffer,
> + IN UINTN DataLen,
> + OUT UINT32 *USBStatus
> + )
> +{
> + EFI_STATUS Status;
> + Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> + UsbDisplayLinkDev->UsbIo,
> + UsbDisplayLinkDev->BulkOutEndpointDescriptor.EndpointAddress,
> + (VOID*)Buffer,
> + &DataLen,
> + DISPLAYLINK_USB_BULK_TIMEOUT,
> + USBStatus);
> +
> + return Status;
> +}
> +
> +/**
> +* Read data from the DisplayLink device using the USBIO protocol.
> +* @param UsbDisplayLinkDev
> +* @param Buffer
> +* @param BufferLen
> +* @return 0 if an error occurred or 0 bytes were read, otherwise the number of bytes read
> + */
> +UINTN
> +DlUsbBulkRead (
> + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> + IN UINT8* Buffer,
> + IN UINTN BufferLen
> + )
> +{
> + UINT32 Result;
> + UINTN ReadLen;
> + EFI_STATUS Status;
> +
> + ReadLen = BufferLen;
> +
> + Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> + UsbDisplayLinkDev->UsbIo,
> + UsbDisplayLinkDev->BulkInEndpointDescriptor.EndpointAddress,
> + Buffer,
> + &ReadLen,
> + DISPLAYLINK_USB_BULK_TIMEOUT,
> + &Result);
> +
> + if (EFI_ERROR (Status)) {
> + return 0;
> + }
> +
> + return ReadLen;
> +}
> +
> +
> +/**
> +Send a control message (e.g set video mode) message to the DisplayLink device.
> +
> +@param Device USB device handle.
> +@param request Request type, e.g. SET_VIDEO_MODE
> +@param value
> +@param controlMsg Pointer to the message to send.
> +@param controlMsgLen Length of the message.
> +
> +@retval EFI_SUCCESS Successfully sent message.
> +
> +**/
> +EFI_STATUS
> +DlUsbSendControlWriteMessage (
> + IN USB_DISPLAYLINK_DEV *Device,
> + IN UINT8 Request,
> + IN UINT16 Value,
> + IN CONST VOID *ControlMsg,
> + IN UINT16 ControlMsgLen
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> + EFI_USB_DEVICE_REQUEST UsbRequest;
> +
> + ZeroMem (&Request, sizeof (Request));
> + UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE;
> + UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> + UsbRequest.Request = Request;
> + UsbRequest.Value = Value;
> + UsbRequest.Length = ControlMsgLen;
> +
> + Status = Device->UsbIo->UsbControlTransfer (
> + Device->UsbIo,
> + &UsbRequest,
> + EfiUsbDataOut,
> + DISPLAYLINK_USB_CTRL_TIMEOUT,
> + (VOID *)ControlMsg,
> + ControlMsgLen,
> + &UsbStatus);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "USB write control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> + Status = EFI_DEVICE_ERROR;
> + }
> + return Status;
> +}
> +
> +
> +/**
> +Request data from the DisplayLink device (e.g. the monitor EDID)
> +
> +@param Device USB device handle.
> +@param request Request type, e.g. GET_OUTPUT_EDID
> +@param value
> +@param controlMsg Pointer to the message to send.
> +@param controlMsgLen Length of the message.
> +
> +@retval EFI_SUCCESS Successfully sent message.
> +
> +**/
> +EFI_STATUS
> +DlUsbSendControlReadMessage (
> + IN USB_DISPLAYLINK_DEV *Device,
> + IN UINT8 Request,
> + IN UINT16 Value,
> + OUT VOID *ControlMsg,
> + IN UINT16 ControlMsgLen
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 UsbStatus;
> + EFI_USB_DEVICE_REQUEST UsbRequest;
> +
> + ZeroMem (&UsbRequest, sizeof (UsbRequest));
> + UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE | USB_ENDPOINT_DIR_IN;
> + UsbRequest.Request = Request;
> + UsbRequest.Value = Value;
> + UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> + UsbRequest.Length = ControlMsgLen;
> +
> + Status = Device->UsbIo->UsbControlTransfer (
> + Device->UsbIo,
> + &UsbRequest,
> + EfiUsbDataIn,
> + DISPLAYLINK_USB_CTRL_TIMEOUT,
> + (VOID *)ControlMsg,
> + ControlMsgLen,
> + &UsbStatus);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "USB read control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> + Status = EFI_DEVICE_ERROR;
> + }
> + return Status;
> +}
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> new file mode 100644
> index 000000000000..6218c093147c
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> @@ -0,0 +1,254 @@
> +/**
> + * @file VideoModes.c
> + * @brief Pre-calculated video timings sent to the DisplayLink device when a video mode is selected
> + *
> + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> + *
> + * SPDX-License-Identifier: BSD-2-Clause-Patent
> + *
> +**/
> +
> +#include "UsbDisplayLink.h"
> +
> +
> +// Supported video modes - must be in order of pixel count (i.e. hres x vres)
> +
> +STATIC CONST struct VideoMode ModeData[] = {
> + {
> + // 640 x 480 @ 60Hz
> + .Reserved2 = 2,
> + .PixelClock = 2517,
> + .HActive = 640,
> + .HBlanking = 160,
> + .HSyncOffset = 16,
> + .HSyncWidth = 96,
> + .VActive = 480,
> + .VBlanking = 45,
> + .VSyncOffset = 10,
> + .VSyncWidth = 2,
> + .Flags = 0x00000300,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + },
> + {
> + // 800 x 600 @ 60Hz
> + .Reserved2 = 2,
> + .PixelClock = 4000,
> + .HActive = 800,
> + .HBlanking = 256,
> + .HSyncOffset = 40,
> + .HSyncWidth = 128,
> + .VActive = 600,
> + .VBlanking = 28,
> + .VSyncOffset = 1,
> + .VSyncWidth = 3,
> + .Flags = 0x00000000,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + },
> + {
> + // 1024x768 @ 60Hz
> + .Reserved1 = 0,
> + .Reserved2 = 2,
> + .PixelClock = 6500,
> + .HActive = 1024,
> + .HBlanking = 320,
> + .HSyncOffset = 24,
> + .HSyncWidth = 136,
> + .VActive = 768,
> + .VBlanking = 38,
> + .VSyncOffset = 3,
> + .VSyncWidth = 6,
> + .Flags = 0x00000300,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + },
> + {
> + // 1360x768 @ 60Hz
> + .Reserved1 = 0,
> + .Reserved2 = 2,
> + .PixelClock = 8550,
> + .HActive = 1360,
> + .HBlanking = 432,
> + .HSyncOffset = 64,
> + .HSyncWidth = 112,
> + .VActive = 768,
> + .VBlanking = 27,
> + .VSyncOffset = 3,
> + .VSyncWidth = 6,
> + .Flags = 0x00000000,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + },
> + {
> + // 1280x960 @ 60Hz
> + .Reserved1 = 0,
> + .Reserved2 = 2,
> + .PixelClock = 10800,
> + .HActive = 1280,
> + .HBlanking = 520,
> + .HSyncOffset = 96,
> + .HSyncWidth = 112,
> + .VActive = 960,
> + .VBlanking = 40,
> + .VSyncOffset = 1,
> + .VSyncWidth = 3,
> + .Flags = 0x00000000,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + },
> + {
> + // 1280x1024 @ 60Hz
> + .Reserved1 = 0,
> + .Reserved2 = 2,
> + .PixelClock = 10800,
> + .HActive = 1280,
> + .HBlanking = 408,
> + .HSyncOffset = 48,
> + .HSyncWidth = 112,
> + .VActive = 1024,
> + .VBlanking = 42,
> + .VSyncOffset = 1,
> + .VSyncWidth = 3,
> + .Flags = 0x00000000,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + },
> + {
> + // 1600x900 @ 60Hz
> + .Reserved2 = 2,
> + .PixelClock = 11825,
> + .HActive = 1600,
> + .HBlanking = 512,
> + .HSyncOffset = 88,
> + .HSyncWidth = 168,
> + .VActive = 900,
> + .VBlanking = 34,
> + .VSyncOffset = 3,
> + .VSyncWidth = 5,
> + .Flags = 0x00000500,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + },
> + {
> + // 1400x1050 @ 60Hz
> + .Reserved1 = 0,
> + .Reserved2 = 2,
> + .PixelClock = 12175,
> + .HActive = 1400,
> + .HBlanking = 464,
> + .HSyncOffset = 88,
> + .HSyncWidth = 144,
> + .VActive = 1050,
> + .VBlanking = 39,
> + .VSyncOffset = 3,
> + .VSyncWidth = 4,
> + .Flags = 0x00000100,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + },
> + {
> + // 1600x1200 @ 60Hz
> + .Reserved1 = 0,
> + .Reserved2 = 2,
> + .PixelClock = 16200,
> + .HActive = 1600,
> + .HBlanking = 560,
> + .HSyncOffset = 64,
> + .HSyncWidth = 192,
> + .VActive = 1200,
> + .VBlanking = 50,
> + .VSyncOffset = 1,
> + .VSyncWidth = 3,
> + .Flags = 0x00000000,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + },
> + {
> + // 1920 x 1080
> + .Reserved2 = 2,
> + .PixelClock = 14850,
> + .HActive = 1920,
> + .HBlanking = 280,
> + .HSyncOffset = 88,
> + .HSyncWidth = 44,
> + .VActive = 1080,
> + .VBlanking = 45,
> + .VSyncOffset = 4,
> + .VSyncWidth = 5,
> + .Flags = 0x00000000,
> + .Accumulate = 1,
> + .Reserved3 = 0,
> + .Reserved4 = 0,
> + .Reserved5 = 0x00000000,
> + .Vic = 0,
> + .ActiveFormat = 0,
> + }
> +};
> +
> +STATIC CONST UINT32 NumSupportedVideoModes = (sizeof (ModeData) / sizeof (struct VideoMode));
> +
> +/**
> +Find the number of pre-calculated video modes that we support.
> +
> +@retval Number of modes.
> +
> +**/
> +UINT32 DlVideoModeGetNumSupportedVideoModes ()
> +{
> + return NumSupportedVideoModes;
> +}
> +
> +/**
> +Get one of the pre-calculated video modes
> +
> +@param index The video mode that we want.
> +
> +@retval NULL The index was out of range.
> +
> +**/
> +CONST struct VideoMode *DlVideoModeGetSupportedVideoMode (
> + UINT32 Index
> + )
> +{
> + if (Index >= NumSupportedVideoModes) {
> + return NULL;
> + }
> + return &ModeData[Index];
> +}
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> new file mode 100644
> index 000000000000..955331ba6076
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> @@ -0,0 +1,61 @@
> +#/** @file
> +#
> +# Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +[Defines]
> + PLATFORM_NAME = DisplayLinkPkg
> + PLATFORM_GUID = ad3b37b0-f798-4f97-9b3f-0c6f43d7c993
> + PLATFORM_VERSION = 0.1
> + DSC_SPECIFICATION = 0x0001001C
> + OUTPUT_DIRECTORY = Build/DisplayLink
> + SUPPORTED_ARCHITECTURES = X64|IA32|AARCH64|ARM
> + BUILD_TARGETS = DEBUG|RELEASE|NOOPT
> + SKUID_IDENTIFIER = DEFAULT
> +
> +[LibraryClasses]
> + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
> + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
> + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
> + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
> + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
> + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
> + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
> + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
> + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
> + UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
> +
> +[LibraryClasses.common.UEFI_DRIVER]
> + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
> +
> +[LibraryClasses.AARCH64]
> + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> +
> +[LibraryClasses.ARM]
> + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> +
> +[PcdsFixedAtBuild]
> +!ifdef $(DEBUG_ENABLE_OUTPUT)
> + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x3f
> + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80080043 # Flags to control amount of debug output - see https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging<https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging>
> + gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x07
> +!endif
> +
> +[Components]
> + Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> +
> +[BuildOptions]
> + *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES -D INF_DRIVER_VERSION=$(INF_DRIVER_VERSION)
> + GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG
> + MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
> +!ifdef $(COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE)
> + *_*_*_CC_FLAGS = -D COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> +!endif
> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> new file mode 100644
> index 000000000000..40061f1eb46d
> --- /dev/null
> +++ b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> @@ -0,0 +1,77 @@
> +# DISPLAYLINK DRIVERS
> +This package contains a GOP driver for Universal USB-connected docks containing the
> +DisplayLink DL-6xxx chip or newer.
> +
> +[DisplayLink Website](http://www.displaylink.com<http://www.displaylink.com>)
> +
> +[Products](https://www.displaylink.com/products/universal-docking-stations<https://www.displaylink.com/products/universal-docking-stations>)
> +
> +# INDEX
> +
> +* [Resolutions Supported](#resolutions-supported)
> +* [Frame rates](#frame-rates)
> +* [Multiple monitor outputs](#multiple-monitor-outputs)
> +* [Multiple DisplayLink devices](#multiple-displaylink-devices)
> +* [Behaviour with no monitor connected](#behaviour-with-no-monitor-connected)
> +
> +# Resolutions supported
> +
> +The driver supports the following resolutions:
> +
> +640 x 480 @ 60Hz
> +
> +800 x 600 @ 60Hz
> +
> +1024x768 @ 60Hz
> +
> +1360x768 @ 60Hz
> +
> +1280x960 @ 60Hz
> +
> +1280x1024 @ 60Hz
> +
> +1600x900 @ 60Hz
> +
> +1400x1050 @ 60Hz
> +
> +1600x1200 @ 60Hz
> +
> +1920x1080 @ 60Hz
> +
> +
> +Note that the list of resolutions advertised by the driver may be smaller than
> +this if a connected monitor does not support a particular resolution. The driver
> +interrogates connected monitors to see which modes can be supported.It<http://supported.It> is the
> +responsibility of the BIOS to select the video mode from this list which most
> +closely matches its requirements. In some cases this may lead to the BIOS
> +scaling its display.
> +
> +# Frame rates
> +
> +The driver is limited to a maximum of ten frames per second. Some slower systems
> +at higher screen resolutions may perform at a lower rate than this.
> +
> +# Multiple monitor outputs
> +
> +If multiple monitors are connected to the DisplayLinkdevice, the display will be
> +duplicated (cloned) across all outputs at the same resolution. The resolution
> +used will be limited by the capability of the monitor with the
> +lowest specification.
> +
> +# Multiple DisplayLink devices
> +
> +The driver will support the connection of multiple DisplayLink devices. The
> +exact behaviourof the system with multiple devices connected is defined by the
> +rest of the BIOS; usually, the BIOS causes the displays to be duplicated
> +(cloned) across all devices. Note that the system performance and frame rate
> +will be affected by the number of DisplayLink devices connected.
> +
> +# Behaviour with no monitor connected
> +
> +The driver uses the EDID (Extended Display Identification Data) protocol to
> +detect the list of resolutions that a monitor will support.In<http://support.In> some monitors this
> +may take some time, and occasionally no EDID information will be returned at
> +all. In this case the driver will not be able to detect that there is a monitor
> +connected. To improve the user experience in these cases, the driver will behave
> +as if there is a monitor connected, and will fall back to presenting the full
> +range of supported resolutions to the BIOS.
> diff --git a/Maintainers.txt b/Maintainers.txt
> index 876ae5612ad8..47aac133abb1 100644
> --- a/Maintainers.txt
> +++ b/Maintainers.txt
> @@ -47,6 +47,11 @@ Drivers/OptionRomPkg
> W: https://github.com/tianocore/tianocore.github.io/wiki/OptionRomPkg<https://github.com/tianocore/tianocore.github.io/wiki/OptionRomPkg>
> M: Ray Ni <ray.ni@intel.com>
>
> +Drivers/DisplayLink
> +M: Leif Lindholm <leif.lindholm@linaro.org>
> +M: Ard Bieshuevel <ard.bieshuevel@linaro.org>
> +R: Andy Hayes <andy.hayes@displaylink.com>
> +
> Platform
> M: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> M: Leif Lindholm <leif.lindholm@linaro.org>
> --
> 2.20.1
>

[-- Attachment #2: Type: text/html, Size: 182959 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [External] Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips
  2019-09-09  8:06     ` [External] " Andy Hayes
@ 2019-09-09 11:00       ` Leif Lindholm
  0 siblings, 0 replies; 6+ messages in thread
From: Leif Lindholm @ 2019-09-09 11:00 UTC (permalink / raw)
  To: Andy Hayes; +Cc: devel@edk2.groups.io, Michael D Kinney, Ni, Ray

Hi Andy,

If no one has commented by now, I'd say we're good to go.
Pushed as 9df63499ea01.

Many thanks for your contribution.

Best Regards,

Leif

On Mon, Sep 09, 2019 at 08:06:48AM +0000, Andy Hayes wrote:
> Hi,
> 
> Is it OK to commit this now? Does anyone else have any comments on it?
> 
> Best Regards,
> 
> Andy Hayes
> 
> From: Leif Lindholm <leif.lindholm@linaro.org>
> Sent: 30 August 2019 16:27
> To: Andy Hayes <andy.hayes@displaylink.com>
> Cc: devel@edk2.groups.io; Michael D Kinney <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>
> Subject: [External] Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips
> 
> Hi Andy,
> 
> This looks fine to me - all my feedback has been addressed.
> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org<mailto:leif.lindholm@linaro.org>>
> 
> Ray - did you have any comments on this, or can I go ahead and commit?
> 
> Best Regards,
> 
> Leif
> 
> On Mon, Aug 19, 2019 at 02:32:00PM +0100, Andy Hayes wrote:
> > Cc: Leif Lindholm <leif.lindholm@linaro.org<mailto:leif.lindholm@linaro.org>>
> > Cc: Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
> > Signed-off-by: Andy Hayes <andy.hayes@displaylink.com<mailto:andy.hayes@displaylink.com>>
> > ---
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c | 137 +++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c | 235 +++++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf | 65 ++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c | 598 +++++++++++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h | 129 +++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c | 578 +++++++++++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c | 145 +++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h | 109 ++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c | 1082 ++++++++++++++++++++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h | 278 +++++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c | 180 ++++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c | 254 +++++
> > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc | 61 ++
> > Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md | 77 ++
> > Maintainers.txt | 5 +
> > 15 files changed, 3933 insertions(+)
> >
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> > new file mode 100644
> > index 000000000000..4bfadd770b81
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> > @@ -0,0 +1,137 @@
> > +/** @file CapabilityDescriptor.c
> > + * @brief Definitions for reading USB capability descriptor DisplayLink dock
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +#include "UsbDescriptors.h"
> > +
> > +/**
> > + * Check that the Capability Descriptor is valid and hasn't been tampered with.
> > + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> > + * @param Length
> > + * @param out
> > + * @return
> > + */
> > +STATIC EFI_STATUS
> > +ValidateHeader (
> > + CONST IN VOID* Data,
> > + IN UINTN Length,
> > + OUT CONST VendorDescriptorGeneric** Out
> > + )
> > +{
> > + if (Length < sizeof (VendorDescriptorGeneric)) {
> > + DEBUG ((DEBUG_ERROR, "Data too short (%d bytes) for capability descriptor header section\n", Length));
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + CONST VendorDescriptorGeneric* Desc = (VendorDescriptorGeneric*)Data;
> > + if (Desc->Length > Length) {
> > + DEBUG ((DEBUG_ERROR, "Capability descriptor: Descriptor (%d bytes) exceeds buffer (%d bytes)\n",
> > + Length, Desc->Length));
> > + return EFI_BUFFER_TOO_SMALL;
> > + }
> > + if (Desc->Type != DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY) {
> > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid type (0x%08x)\n", Desc->Type));
> > + return EFI_UNSUPPORTED;
> > + }
> > + if (Desc->CapabilityVersion != 1) {
> > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid version (%d)\n", Desc->CapabilityVersion));
> > + return EFI_INCOMPATIBLE_VERSION;
> > + }
> > + // Capability length must fit within remaining space
> > + if (Desc->CapabilityLength > (Desc->Length - (sizeof (Desc->Length) + sizeof (Desc->Type)))) {
> > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid CapabilityLength (%d)\n", Desc->CapabilityLength));
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + *Out = Desc;
> > + return EFI_SUCCESS;
> > +}
> > +
> > +
> > +/**
> > + * Check that the connected DisplayLink device supports the functionality that this driver requires, e.g. video formats
> > + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> > + * @param Length
> > + * @param Output
> > + * @return
> > + */
> > +EFI_STATUS
> > +UsbDisplayLinkParseCapabilitiesDescriptor (
> > + CONST IN VOID* Data,
> > + IN UINTN Length,
> > + OUT VendorDescriptor* Output
> > + )
> > +{
> > + CONST VendorDescriptorGeneric* Desc;
> > + EFI_STATUS Status;
> > +
> > + Desc = NULL;
> > + Status = ValidateHeader (Data, Length, &Desc);
> > +
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + // Default capabilities
> > + Output->Capabilities1 = 0;
> > +
> > + CONST UINTN CapsHeaderLength = sizeof (Desc->CapabilityVersion) + sizeof (Desc->CapabilityLength);
> > + ASSERT (CapsHeaderLength < MAX_UINT8);
> > +
> > + UINTN DataRemaining;
> > + UINTN Offset;
> > +
> > + DataRemaining = Desc->CapabilityLength - CapsHeaderLength;
> > + Offset = 0;
> > +
> > + while (DataRemaining >= sizeof (DescriptorKLV)) {
> > + CONST DescriptorKLV* KeyHeader = (CONST DescriptorKLV*)(Desc->Klv + Offset);
> > + CONST UINTN KeyValueSize = sizeof (DescriptorKLV) + KeyHeader->Length;
> > + if (KeyValueSize > DataRemaining) {
> > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid value Length (%d)\n", Desc->CapabilityLength));
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + switch (KeyHeader->Key) {
> > + case CAPABILITIES1_KEY: {
> > + if (KeyHeader->Length != CAPABILITIES1_LENGTH) {
> > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid length (%d) for Capabilities 1\n", KeyHeader->Length));
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + Output->Capabilities1 = *(UINT32*)KeyHeader->Value;
> > + break;
> > + default:
> > + // Ignore unknown types
> > + break;
> > + }
> > + }
> > + DataRemaining -= KeyValueSize;
> > + Offset += KeyValueSize;
> > + }
> > + return EFI_SUCCESS;
> > +}
> > +
> > +
> > +/**
> > + * Check that the DisplayLink device supports the basic level of functionality to display GOP pixels.
> > + * @param Descriptor The USB descriptor received from the DisplayLink device
> > + * @return True we can bind, False we can't
> > + */
> > +BOOLEAN
> > +UsbDisplayLinkCapabilitiesSufficientToBind (
> > + CONST IN VendorDescriptor* Descriptor
> > + )
> > +{
> > + BOOLEAN Sufficient;
> > + Sufficient = (BOOLEAN)(Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL);
> > +
> > + if (Sufficient == FALSE) {
> > + DEBUG ((DEBUG_ERROR, "DisplayLink device does not report support for base capabilites - reports x%x, required x%x\n", Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL));
> > + }
> > + return Sufficient;
> > +}
> > +
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> > new file mode 100644
> > index 000000000000..74498f339eb7
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> > @@ -0,0 +1,235 @@
> > +/**
> > + * @file ComponentName.c
> > + * @brief UEFI Component Name protocol implementation for USB DisplayLink driver.
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkComponentNameGetDriverName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **DriverName
> > +);
> > +
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkComponentNameGetControllerName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_HANDLE ChildHandle OPTIONAL,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **ControllerName
> > +);
> > +
> > +
> > +//
> > +// EFI Component Name Protocol
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL mUsbDisplayLinkComponentName = {
> > + UsbDisplayLinkComponentNameGetDriverName,
> > + UsbDisplayLinkComponentNameGetControllerName,
> > + "eng"
> > +};
> > +
> > +//
> > +// EFI Component Name 2 Protocol
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplayLinkComponentName2 = {
> > + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbDisplayLinkComponentNameGetDriverName,
> > + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbDisplayLinkComponentNameGetControllerName,
> > + "en"
> > +};
> > +
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbDisplayLinkDriverNameTable[] = {
> > + { (CHAR8*)"eng;en", (CHAR16*)L"DisplayLink USB GOP Driver" },
> > + { (CHAR8*)NULL , (CHAR16*)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 A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> > + EFI_COMPONENT_NAME_PROTOCOL instance.
> > + @param Language 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 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
> > +UsbDisplayLinkComponentNameGetDriverName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **DriverName
> > + )
> > +{
> > + return LookupUnicodeString2 (
> > + Language,
> > + This->SupportedLanguages,
> > + mUsbDisplayLinkDriverNameTable,
> > + DriverName,
> > + (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> > +}
> > +
> > +/**
> > + 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 A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> > + EFI_COMPONENT_NAME_PROTOCOL instance.
> > + @param ControllerHandle 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 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 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 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 not a valid EFI_HANDLE.
> > + @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
> > +UsbDisplayLinkComponentNameGetControllerName (
> > + IN EFI_COMPONENT_NAME_PROTOCOL *This,
> > + IN EFI_HANDLE ControllerHandle,
> > + IN EFI_HANDLE ChildHandle OPTIONAL,
> > + IN CHAR8 *Language,
> > + OUT CHAR16 **ControllerName
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
> > + EFI_USB_IO_PROTOCOL *UsbIoProtocol;
> > +
> > + //
> > + // This is a device driver, so ChildHandle must be NULL.
> > + //
> > + if (ChildHandle != NULL) {
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + //
> > + // Check Controller's handle
> > + //
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + (VOID **) &UsbIoProtocol,
> > + gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER);
> > +
> > + if (!EFI_ERROR (Status)) {
> > + gBS->CloseProtocol (
> > + ControllerHandle,
> > + &gEfiUsbIoProtocolGuid,
> > + gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> > + ControllerHandle);
> > +
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + if (Status != EFI_ALREADY_STARTED) {
> > + return EFI_UNSUPPORTED;
> > + }
> > + //
> > + // Get the device context
> > + //
> > + Status = gBS->OpenProtocol (
> > + ControllerHandle,
> > + &gEfiGraphicsOutputProtocolGuid,
> > + (VOID**)&GraphicsOutputProtocol,
> > + gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> > + ControllerHandle,
> > + EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > +
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> > +
> > + return LookupUnicodeString2 (
> > + Language,
> > + This->SupportedLanguages,
> > + UsbDisplayLinkDev->ControllerNameTable,
> > + ControllerName,
> > + (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> > +}
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > new file mode 100644
> > index 000000000000..0f458fedcc88
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > @@ -0,0 +1,65 @@
> > +#/** @file
> > +# USB DisplayLink driver that implements blt and EDID commands
> > +#
> > +# USB DisplayLink driver consumes I/O Protocol and Device Path Protocol, and produces
> > +# Graphics Output Protocol on DisplayLink devices.
> > +# 1. DisplayLink reference
> > +# 2. UEFI Specification, v2.1
> > +#
> > +# Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > +#
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +#**/
> > +
> > +
> > +[Defines]
> > + INF_VERSION = 0x0001001B
> > + BASE_NAME = DisplayLinkGop
> > + FILE_GUID = 2D2E62AA-9ECF-43b7-8219-94E7FC713DFF
> > + MODULE_TYPE = UEFI_DRIVER
> > + VERSION_STRING = 1.0
> > + ENTRY_POINT = UsbDisplayLinkDriverBindingEntryPoint
> > + UNLOAD_IMAGE = UsbDisplayLinkDriverCombinedGopUnload
> > + INF_DRIVER_VERSION = 0x00000001
> > +
> > +[Sources]
> > + CapabilityDescriptor.c
> > + ComponentName.c
> > + Edid.c
> > + Edid.h
> > + Gop.c
> > + UsbDescriptors.c
> > + UsbDescriptors.h
> > + UsbDisplayLink.c
> > + UsbDisplayLink.h
> > + UsbTransfer.c
> > + VideoModes.c
> > +
> > +[Packages]
> > + MdePkg/MdePkg.dec
> > +
> > +[LibraryClasses]
> > + BaseMemoryLib
> > + DebugLib
> > + MemoryAllocationLib
> > + ReportStatusCodeLib
> > + UefiBootServicesTableLib
> > + UefiDriverEntryPoint
> > + UefiLib
> > + UefiUsbLib
> > +
> > +[Protocols]
> > + gEfiUsbIoProtocolGuid ## TO_START
> > + gEfiEdidActiveProtocolGuid # PROTOCOL BY_START
> > + gEfiEdidDiscoveredProtocolGuid # PROTOCOL BY_START
> > + gEfiEdidOverrideProtocolGuid # PROTOCOL TO_START
> > + gEfiHiiDatabaseProtocolGuid
> > + gEfiHiiFontProtocolGuid
> > +
> > +[Guids]
> > + gEfiEventExitBootServicesGuid
> > + gEfiGlobalVariableGuid
> > +
> > +[Pcd]
> > + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize ## CONSUMES
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> > new file mode 100644
> > index 000000000000..21f4b7d9c736
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> > @@ -0,0 +1,598 @@
> > +/** @file Edid.c
> > + * @brief Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +#include "Edid.h"
> > +
> > +CONST UINT8 ExpectedEdidHeader[EDID_HEADER_SIZE] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
> > +
> > +//
> > +// Standard timing defined by VESA EDID
> > +//
> > +CONST EDID_TIMING EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES][8] = {
> > + //
> > + // Established Timing I
> > + //
> > + {
> > + { 800, 600, 60 },
> > + { 800, 600, 56 },
> > + { 640, 480, 75 },
> > + { 640, 480, 72 },
> > + { 640, 480, 67 },
> > + { 640, 480, 60 },
> > + { 720, 400, 88 },
> > + { 720, 400, 70 },
> > + },
> > + {
> > + //
> > + // Established Timing II
> > + //
> > + { 1280, 1024, 75 },
> > + { 1024, 768, 75 },
> > + { 1024, 768, 70 },
> > + { 1024, 768, 60 },
> > + { 1024, 768, 87 },
> > + { 832, 624, 75 },
> > + { 800, 600, 75 },
> > + { 800, 600, 72 },
> > + },
> > + //
> > + // Established Timing III
> > + //
> > + {
> > + { 1152, 870, 75 },
> > + { 0, 0, 0 },
> > + { 0, 0, 0 },
> > + { 0, 0, 0 },
> > + { 0, 0, 0 },
> > + { 0, 0, 0 },
> > + { 0, 0, 0 },
> > + { 0, 0, 0 },
> > + }
> > +};
> > +
> > +/**
> > + * Requests the monitor EDID data from the connected DisplayLink device
> > + * @param UsbDisplayLinkDev
> > + * @param EdidDataBlock
> > + * @param EdidSize
> > + * @retval EFI_DEVICE_ERROR - No EDID received, or EDID is corrupted
> > + * @retval EFI_OUT_OF_RESOURCES - Cannot allocate memory
> > + * @retval EFI_SUCCESS
> > + *
> > + */
> > +STATIC EFI_STATUS
> > +ReadEdidData (
> > + IN USB_DISPLAYLINK_DEV *UsbDisplayLinkDev,
> > + OUT UINT8 **EdidDataBlock,
> > + OUT UINTN *EdidSize
> > +)
> > +{
> > + EFI_STATUS Status;
> > +
> > + UINT8 EdidDataRead[EDID_BLOCK_SIZE];
> > + UINT8 *EdidData = EdidDataRead;
> > + UINT8* ValidEdid;
> > +
> > + Status = DlUsbSendControlReadMessage (UsbDisplayLinkDev, GET_OUTPUT_EDID, 0, EdidDataRead, sizeof (EdidDataRead));
> > +
> > + if (EFI_ERROR (Status) || (EdidData[0] != 0)) {
> > + DEBUG ((DEBUG_ERROR, "No monitor EDID received from DisplayLink device - System error %r, EDID error %d. Monitor connected correctly?\n", Status, EdidData[0]));
> > + return EFI_DEVICE_ERROR;
> > + } else {
> > + //
> > + // Search for the EDID signature
> > + //
> > + ValidEdid = &EdidData[0];
> > + CONST UINT64 Signature = 0x00ffffffffffff00ull;
> > + if (CompareMem (ValidEdid, &Signature, 8) != 0) {
> > + //
> > + // No EDID signature found
> > + //
> > + DEBUG ((DEBUG_ERROR, "Monitor EDID received from DisplayLink device did not have a valid signature - corrupted?\n"));
> > + Status = EFI_DEVICE_ERROR;
> > + return Status;
> > + }
> > + }
> > +
> > + *EdidDataBlock = (UINT8*)AllocateCopyPool (
> > + EDID_BLOCK_SIZE,
> > + ValidEdid);
> > +
> > + if (*EdidDataBlock == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + //
> > + // Currently only support EDID 1.x
> > + //
> > + *EdidSize = EDID_BLOCK_SIZE;
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +
> > +/**
> > +Calculates the mod256 checksum of the EDID and compares it with the one supplied at the end of the EDID
> > +@param EDID Pointer to the 128-byte EDID
> > +@retval TRUE The EDID checksum is correct
> > +**/
> > +BOOLEAN
> > +IsEdidChecksumCorrect (
> > + CONST VOID *EDID
> > + )
> > +{
> > + CONST UINT8 EdidChecksum = ((UINT8 *)EDID)[EDID_BLOCK_SIZE - 1];
> > + UINT8 CalculatedChecksum;
> > +
> > + CalculatedChecksum = 0;
> > +
> > + UINTN i;
> > + for (i = 0; i < EDID_BLOCK_SIZE - 1; i++) {
> > + CalculatedChecksum += ((UINT8 *)EDID)[i];
> > + }
> > + CalculatedChecksum = 0 - CalculatedChecksum;
> > +
> > + return (CalculatedChecksum == EdidChecksum);
> > +}
> > +
> > +/**
> > +Check if a particular video mode is in the Established Timings section of the EDID.
> > +
> > +@param EDID Pointer to the 128-byte EDID
> > +@param hRes Horizontal resolution
> > +@param vRes Vertical resolution
> > +@param refresh Refresh rate
> > +@retval TRUE The requested mode is present in the Established Timings section
> > +
> > +**/
> > +STATIC BOOLEAN
> > +IsModeInEstablishedTimings (
> > + IN CONST VOID *EDID,
> > + IN UINT16 HRes,
> > + IN UINT16 VRes,
> > + IN UINT16 Refresh
> > + )
> > +{
> > + CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> > + BOOLEAN ModeSupported;
> > +
> > + ModeSupported = FALSE;
> > +
> > + int EstByteNum;
> > + int BitNum;
> > + for (EstByteNum = 0; EstByteNum < EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES; EstByteNum++) {
> > + for (BitNum = 0; BitNum < 8; BitNum++) {
> > + if (pEDID->EstablishedTimings[EstByteNum] & (1 << BitNum)) { // The bit is set in the established timings of the EDID
> > +
> > + if ((EstablishedTimings[EstByteNum][BitNum].HRes == HRes) && // The passed-in resolution matches the resolution represented by the set bit
> > + (EstablishedTimings[EstByteNum][BitNum].VRes == VRes) &&
> > + (EstablishedTimings[EstByteNum][BitNum].Refresh == Refresh)) {
> > +
> > + ModeSupported = TRUE;
> > + break;
> > + }
> > + }
> > + }
> > + if (ModeSupported == TRUE) {
> > + break;
> > + }
> > + }
> > + return ModeSupported;
> > +}
> > +
> > +/**
> > +Extract the resolutions and refresh rate from one of the entries in the Standard Timings section of the EDID.
> > +
> > +@param EDID Pointer to the 128-byte EDID
> > +@param timingNumber The entry that we want to extract
> > +@param hRes Output - Horizontal resolution
> > +@param vRes Output - Vertical resolution
> > +@param refresh Output - Refresh rate
> > +@retval TRUE The requested Standard Timings entry contains valid data
> > +
> > +**/
> > +STATIC BOOLEAN ReadStandardTiming (
> > + CONST VOID *EDID,
> > + IN UINT8 TimingNumber,
> > + OUT UINT16 *HRes,
> > + OUT UINT16 *VRes,
> > + OUT UINT8 *Refresh)
> > +{
> > + CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> > +
> > + // See section 3.9.1 of the VESA EDID spec
> > +
> > + if (((pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels) == 0x01) &&
> > + (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh) == 0x01) {
> > + *HRes = 0;
> > + *VRes = 0;
> > + *Refresh = 0;
> > + return FALSE;
> > + }
> > + *HRes = (pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels + 31) * 8;
> > +
> > + UINT8 AspectRatio;
> > + AspectRatio = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh >> 6) & 0x3;
> > +
> > + switch (AspectRatio) {
> > + case 0: *VRes = (*HRes * 10) / 16;
> > + break;
> > + case 1: *VRes = (*HRes * 3) / 4;
> > + break;
> > + case 2: *VRes = (*HRes * 4) / 5;
> > + break;
> > + case 3: *VRes = (*HRes * 9) / 16;
> > + break;
> > + default: break;
> > + }
> > +
> > + // WORKAROUND - 1360x768 is not a perfect aspect ratio
> > + if ((*HRes == 1360) && (*VRes == 765)) {
> > + *VRes = 768;
> > + }
> > +
> > + *Refresh = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh & 0x1F) + 60;
> > +
> > + return TRUE;
> > +}
> > +
> > +/**
> > +Extract the resolutions and refresh rate from one of the entries in the Detailed Timings section of the EDID.
> > +
> > +@param EDID Pointer to the 128-byte EDID
> > +@param timingNumber The entry that we want to extract
> > +@param videoMode Output - Filled in with details from the detailed timing
> > +@retval TRUE The requested Detailed Timings entry contains valid data
> > +
> > +**/
> > +STATIC BOOLEAN
> > +ReadDetailedTiming (
> > + IN CONST VOID *EDID,
> > + IN UINT8 TimingNumber,
> > + OUT struct VideoMode *VideoMode
> > + )
> > +{
> > + if (TimingNumber >= EDID_NUMBER_OF_DETAILED_TIMINGS) {
> > + return FALSE;
> > + }
> > +
> > + UINT16 NumValidDetailedTimingsFound;
> > + NumValidDetailedTimingsFound = 0;
> > +
> > + // Spin through the detailed timings until we find a valid one - then check if this has the index that we want
> > + int BlockNumber;
> > + for (BlockNumber = 0; BlockNumber < EDID_NUMBER_OF_DETAILED_TIMINGS; BlockNumber++) {
> > + CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> > + CONST struct DetailedTimingIdentification *pTiming = &pEDID->detailedTimingDescriptions[BlockNumber];
> > +
> > + if (((BlockNumber == 0) && (pTiming->PixelClock == EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK)) ||
> > + (pTiming->PixelClock == 0)) {
> > + // This is not a valid detailed timing descriptor
> > + continue;
> > + }
> > +
> > + if ((pTiming->Features & EdidDetailedTimingsFeaturesSyncSchemeMask) != EdidDetailedTimingsFeaturesSyncSchemeMask) {
> > + DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported sync scheme found - not processing.\n"));
> > + continue;
> > + }
> > +
> > + if ((pTiming->Features & EdidDetailedTimingsFeaturesStereoModeMask) != 0) {
> > + DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported stereo mode found - not processing.\n"));
> > + continue;
> > + }
> > +
> > + // We've found a supported detailed timing - now see if this is the requested one
> > + if (TimingNumber != NumValidDetailedTimingsFound) {
> > + NumValidDetailedTimingsFound++;
> > + continue;
> > + }
> > +
> > + ZeroMem ((VOID *)VideoMode, sizeof (struct VideoMode));
> > +
> > + // Bit manipulations copied from host software class EDIDTimingDescriptor
> > +
> > + VideoMode->PixelClock = (UINT16)pTiming->PixelClock;
> > + VideoMode->HActive = pTiming->HActiveLo + ((pTiming->HActiveHiBlankingHi & 0xF0) << 4);
> > + VideoMode->VActive = pTiming->VActiveLo + ((pTiming->VActiveHiBlankingHi & 0xF0) << 4);
> > +
> > + VideoMode->HBlanking = pTiming->HBlankingLo + ((pTiming->HActiveHiBlankingHi & 0x0F) << 8);
> > + VideoMode->VBlanking = pTiming->VBlankingLo + ((pTiming->VActiveHiBlankingHi & 0x0F) << 8);
> > +
> > + VideoMode->HSyncOffset = pTiming->HSyncOffsetLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0xC0) << 2); // Horizontal Front Porch
> > + VideoMode->HSyncWidth = pTiming->HSyncWidthLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x30) << 4);
> > +
> > + VideoMode->VSyncOffset = ((pTiming->VSyncOffsetLoSyncWidthLo & 0xF0) >> 4) + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x0C) << 2); // Vertical Front Porch
> > + VideoMode->VSyncWidth = (pTiming->VSyncOffsetLoSyncWidthLo & 0x0F) + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x03) << 4);
> > +
> > + VideoMode->Reserved2 = 2;
> > + VideoMode->Accumulate = 1;
> > +
> > + // Horizontal and vertical sync inversions - positive if bit set in descriptor (EDID spec)
> > + // In the VideoMode, they are negative if the bit is set (NR-110497-TC 4.3.3 0x22 Set Video Mode)
> > +
> > + // Horizontal sync
> > + if ((pTiming->Features & EdidDetailedTimingsFeaturesHorizontalSyncPositive) == 0) {
> > + VideoMode->Flags |= VideoModeFlagsHorizontalSyncInverted;
> > + }
> > + // Vertical sync
> > + if ((pTiming->Features & EdidDetailedTimingsFeaturesVerticalSyncPositive) == 0) {
> > + VideoMode->Flags |= VideoModeFlagsVerticalSyncInverted;
> > + }
> > + // Interlace
> > + if ((pTiming->Features & EdidDetailedTimingsFeaturesInterlaced) == EdidDetailedTimingsFeaturesInterlaced) {
> > + VideoMode->Flags |= VideoModeFlagsInterlaced;
> > + }
> > +
> > + DEBUG ((DEBUG_INFO, "Read mode %dx%d from detailed timings\n", VideoMode->HActive, VideoMode->VActive));
> > + return TRUE;
> > + }
> > + return FALSE;
> > +}
> > +
> > +/**
> > +Check if a particular video mode is in either the Established or Standard Timings section of the EDID.
> > +
> > +@param EDID Pointer to the 128-byte EDID
> > +@param hRes Horizontal resolution
> > +@param vRes Vertical resolution
> > +@param refresh Refresh rate
> > +@retval TRUE The requested mode is present in the EDID
> > +
> > +**/
> > +STATIC BOOLEAN
> > +IsModeInEdid (
> > + IN CONST VOID *EDID,
> > + IN UINT16 HRes,
> > + IN UINT16 VRes,
> > + IN UINT16 Refresh
> > + )
> > +{
> > + UINT16 EdidHRes;
> > + UINT16 EdidVRes;
> > + UINT8 EdidRefresh;
> > + BOOLEAN ModeSupported;
> > +
> > + ModeSupported = IsModeInEstablishedTimings (EDID, HRes, VRes, Refresh);
> > +
> > + if (ModeSupported == FALSE) {
> > + // Check if the mode is in the Standard Timings section of the EDID
> > + UINT8 i;
> > + for (i = 0; i < EDID_NUMBER_OF_STANDARD_TIMINGS; i++) {
> > + if (TRUE == ReadStandardTiming (EDID, i, &EdidHRes, &EdidVRes, &EdidRefresh)) {
> > + if ((HRes == EdidHRes) && (VRes == EdidVRes) && (Refresh == EdidRefresh)) {
> > + ModeSupported = TRUE;
> > + break;
> > + }
> > + }
> > + }
> > + }
> > + return ModeSupported;
> > +}
> > +
> > +/**
> > +Returns the (index)'th entry from the list of pre-calculated video timings that is also present in the EDID,
> > +or, video mode data corresponding to any detailed timings present in the EDID.
> > +
> > +Like QueryVideoMode, finds the number (and contents) of video modes available by repeatedly calling this function
> > +with an increasing index value, until it returns FALSE
> > +@param index The caller wants the _index_'th video mode
> > +@param EDID Pointer to the 128-byte EDID
> > +@param edidSize Size in bytes of the EDID
> > +@param videoMode Video timings extracted from the modeData structure
> > +@retval EFI_SUCCESS The requested mode is present in the EDID
> > +@retval EFI_INVALID_PARAMETER The requested mode is not present in the EDID
> > +**/
> > +EFI_STATUS
> > +DlEdidGetSupportedVideoMode (
> > + IN UINT32 Index,
> > + IN CONST VOID *EDID,
> > + IN UINT32 EdidSize,
> > + OUT CONST struct VideoMode **VideoMode
> > + )
> > +{
> > + UINTN SupportedVideoModesFoundInEdid;
> > + EFI_STATUS Status;
> > +
> > + SupportedVideoModesFoundInEdid = 0;
> > + Status = EFI_INVALID_PARAMETER;
> > +
> > + // If we didn't manage to find an EDID earlier, just use one of the hard-coded video modes
> > + if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> > + if (Index >= DlVideoModeGetNumSupportedVideoModes ()) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + else {
> > + *VideoMode = DlVideoModeGetSupportedVideoMode (Index);
> > + DEBUG ((DEBUG_WARN, "No monitor EDID loaded - returning mode from default list (%dx%d)\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
> > + return EFI_SUCCESS;
> > + }
> > + }
> > +
> > + UINT16 ModeNumber;
> > + for (ModeNumber = 0; ModeNumber < DlVideoModeGetNumSupportedVideoModes (); ModeNumber++) {
> > +
> > + CONST struct VideoMode *SupportedVideoMode = DlVideoModeGetSupportedVideoMode (ModeNumber);
> > + ASSERT (SupportedVideoMode);
> > +
> > + if (IsModeInEdid (EDID, SupportedVideoMode->HActive, SupportedVideoMode->VActive, DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE)) {
> > + if (Index == SupportedVideoModesFoundInEdid) {
> > + *VideoMode = SupportedVideoMode;
> > + Status = EFI_SUCCESS;
> > + break;
> > + }
> > + SupportedVideoModesFoundInEdid++;
> > + }
> > + }
> > +
> > + if (EFI_ERROR (Status)) {
> > + // Have a look in the detailed timings
> > + UINTN DetailedTimingNumber;
> > + STATIC struct VideoMode TmpVideoMode;
> > + DetailedTimingNumber = Index - SupportedVideoModesFoundInEdid;
> > +
> > + if (DetailedTimingNumber < EDID_NUMBER_OF_DETAILED_TIMINGS) {
> > + if (ReadDetailedTiming (EDID, (UINT8)DetailedTimingNumber, &TmpVideoMode)) {
> > + *VideoMode = &TmpVideoMode;
> > + Status = EFI_SUCCESS;
> > + }
> > + }
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + * Like GetSupportedEdidVideoMode, but will return a fallback fixed mode of 640x480@60Hz
> > + * for index 0 if no suitable modes found in EDID.
> > + * @param index
> > + * @param EDID
> > + * @param edidSize
> > + * @param videoMode
> > + * @return EFI_SUCCESS
> > + */
> > +EFI_STATUS
> > +DlEdidGetSupportedVideoModeWithFallback (
> > + IN UINT32 Index,
> > + IN CONST VOID *EDID,
> > + IN UINT32 EdidSize,
> > + OUT CONST struct VideoMode **VideoMode
> > + )
> > +{
> > + EFI_STATUS Status;
> > + Status = DlEdidGetSupportedVideoMode (Index, EDID, EdidSize, VideoMode);
> > +
> > + if (EFI_ERROR (Status)) {
> > + // Special case - if we didn't find any matching video modes in the EDID, fall back to 640x480@60Hz
> > + if (Index == 0) {
> > + *VideoMode = DlVideoModeGetSupportedVideoMode (0);
> > + DEBUG ((DEBUG_WARN, "No video modes supported by driver found in monitor EDID received from DL device - falling back to %dx%d\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
> > + Status = EFI_SUCCESS;
> > + }
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > +Count the number of video modes that we have timing information for that are present in the EDID
> > +@param EDID Pointer to the 128-byte EDID
> > +@param edidSize
> > +@retval The number of modes in the EDID
> > +
> > +**/
> > +UINT32
> > +DlEdidGetNumSupportedModesInEdid (
> > + IN CONST VOID *EDID,
> > + IN UINT32 EdidSize
> > + )
> > +{
> > + UINT32 MaxMode;
> > +
> > + if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> > + return DlVideoModeGetNumSupportedVideoModes ();
> > + }
> > +
> > + for (MaxMode = 0; ; MaxMode++) {
> > + CONST struct VideoMode *videoMode;
> > + if (EFI_ERROR (DlEdidGetSupportedVideoMode (MaxMode, EDID, EdidSize, &videoMode))) {
> > + break;
> > + }
> > + }
> > + DEBUG ((DEBUG_INFO, "Found %d video modes supported by driver in monitor EDID.\n", MaxMode));
> > + return MaxMode;
> > +}
> > +
> > +
> > +
> > +/**
> > + * Read the EDID from the connected monitor, store it in the local data structure
> > + * @param UsbDisplayLinkDev
> > + * @retval EFI_OUT_OF_RESOURCES - Could not allocate memory
> > + * @retval EFI_SUCCESS
> > + */
> > +EFI_STATUS
> > +DlReadEdid (
> > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > + )
> > +{
> > + EFI_STATUS Status;
> > + BOOLEAN EdidFound;
> > + EFI_EDID_OVERRIDE_PROTOCOL* EdidOverride;
> > +
> > + //
> > + // setup EDID information
> > + //
> > + UsbDisplayLinkDev->EdidDiscovered.Edid = (UINT8 *)NULL;
> > + UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = 0;
> > +
> > + EdidFound = FALSE;
> > +
> > + //
> > + // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
> > + //
> > + Status = gBS->LocateProtocol (&gEfiEdidOverrideProtocolGuid, NULL, (VOID**)&EdidOverride);
> > +
> > + if (!EFI_ERROR (Status)) {
> > + UINT32 EdidAttributes = 0xff;
> > + UINTN EdidDataSize = 0;
> > + UINT8* EdidDataBlock = (UINT8*)NULL;
> > +
> > + // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
> > + EdidDataBlock = (UINT8*)AllocatePool (EDID_BLOCK_SIZE * 2);
> > +
> > + if (NULL == EdidDataBlock) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + Status = EdidOverride->GetEdid (
> > + EdidOverride,
> > + &UsbDisplayLinkDev->Handle,
> > + &EdidAttributes,
> > + &EdidDataSize,
> > + &EdidDataBlock);
> > +
> > + if (!EFI_ERROR (Status) && EdidAttributes == 0 && EdidDataSize != 0) {
> > + UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> > + UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> > + EdidFound = TRUE;
> > + }
> > + else {
> > + FreePool (EdidDataBlock);
> > + EdidDataBlock = NULL;
> > + }
> > + }
> > +
> > + if (EdidFound != TRUE) {
> > + UINTN EdidDataSize = 0;
> > + UINT8* EdidDataBlock = (UINT8*)NULL;
> > +
> > + if (ReadEdidData (UsbDisplayLinkDev, &EdidDataBlock, &EdidDataSize) == EFI_SUCCESS) {
> > +
> > + if (IsEdidChecksumCorrect (EdidDataBlock)) {
> > + UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> > + UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> > + EdidFound = TRUE;
> > + } else {
> > + DEBUG ((DEBUG_WARN, "Monitor EDID received from DisplayLink device had an invalid checksum. Corrupted?\n"));
> > + }
> > + }
> > + }
> > +
> > + if (EdidFound == FALSE) {
> > + DEBUG ((DEBUG_WARN, "No valid monitor EDID received from DisplayLink device. Cannot detect resolutions supported by monitor.\n"));
> > + }
> > +
> > + // Set the EDID active.
> > + // In an error case this will be set 0/NULL, which flags to the parsing code that there is no EDID.
> > + UsbDisplayLinkDev->EdidActive.SizeOfEdid = UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid;
> > + UsbDisplayLinkDev->EdidActive.Edid = UsbDisplayLinkDev->EdidDiscovered.Edid;
> > +
> > + return EFI_SUCCESS;
> > +}
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> > new file mode 100644
> > index 000000000000..a1b8a0512d1a
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> > @@ -0,0 +1,129 @@
> > +/** @file Edid.h
> > + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> > + * Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#ifndef EDID_H
> > +#define EDID_H
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +#define EDID_HEADER_SIZE ((UINTN)8)
> > +#define EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES ((UINTN)3)
> > +#define EDID_NUMBER_OF_STANDARD_TIMINGS ((UINTN)8)
> > +#define EDID_NUMBER_OF_DETAILED_TIMINGS ((UINTN)4)
> > +
> > +
> > +typedef struct {
> > + UINT16 HRes;
> > + UINT16 VRes;
> > + UINT16 Refresh;
> > +} EDID_TIMING;
> > +
> > +
> > +EFI_STATUS
> > +DlEdidGetSupportedVideoMode (
> > + UINT32 ModeNumber,
> > + CONST VOID *EDID,
> > + UINT32 EdidSize,
> > + CONST struct VideoMode **VideoMode
> > + );
> > +
> > +EFI_STATUS
> > +DlEdidGetSupportedVideoModeWithFallback (
> > + UINT32 ModeNumber,
> > + CONST VOID *EDID,
> > + UINT32 EdidSize,
> > + CONST struct VideoMode **VideoMode
> > + );
> > +
> > +UINT32
> > +DlEdidGetNumSupportedModesInEdid (
> > + CONST VOID *EDID,
> > + UINT32 EdidSize
> > + );
> > +
> > +EFI_STATUS
> > +DlReadEdid (
> > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > +);
> > +
> > +// EDID Detailed timings section - Features
> > +enum EdidDetailedTimingsFeatures {
> > + EdidDetailedTimingsFeaturesInterlaced = 0x80,
> > + EdidDetailedTimingsFeaturesStereoModeMask = 0x60,
> > + EdidDetailedTimingsFeaturesSyncSchemeMask = 0x18,
> > + EdidDetailedTimingsFeaturesHorizontalSyncPositive = 0x02,
> > + EdidDetailedTimingsFeaturesVerticalSyncPositive = 0x04,
> > +};
> > +
> > +// NR-110497-TC-7ZM Section 4.3.3 0x22 Set Video Mode - Flags
> > +enum VideoModeFlags {
> > + VideoModeFlagsInterlaced = 0x0001,
> > + VideoModeFlagsHorizontalSyncInverted = 0x0100,
> > + VideoModeFlagsVerticalSyncInverted = 0x0200,
> > +};
> > +
> > +struct StandardTimingIdentification {
> > + UINT8 HorizontalActivePixels; // X resolution, from 256->2288 in increments of 8 pixels
> > + UINT8 ImageAspectRatioAndrefresh; // Bits 7,6 Aspect ratio - 0=16:10 1=4:3 2=5:4 3=16:9
> > + // Bits 5,0 Refresh rate Range 60->1213Hz
> > +};
> > +
> > +struct DetailedTimingIdentification {
> > + UINT16 PixelClock; // wPixelClock in VideoMode struct
> > + UINT8 HActiveLo; // wHActive
> > + UINT8 HBlankingLo; // wHBlanking
> > + UINT8 HActiveHiBlankingHi;
> > + UINT8 VActiveLo; // wVActive
> > + UINT8 VBlankingLo; // wVBlanking
> > + UINT8 VActiveHiBlankingHi;
> > + UINT8 HSyncOffsetLo; // wHSyncOffset, front porch
> > + UINT8 HSyncWidthLo; // wHSyncWidth
> > + UINT8 VSyncOffsetLoSyncWidthLo;
> > + UINT8 HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi;
> > + UINT8 HImageSizeHi;
> > + UINT8 VImageSizeHi;
> > + UINT8 HImageSizeLoVImageSizeLo;
> > + UINT8 HBorder;
> > + UINT8 VBorder;
> > + UINT8 Features;
> > +};
> > +
> > +struct Edid {
> > + UINT8 Header[EDID_HEADER_SIZE]; //EDID header "00 FF FF FF FF FF FF 00"
> > + UINT16 ManufactureName; //EISA 3-character ID
> > + UINT16 ProductCode; //Vendor assigned code
> > + UINT32 SerialNumber; //32-bit serial number
> > + UINT8 WeekOfManufacture; //Week number
> > + UINT8 YearOfManufacture; //Year
> > + UINT8 EdidVersion; //EDID Structure Version
> > + UINT8 EdidRevision; //EDID Structure Revision
> > + UINT8 VideoInputDefinition;
> > + UINT8 MaxHorizontalImageSize; //cm
> > + UINT8 MaxVerticalImageSize; //cm
> > + UINT8 DisplayTransferCharacteristic;
> > + UINT8 FeatureSupport;
> > + UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
> > + UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
> > + UINT8 RedX; //Red-x Bits 9 - 2
> > + UINT8 RedY; //Red-y Bits 9 - 2
> > + UINT8 GreenX; //Green-x Bits 9 - 2
> > + UINT8 GreenY; //Green-y Bits 9 - 2
> > + UINT8 BlueX; //Blue-x Bits 9 - 2
> > + UINT8 BlueY; //Blue-y Bits 9 - 2
> > + UINT8 WhiteX; //White-x Bits 9 - 2
> > + UINT8 WhiteY; //White-x Bits 9 - 2
> > + UINT8 EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES];
> > + struct StandardTimingIdentification standardTimingIdentifications[EDID_NUMBER_OF_STANDARD_TIMINGS];
> > + struct DetailedTimingIdentification detailedTimingDescriptions[EDID_NUMBER_OF_DETAILED_TIMINGS];
> > + UINT8 ExtensionFlag; //Number of (optional) 128-byte EDID extension blocks to follow
> > + UINT8 Checksum;
> > +};
> > +
> > +#endif // EDID_H
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> > new file mode 100644
> > index 000000000000..3e483afdba72
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> > @@ -0,0 +1,578 @@
> > +/**
> > + * @file Gop.c
> > + * @brief UEFI GOP protocol API implementation for USB DisplayLink driver.
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +#include "Edid.h"
> > +
> > +
> > +/**
> > + *
> > + * @param This Pointer to the instance of the GOP protocol
> > + * @param BltOperation
> > + * @param SourceX
> > + * @param SourceY
> > + * @param Width
> > + * @param Height
> > + * @param DestinationX
> > + * @param DestinationY
> > + * @return
> > + */
> > +STATIC EFI_STATUS
> > +CheckBounds (
> > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL* This,
> > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> > + IN UINTN SourceX,
> > + IN UINTN SourceY,
> > + IN UINTN Width,
> > + IN UINTN Height,
> > + IN UINTN DestinationX,
> > + IN UINTN DestinationY
> > + )
> > +{
> > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> > + EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> > +
> > + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> > + Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> > +
> > + CONST EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* ScreenMode = Gop->Mode->Info;
> > +
> > + if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
> > + if (SourceY + Height > ScreenMode->VerticalResolution) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (SourceX + Width > ScreenMode->HorizontalResolution) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + }
> > +
> > + if (BltOperation == EfiBltBufferToVideo
> > + || BltOperation == EfiBltVideoToVideo
> > + || BltOperation == EfiBltVideoFill) {
> > + if (DestinationY + Height > ScreenMode->VerticalResolution) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (DestinationX + Width > ScreenMode->HorizontalResolution) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > + }
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + * Update the local copy of the Frame Buffer. This local copy is periodically transmitted to the
> > + * DisplayLink device (via DlGopSendScreenUpdate)
> > + * @param UsbDisplayLinkDev
> > + * @param BltBuffer
> > + * @param BltOperation
> > + * @param SourceX
> > + * @param SourceY
> > + * @param DestinationX
> > + * @param DestinationY
> > + * @param Width
> > + * @param Height
> > + * @param BltBufferStride
> > + * @param PixelsPerScanLine
> > + */
> > +STATIC VOID
> > +BuildBackBuffer (
> > + IN USB_DISPLAYLINK_DEV *UsbDisplayLinkDev,
> > + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
> > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> > + IN UINTN SourceX,
> > + IN UINTN SourceY,
> > + IN UINTN DestinationX,
> > + IN UINTN DestinationY,
> > + IN UINTN Width,
> > + IN UINTN Height,
> > + IN UINTN BltBufferStride,
> > + IN UINTN PixelsPerScanLine
> > +)
> > +{
> > + UINTN H;
> > + UINTN W;
> > + switch (BltOperation) {
> > + case EfiBltVideoToBltBuffer:
> > + {
> > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> > + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)((UINT8 *)BltBuffer + (DestinationY * BltBufferStride) + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> > + SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> > +
> > + for (H = 0; H < Height; H++) {
> > + for (W = 0; W < Width; W++) {
> > + Blt[W] = *SrcB++;
> > + }
> > + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> > + SrcB += PixelsPerScanLine - Width;
> > + }
> > + }
> > + break;
> > +
> > + case EfiBltBufferToVideo:
> > + {
> > + // Update the store of the area of the screen that is "dirty" - that we need to send in the next screen update.
> > + if (DestinationY < UsbDisplayLinkDev->LastY1) {
> > + UsbDisplayLinkDev->LastY1 = DestinationY;
> > + }
> > + if ((DestinationY + Height) > UsbDisplayLinkDev->LastY2) {
> > + UsbDisplayLinkDev->LastY2 = DestinationY + Height;
> > + }
> > +
> > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> > + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)(((UINT8 *)BltBuffer) + (SourceY * BltBufferStride) + SourceX * sizeof *Blt);
> > + DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> > +
> > + for (H = 0; H < Height; H++) {
> > + for (W = 0; W < Width; W++) {
> > + *DstB++ = Blt[W];
> > + }
> > + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> > + DstB += PixelsPerScanLine - Width;
> > + }
> > + }
> > + break;
> > +
> > + case EfiBltVideoToVideo:
> > + {
> > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> > + SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> > + DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> > +
> > + for (H = 0; H < Height; H++) {
> > + for (W = 0; W < Width; W++) {
> > + *DstB++ = *SrcB++;
> > + }
> > + SrcB += PixelsPerScanLine - Width;
> > + DstB += PixelsPerScanLine - Width;
> > + }
> > + }
> > + break;
> > +
> > + case EfiBltVideoFill:
> > + {
> > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> > + DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> > + for (H = 0; H < Height; H++) {
> > + for (W = 0; W < Width; W++) {
> > + *DstB++ = *BltBuffer;
> > + }
> > + DstB += PixelsPerScanLine - Width;
> > + }
> > + }
> > + break;
> > + default: break;
> > + }
> > +}
> > +
> > +/**
> > + * Display a colour bar pattern on the DisplayLink device.
> > + * @param UsbDisplayLinkDev
> > + * @param PatternNumber
> > + * @return
> > + */
> > +EFI_STATUS
> > +DlGopSendTestPattern (
> > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > + IN UINTN PatternNumber)
> > +{
> > + EFI_STATUS Status;
> > + UINTN DataLen;
> > + UINT8 *DstBuf;
> > + UINT32 USBStatus;
> > +
> > + Status = EFI_SUCCESS;
> > + DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per pixel
> > + DstBuf = AllocateZeroPool (DataLen);
> > +
> > + if (DstBuf == NULL) {
> > + DEBUG ((DEBUG_ERROR, "SendTestPattern Failed to allocate memory\n"));
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + //DEBUG ((DEBUG_ERROR, "Called DlGopSendTestPattern %d\n", PatternNumber));
> > +
> > + CONST UINT8 RedPixel[3] = { 0xFF, 0x00, 0x00 };
> > + CONST UINT8 GreenPixel[3] = { 0x00, 0xFF, 0x00 };
> > + CONST UINT8 BluePixel[3] = { 0x00, 0x00, 0xFF };
> > + CONST UINT8 YellowPixel[3] = { 0xFF, 0xFF, 0x00 };
> > + CONST UINT8 MagentaPixel[3] = { 0xFF, 0x00, 0xFF };
> > + CONST UINT8 CyanPixel[3] = { 0x00, 0xFF, 0xFF };
> > +
> > + UINTN Row;
> > + UINTN Column;
> > + for (Row = 0; Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution; Row++) {
> > + for (Column = 0; Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution; Column++) {
> > +
> > + if (0 == PatternNumber) {
> > + if (Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution / 3) {
> > + CopyMem (&DstBuf[Column * 3], RedPixel, sizeof (RedPixel));
> > + }
> > + else if (Row < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution * 2) / 3)
> > + {
> > + CopyMem (&DstBuf[Column * 3], GreenPixel, sizeof (GreenPixel));
> > + }
> > + else {
> > + CopyMem (&DstBuf[Column * 3], BluePixel, sizeof (BluePixel));
> > + }
> > + }
> > + else {
> > + if (Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution / 3) {
> > + CopyMem (&DstBuf[Column * 3], YellowPixel, sizeof (RedPixel));
> > + }
> > + else if (Column < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 2) / 3)
> > + {
> > + CopyMem (&DstBuf[Column * 3], MagentaPixel, sizeof (GreenPixel));
> > + }
> > + else {
> > + CopyMem (&DstBuf[Column * 3], CyanPixel, sizeof (BluePixel));
> > + }
> > + }
> > + }
> > + DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, DataLen, &USBStatus);
> > + }
> > + // Payload with length of 1 to terminate the frame
> > + DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, 1, &USBStatus);
> > + FreePool (DstBuf);
> > +
> > + return Status;
> > +}
> > +
> > +
> > +/**
> > + * Transfer the latest copy of the Blt buffer over USB to the DisplayLink device
> > + * @param UsbDisplayLinkDev
> > + * @return
> > + */
> > +EFI_STATUS
> > +DlGopSendScreenUpdate (
> > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 USBStatus;
> > + Status = EFI_SUCCESS;
> > +
> > + // If it has been a while since we sent an update, send a full screen.
> > + // This allows us to update a hot-plugged monitor quickly.
> > + if (UsbDisplayLinkDev->TimeSinceLastScreenUpdate > DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD) {
> > + UsbDisplayLinkDev->LastY1 = 0;
> > + UsbDisplayLinkDev->LastY2 = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution - 1;
> > + }
> > +
> > + // If there has been no BLT since the last update/poll, drop out quietly.
> > + if (UsbDisplayLinkDev->LastY2 < UsbDisplayLinkDev->LastY1) {
> > + UsbDisplayLinkDev->TimeSinceLastScreenUpdate += (DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 1000); // Convert us to ms
> > + return EFI_SUCCESS;
> > + }
> > +
> > + UsbDisplayLinkDev->TimeSinceLastScreenUpdate = 0;
> > +
> > + EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> > +
> > + UINTN DataLen;
> > + UINTN Width;
> > + UINTN Height;
> > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcPtr;
> > + UINT8* DstPtr;
> > + UINT8 DstBuffer[1920 * 3]; // Get rid of the magic numbers at some point
> > + // Could also use a buffer allocated at runtime to store the line, stored in the USB_DISPLAYLINK_DEV structure.
> > + UINTN H;
> > +
> > + DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per pixel
> > + Width = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution;
> > + Height = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution;
> > + SrcPtr = UsbDisplayLinkDev->Screen;
> > + DstPtr = DstBuffer;
> > +
> > + for (H = 0; H < Height; H++) {
> > + DstPtr = DstBuffer;
> > +
> > + UINTN W;
> > + for (W = 0; W < Width; W++) {
> > + // Need to swap round the RGB values
> > + DstPtr[0] = ((UINT8 *)SrcPtr)[2];
> > + DstPtr[1] = ((UINT8 *)SrcPtr)[1];
> > + DstPtr[2] = ((UINT8 *)SrcPtr)[0];
> > + SrcPtr++;
> > + DstPtr += 3;
> > + }
> > +
> > + Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, DataLen, &USBStatus);
> > +
> > + // USBStatus values defined in usbio.h, e.g. EFI_USB_ERR_TIMEOUT 0x40
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB status x%x\n", H, DataLen, Status, USBStatus));
> > + break;
> > + }
> > + // Need an extra DlUsbBulkWrite if the data length is divisible by USB MaxPacketSize. This spare data will just get written into the (invisible) stride area.
> > + // Note that the API doesn't let us do a bulk write of 0.
> > + if ((DataLen & (UsbDisplayLinkDev->BulkOutEndpointDescriptor.MaxPacketSize - 1)) == 0) {
> > + Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 2, &USBStatus);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB status x%x\n", H, DataLen, Status, USBStatus));
> > + break;
> > + }
> > + }
> > + }
> > +
> > + if (!EFI_ERROR (Status)) {
> > + // If we've successfully transmitted the frame, reset the values that store which area of the screen has been BLTted to.
> > + // If we haven't succeeded, this will mean we'll try to resend it after the next poll period.
> > + UsbDisplayLinkDev->LastY2 = 0;
> > + UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> > + }
> > +
> > + // Payload with length of 1 to terminate the frame
> > + // We need to do this even if we had an error, to indicate to the DL device that it should now expect a new frame.
> > + DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 1, &USBStatus);
> > +
> > + gBS->RestoreTPL (OriginalTPL);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + * Calculate the video refresh rate from the video timing parameters (pixel clock etc)
> > + * @param videoMode
> > + * @return
> > + */
> > +#ifndef MDEPKG_NDEBUG
> > +STATIC inline UINT16
> > +CalculateRefreshRate (
> > + IN CONST struct VideoMode *VideoMode)
> > +{
> > + UINT16 RefreshRate;
> > + UINT16 Rmod;
> > + UINT16 Rate10Hz;
> > +
> > + RefreshRate = (VideoMode->PixelClock * 10000) / ((VideoMode->HActive + VideoMode->HBlanking) * (VideoMode->VActive + VideoMode->VBlanking));
> > + Rmod = RefreshRate % 10;
> > + Rate10Hz = RefreshRate - Rmod;
> > +
> > + if (Rmod >= 5) {
> > + Rate10Hz += 10;
> > + }
> > + return Rate10Hz;
> > +}
> > +#endif // MDEPKG_NDEBUG
> > +/* ***************************************************************************************************** */
> > +/* ***************************************************************************************************** */
> > +/* ****************** START OF FUNCTIONS WHICH IMPLEMENT GOP INTERFACE ****************** */
> > +/* ***************************************************************************************************** */
> > +/* ***************************************************************************************************** */
> > +
> > +
> > +/**
> > + *
> > + * @param Gop Pointer to the instance of the GOP protocol
> > + * @param ModeNumber
> > + * @param SizeOfInfo
> > + * @param Info
> > + * @return
> > + */
> > +EFI_STATUS
> > +EFIAPI
> > +DisplayLinkQueryMode (
> > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,
> > + IN UINT32 ModeNumber,
> > + OUT UINTN *SizeOfInfo,
> > + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
> > +)
> > +{
> > + USB_DISPLAYLINK_DEV *Dev;
> > + CONST struct VideoMode *VideoMode;
> > + EFI_STATUS Status;
> > +
> > + Dev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> > + Status = EFI_INVALID_PARAMETER;
> > +
> > + if ((SizeOfInfo == NULL) || (Info == NULL)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + // Get a video mode from the EDID
> > + Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, Dev->EdidActive.Edid, Dev->EdidActive.SizeOfEdid, &VideoMode);
> > +
> > + if (!EFI_ERROR (Status)) {
> > +
> > + *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> > + if (*Info == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + DEBUG ((DEBUG_INFO, "BIOS querying mode number %d - returning %dx%d @ %dHz\n", ModeNumber, VideoMode->HActive, VideoMode->VActive, CalculateRefreshRate (VideoMode)));
> > +
> > + *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> > +
> > + (*Info)->Version = 0;
> > + (*Info)->HorizontalResolution = VideoMode->HActive;
> > + (*Info)->VerticalResolution = VideoMode->VActive;
> > + (*Info)->PixelFormat = PixelBltOnly;
> > + (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;
> > + (*Info)->PixelInformation.RedMask = 0;
> > + (*Info)->PixelInformation.GreenMask = 0;
> > + (*Info)->PixelInformation.BlueMask = 0;
> > + (*Info)->PixelInformation.ReservedMask = 0;
> > + }
> > + return Status;
> > +}
> > +
> > +/**
> > + *
> > + * @param Gop Pointer to the instance of the GOP protocol
> > + * @param ModeNumber
> > + * @return
> > + */
> > +EFI_STATUS
> > +EFIAPI
> > +DisplayLinkSetMode (
> > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop,
> > + IN UINT32 ModeNumber
> > +)
> > +{
> > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> > + EFI_STATUS Status;
> > + CONST struct VideoMode *VideoMode;
> > +
> > + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> > +
> > + // Prevent the DisplayLinkPeriodicTimer from interrupting us (bug 28877).
> > + // When the driver is manually loaded, the TPL is TPL_NOTIFY (16) which prevents the interrupt from the timer.
> > + // When the GOP driver is sideloaded, the TPL of this call is TPL_APPLICATION (4) and the timer can interrupt us.
> > + Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> > +
> > + // Get a video mode from the EDID
> > + Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, UsbDisplayLinkDev->EdidActive.Edid, UsbDisplayLinkDev->EdidActive.SizeOfEdid, &VideoMode);
> > +
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + Gop->Mode->Info->Version = 0;
> > + Gop->Mode->Info->HorizontalResolution = VideoMode->HActive;
> > + Gop->Mode->Info->VerticalResolution = VideoMode->VActive;
> > + Gop->Mode->Info->PixelFormat = PixelBltOnly;
> > + Gop->Mode->Info->PixelsPerScanLine = Gop->Mode->Info->HorizontalResolution;
> > + Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> > + Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> > + Gop->Mode->FrameBufferSize = 0;
> > +
> > + //
> > + // Allocate the back buffer
> > + //
> > + if (UsbDisplayLinkDev->Screen != NULL) {
> > + FreePool (UsbDisplayLinkDev->Screen);
> > + }
> > +
> > + UsbDisplayLinkDev->Screen = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)AllocateZeroPool (
> > + Gop->Mode->Info->HorizontalResolution *
> > + Gop->Mode->Info->VerticalResolution *
> > + sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> > +
> > + if (UsbDisplayLinkDev->Screen == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + DEBUG ((DEBUG_INFO, "Video mode %d selected by BIOS - %d x %d.\n", ModeNumber, VideoMode->HActive, VideoMode->VActive));
> > + // Wait until we are sure that we can set the video mode before we tell the firmware
> > + Status = DlUsbSendControlWriteMessage (UsbDisplayLinkDev, SET_VIDEO_MODE, 0, VideoMode, sizeof (struct VideoMode));
> > +
> > + if (Status != EFI_SUCCESS) {
> > + // Flag up that we haven't set the video mode correctly yet.
> > + DEBUG ((DEBUG_ERROR, "Failed to send USB message to DisplayLink device to set monitor video mode. Monitor connected correctly?\n"));
> > + Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> > + FreePool (UsbDisplayLinkDev->Screen);
> > + UsbDisplayLinkDev->Screen = NULL;
> > + } else {
> > + BuildBackBuffer (
> > + UsbDisplayLinkDev,
> > + UsbDisplayLinkDev->Screen,
> > + EfiBltBufferToVideo,
> > + 0, 0,
> > + 0, 0,
> > + Gop->Mode->Info->HorizontalResolution,
> > + Gop->Mode->Info->VerticalResolution,
> > + Gop->Mode->Info->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
> > + Gop->Mode->Info->HorizontalResolution);
> > + // unlock the DisplayLinkPeriodicTimer
> > + Gop->Mode->Mode = ModeNumber;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + * Implementation of the GOP protocol Blt API function
> > + * @param This Pointer to the instance of the GOP protocol
> > + * @param BltBuffer
> > + * @param BltOperation
> > + * @param SourceX
> > + * @param SourceY
> > + * @param DestinationX
> > + * @param DestinationY
> > + * @param Width
> > + * @param Height
> > + * @param Delta
> > + * @return
> > + */
> > +EFI_STATUS
> > +EFIAPI
> > +DisplayLinkBlt (
> > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> > + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
> > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> > + IN UINTN SourceX,
> > + IN UINTN SourceY,
> > + IN UINTN DestinationX,
> > + IN UINTN DestinationY,
> > + IN UINTN Width,
> > + IN UINTN Height,
> > + IN UINTN Delta OPTIONAL
> > +)
> > +{
> > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> > + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> > +
> > + // Drop out if we haven't set the video mode up yet
> > + if (This->Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> > + return EFI_SUCCESS;
> > + }
> > +
> > + if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + if (Width == 0 || Height == 0) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + // Lock so we make an atomic write the frame buffer.
> > + // We would not want a timer based event (Cursor, ...) to come in while we are doing this operation.
> > + EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> > +
> > + CONST UINTN BltBufferStride = (Delta == 0) ? Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) : Delta;
> > + CONST EFI_STATUS boundsCheckStatus = CheckBounds (This, BltOperation, SourceX, SourceY, Width, Height, DestinationX, DestinationY);
> > + if (EFI_ERROR (boundsCheckStatus)) {
> > + gBS->RestoreTPL (OriginalTPL);
> > + return boundsCheckStatus;
> > + }
> > +
> > + BuildBackBuffer (UsbDisplayLinkDev, BltBuffer, BltOperation, SourceX, SourceY, DestinationX, DestinationY, Width, Height, BltBufferStride, This->Mode->Info->PixelsPerScanLine);
> > +
> > + gBS->RestoreTPL (OriginalTPL);
> > + return EFI_SUCCESS;
> > +}
> > +
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> > new file mode 100644
> > index 000000000000..c12a80a6e1ab
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> > @@ -0,0 +1,145 @@
> > +/**
> > + * @file UsbDescriptors.c
> > + * @brief Functions to read USB Interface and Capabilities descriptors
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +#include "UsbDescriptors.h"
> > +
> > +/**
> > + *
> > + * @param UsbIo
> > + * @param descriptorType
> > + * @param index
> > + * @param Buffer
> > + * @param Length
> > + * @param UsbStatus
> > + * @return
> > + */
> > +STATIC EFI_STATUS
> > +ReadDescriptor (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + UINT8 DescriptorType,
> > + UINT8 Index,
> > + VOID* Buffer,
> > + UINT16 Length,
> > + UINT32* UsbStatus)
> > +{
> > + EFI_STATUS Status;
> > +
> > + UINT8 Header[2];
> > + ZeroMem (Header, sizeof (Header));
> > +
> > + EFI_USB_DEVICE_REQUEST Request;
> > + ZeroMem (&Request, sizeof (Request));
> > + Request.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_STANDARD | USB_TARGET_DEVICE;
> > + Request.Request = USB_REQ_GET_DESCRIPTOR;
> > + Request.Index = 0;
> > + Request.Value = DescriptorType << 8 | Index;
> > + Request.Length = sizeof (Header);
> > +
> > + // Read the descriptor header to see how many bytes it contains
> > + Status = UsbIo->UsbControlTransfer (
> > + UsbIo,
> > + &Request,
> > + EfiUsbDataIn,
> > + DISPLAYLINK_USB_CTRL_TIMEOUT,
> > + Header,
> > + sizeof (Header),
> > + UsbStatus);
> > +
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Failed to read length of descriptor type x%x, index %u (code %r, USB status x%x)\n",
> > + DescriptorType, Index, Status, *UsbStatus));
> > + return Status;
> > + }
> > + CONST UINT16 TotalLength = Header[0];
> > +
> > + // Now we know the size of it, we can read the entire descriptor
> > + Request.Length = TotalLength;
> > +
> > + Status = UsbIo->UsbControlTransfer (
> > + UsbIo,
> > + &Request,
> > + EfiUsbDataIn,
> > + DISPLAYLINK_USB_CTRL_TIMEOUT,
> > + Buffer,
> > + TotalLength,
> > + UsbStatus);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Perform a USB control transfer to read the DisplayLink vendor descriptor.
> > +
> > + @param UsbIo Pointer to the instance of the USBIO protocol
> > + @param Buffer Pointer to the buffer where descriptor should be written
> > + @param Length Length of buffer (and the maximum amount of descriptor data that shall be read)
> > +
> > + @retval EFI_SUCCESS The descriptor has been copied into Buffer
> > + @retval Other The descriptor could not be read
> > +**/
> > +EFI_STATUS
> > +ReadCapabilitiesDescriptor (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + OUT VOID* Buffer,
> > + IN UINT16 Length)
> > +{
> > + UINT32 UsbStatus;
> > + EFI_STATUS Status;
> > +
> > + Status = ReadDescriptor (
> > + UsbIo,
> > + DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY,
> > + 0,
> > + Buffer,
> > + Length,
> > + &UsbStatus);
> > +
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Could not read capabilities descriptor from DL device (code %r, USB status x%x). Unrecognised firmware version?\n", Status, UsbStatus));
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +
> > +/**
> > + An alternative to the UBSIO protocol function EFI_USB_IO_GET_INTERFACE_DESCRIPTOR.
> > + This version allows you to specify an index.
> > + * @param UsbIo Pointer to the instance of the USBIO protocol
> > + * @param interfaceDescriptor Where the descriptor should be written
> > + * @param index The index of the descriptor required (the standard USBIO function doesn't let you do this)
> > + * @return
> > + */
> > +EFI_STATUS
> > +UsbDisplayLinkGetInterfaceDescriptor (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + OUT EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> > + UINT8 Index
> > + )
> > +{
> > + UINT32 UsbStatus;
> > + EFI_STATUS Status;
> > +
> > + Status = ReadDescriptor (
> > + UsbIo,
> > + USB_DESC_TYPE_INTERFACE,
> > + Index,
> > + InterfaceDescriptor,
> > + sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
> > + &UsbStatus);
> > +
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "USB control transfer failed while reading interface descriptor (code %r, USB status x%x)\n", Status, UsbStatus));
> > + }
> > +
> > + return Status;
> > +}
> > +
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> > new file mode 100644
> > index 000000000000..cdc01aad193a
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> > @@ -0,0 +1,109 @@
> > +/**
> > + * @file UsbDescriptors.h
> > + * @brief Functions to read USB Interface and Capabilities descriptors
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#ifndef USB_DESCRIPTORS_H_
> > +#define USB_DESCRIPTORS_H_
> > +
> > + /**
> > + Type of the Direct Framebuffer capability descriptor.
> > + This is a vendor specific USB descriptor for DisplayLink.
> > + @see NR-140082 Section 3.5
> > + **/
> > +#define DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY 0x5e
> > +
> > + /**
> > + Identifiers for capabllity keys
> > + @see NR-140082 Section 3.2
> > + **/
> > +
> > + /**
> > + Key for Capabilities 1 - See section 3.2.1
> > + **/
> > +#define CAPABILITIES1_KEY 0x0
> > +
> > + /**
> > + Lengths for capabllity fields
> > + **/
> > +#define CAPABILITIES1_LENGTH 0x4
> > +
> > + /**
> > + Bits for the capability bitmask Capabilities1
> > + **/
> > +
> > + /**
> > + This is the first capability defined for the protocol.
> > + It represents the mode of operation as of initial release.
> > + If a device ever breaks compatibility with this initial release,
> > + it will cease
> > + to support CapabilityBaseProtocol.
> > + **/
> > +#define CAPABILITIES1_BASE_PROTOCOL (1 << 0)
> > +
> > + /**
> > + Idealised VendorDescriptor which is the result
> > + of parsing vendor descriptor from device.
> > + **/
> > + typedef struct {
> > + UINT32 Capabilities1;
> > + } VendorDescriptor;
> > +
> > +#pragma pack(push, 1)
> > + typedef struct {
> > + UINT16 Key; /** Really of type enum DescrptorKeys */
> > + UINT8 Length;
> > + UINT8 Value[];
> > + } DescriptorKLV;
> > +
> > + typedef struct {
> > + UINT8 Length;
> > + UINT8 Type;
> > + UINT16 CapabilityVersion;
> > + UINT8 CapabilityLength;
> > + UINT8 Klv[];
> > + } VendorDescriptorGeneric;
> > +#pragma pack(pop)
> > +
> > +
> > +EFI_STATUS UsbDisplayLinkGetInterfaceDescriptor (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> > + UINT8 index
> > + );
> > +
> > +EFI_STATUS ReadCapabilitiesDescriptor (IN EFI_USB_IO_PROTOCOL *UsbIo, VOID* Buffer, UINT16 Length);
> > +
> > +/**
> > +Parse data in buffer to a VendorDescriptor, if possible.
> > +
> > +@param Data Buffer
> > +@param Length Length of buffer
> > +
> > +@retval EFI_SUCCESS The descriptor was parsed successfully
> > +@retval EFI_UNSUPPORTED Simple Pointer Protocol is not installed on Controller.
> > +**/
> > +EFI_STATUS
> > +UsbDisplayLinkParseCapabilitiesDescriptor (
> > + CONST IN VOID* Data,
> > + IN UINTN Length,
> > + OUT VendorDescriptor* Descriptor
> > +);
> > +
> > +/**
> > +Decide if binding may proceed, given capabilities
> > +
> > +@retval TRUE Binding may proceed
> > +@retval FALSE Binding is not possible
> > +**/
> > +BOOLEAN
> > +UsbDisplayLinkCapabilitiesSufficientToBind (
> > + CONST IN VendorDescriptor* Descriptor
> > +);
> > +
> > +#endif // USB_DESCRIPTORS_H_
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> > new file mode 100644
> > index 000000000000..997a3e307f38
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> > @@ -0,0 +1,1082 @@
> > +/**
> > + * @file UsbDisplayLink.c
> > + * @brief USB DisplayLink Driver that manages USB DisplayLink device and produces Graphics Output Protocol
> > + * This file implements the functions of the Driver Binding / Start / Stop / Unload interface
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +#include <Library/UefiRuntimeServicesTableLib.h>
> > +#include <Library/PrintLib.h>
> > +#include <Protocol/HiiFont.h>
> > +
> > +#include "Edid.h"
> > +#include "UsbDescriptors.h"
> > +
> > +//
> > +// Functions of Driver Binding Protocol
> > +//
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingSupported (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > +);
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingStart (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > +);
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingStop (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN UINTN NumberOfChildren,
> > + IN EFI_HANDLE *ChildHandleBuffer
> > +);
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingEntryPoint (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable
> > +);
> > +
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable,
> > + IN EFI_HANDLE DriverBindingHandle
> > +);
> > +
> > +
> > +// Generated with https://www.guidgen.com/<https://www.guidgen.com/> - "B70E5A79-C6D6-4267-B02E-9108C989E287"
> > +EFI_GUID gEfiDlGopVariableGuid = { 0xB70E5A79, 0xC6D6, 0x4267,{ 0xB0, 0x2E, 0x91, 0x08, 0xC9, 0x89, 0xE2, 0x87 } };
> > +
> > +
> > +EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding = {
> > + UsbDisplayLinkDriverBindingSupported,
> > + UsbDisplayLinkDriverBindingStart,
> > + UsbDisplayLinkDriverBindingStop,
> > + INF_DRIVER_VERSION,
> > + NULL,
> > + NULL
> > +};
> > +
> > +
> > +/**
> > + * Reads integer environment variable with default fallback.
> > + * @param variableName variable name to read
> > + * @param defaultValue default value to return if requested not found
> > + */
> > +STATIC UINT32
> > +ReadEnvironmentInt (
> > + CHAR16 *VariableName,
> > + UINT32 DefaultValue
> > + )
> > +{
> > + UINT32 Result;
> > + UINTN DataSize;
> > + DataSize = sizeof (Result);
> > + CONST EFI_STATUS Status = gRT->GetVariable (VariableName, &gEfiDlGopVariableGuid, (UINT32*)NULL, &DataSize, &Result);
> > + if (!EFI_ERROR (Status) && (sizeof (Result) == DataSize)) {
> > + return Result;
> > + }
> > + return DefaultValue;
> > +}
> > +
> > +/**
> > +* Reads boolean environment variable with default fallback.
> > +* @param variableName variable name to read
> > +* @param defaultValue default value to return if requested not found
> > +*/
> > +STATIC BOOLEAN
> > +ReadEnvironmentBool (
> > + CHAR16 *VariableName,
> > + BOOLEAN DefaultValue
> > + )
> > +{
> > + return ReadEnvironmentInt (VariableName, DefaultValue ? 1 : 0) == 1;
> > +}
> > +
> > +
> > +/**
> > +*
> > +* @param UsbDisplayLinkDev
> > +* @return
> > +*/
> > +STATIC EFI_STATUS
> > +InitializeUsbDisplayLinkDevice (
> > + IN OUT USB_DISPLAYLINK_DEV *UsbDisplayLinkDev
> > +)
> > +{
> > + EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> > + Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> > + Gop->QueryMode = DisplayLinkQueryMode;
> > + Gop->SetMode = DisplayLinkSetMode;
> > + Gop->Blt = DisplayLinkBlt;
> > +
> > + //
> > + // Allocate buffer for Graphics Output Protocol mode information
> > + //
> > + Gop->Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
> > + if (Gop->Mode == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > + Gop->Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> > + if (Gop->Mode->Info == NULL) {
> > + FreePool (Gop->Mode);
> > + Gop->Mode = NULL;
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + Gop->Mode->MaxMode = MAX(1, DlEdidGetNumSupportedModesInEdid (UsbDisplayLinkDev->EdidActive.Edid, UsbDisplayLinkDev->EdidActive.SizeOfEdid));
> > +
> > + Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> > + Gop->Mode->Info->Version = 0;
> > + // Initialising the horizontal resolution prevents certain BIOSs from hanging on boot, but
> > + // it is not yet clear why. See bug 28194.
> > + Gop->Mode->Info->HorizontalResolution = DlVideoModeGetSupportedVideoMode (0)->HActive;
> > + Gop->Mode->Info->VerticalResolution = 0;
> > + Gop->Mode->Info->PixelFormat = PixelBltOnly;
> > + Gop->Mode->Info->PixelsPerScanLine = 0;
> > + Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> > + Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> > + Gop->Mode->FrameBufferSize = 0;
> > +
> > + // Prevent DlGopSendScreenUpdate from running until we are sure that the video mode is set
> > + UsbDisplayLinkDev->LastY2 = 0;
> > + UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + Look for alternate settings for the UsbIo handle's interface
> > + which offer protocol DL_PROTOCOL_DIRECT_FB.
> > +
> > + @retval -1 Not found
> > + @retval Other The alternate setting
> > +**/
> > +STATIC INTN
> > +GetDirectFbAltSetting (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + IN UINT8 ParentInterfaceNumber
> > + )
> > +{
> > + EFI_STATUS Status;
> > + INTN AltSettingIndex;
> > + UINT16 InterfaceIndex;
> > +
> > + AltSettingIndex = -1;
> > +
> > + for (InterfaceIndex = 0; InterfaceIndex <= 0xFF; InterfaceIndex++) {
> > + EFI_USB_INTERFACE_DESCRIPTOR interfaceDescriptor;
> > + Status = UsbDisplayLinkGetInterfaceDescriptor (UsbIo, &interfaceDescriptor, (UINT8)InterfaceIndex);
> > + if (EFI_ERROR (Status)) {
> > + break;
> > + }
> > +
> > + if (interfaceDescriptor.InterfaceNumber == ParentInterfaceNumber &&
> > + (interfaceDescriptor.InterfaceClass == CLASS_VENDOR) &&
> > + interfaceDescriptor.InterfaceProtocol == INTERFACE_PROTOCOL_DIRECT_FB) {
> > + AltSettingIndex = interfaceDescriptor.AlternateSetting;
> > + break;
> > + }
> > + }
> > + return AltSettingIndex;
> > +}
> > +
> > +/**
> > + *
> > + * @param UsbIo
> > + * @param altSettingIndex
> > + * @return
> > + */
> > +STATIC EFI_STATUS
> > +SelectAltSetting (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + IN UINTN AltSettingIndex)
> > +{
> > + // Set alternate setting 1 on the interface
> > + EFI_STATUS Status;
> > + UINT32 UsbStatus;
> > + EFI_USB_DEVICE_REQUEST Request;
> > + ZeroMem (&Request, sizeof (Request));
> > + Request.RequestType = USB_REQ_TYPE_STANDARD | USB_TARGET_INTERFACE;
> > + Request.Request = USB_REQ_SET_INTERFACE;
> > + Request.Index = DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO;
> > + Request.Value = (UINT16)AltSettingIndex;
> > +
> > + Status = UsbIo->UsbControlTransfer (
> > + UsbIo,
> > + &Request,
> > + EfiUsbNoData,
> > + DISPLAYLINK_USB_CTRL_TIMEOUT,
> > + NULL,
> > + 0,
> > + &UsbStatus);
> > +
> > + if (EFI_ERROR (Status)) {
> > + Status = EFI_UNSUPPORTED;
> > + DEBUG ((DEBUG_ERROR, "USB control transfer failed while attempting to select alt setting %d on interface (code %r, USB status x%x). DisplayLink device has unsupported firmware version?\n", AltSettingIndex, Status, UsbStatus));
> > + }
> > + return Status;
> > +}
> > +
> > +
> > +/**
> > + Report whether the driver can support the device attached via UsbIo
> > + by seeing what if any capabilities it reports.
> > +
> > + @retval TRUE Device has sufficient capabilities for this driver.
> > + @retval FALSE Device lacks sufficient capabilities.
> > +**/
> > +STATIC BOOLEAN
> > +CapabilitiesSupported (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo
> > + )
> > +{
> > + UINT8 Buffer[256];
> > + EFI_STATUS Status;
> > +
> > + Status = ReadCapabilitiesDescriptor (UsbIo, Buffer, sizeof (Buffer));
> > + if (EFI_ERROR (Status)) {
> > + return FALSE;
> > + }
> > +
> > + VendorDescriptor descriptor;
> > + Status = UsbDisplayLinkParseCapabilitiesDescriptor (Buffer, sizeof (Buffer), &descriptor);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Failed to parse capabilities descriptor (code %r)\n", Status));
> > + return FALSE;
> > + }
> > +
> > + return UsbDisplayLinkCapabilitiesSufficientToBind (&descriptor);
> > +}
> > +
> > +
> > +/**
> > + *
> > + * @param UsbIo
> > + * @param InterfaceDescriptor
> > + * @param altSettingIndex
> > + * @return
> > + */
> > +STATIC BOOLEAN
> > +IsDLDirectFbCapableInterface (
> > + IN EFI_USB_IO_PROTOCOL *UsbIo,
> > + IN EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor,
> > + IN INTN *AltSettingIndex)
> > +{
> > + EFI_STATUS Status;
> > + EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
> > +
> > + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DeviceDescriptor);
> > +
> > + if (EFI_ERROR (Status)) {
> > + return FALSE;
> > + }
> > +
> > + if (DeviceDescriptor.IdVendor != VENDOR_DISPLAYLINK) {
> > + return FALSE;
> > + }
> > +
> > + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, InterfaceDescriptor);
> > + if (EFI_ERROR (Status)) {
> > + return FALSE;
> > + }
> > +
> > + // We can assume that the interface that we want to talk to - the NIVO interface - is number 0
> > + if (InterfaceDescriptor->InterfaceNumber != DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO) {
> > + return FALSE;
> > + }
> > +
> > + // Check if we have an interface (alt setting) descriptor with the correct interface protocol
> > + *AltSettingIndex = GetDirectFbAltSetting (UsbIo, InterfaceDescriptor->InterfaceNumber);
> > +
> > + if (*AltSettingIndex == -1) {
> > + DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to find setting on device which supports GOP functionality. Check firmware / device version?\n"));
> > + return FALSE;
> > + }
> > +
> > + // Now check that the capabilities that we need are properly supported
> > + if (CapabilitiesSupported (UsbIo) == FALSE) {
> > + DEBUG ((DEBUG_ERROR, "DisplayLink GOP: DL device detected, but it doesn't support the required GOP features. Check firmware / device version?\n"));
> > + return FALSE;
> > + }
> > +
> > + return TRUE;
> > +}
> > +
> > +
> > +/**
> > + * Prints a block of text in the framebuffer (helper function).
> > + * @param X x coordinate
> > + * @param Y y coordinate
> > + */
> > +STATIC VOID
> > +DisplayLinkPrintTextToScreenInternal (
> > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> > + UINTN X,
> > + UINTN Y,
> > + IN CHAR16 *Buffer
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_HII_FONT_PROTOCOL *HiiFont;
> > + EFI_IMAGE_OUTPUT *Blt;
> > + EFI_FONT_DISPLAY_INFO FontInfo;
> > + EFI_HII_OUT_FLAGS Flags;
> > +
> > + Blt = (EFI_IMAGE_OUTPUT*)NULL;
> > +
> > + Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **)&HiiFont);
> > + if (!EFI_ERROR (Status)) {
> > + Blt = (EFI_IMAGE_OUTPUT*)AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
> > + Blt->Width = (UINT16)GraphicsOutput->Mode->Info->HorizontalResolution;
> > + Blt->Height = (UINT16)GraphicsOutput->Mode->Info->VerticalResolution;
> > + Blt->Image.Screen = GraphicsOutput;
> > +
> > + ZeroMem (&FontInfo, sizeof (EFI_FONT_DISPLAY_INFO));
> > + FontInfo.ForegroundColor.Red<http://FontInfo.ForegroundColor.Red> = 0;
> > + FontInfo.ForegroundColor.Green<http://FontInfo.ForegroundColor.Green> = 0;
> > + FontInfo.ForegroundColor.Blue<http://FontInfo.ForegroundColor.Blue> = 0;
> > + FontInfo.BackgroundColor.Red<http://FontInfo.BackgroundColor.Red> = 0xff;
> > + FontInfo.BackgroundColor.Green<http://FontInfo.BackgroundColor.Green> = 0xff;
> > + FontInfo.BackgroundColor.Blue<http://FontInfo.BackgroundColor.Blue> = 0xff;
> > +
> > + Flags = EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_OUT_FLAG_CLIP |
> > + EFI_HII_OUT_FLAG_CLIP_CLEAN_X | EFI_HII_OUT_FLAG_CLIP_CLEAN_Y |
> > + EFI_HII_IGNORE_LINE_BREAK | EFI_HII_DIRECT_TO_SCREEN;
> > +
> > + Status = HiiFont->StringToImage (
> > + HiiFont,
> > + Flags,
> > + Buffer,
> > + &FontInfo,
> > + &Blt,
> > + X,
> > + Y,
> > + (EFI_HII_ROW_INFO**)NULL,
> > + (UINTN*)NULL,
> > + (UINTN*)NULL);
> > + }
> > +
> > + if (Blt != NULL) {
> > + FreePool (Blt);
> > + }
> > +}
> > +
> > +
> > +/**
> > +* Prints a block of text in the framebuffer.
> > +* @param X x coordinate
> > +* @param Y y coordinate
> > +* @param Format string format similar to stdlib's vsnprintf
> > +* @param ... arguments
> > +*/
> > +VOID
> > +EFIAPI
> > +DlGopPrintTextToScreen (
> > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> > + UINTN X,
> > + UINTN Y,
> > + IN CONST CHAR16 *Format,
> > + ...
> > + )
> > +{
> > + VA_LIST Marker;
> > + CHAR16 *Buffer;
> > + UINTN BufferSize;
> > +
> > + ASSERT (Format != NULL);
> > + ASSERT (((UINTN) Format & BIT0) == 0);
> > +
> > + VA_START(Marker, Format);
> > +
> > + BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);
> > +
> > + Buffer = (CHAR16*)AllocatePool (BufferSize);
> > + ASSERT (Buffer != NULL);
> > +
> > + UnicodeVSPrint (Buffer, BufferSize, Format, Marker);
> > +
> > + VA_END(Marker);
> > +
> > + DisplayLinkPrintTextToScreenInternal (GraphicsOutput, X, Y, Buffer);
> > +
> > + FreePool (Buffer);
> > +}
> > +
> > +
> > +/**
> > + * Sometimes platforms only write to the first GOP device that they find. Enabling this function allows us to copy the pixels from this device.
> > + * @param UsbDisplayLinkDev
> > + */
> > +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > +STATIC VOID
> > +DisplayLinkCopyFromPrimaryGopDevice (
> > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > + )
> > +{
> > + UINTN HandleCount;
> > + EFI_HANDLE *HandleBuffer;
> > + UINTN HandleIndex;
> > + EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
> > +
> > + gBS->LocateHandleBuffer (
> > + ByProtocol,
> > + &gEfiGraphicsOutputProtocolGuid,
> > + NULL,
> > + &HandleCount,
> > + &HandleBuffer);
> > +
> > + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
> > + gBS->HandleProtocol (HandleBuffer[HandleIndex], &gEfiGraphicsOutputProtocolGuid, (VOID**)&Gop);
> > + if (Gop != &UsbDisplayLinkDev->GraphicsOutputProtocol && Gop->Mode->FrameBufferBase != (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
> > +
> > + // See if we need to do a screen update - calculate a really noddy hash to see if any screen updates have happened.
> > + STATIC UINT32 prevframeBufferHash = 0; // 4 bytes per pixel
> > + UINT32 currFrameBufferHash = 0;
> > + UINTN i;
> > + for (i = 0; i < (Gop->Mode->Info->HorizontalResolution * Gop->Mode->Info->VerticalResolution); i++) {
> > + currFrameBufferHash += ((UINT32*)(UINTN)Gop->Mode->FrameBufferBase)[i];
> > + }
> > +
> > + if (currFrameBufferHash != prevframeBufferHash) {
> > + prevframeBufferHash = currFrameBufferHash;
> > +
> > + DisplayLinkBlt (
> > + &UsbDisplayLinkDev->GraphicsOutputProtocol,
> > + (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(UINTN)Gop->Mode->FrameBufferBase,
> > + EfiBltBufferToVideo,
> > + 0,
> > + 0,
> > + 0,
> > + 0,
> > + Gop->Mode->Info->HorizontalResolution,
> > + Gop->Mode->Info->VerticalResolution,
> > + 0);
> > + }
> > + break;
> > + }
> > + }
> > +
> > + FreePool (HandleBuffer);
> > +}
> > +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > +
> > +
> > +/**
> > + * Exit from boot services: signal handler.
> > + */
> > +STATIC VOID
> > +EFIAPI
> > +DisplayLinkDriverExitBootServices (
> > + IN EFI_EVENT Event,
> > + IN VOID *Context
> > + )
> > +{
> > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> > + UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> > +
> > + gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> > +}
> > +
> > +/**
> > + * Periodic screen update: timer callback.
> > + */
> > +VOID
> > +EFIAPI
> > +DisplayLinkPeriodicTimer (
> > + IN EFI_EVENT Event,
> > + IN VOID* Context
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> > +
> > + Status = EFI_SUCCESS;
> > + UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> > +
> > + // Drop out if we haven't set the video mode up yet
> > + if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> > + // Restart the one-shot timer to poll the status again.
> > + Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> > + }
> > + return;
> > + }
> > +
> > +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > + DisplayLinkCopyFromPrimaryGopDevice (UsbDisplayLinkDev);
> > +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > +
> > + if (UsbDisplayLinkDev->ShowBandwidth) {
> > + STATIC UINTN Count = 0;
> > +
> > + if (Count++ % 50 == 0) {
> > + DlGopPrintTextToScreen (&UsbDisplayLinkDev->GraphicsOutputProtocol, 32, 48, (CONST CHAR16*)L" Bandwidth: %d MB/s ", UsbDisplayLinkDev->DataSent * 10000000 / DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 50 / 1024 / 1024);
> > + UsbDisplayLinkDev->DataSent = 0;
> > + }
> > + }
> > +
> > + if (UsbDisplayLinkDev->ShowTestPattern)
> > + {
> > + if (UsbDisplayLinkDev->ShowTestPattern == 5) {
> > + DlGopSendTestPattern (UsbDisplayLinkDev, 0);
> > + } else if (UsbDisplayLinkDev->ShowTestPattern >= 10) {
> > + DlGopSendTestPattern (UsbDisplayLinkDev, 1);
> > + UsbDisplayLinkDev->ShowTestPattern = 0;
> > + }
> > + UsbDisplayLinkDev->ShowTestPattern++;
> > +
> > + }
> > +
> > + // Send the latest version of the frame buffer to the DL device over USB
> > + DlGopSendScreenUpdate (UsbDisplayLinkDev);
> > +
> > + // Restart the timer now we've finished
> > + Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> > + }
> > +}
> > +
> > +/* ****************************************************************************************************** */
> > +/* ****************************************************************************************************** */
> > +/* ****************** START OF FUNCTIONS WHICH IMPLEMENT DRIVER BINDING INTERFACE ****************** */
> > +/* ****************************************************************************************************** */
> > +/* ****************************************************************************************************** */
> > +
> > +/**
> > + Check whether USB DisplayLink driver supports this device.
> > +
> > + @param This The USB DisplayLink driver 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
> > +UsbDisplayLinkDriverBindingSupported (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > +
> > + Status = gBS->OpenProtocol (
> > + Controller,
> > + &gEfiUsbIoProtocolGuid,
> > + (VOID **) &UsbIo,
> > + This->DriverBindingHandle,
> > + Controller,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER);
> > +
> > + if (EFI_ERROR (Status)) {
> > + return Status;
> > + }
> > +
> > + //
> > + // Use the USB I/O Protocol interface to check whether Controller is
> > + // a DisplayLink device that can be managed by this driver.
> > + //
> > + Status = EFI_UNSUPPORTED;
> > + EFI_USB_INTERFACE_DESCRIPTOR DummyInterfaceDescriptor;
> > + INTN DummyAltSettingIndex;
> > +
> > + if (IsDLDirectFbCapableInterface (UsbIo, &DummyInterfaceDescriptor, &DummyAltSettingIndex)){
> > + Status = EFI_SUCCESS;
> > + }
> > +
> > + gBS->CloseProtocol (
> > + Controller,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + Controller);
> > +
> > + return Status;
> > +}
> > +
> > +
> > +/**
> > + Starts the DisplayLink device with this driver.
> > +
> > + This function consumes USB I/O Protocol, intializes USB DisplayLink device,
> > + installs Graphics Output Protocol
> > + Transfer to manage the USB DisplayLink device.
> > +
> > + @param This The USB DisplayLink 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 This driver supports this device.
> > + @retval EFI_UNSUPPORTED This driver does not support this device.
> > + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
> > + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
> > + @retval EFI_ALREADY_STARTED This driver has been started.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingStart (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> > + UINT8 EndpointNumber;
> > + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
> > + UINT8 Index;
> > + BOOLEAN FoundOut;
> > + BOOLEAN FoundIn;
> > + EFI_TPL OriginalTPL;
> > + INTN altSettingIndex;
> > +
> > + OriginalTPL = gBS->RaiseTPL (TPL_CALLBACK);
> > +
> > + UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)AllocateZeroPool (sizeof (USB_DISPLAYLINK_DEV));
> > + if (UsbDisplayLinkDev == NULL) {
> > + DEBUG ((DEBUG_ERROR, "Device initialialisation - Failed to allocate memory for device.\n"));
> > + gBS->RestoreTPL (OriginalTPL);
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + UsbDisplayLinkDev->Signature = USB_DISPLAYLINK_DEV_SIGNATURE;
> > +
> > + UsbDisplayLinkDev->ShowBandwidth = ReadEnvironmentBool (L"DisplayLinkShowBandwidth", FALSE);
> > + UsbDisplayLinkDev->ShowTestPattern = ReadEnvironmentBool (L"DisplayLinkShowTestPatterns", FALSE);
> > +
> > + //
> > + // Open USB I/O Protocol
> > + //
> > + Status = gBS->OpenProtocol (
> > + Controller,
> > + &gEfiUsbIoProtocolGuid,
> > + (VOID **) &UsbDisplayLinkDev->UsbIo,
> > + This->DriverBindingHandle,
> > + Controller,
> > + EFI_OPEN_PROTOCOL_BY_DRIVER);
> > +
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Failed to open usbio protocol. Is USB correctly supported on this platform?.\n"));
> > + Status = EFI_UNSUPPORTED;
> > + goto ErrorExit2;
> > + }
> > +
> > + if (!IsDLDirectFbCapableInterface (UsbDisplayLinkDev->UsbIo, &UsbDisplayLinkDev->InterfaceDescriptor, &altSettingIndex)) {
> > + Status = EFI_UNSUPPORTED;
> > + goto ErrorExit4;
> > + }
> > +
> > + Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, altSettingIndex);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to select alternate setting.\n"));
> > + Status = EFI_UNSUPPORTED;
> > + goto ErrorExit4;
> > + }
> > +
> > + //
> > + // Parse endpoint descriptor
> > + //
> > + EndpointNumber = UsbDisplayLinkDev->InterfaceDescriptor.NumEndpoints;
> > +
> > + //
> > + // Traverse endpoints to find bulk endpoint
> > + //
> > + FoundOut = FALSE;
> > + FoundIn = FALSE;
> > + for (Index = 0; Index < EndpointNumber; Index++) {
> > + UsbDisplayLinkDev->UsbIo->UsbGetEndpointDescriptor (
> > + UsbDisplayLinkDev->UsbIo,
> > + Index,
> > + &EndpointDescriptor);
> > +
> > + if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_BULK) {
> > + if (!FoundOut && (EndpointDescriptor.EndpointAddress & BIT7) == 0) {
> > + CopyMem (&UsbDisplayLinkDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> > + FoundOut = TRUE;
> > + } else if (!FoundIn && (EndpointDescriptor.EndpointAddress & BIT7) == BIT7) {
> > + CopyMem (&UsbDisplayLinkDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> > + FoundIn = TRUE;
> > + }
> > + }
> > + }
> > +
> > + if (FoundOut == FALSE) {
> > + Status = EFI_UNSUPPORTED;
> > + DEBUG ((DEBUG_ERROR, "No endpoints found. Num endpoints searched = %d.\n", EndpointNumber));
> > + goto ErrorExit4;
> > + }
> > +
> > + Status = DlReadEdid (UsbDisplayLinkDev);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Failed to read monitor EDID from DisplayLink device (code %r)\n", Status));
> > + goto ErrorExit7;
> > + }
> > +
> > + Status = InitializeUsbDisplayLinkDevice (UsbDisplayLinkDev);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Failed to initialise DisplayLink device (code %r)\n", Status));
> > + goto ErrorExit7;
> > + }
> > +
> > + Status = gBS->InstallMultipleProtocolInterfaces (
> > + &Controller,
> > + &gEfiGraphicsOutputProtocolGuid,
> > + &UsbDisplayLinkDev->GraphicsOutputProtocol,
> > + &gEfiEdidDiscoveredProtocolGuid,
> > + &UsbDisplayLinkDev->EdidDiscovered,
> > + &gEfiEdidActiveProtocolGuid,
> > + &UsbDisplayLinkDev->EdidActive,
> > + NULL);
> > +
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "Failed to install Graphics Output and EDID protocol interfaces - driver not installed correctly - %r\n", Status));
> > + goto ErrorExit8;
> > + }
> > +
> > + UsbDisplayLinkDev->ControllerNameTable = (EFI_UNICODE_STRING_TABLE*)NULL;
> > +
> > + AddUnicodeString2 (
> > + "eng",
> > + mUsbDisplayLinkComponentName.SupportedLanguages,
> > + &UsbDisplayLinkDev->ControllerNameTable,
> > + (CONST CHAR16*)L"Generic Usb DisplayLink",
> > + TRUE);
> > +
> > + AddUnicodeString2 (
> > + "en",
> > + mUsbDisplayLinkComponentName2.SupportedLanguages,
> > + &UsbDisplayLinkDev->ControllerNameTable,
> > + (CONST CHAR16*)L"Generic Usb DisplayLink",
> > + FALSE);
> > +
> > + //
> > + // Setup a periodic timer
> > + //
> > + Status = gBS->CreateEvent (
> > + EVT_TIMER | EVT_NOTIFY_SIGNAL,
> > + TPL_CALLBACK,
> > + DisplayLinkPeriodicTimer,
> > + UsbDisplayLinkDev,
> > + &UsbDisplayLinkDev->TimerEvent);
> > +
> > + if (EFI_ERROR (Status)) {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + DEBUG ((DEBUG_ERROR, "Failed to create screeen update polling event.\n"));
> > + goto ErrorExit8;
> > + }
> > +
> > + // Start one-shot timer. The rendering operations can take quite a long time, so we
> > + // don't want another timer event to happen until we have finished; so we'll restart
> > + // the timer from DisplayLinkPeriodicTimer, the event handler function.
> > + Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> > + if (EFI_ERROR (Status)) {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + DEBUG ((DEBUG_ERROR, "Failed to create screen update polling timer.\n"));
> > + goto ErrorExit8;
> > + }
> > +
> > + Status = gBS->CreateEventEx (
> > + EVT_NOTIFY_SIGNAL,
> > + TPL_NOTIFY,
> > + DisplayLinkDriverExitBootServices,
> > + UsbDisplayLinkDev,
> > + &gEfiEventExitBootServicesGuid,
> > + &UsbDisplayLinkDev->DriverExitBootServicesEvent);
> > +
> > + if (EFI_ERROR (Status)) {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + DEBUG ((DEBUG_ERROR, "Failed to create event for bootexit.\n"));
> > + goto ErrorExit8;
> > + }
> > +
> > + gBS->RestoreTPL (OriginalTPL);
> > +
> > + DEBUG ((DEBUG_INFO, "DisplayLink GOP driver successfully bound to device.\n"));
> > +
> > + return EFI_SUCCESS;
> > +
> > + //
> > + // Error handler
> > + //
> > + ErrorExit8:
> > + ErrorExit7:
> > + ErrorExit4:
> > + gBS->CloseProtocol (
> > + Controller,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + Controller);
> > +
> > + ErrorExit2:
> > + if (UsbDisplayLinkDev != NULL) {
> > + FreePool (UsbDisplayLinkDev);
> > + UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)NULL;
> > + }
> > +
> > + DEBUG ((DEBUG_ERROR, "Exiting - Failed to initialise driver.\n"));
> > +
> > + gBS->RestoreTPL (OriginalTPL);
> > + return Status;
> > +}
> > +
> > +/**
> > +Entrypoint of USB DisplayLink Driver.
> > +
> > +This function is the entrypoint of a combined USB DisplayLink GOP Driver. It installs Driver Binding
> > +Protocols together with Component Name Protocols.
> > +
> > +@param ImageHandle The firmware allocated handle for the EFI image.
> > +@param SystemTable A pointer to the EFI System Table.
> > +@param DriverBindingHandle The Driver binding handle
> > +
> > +@retval EFI_SUCCESS The entry point is executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable,
> > + IN EFI_HANDLE DriverBindingHandle
> > +)
> > +{
> > + EFI_STATUS Status;
> > +
> > + Status = EfiLibInstallDriverBindingComponentName2 (
> > + ImageHandle,
> > + SystemTable,
> > + &gUsbDisplayLinkDriverBinding,
> > + DriverBindingHandle,
> > + &mUsbDisplayLinkComponentName,
> > + &mUsbDisplayLinkComponentName2);
> > +
> > + ASSERT_EFI_ERROR (Status);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +
> > +/**
> > +Entrypoint of USB DisplayLink Driver.
> > +
> > +This function is the entrypoint of USB DisplayLink Driver. It installs Driver Binding
> > +Protocols together with Component Name Protocols.
> > +
> > +@param ImageHandle The firmware allocated handle for the EFI image.
> > +@param SystemTable A pointer to the EFI System Table.
> > +
> > +@retval EFI_SUCCESS The entry point is executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingEntryPoint (
> > + IN EFI_HANDLE ImageHandle,
> > + IN EFI_SYSTEM_TABLE *SystemTable
> > +)
> > +{
> > + return UsbDisplayLinkDriverCombinedGopBindingEntryPoint (ImageHandle, SystemTable, ImageHandle);
> > +}
> > +
> > +
> > +/**
> > +Unloads an image.
> > +@param ImageHandle Handle that identifies the image to be unloaded.
> > +@retval EFI_SUCCESS The image has been unloaded.
> > +@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverCombinedGopUnload (
> > + IN EFI_HANDLE ImageHandle
> > +)
> > +{
> > + EFI_STATUS Status = EFI_SUCCESS;
> > + EFI_STATUS handleDisconnectStatus;
> > + EFI_HANDLE *HandleBuffer;
> > + UINTN HandleCount;
> > + UINTN Index;
> > +
> > + //
> > + // Retrieve array of all handles in the handle database
> > + //
> > + handleDisconnectStatus = gBS->LocateHandleBuffer (
> > + AllHandles,
> > + NULL,
> > + NULL,
> > + &HandleCount,
> > + &HandleBuffer
> > + );
> > + if (! EFI_ERROR (handleDisconnectStatus)) {
> > + //
> > + // Disconnect the current driver from handles in the handle database
> > + //
> > + for (Index = 0; Index < HandleCount; Index++) {
> > + Status = gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
> > + }
> > + //
> > + // Free the array of handles
> > + //
> > + if (HandleBuffer != NULL)
> > + {
> > + FreePool (HandleBuffer);
> > + }
> > + }
> > +
> > + // Even if we didn't manage to disconnect the handles, try to uninstall the protocols
> > + //
> > + // Uninstall protocols installed in the driver entry point
> > + //
> > + Status = gBS->UninstallMultipleProtocolInterfaces (
> > + ImageHandle,
> > + &gEfiDriverBindingProtocolGuid,
> > + &gUsbDisplayLinkDriverBinding,
> > + &gEfiComponentNameProtocolGuid,
> > + &mUsbDisplayLinkComponentName,
> > + &gEfiComponentName2ProtocolGuid,
> > + &mUsbDisplayLinkComponentName2,
> > + NULL
> > + );
> > +
> > + if (EFI_ERROR (handleDisconnectStatus))
> > + {
> > + return handleDisconnectStatus;
> > + }
> > + return Status;
> > +}
> > +
> > +
> > +/**
> > + Stop the USB DisplayLink device handled by this driver.
> > +
> > + @param This The USB DisplayLink 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_UNSUPPORTED Simple Pointer Protocol is not installed on Controller.
> > + @retval Others Fail to uninstall protocols attached on the device.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingStop (
> > + IN EFI_DRIVER_BINDING_PROTOCOL *This,
> > + IN EFI_HANDLE Controller,
> > + IN UINTN NumberOfChildren,
> > + IN EFI_HANDLE *ChildHandleBuffer
> > + )
> > +{
> > + EFI_STATUS Status;
> > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
> > +
> > + Status = gBS->OpenProtocol (
> > + Controller,
> > + &gEfiGraphicsOutputProtocolGuid,
> > + (VOID **) &GraphicsOutputProtocol,
> > + This->DriverBindingHandle,
> > + Controller,
> > + EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > +
> > + if (EFI_ERROR (Status)) {
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> > +
> > + // Reset the video mode to clear the display. Don't drop out if there is a problem, just press on.
> > + // Note that this will also clear the frame buffer, as the screen buffer will be re-allocated with AllocateZeroPool.
> > + if ((GraphicsOutputProtocol->Mode != NULL) &&
> > + (GraphicsOutputProtocol->Mode->Mode != GRAPHICS_OUTPUT_INVALID_MODE_NUMBER)) {
> > + Status = DisplayLinkSetMode (GraphicsOutputProtocol, GraphicsOutputProtocol->Mode->Mode);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_WARN, "Driver stop - Problem resetting video mode - %r.\n", Status));
> > + }
> > + }
> > +
> > + // Reset the alt setting on the interface (to the DL3 alt setting)
> > + Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, 0);
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_WARN, "Error resetting USB interface alternate setting - %r.\n", Status));
> > + }
> > +
> > + Status = gBS->UninstallMultipleProtocolInterfaces (
> > + Controller,
> > + &gEfiGraphicsOutputProtocolGuid,
> > + &UsbDisplayLinkDev->GraphicsOutputProtocol,
> > + &gEfiEdidDiscoveredProtocolGuid,
> > + &UsbDisplayLinkDev->EdidDiscovered,
> > + &gEfiEdidActiveProtocolGuid,
> > + &UsbDisplayLinkDev->EdidActive,
> > + NULL);
> > +
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_WARN, "Error uninstalling Graphics Output and EDID protocol interfaces - %r.\n", Status));
> > + return Status;
> > + }
> > +
> > + gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> > +
> > + gBS->CloseProtocol (
> > + Controller,
> > + &gEfiUsbIoProtocolGuid,
> > + This->DriverBindingHandle,
> > + Controller);
> > +
> > + //
> > + // Free all resources.
> > + //
> > + if (UsbDisplayLinkDev->ControllerNameTable != NULL) {
> > + FreeUnicodeStringTable (UsbDisplayLinkDev->ControllerNameTable);
> > + }
> > +
> > + if (UsbDisplayLinkDev->Screen != NULL) {
> > + FreePool (UsbDisplayLinkDev->Screen);
> > + UsbDisplayLinkDev->Screen = NULL;
> > + }
> > +
> > + if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode) {
> > + if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info) {
> > + FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info);
> > + UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info = NULL;
> > + }
> > + FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode);
> > + UsbDisplayLinkDev->GraphicsOutputProtocol.Mode = NULL;
> > + }
> > +
> > + FreePool (UsbDisplayLinkDev);
> > +
> > + return EFI_SUCCESS;
> > +
> > +}
> > +
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> > new file mode 100644
> > index 000000000000..497a2621bc2c
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> > @@ -0,0 +1,278 @@
> > +/**
> > + * @file UsbDisplayLink.h
> > + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#ifndef _EFI_USB_DISPLAYLINK_H_
> > +#define _EFI_USB_DISPLAYLINK_H_
> > +
> > +#include <Uefi/UefiBaseType.h>
> > +#include <Uefi/UefiSpec.h>
> > +
> > +#include <Protocol/EdidActive.h>
> > +#include <Protocol/EdidDiscovered.h>
> > +#include <Protocol/EdidOverride.h>
> > +#include <Protocol/GraphicsOutput.h>
> > +#include <Protocol/UsbIo.h>
> > +
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/ReportStatusCodeLib.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/UefiLib.h>
> > +
> > +#define VENDOR_DISPLAYLINK 0x17e9
> > +#define CLASS_VENDOR 0xFF
> > +
> > +#define DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO ((UINTN)0)
> > +
> > +#define INTERFACE_PROTOCOL_DIRECT_FB 4
> > +
> > +#define USB_TRANSFER_LENGTH (64 * 1024)
> > +#define DISPLAYLINK_MODE_DATA_LENGTH (146)
> > +#define DISPLAYLINK_USB_CTRL_TIMEOUT (1000)
> > +#define DISPLAYLINK_USB_BULK_TIMEOUT (1)
> > +
> > +#define DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD ((UINTN)1000000) // 0.1s in us
> > +#define DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD ((UINTN)30000) // 3s in ticks
> > +
> > +#define DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE ((UINT16)60)
> > +
> > +// Requests to read values from the firmware
> > +#define EDID_BLOCK_SIZE 128
> > +#define EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK ((UINT16)(0x64))
> > +
> > +/** Structures ported from firmware - protocol.h */
> > +enum ID {
> > + // VideoCommands
> > + GET_OUTPUT_EDID = 0,
> > + SET_VIDEO_MODE = 1
> > +};
> > +
> > +typedef struct {
> > + UINT32 HorizontalResolution;
> > + UINT32 VerticalResolution;
> > + UINT32 ColorDepth;
> > + UINT32 RefreshRate;
> > + UINT8 Commands[DISPLAYLINK_MODE_DATA_LENGTH];
> > +} DISPLAYLINK_MODE_DATA;
> > +
> > +#define GRAPHICS_OUTPUT_INVALID_MODE_NUMBER 0xffff
> > +
> > +/**
> > + * Device instance of USB display.
> > + */
> > +typedef struct {
> > + UINT64 Signature;
> > + EFI_HANDLE Handle;
> > + EFI_USB_IO_PROTOCOL *UsbIo;
> > + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
> > + EFI_USB_ENDPOINT_DESCRIPTOR BulkOutEndpointDescriptor;
> > + EFI_USB_ENDPOINT_DESCRIPTOR BulkInEndpointDescriptor;
> > + EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutputProtocol;
> > + EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered;
> > + EFI_EDID_ACTIVE_PROTOCOL EdidActive;
> > + EFI_UNICODE_STRING_TABLE *ControllerNameTable;
> > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Screen;
> > + UINTN DataSent; /** Debug - used to track the bandwidth */
> > + EFI_EVENT TimerEvent;
> > + EFI_EVENT DriverExitBootServicesEvent;
> > + BOOLEAN ShowBandwidth; /** Debugging - show the bandwidth on the screen */
> > + BOOLEAN ShowTestPattern; /** Show a colourbar pattern instead of the BLTd contents of the framebuffer */
> > + UINTN LastY1; /** Used to track if we can do a partial screen update */
> > + UINTN LastY2;
> > + UINTN LastWidth;
> > + UINTN TimeSinceLastScreenUpdate; /** Do a full screen update every (x) seconds */
> > +} USB_DISPLAYLINK_DEV;
> > +
> > +#define USB_DISPLAYLINK_DEV_SIGNATURE SIGNATURE_32 ('d', 'l', 'i', 'n')
> > +
> > +struct VideoMode {
> > + UINT8 Reserved1; /* Reserved - must be 0. */
> > + UINT8 Reserved2; /* Reserved - must be 2. */
> > +
> > + // Values matching the EDID Detailed Timing Descriptor spec
> > + UINT16 PixelClock;
> > + UINT16 HActive;
> > + UINT16 HBlanking;
> > + UINT16 HSyncOffset; // Horizontal Front Porch
> > + UINT16 HSyncWidth;
> > + UINT16 VActive;
> > + UINT16 VBlanking;
> > + UINT16 VSyncOffset; // Vertical Front Porch
> > + UINT16 VSyncWidth;
> > + // End of Edid Detailed Timing Descriptor
> > +
> > + UINT16 Flags /*ModeFlags*/;
> > + UINT16 Accumulate;
> > + UINT16 Reserved3; /* Reserved - must be 0. */
> > + UINT16 Reserved4; /* Reserved - must be 0. */
> > + UINT16 InsetLeft;
> > + UINT16 InsetTop;
> > + UINT16 InsetRight;
> > + UINT16 InsetBottom;
> > + UINT32 FillValue;
> > + UINT32 Reserved5; /* Reserved - must be 0. */
> > + UINT8 Vic;
> > + UINT8 ActiveFormat;
> > + UINT16 Reserved6;
> > +};
> > +
> > +#define USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(a) \
> > + CR(a, USB_DISPLAYLINK_DEV, GraphicsOutputProtocol, USB_DISPLAYLINK_DEV_SIGNATURE)
> > +
> > +//
> > +// Global Variables
> > +//
> > +extern EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding;
> > +extern EFI_COMPONENT_NAME_PROTOCOL mUsbDisplayLinkComponentName;
> > +extern EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplayLinkComponentName2;
> > +
> > +
> > +/* ******************************************* */
> > +/* ******** GOP interface functions ******** */
> > +/* ******************************************* */
> > +
> > +/**
> > + * Implementation of the GOP protocol QueryMode API function
> > + * @param This Instance of the GOP protocol
> > + * @param ModeNumber
> > + * @param SizeOfInfo
> > + * @param Info
> > + * @return
> > + */
> > +EFI_STATUS
> > + EFIAPI
> > + DisplayLinkQueryMode (
> > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> > + IN UINT32 ModeNumber,
> > + OUT UINTN *SizeOfInfo,
> > + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
> > + );
> > +
> > +
> > +/**
> > + * Implementation of the GOP protocol SetMode API function
> > + * @param This
> > + * @param ModeNumber
> > + * @return
> > + */
> > +EFI_STATUS
> > + EFIAPI
> > + DisplayLinkSetMode (
> > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> > + IN UINT32 ModeNumber
> > + );
> > +
> > +/**
> > + * Implementation of the GOP protocol Blt API function
> > + * @param This
> > + * @param BltBuffer
> > + * @param BltOperation
> > + * @param SourceX
> > + * @param SourceY
> > + * @param DestinationX
> > + * @param DestinationY
> > + * @param Width
> > + * @param Height
> > + * @param Delta
> > + * @return
> > + */
> > +EFI_STATUS
> > + EFIAPI
> > + DisplayLinkBlt (
> > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
> > + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
> > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> > + IN UINTN SourceX,
> > + IN UINTN SourceY,
> > + IN UINTN DestinationX,
> > + IN UINTN DestinationY,
> > + IN UINTN Width,
> > + IN UINTN Height,
> > + IN UINTN Delta OPTIONAL
> > + );
> > +
> > +/* *************************** */
> > +/* ** GOP helper functions ** */
> > +/* *************************** */
> > +
> > +VOID
> > +EFIAPI
> > +DlGopPrintTextToScreen (
> > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> > + UINTN X,
> > + UINTN Y,
> > + IN CONST CHAR16 *Format,
> > + ...
> > +);
> > +
> > +EFI_STATUS
> > +DlGopSendTestPattern (
> > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > + UINTN PatternNumber
> > +);
> > +
> > +EFI_STATUS
> > +DlGopSendScreenUpdate (
> > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > +);
> > +
> > +
> > +/* ******************************************* */
> > +/* ******** USB interface functions ******** */
> > +/* ******************************************* */
> > +
> > +EFI_STATUS
> > +DlUsbSendControlWriteMessage (
> > + IN USB_DISPLAYLINK_DEV *Device,
> > + IN UINT8 Request,
> > + IN UINT16 Value,
> > + IN CONST VOID *ControlMsg,
> > + IN UINT16 ControlMsgLen
> > +);
> > +
> > +EFI_STATUS
> > +DlUsbSendControlReadMessage (
> > + IN USB_DISPLAYLINK_DEV *Device,
> > + IN UINT8 Request,
> > + IN UINT16 Value,
> > + OUT VOID *ControlMsg,
> > + IN UINT16 ControlMsgLen
> > +);
> > +
> > +EFI_STATUS
> > +DlUsbBulkWrite (
> > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > + CONST UINT8* Buffer,
> > + UINTN DataLen,
> > + UINT32 *USBStatus
> > +);
> > +
> > +UINTN
> > +DlUsbBulkRead (
> > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > + UINT8* Buffer,
> > + UINTN BufferLen
> > +);
> > +
> > +/* ******************************************* */
> > +/* ******** Video Mode functions ******** */
> > +/* ******************************************* */
> > +
> > +// Pre-calculated video modes
> > +UINT32
> > +DlVideoModeGetNumSupportedVideoModes ();
> > +
> > +CONST struct VideoMode *
> > +DlVideoModeGetSupportedVideoMode (
> > + UINT32 index
> > +);
> > +
> > +#endif
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> > new file mode 100644
> > index 000000000000..252293da39d4
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> > @@ -0,0 +1,180 @@
> > +/**
> > + * @file UsbTransfer.c
> > + * @brief Wrapper of UEFI USB bulk and control transfer interface for USB DisplayLink driver.
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +/**
> > + * Write the data to the DisplayLink device using the USBIO protocol.
> > + * @param UsbDisplayLinkDev
> > + * @param Buffer
> > + * @param DataLen
> > + * @param USBStatus
> > + * @return
> > + * EFI_SUCCESS The bulk transfer has been successfully executed.
> > + * EFI_INVALID_PARAMETER If DeviceEndpoint is not valid.
> > + * EFI_INVALID_PARAMETER Data is NULL.
> > + * EFI_INVALID_PARAMETER DataLength is NULL.
> > + * EFI_INVALID_PARAMETER Status is NULL.
> > + * EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
> > + * EFI_TIMEOUT The bulk transfer cannot be completed within Timeout timeframe.
> > + * EFI_DEVICE_ERROR The transfer failed other than timeout, and the transfer status is returned in Status.
> > + */
> > +EFI_STATUS
> > +DlUsbBulkWrite (
> > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > + IN CONST UINT8* Buffer,
> > + IN UINTN DataLen,
> > + OUT UINT32 *USBStatus
> > + )
> > +{
> > + EFI_STATUS Status;
> > + Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> > + UsbDisplayLinkDev->UsbIo,
> > + UsbDisplayLinkDev->BulkOutEndpointDescriptor.EndpointAddress,
> > + (VOID*)Buffer,
> > + &DataLen,
> > + DISPLAYLINK_USB_BULK_TIMEOUT,
> > + USBStatus);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > +* Read data from the DisplayLink device using the USBIO protocol.
> > +* @param UsbDisplayLinkDev
> > +* @param Buffer
> > +* @param BufferLen
> > +* @return 0 if an error occurred or 0 bytes were read, otherwise the number of bytes read
> > + */
> > +UINTN
> > +DlUsbBulkRead (
> > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > + IN UINT8* Buffer,
> > + IN UINTN BufferLen
> > + )
> > +{
> > + UINT32 Result;
> > + UINTN ReadLen;
> > + EFI_STATUS Status;
> > +
> > + ReadLen = BufferLen;
> > +
> > + Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> > + UsbDisplayLinkDev->UsbIo,
> > + UsbDisplayLinkDev->BulkInEndpointDescriptor.EndpointAddress,
> > + Buffer,
> > + &ReadLen,
> > + DISPLAYLINK_USB_BULK_TIMEOUT,
> > + &Result);
> > +
> > + if (EFI_ERROR (Status)) {
> > + return 0;
> > + }
> > +
> > + return ReadLen;
> > +}
> > +
> > +
> > +/**
> > +Send a control message (e.g set video mode) message to the DisplayLink device.
> > +
> > +@param Device USB device handle.
> > +@param request Request type, e.g. SET_VIDEO_MODE
> > +@param value
> > +@param controlMsg Pointer to the message to send.
> > +@param controlMsgLen Length of the message.
> > +
> > +@retval EFI_SUCCESS Successfully sent message.
> > +
> > +**/
> > +EFI_STATUS
> > +DlUsbSendControlWriteMessage (
> > + IN USB_DISPLAYLINK_DEV *Device,
> > + IN UINT8 Request,
> > + IN UINT16 Value,
> > + IN CONST VOID *ControlMsg,
> > + IN UINT16 ControlMsgLen
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 UsbStatus;
> > + EFI_USB_DEVICE_REQUEST UsbRequest;
> > +
> > + ZeroMem (&Request, sizeof (Request));
> > + UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE;
> > + UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> > + UsbRequest.Request = Request;
> > + UsbRequest.Value = Value;
> > + UsbRequest.Length = ControlMsgLen;
> > +
> > + Status = Device->UsbIo->UsbControlTransfer (
> > + Device->UsbIo,
> > + &UsbRequest,
> > + EfiUsbDataOut,
> > + DISPLAYLINK_USB_CTRL_TIMEOUT,
> > + (VOID *)ControlMsg,
> > + ControlMsgLen,
> > + &UsbStatus);
> > +
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "USB write control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> > + Status = EFI_DEVICE_ERROR;
> > + }
> > + return Status;
> > +}
> > +
> > +
> > +/**
> > +Request data from the DisplayLink device (e.g. the monitor EDID)
> > +
> > +@param Device USB device handle.
> > +@param request Request type, e.g. GET_OUTPUT_EDID
> > +@param value
> > +@param controlMsg Pointer to the message to send.
> > +@param controlMsgLen Length of the message.
> > +
> > +@retval EFI_SUCCESS Successfully sent message.
> > +
> > +**/
> > +EFI_STATUS
> > +DlUsbSendControlReadMessage (
> > + IN USB_DISPLAYLINK_DEV *Device,
> > + IN UINT8 Request,
> > + IN UINT16 Value,
> > + OUT VOID *ControlMsg,
> > + IN UINT16 ControlMsgLen
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT32 UsbStatus;
> > + EFI_USB_DEVICE_REQUEST UsbRequest;
> > +
> > + ZeroMem (&UsbRequest, sizeof (UsbRequest));
> > + UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE | USB_ENDPOINT_DIR_IN;
> > + UsbRequest.Request = Request;
> > + UsbRequest.Value = Value;
> > + UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> > + UsbRequest.Length = ControlMsgLen;
> > +
> > + Status = Device->UsbIo->UsbControlTransfer (
> > + Device->UsbIo,
> > + &UsbRequest,
> > + EfiUsbDataIn,
> > + DISPLAYLINK_USB_CTRL_TIMEOUT,
> > + (VOID *)ControlMsg,
> > + ControlMsgLen,
> > + &UsbStatus);
> > +
> > + if (EFI_ERROR (Status)) {
> > + DEBUG ((DEBUG_ERROR, "USB read control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> > + Status = EFI_DEVICE_ERROR;
> > + }
> > + return Status;
> > +}
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> > new file mode 100644
> > index 000000000000..6218c093147c
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> > @@ -0,0 +1,254 @@
> > +/**
> > + * @file VideoModes.c
> > + * @brief Pre-calculated video timings sent to the DisplayLink device when a video mode is selected
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +
> > +// Supported video modes - must be in order of pixel count (i.e. hres x vres)
> > +
> > +STATIC CONST struct VideoMode ModeData[] = {
> > + {
> > + // 640 x 480 @ 60Hz
> > + .Reserved2 = 2,
> > + .PixelClock = 2517,
> > + .HActive = 640,
> > + .HBlanking = 160,
> > + .HSyncOffset = 16,
> > + .HSyncWidth = 96,
> > + .VActive = 480,
> > + .VBlanking = 45,
> > + .VSyncOffset = 10,
> > + .VSyncWidth = 2,
> > + .Flags = 0x00000300,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + },
> > + {
> > + // 800 x 600 @ 60Hz
> > + .Reserved2 = 2,
> > + .PixelClock = 4000,
> > + .HActive = 800,
> > + .HBlanking = 256,
> > + .HSyncOffset = 40,
> > + .HSyncWidth = 128,
> > + .VActive = 600,
> > + .VBlanking = 28,
> > + .VSyncOffset = 1,
> > + .VSyncWidth = 3,
> > + .Flags = 0x00000000,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + },
> > + {
> > + // 1024x768 @ 60Hz
> > + .Reserved1 = 0,
> > + .Reserved2 = 2,
> > + .PixelClock = 6500,
> > + .HActive = 1024,
> > + .HBlanking = 320,
> > + .HSyncOffset = 24,
> > + .HSyncWidth = 136,
> > + .VActive = 768,
> > + .VBlanking = 38,
> > + .VSyncOffset = 3,
> > + .VSyncWidth = 6,
> > + .Flags = 0x00000300,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + },
> > + {
> > + // 1360x768 @ 60Hz
> > + .Reserved1 = 0,
> > + .Reserved2 = 2,
> > + .PixelClock = 8550,
> > + .HActive = 1360,
> > + .HBlanking = 432,
> > + .HSyncOffset = 64,
> > + .HSyncWidth = 112,
> > + .VActive = 768,
> > + .VBlanking = 27,
> > + .VSyncOffset = 3,
> > + .VSyncWidth = 6,
> > + .Flags = 0x00000000,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + },
> > + {
> > + // 1280x960 @ 60Hz
> > + .Reserved1 = 0,
> > + .Reserved2 = 2,
> > + .PixelClock = 10800,
> > + .HActive = 1280,
> > + .HBlanking = 520,
> > + .HSyncOffset = 96,
> > + .HSyncWidth = 112,
> > + .VActive = 960,
> > + .VBlanking = 40,
> > + .VSyncOffset = 1,
> > + .VSyncWidth = 3,
> > + .Flags = 0x00000000,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + },
> > + {
> > + // 1280x1024 @ 60Hz
> > + .Reserved1 = 0,
> > + .Reserved2 = 2,
> > + .PixelClock = 10800,
> > + .HActive = 1280,
> > + .HBlanking = 408,
> > + .HSyncOffset = 48,
> > + .HSyncWidth = 112,
> > + .VActive = 1024,
> > + .VBlanking = 42,
> > + .VSyncOffset = 1,
> > + .VSyncWidth = 3,
> > + .Flags = 0x00000000,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + },
> > + {
> > + // 1600x900 @ 60Hz
> > + .Reserved2 = 2,
> > + .PixelClock = 11825,
> > + .HActive = 1600,
> > + .HBlanking = 512,
> > + .HSyncOffset = 88,
> > + .HSyncWidth = 168,
> > + .VActive = 900,
> > + .VBlanking = 34,
> > + .VSyncOffset = 3,
> > + .VSyncWidth = 5,
> > + .Flags = 0x00000500,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + },
> > + {
> > + // 1400x1050 @ 60Hz
> > + .Reserved1 = 0,
> > + .Reserved2 = 2,
> > + .PixelClock = 12175,
> > + .HActive = 1400,
> > + .HBlanking = 464,
> > + .HSyncOffset = 88,
> > + .HSyncWidth = 144,
> > + .VActive = 1050,
> > + .VBlanking = 39,
> > + .VSyncOffset = 3,
> > + .VSyncWidth = 4,
> > + .Flags = 0x00000100,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + },
> > + {
> > + // 1600x1200 @ 60Hz
> > + .Reserved1 = 0,
> > + .Reserved2 = 2,
> > + .PixelClock = 16200,
> > + .HActive = 1600,
> > + .HBlanking = 560,
> > + .HSyncOffset = 64,
> > + .HSyncWidth = 192,
> > + .VActive = 1200,
> > + .VBlanking = 50,
> > + .VSyncOffset = 1,
> > + .VSyncWidth = 3,
> > + .Flags = 0x00000000,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + },
> > + {
> > + // 1920 x 1080
> > + .Reserved2 = 2,
> > + .PixelClock = 14850,
> > + .HActive = 1920,
> > + .HBlanking = 280,
> > + .HSyncOffset = 88,
> > + .HSyncWidth = 44,
> > + .VActive = 1080,
> > + .VBlanking = 45,
> > + .VSyncOffset = 4,
> > + .VSyncWidth = 5,
> > + .Flags = 0x00000000,
> > + .Accumulate = 1,
> > + .Reserved3 = 0,
> > + .Reserved4 = 0,
> > + .Reserved5 = 0x00000000,
> > + .Vic = 0,
> > + .ActiveFormat = 0,
> > + }
> > +};
> > +
> > +STATIC CONST UINT32 NumSupportedVideoModes = (sizeof (ModeData) / sizeof (struct VideoMode));
> > +
> > +/**
> > +Find the number of pre-calculated video modes that we support.
> > +
> > +@retval Number of modes.
> > +
> > +**/
> > +UINT32 DlVideoModeGetNumSupportedVideoModes ()
> > +{
> > + return NumSupportedVideoModes;
> > +}
> > +
> > +/**
> > +Get one of the pre-calculated video modes
> > +
> > +@param index The video mode that we want.
> > +
> > +@retval NULL The index was out of range.
> > +
> > +**/
> > +CONST struct VideoMode *DlVideoModeGetSupportedVideoMode (
> > + UINT32 Index
> > + )
> > +{
> > + if (Index >= NumSupportedVideoModes) {
> > + return NULL;
> > + }
> > + return &ModeData[Index];
> > +}
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> > new file mode 100644
> > index 000000000000..955331ba6076
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> > @@ -0,0 +1,61 @@
> > +#/** @file
> > +#
> > +# Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > +#
> > +# SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +#**/
> > +
> > +[Defines]
> > + PLATFORM_NAME = DisplayLinkPkg
> > + PLATFORM_GUID = ad3b37b0-f798-4f97-9b3f-0c6f43d7c993
> > + PLATFORM_VERSION = 0.1
> > + DSC_SPECIFICATION = 0x0001001C
> > + OUTPUT_DIRECTORY = Build/DisplayLink
> > + SUPPORTED_ARCHITECTURES = X64|IA32|AARCH64|ARM
> > + BUILD_TARGETS = DEBUG|RELEASE|NOOPT
> > + SKUID_IDENTIFIER = DEFAULT
> > +
> > +[LibraryClasses]
> > + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
> > + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> > + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
> > + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
> > + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> > + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> > + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
> > + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
> > + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
> > + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
> > + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
> > + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
> > + UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
> > +
> > +[LibraryClasses.common.UEFI_DRIVER]
> > + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
> > +
> > +[LibraryClasses.AARCH64]
> > + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> > + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> > +
> > +[LibraryClasses.ARM]
> > + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> > + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> > +
> > +[PcdsFixedAtBuild]
> > +!ifdef $(DEBUG_ENABLE_OUTPUT)
> > + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x3f
> > + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80080043 # Flags to control amount of debug output - see https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging<https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging>
> > + gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x07
> > +!endif
> > +
> > +[Components]
> > + Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > +
> > +[BuildOptions]
> > + *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES -D INF_DRIVER_VERSION=$(INF_DRIVER_VERSION)
> > + GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG
> > + MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
> > +!ifdef $(COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE)
> > + *_*_*_CC_FLAGS = -D COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > +!endif
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> > new file mode 100644
> > index 000000000000..40061f1eb46d
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> > @@ -0,0 +1,77 @@
> > +# DISPLAYLINK DRIVERS
> > +This package contains a GOP driver for Universal USB-connected docks containing the
> > +DisplayLink DL-6xxx chip or newer.
> > +
> > +[DisplayLink Website](http://www.displaylink.com<http://www.displaylink.com>)
> > +
> > +[Products](https://www.displaylink.com/products/universal-docking-stations<https://www.displaylink.com/products/universal-docking-stations>)
> > +
> > +# INDEX
> > +
> > +* [Resolutions Supported](#resolutions-supported)
> > +* [Frame rates](#frame-rates)
> > +* [Multiple monitor outputs](#multiple-monitor-outputs)
> > +* [Multiple DisplayLink devices](#multiple-displaylink-devices)
> > +* [Behaviour with no monitor connected](#behaviour-with-no-monitor-connected)
> > +
> > +# Resolutions supported
> > +
> > +The driver supports the following resolutions:
> > +
> > +640 x 480 @ 60Hz
> > +
> > +800 x 600 @ 60Hz
> > +
> > +1024x768 @ 60Hz
> > +
> > +1360x768 @ 60Hz
> > +
> > +1280x960 @ 60Hz
> > +
> > +1280x1024 @ 60Hz
> > +
> > +1600x900 @ 60Hz
> > +
> > +1400x1050 @ 60Hz
> > +
> > +1600x1200 @ 60Hz
> > +
> > +1920x1080 @ 60Hz
> > +
> > +
> > +Note that the list of resolutions advertised by the driver may be smaller than
> > +this if a connected monitor does not support a particular resolution. The driver
> > +interrogates connected monitors to see which modes can be supported.It<http://supported.It> is the
> > +responsibility of the BIOS to select the video mode from this list which most
> > +closely matches its requirements. In some cases this may lead to the BIOS
> > +scaling its display.
> > +
> > +# Frame rates
> > +
> > +The driver is limited to a maximum of ten frames per second. Some slower systems
> > +at higher screen resolutions may perform at a lower rate than this.
> > +
> > +# Multiple monitor outputs
> > +
> > +If multiple monitors are connected to the DisplayLinkdevice, the display will be
> > +duplicated (cloned) across all outputs at the same resolution. The resolution
> > +used will be limited by the capability of the monitor with the
> > +lowest specification.
> > +
> > +# Multiple DisplayLink devices
> > +
> > +The driver will support the connection of multiple DisplayLink devices. The
> > +exact behaviourof the system with multiple devices connected is defined by the
> > +rest of the BIOS; usually, the BIOS causes the displays to be duplicated
> > +(cloned) across all devices. Note that the system performance and frame rate
> > +will be affected by the number of DisplayLink devices connected.
> > +
> > +# Behaviour with no monitor connected
> > +
> > +The driver uses the EDID (Extended Display Identification Data) protocol to
> > +detect the list of resolutions that a monitor will support.In<http://support.In> some monitors this
> > +may take some time, and occasionally no EDID information will be returned at
> > +all. In this case the driver will not be able to detect that there is a monitor
> > +connected. To improve the user experience in these cases, the driver will behave
> > +as if there is a monitor connected, and will fall back to presenting the full
> > +range of supported resolutions to the BIOS.
> > diff --git a/Maintainers.txt b/Maintainers.txt
> > index 876ae5612ad8..47aac133abb1 100644
> > --- a/Maintainers.txt
> > +++ b/Maintainers.txt
> > @@ -47,6 +47,11 @@ Drivers/OptionRomPkg
> > W: https://github.com/tianocore/tianocore.github.io/wiki/OptionRomPkg<https://github.com/tianocore/tianocore.github.io/wiki/OptionRomPkg>
> > M: Ray Ni <ray.ni@intel.com>
> >
> > +Drivers/DisplayLink
> > +M: Leif Lindholm <leif.lindholm@linaro.org>
> > +M: Ard Bieshuevel <ard.bieshuevel@linaro.org>
> > +R: Andy Hayes <andy.hayes@displaylink.com>
> > +
> > Platform
> > M: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > M: Leif Lindholm <leif.lindholm@linaro.org>
> > --
> > 2.20.1
> >

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips
  2019-08-30 15:27   ` [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips Leif Lindholm
  2019-09-09  8:06     ` [External] " Andy Hayes
@ 2019-09-13  7:57     ` Ni, Ray
  2019-09-19 16:42       ` Leif Lindholm
  2019-10-04 19:54     ` [edk2-devel] " Laszlo Ersek
  2 siblings, 1 reply; 6+ messages in thread
From: Ni, Ray @ 2019-09-13  7:57 UTC (permalink / raw)
  To: Leif Lindholm, Andy Hayes, Kinney, Michael D; +Cc: devel@edk2.groups.io

Leif, Mike,
I have two general comments regarding the edk2-platforms/Drivers directory:
1. should we change it to "Driver" because the other two don't carry a "s"?
2. Where should OptionRomPkg go? "Platform" and "Silicon" both contains vendor sub-directories. Now "Driver" contains vendor sub-directory as well. But OptionRomPkg is in the root of "Driver". Do we need to put it as a future task to separate the OptionRomPkg according to vendors? or create "Driver/Intel" and put OptionRomPkg there?

(sorry I thought I sent the mail long time ago.)

Thanks,
Ray

> -----Original Message-----
> From: Leif Lindholm <leif.lindholm@linaro.org>
> Sent: Friday, August 30, 2019 8:27 AM
> To: Andy Hayes <andy.hayes@displaylink.com>
> Cc: devel@edk2.groups.io; Kinney, Michael D <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>
> Subject: Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on
> DisplayLink chips
> 
> Hi Andy,
> 
> This looks fine to me - all my feedback has been addressed.
> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
> 
> Ray - did you have any comments on this, or can I go ahead and commit?
> 
> Best Regards,
> 
> Leif
> 
> On Mon, Aug 19, 2019 at 02:32:00PM +0100, Andy Hayes wrote:
> > Cc: Leif Lindholm <leif.lindholm@linaro.org>
> > Cc: Michael D Kinney <michael.d.kinney@intel.com>
> > Signed-off-by: Andy Hayes <andy.hayes@displaylink.com>
> > ---
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c |  137 +++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c        |  235 +++++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf  |   65 ++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c                 |  598 +++++++++++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h                 |  129 +++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c                  |  578 +++++++++++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c       |  145 +++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h       |  109 ++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c       | 1082 ++++++++++++++++++++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h       |  278 +++++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c          |  180 ++++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c           |  254 +++++
> >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc                    |   61 ++
> >  Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md                             |   77 ++
> >  Maintainers.txt                                                          |    5 +
> >  15 files changed, 3933 insertions(+)
> >
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> > new file mode 100644
> > index 000000000000..4bfadd770b81
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> > @@ -0,0 +1,137 @@
> > +/** @file CapabilityDescriptor.c
> > + * @brief Definitions for reading USB capability descriptor DisplayLink dock
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +#include "UsbDescriptors.h"
> > +
> > +/**
> > + * Check that the Capability Descriptor is valid and hasn't been tampered with.
> > + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> > + * @param Length
> > + * @param out
> > + * @return
> > + */
> > +STATIC EFI_STATUS
> > +ValidateHeader (
> > +    CONST IN VOID* Data,
> > +    IN UINTN Length,
> > +    OUT CONST VendorDescriptorGeneric** Out
> > +    )
> > +{
> > +  if (Length < sizeof (VendorDescriptorGeneric)) {
> > +    DEBUG ((DEBUG_ERROR, "Data too short (%d bytes) for capability descriptor header section\n", Length));
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +  CONST VendorDescriptorGeneric* Desc = (VendorDescriptorGeneric*)Data;
> > +  if (Desc->Length > Length) {
> > +    DEBUG ((DEBUG_ERROR, "Capability descriptor: Descriptor (%d bytes) exceeds buffer (%d bytes)\n",
> > +          Length, Desc->Length));
> > +    return EFI_BUFFER_TOO_SMALL;
> > +  }
> > +  if (Desc->Type != DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY) {
> > +    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid type (0x%08x)\n", Desc->Type));
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +  if (Desc->CapabilityVersion != 1) {
> > +    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid version (%d)\n", Desc->CapabilityVersion));
> > +    return EFI_INCOMPATIBLE_VERSION;
> > +  }
> > +  // Capability length must fit within remaining space
> > +  if (Desc->CapabilityLength > (Desc->Length - (sizeof (Desc->Length) + sizeof (Desc->Type)))) {
> > +    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid CapabilityLength (%d)\n", Desc->CapabilityLength));
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +  *Out = Desc;
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +
> > +/**
> > + * Check that the connected DisplayLink device supports the functionality that this driver requires, e.g. video formats
> > + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> > + * @param Length
> > + * @param Output
> > + * @return
> > + */
> > +EFI_STATUS
> > +UsbDisplayLinkParseCapabilitiesDescriptor (
> > +    CONST IN VOID* Data,
> > +    IN UINTN Length,
> > +    OUT VendorDescriptor* Output
> > +    )
> > +{
> > +  CONST VendorDescriptorGeneric* Desc;
> > +  EFI_STATUS Status;
> > +
> > +  Desc = NULL;
> > +  Status = ValidateHeader (Data, Length, &Desc);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  // Default capabilities
> > +  Output->Capabilities1 = 0;
> > +
> > +  CONST UINTN CapsHeaderLength = sizeof (Desc->CapabilityVersion) + sizeof (Desc->CapabilityLength);
> > +  ASSERT (CapsHeaderLength < MAX_UINT8);
> > +
> > +  UINTN DataRemaining;
> > +  UINTN Offset;
> > +
> > +  DataRemaining = Desc->CapabilityLength - CapsHeaderLength;
> > +  Offset = 0;
> > +
> > +  while (DataRemaining >= sizeof (DescriptorKLV)) {
> > +    CONST DescriptorKLV* KeyHeader = (CONST DescriptorKLV*)(Desc->Klv + Offset);
> > +    CONST UINTN KeyValueSize = sizeof (DescriptorKLV) + KeyHeader->Length;
> > +    if (KeyValueSize > DataRemaining) {
> > +      DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid value Length (%d)\n", Desc->CapabilityLength));
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    switch (KeyHeader->Key) {
> > +      case CAPABILITIES1_KEY: {
> > +        if (KeyHeader->Length != CAPABILITIES1_LENGTH) {
> > +          DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid length (%d) for Capabilities 1\n", KeyHeader->Length));
> > +          return EFI_INVALID_PARAMETER;
> > +        }
> > +        Output->Capabilities1 = *(UINT32*)KeyHeader->Value;
> > +        break;
> > +      default:
> > +        // Ignore unknown types
> > +        break;
> > +      }
> > +    }
> > +    DataRemaining -= KeyValueSize;
> > +    Offset += KeyValueSize;
> > +  }
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +
> > +/**
> > + * Check that the DisplayLink device supports the basic level of functionality to display GOP pixels.
> > + * @param Descriptor The USB descriptor received from the DisplayLink device
> > + * @return True we can bind, False we can't
> > + */
> > +BOOLEAN
> > +UsbDisplayLinkCapabilitiesSufficientToBind (
> > +    CONST IN VendorDescriptor* Descriptor
> > +    )
> > +{
> > +  BOOLEAN Sufficient;
> > +  Sufficient = (BOOLEAN)(Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL);
> > +
> > +  if (Sufficient == FALSE) {
> > +    DEBUG ((DEBUG_ERROR, "DisplayLink device does not report support for base capabilites - reports x%x, required x%x\n",
> Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL));
> > +  }
> > +  return Sufficient;
> > +}
> > +
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> > new file mode 100644
> > index 000000000000..74498f339eb7
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> > @@ -0,0 +1,235 @@
> > +/**
> > + * @file ComponentName.c
> > + * @brief UEFI Component Name protocol implementation for USB DisplayLink driver.
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkComponentNameGetDriverName (
> > +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> > +  IN  CHAR8                        *Language,
> > +  OUT CHAR16                       **DriverName
> > +);
> > +
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkComponentNameGetControllerName (
> > +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> > +  IN  EFI_HANDLE                                      ControllerHandle,
> > +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> > +  IN  CHAR8                                           *Language,
> > +  OUT CHAR16                                          **ControllerName
> > +);
> > +
> > +
> > +//
> > +// EFI Component Name Protocol
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  mUsbDisplayLinkComponentName = {
> > +  UsbDisplayLinkComponentNameGetDriverName,
> > +  UsbDisplayLinkComponentNameGetControllerName,
> > +  "eng"
> > +};
> > +
> > +//
> > +// EFI Component Name 2 Protocol
> > +//
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplayLinkComponentName2 = {
> > +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbDisplayLinkComponentNameGetDriverName,
> > +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbDisplayLinkComponentNameGetControllerName,
> > +  "en"
> > +};
> > +
> > +
> > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbDisplayLinkDriverNameTable[] = {
> > +  { (CHAR8*)"eng;en", (CHAR16*)L"DisplayLink USB GOP Driver" },
> > +  { (CHAR8*)NULL , (CHAR16*)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                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> > +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> > +  @param  Language              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            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
> > +UsbDisplayLinkComponentNameGetDriverName (
> > +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> > +  IN  CHAR8                        *Language,
> > +  OUT CHAR16                       **DriverName
> > +  )
> > +{
> > +  return LookupUnicodeString2 (
> > +           Language,
> > +           This->SupportedLanguages,
> > +           mUsbDisplayLinkDriverNameTable,
> > +           DriverName,
> > +           (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> > +}
> > +
> > +/**
> > +  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                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> > +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> > +  @param  ControllerHandle      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           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              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        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 not a valid EFI_HANDLE.
> > +  @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
> > +UsbDisplayLinkComponentNameGetControllerName (
> > +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> > +  IN  EFI_HANDLE                                      ControllerHandle,
> > +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> > +  IN  CHAR8                                           *Language,
> > +  OUT CHAR16                                          **ControllerName
> > +  )
> > +{
> > +  EFI_STATUS                   Status;
> > +  USB_DISPLAYLINK_DEV          *UsbDisplayLinkDev;
> > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
> > +  EFI_USB_IO_PROTOCOL          *UsbIoProtocol;
> > +
> > +  //
> > +  // This is a device driver, so ChildHandle must be NULL.
> > +  //
> > +  if (ChildHandle != NULL) {
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  //
> > +  // Check Controller's handle
> > +  //
> > +  Status = gBS->OpenProtocol  (
> > +                  ControllerHandle,
> > +                  &gEfiUsbIoProtocolGuid,
> > +                  (VOID **) &UsbIoProtocol,
> > +                  gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> > +                  ControllerHandle,
> > +                  EFI_OPEN_PROTOCOL_BY_DRIVER);
> > +
> > +  if (!EFI_ERROR (Status)) {
> > +    gBS->CloseProtocol  (
> > +           ControllerHandle,
> > +           &gEfiUsbIoProtocolGuid,
> > +           gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> > +           ControllerHandle);
> > +
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  if (Status != EFI_ALREADY_STARTED) {
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +  //
> > +  // Get the device context
> > +  //
> > +  Status = gBS->OpenProtocol (
> > +                  ControllerHandle,
> > +                  &gEfiGraphicsOutputProtocolGuid,
> > +                  (VOID**)&GraphicsOutputProtocol,
> > +                  gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> > +                  ControllerHandle,
> > +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> > +
> > +  return LookupUnicodeString2 (
> > +           Language,
> > +           This->SupportedLanguages,
> > +           UsbDisplayLinkDev->ControllerNameTable,
> > +           ControllerName,
> > +           (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> > +}
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > new file mode 100644
> > index 000000000000..0f458fedcc88
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > @@ -0,0 +1,65 @@
> > +#/** @file
> > +# USB DisplayLink driver that implements blt and EDID commands
> > +#
> > +# USB DisplayLink driver consumes I/O Protocol and Device Path Protocol, and produces
> > +# Graphics Output Protocol on DisplayLink devices.
> > +# 1. DisplayLink reference
> > +# 2. UEFI Specification, v2.1
> > +#
> > +#  Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > +#
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +#**/
> > +
> > +
> > +[Defines]
> > +  INF_VERSION                    = 0x0001001B
> > +  BASE_NAME                      = DisplayLinkGop
> > +  FILE_GUID                      = 2D2E62AA-9ECF-43b7-8219-94E7FC713DFF
> > +  MODULE_TYPE                    = UEFI_DRIVER
> > +  VERSION_STRING                 = 1.0
> > +  ENTRY_POINT                    = UsbDisplayLinkDriverBindingEntryPoint
> > +  UNLOAD_IMAGE                   = UsbDisplayLinkDriverCombinedGopUnload
> > +  INF_DRIVER_VERSION             = 0x00000001
> > +
> > +[Sources]
> > +  CapabilityDescriptor.c
> > +  ComponentName.c
> > +  Edid.c
> > +  Edid.h
> > +  Gop.c
> > +  UsbDescriptors.c
> > +  UsbDescriptors.h
> > +  UsbDisplayLink.c
> > +  UsbDisplayLink.h
> > +  UsbTransfer.c
> > +  VideoModes.c
> > +
> > +[Packages]
> > +  MdePkg/MdePkg.dec
> > +
> > +[LibraryClasses]
> > +  BaseMemoryLib
> > +  DebugLib
> > +  MemoryAllocationLib
> > +  ReportStatusCodeLib
> > +  UefiBootServicesTableLib
> > +  UefiDriverEntryPoint
> > +  UefiLib
> > +  UefiUsbLib
> > +
> > +[Protocols]
> > +  gEfiUsbIoProtocolGuid                         ## TO_START
> > +  gEfiEdidActiveProtocolGuid                    # PROTOCOL BY_START
> > +  gEfiEdidDiscoveredProtocolGuid                # PROTOCOL BY_START
> > +  gEfiEdidOverrideProtocolGuid                  # PROTOCOL TO_START
> > +  gEfiHiiDatabaseProtocolGuid
> > +  gEfiHiiFontProtocolGuid
> > +
> > +[Guids]
> > +  gEfiEventExitBootServicesGuid
> > +  gEfiGlobalVariableGuid
> > +
> > +[Pcd]
> > +  gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize     ## CONSUMES
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> > new file mode 100644
> > index 000000000000..21f4b7d9c736
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> > @@ -0,0 +1,598 @@
> > +/** @file Edid.c
> > + * @brief Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +#include "Edid.h"
> > +
> > +CONST UINT8 ExpectedEdidHeader[EDID_HEADER_SIZE] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
> > +
> > +//
> > +// Standard timing defined by VESA EDID
> > +//
> > +CONST EDID_TIMING EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES][8] = {
> > +  //
> > +  // Established Timing I
> > +  //
> > +  {
> > +    { 800, 600, 60 },
> > +    { 800, 600, 56 },
> > +    { 640, 480, 75 },
> > +    { 640, 480, 72 },
> > +    { 640, 480, 67 },
> > +    { 640, 480, 60 },
> > +    { 720, 400, 88 },
> > +    { 720, 400, 70 },
> > +  },
> > +  {
> > +    //
> > +    // Established Timing II
> > +    //
> > +    { 1280, 1024, 75 },
> > +    { 1024,  768, 75 },
> > +    { 1024,  768, 70 },
> > +    { 1024,  768, 60 },
> > +    { 1024,  768, 87 },
> > +    { 832,   624, 75 },
> > +    { 800,   600, 75 },
> > +    { 800,   600, 72 },
> > +  },
> > +  //
> > +  // Established Timing III
> > +  //
> > +  {
> > +    { 1152, 870, 75 },
> > +    { 0, 0, 0 },
> > +    { 0, 0, 0 },
> > +    { 0, 0, 0 },
> > +    { 0, 0, 0 },
> > +    { 0, 0, 0 },
> > +    { 0, 0, 0 },
> > +    { 0, 0, 0 },
> > +  }
> > +};
> > +
> > +/**
> > + * Requests the monitor EDID data from the connected DisplayLink device
> > + * @param UsbDisplayLinkDev
> > + * @param EdidDataBlock
> > + * @param EdidSize
> > + * @retval EFI_DEVICE_ERROR - No EDID received, or EDID is corrupted
> > + * @retval EFI_OUT_OF_RESOURCES - Cannot allocate memory
> > + * @retval EFI_SUCCESS
> > + *
> > + */
> > +STATIC EFI_STATUS
> > +ReadEdidData (
> > +  IN USB_DISPLAYLINK_DEV      *UsbDisplayLinkDev,
> > +  OUT UINT8                    **EdidDataBlock,
> > +  OUT UINTN                    *EdidSize
> > +)
> > +{
> > +  EFI_STATUS Status;
> > +
> > +  UINT8 EdidDataRead[EDID_BLOCK_SIZE];
> > +  UINT8 *EdidData = EdidDataRead;
> > +  UINT8* ValidEdid;
> > +
> > +  Status = DlUsbSendControlReadMessage (UsbDisplayLinkDev, GET_OUTPUT_EDID, 0, EdidDataRead, sizeof (EdidDataRead));
> > +
> > +  if (EFI_ERROR (Status) || (EdidData[0] != 0)) {
> > +    DEBUG ((DEBUG_ERROR, "No monitor EDID received from DisplayLink device - System error %r, EDID error %d. Monitor
> connected correctly?\n", Status, EdidData[0]));
> > +    return EFI_DEVICE_ERROR;
> > +  } else {
> > +    //
> > +    // Search for the EDID signature
> > +    //
> > +    ValidEdid = &EdidData[0];
> > +    CONST UINT64 Signature = 0x00ffffffffffff00ull;
> > +    if (CompareMem (ValidEdid, &Signature, 8) != 0) {
> > +      //
> > +      // No EDID signature found
> > +      //
> > +      DEBUG ((DEBUG_ERROR, "Monitor EDID received from DisplayLink device did not have a valid signature - corrupted?\n"));
> > +      Status = EFI_DEVICE_ERROR;
> > +      return Status;
> > +    }
> > +  }
> > +
> > +  *EdidDataBlock = (UINT8*)AllocateCopyPool (
> > +    EDID_BLOCK_SIZE,
> > +    ValidEdid);
> > +
> > +  if (*EdidDataBlock == NULL) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  //
> > +  // Currently only support EDID 1.x
> > +  //
> > +  *EdidSize = EDID_BLOCK_SIZE;
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +
> > +/**
> > +Calculates the mod256 checksum of the EDID and compares it with the one supplied at the end of the EDID
> > +@param  EDID        Pointer to the 128-byte EDID
> > +@retval TRUE        The EDID checksum is correct
> > +**/
> > +BOOLEAN
> > +IsEdidChecksumCorrect (
> > +    CONST VOID *EDID
> > +    )
> > +{
> > +  CONST UINT8 EdidChecksum = ((UINT8 *)EDID)[EDID_BLOCK_SIZE - 1];
> > +  UINT8 CalculatedChecksum;
> > +
> > +  CalculatedChecksum = 0;
> > +
> > +  UINTN i;
> > +  for (i = 0; i < EDID_BLOCK_SIZE - 1; i++) {
> > +    CalculatedChecksum += ((UINT8 *)EDID)[i];
> > +  }
> > +  CalculatedChecksum = 0 - CalculatedChecksum;
> > +
> > +  return (CalculatedChecksum == EdidChecksum);
> > +}
> > +
> > +/**
> > +Check if a particular video mode is in the Established Timings section of the EDID.
> > +
> > +@param  EDID        Pointer to the 128-byte EDID
> > +@param  hRes        Horizontal resolution
> > +@param  vRes        Vertical resolution
> > +@param  refresh     Refresh rate
> > +@retval TRUE        The requested mode is present in the Established Timings section
> > +
> > +**/
> > +STATIC BOOLEAN
> > +IsModeInEstablishedTimings (
> > +    IN CONST VOID *EDID,
> > +    IN UINT16 HRes,
> > +    IN UINT16 VRes,
> > +    IN UINT16 Refresh
> > +    )
> > +{
> > +  CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> > +  BOOLEAN ModeSupported;
> > +
> > +  ModeSupported = FALSE;
> > +
> > +  int EstByteNum;
> > +  int BitNum;
> > +  for (EstByteNum = 0; EstByteNum < EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES; EstByteNum++) {
> > +    for (BitNum = 0; BitNum < 8; BitNum++) {
> > +      if (pEDID->EstablishedTimings[EstByteNum] & (1 << BitNum)) { // The bit is set in the established timings of the EDID
> > +
> > +        if ((EstablishedTimings[EstByteNum][BitNum].HRes == HRes) && // The passed-in resolution matches the resolution
> represented by the set bit
> > +          (EstablishedTimings[EstByteNum][BitNum].VRes == VRes) &&
> > +          (EstablishedTimings[EstByteNum][BitNum].Refresh == Refresh)) {
> > +
> > +          ModeSupported = TRUE;
> > +          break;
> > +        }
> > +      }
> > +    }
> > +    if (ModeSupported == TRUE) {
> > +      break;
> > +    }
> > +  }
> > +  return ModeSupported;
> > +}
> > +
> > +/**
> > +Extract the resolutions and refresh rate from one of the entries in the Standard Timings section of the EDID.
> > +
> > +@param  EDID          Pointer to the 128-byte EDID
> > +@param  timingNumber  The entry that we want to extract
> > +@param  hRes          Output - Horizontal resolution
> > +@param  vRes          Output - Vertical resolution
> > +@param  refresh       Output - Refresh rate
> > +@retval TRUE          The requested Standard Timings entry contains valid data
> > +
> > +**/
> > +STATIC BOOLEAN ReadStandardTiming (
> > +  CONST VOID *EDID,
> > +  IN UINT8 TimingNumber,
> > +  OUT UINT16 *HRes,
> > +  OUT UINT16 *VRes,
> > +  OUT UINT8 *Refresh)
> > +{
> > +  CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> > +
> > +  // See section 3.9.1 of the VESA EDID spec
> > +
> > +  if (((pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels) == 0x01) &&
> > +    (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh) == 0x01) {
> > +    *HRes = 0;
> > +    *VRes = 0;
> > +    *Refresh = 0;
> > +    return FALSE;
> > +  }
> > +  *HRes = (pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels + 31) * 8;
> > +
> > +  UINT8 AspectRatio;
> > +  AspectRatio = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh >> 6) & 0x3;
> > +
> > +  switch (AspectRatio) {
> > +  case 0: *VRes = (*HRes * 10) / 16;
> > +    break;
> > +  case 1: *VRes = (*HRes * 3) / 4;
> > +    break;
> > +  case 2: *VRes = (*HRes * 4) / 5;
> > +    break;
> > +  case 3: *VRes = (*HRes * 9) / 16;
> > +    break;
> > +  default: break;
> > +  }
> > +
> > +  // WORKAROUND - 1360x768 is not a perfect aspect ratio
> > +  if ((*HRes == 1360) && (*VRes == 765)) {
> > +    *VRes = 768;
> > +  }
> > +
> > +  *Refresh = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh & 0x1F) + 60;
> > +
> > +  return TRUE;
> > +}
> > +
> > +/**
> > +Extract the resolutions and refresh rate from one of the entries in the Detailed Timings section of the EDID.
> > +
> > +@param  EDID          Pointer to the 128-byte EDID
> > +@param  timingNumber  The entry that we want to extract
> > +@param  videoMode     Output - Filled in with details from the detailed timing
> > +@retval TRUE          The requested Detailed Timings entry contains valid data
> > +
> > +**/
> > +STATIC BOOLEAN
> > +ReadDetailedTiming (
> > +  IN CONST VOID *EDID,
> > +  IN UINT8 TimingNumber,
> > +  OUT struct VideoMode *VideoMode
> > +  )
> > +{
> > +  if (TimingNumber >= EDID_NUMBER_OF_DETAILED_TIMINGS) {
> > +    return FALSE;
> > +  }
> > +
> > +  UINT16 NumValidDetailedTimingsFound;
> > +  NumValidDetailedTimingsFound = 0;
> > +
> > +  // Spin through the detailed timings until we find a valid one - then check if this has the index that we want
> > +  int BlockNumber;
> > +  for (BlockNumber = 0; BlockNumber < EDID_NUMBER_OF_DETAILED_TIMINGS; BlockNumber++) {
> > +    CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> > +    CONST struct DetailedTimingIdentification *pTiming = &pEDID->detailedTimingDescriptions[BlockNumber];
> > +
> > +    if (((BlockNumber == 0) && (pTiming->PixelClock == EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK)) ||
> > +      (pTiming->PixelClock == 0)) {
> > +      // This is not a valid detailed timing descriptor
> > +      continue;
> > +    }
> > +
> > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesSyncSchemeMask) != EdidDetailedTimingsFeaturesSyncSchemeMask)
> {
> > +      DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported sync scheme found - not processing.\n"));
> > +      continue;
> > +    }
> > +
> > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesStereoModeMask) != 0) {
> > +      DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported stereo mode found - not processing.\n"));
> > +      continue;
> > +    }
> > +
> > +    // We've found a supported detailed timing - now see if this is the requested one
> > +    if (TimingNumber != NumValidDetailedTimingsFound) {
> > +      NumValidDetailedTimingsFound++;
> > +      continue;
> > +    }
> > +
> > +    ZeroMem ((VOID *)VideoMode, sizeof (struct VideoMode));
> > +
> > +    // Bit manipulations copied from host software class EDIDTimingDescriptor
> > +
> > +    VideoMode->PixelClock = (UINT16)pTiming->PixelClock;
> > +    VideoMode->HActive = pTiming->HActiveLo + ((pTiming->HActiveHiBlankingHi & 0xF0) << 4);
> > +    VideoMode->VActive = pTiming->VActiveLo + ((pTiming->VActiveHiBlankingHi & 0xF0) << 4);
> > +
> > +    VideoMode->HBlanking = pTiming->HBlankingLo + ((pTiming->HActiveHiBlankingHi & 0x0F) << 8);
> > +    VideoMode->VBlanking = pTiming->VBlankingLo + ((pTiming->VActiveHiBlankingHi & 0x0F) << 8);
> > +
> > +    VideoMode->HSyncOffset = pTiming->HSyncOffsetLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi
> & 0xC0) << 2);  // Horizontal Front Porch
> > +    VideoMode->HSyncWidth = pTiming->HSyncWidthLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi
> & 0x30) << 4);
> > +
> > +    VideoMode->VSyncOffset = ((pTiming->VSyncOffsetLoSyncWidthLo & 0xF0) >> 4) + ((pTiming-
> >HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x0C) << 2); // Vertical Front Porch
> > +    VideoMode->VSyncWidth = (pTiming->VSyncOffsetLoSyncWidthLo & 0x0F) + ((pTiming-
> >HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x03) << 4);
> > +
> > +    VideoMode->Reserved2 = 2;
> > +    VideoMode->Accumulate = 1;
> > +
> > +    // Horizontal and vertical sync inversions - positive if bit set in descriptor (EDID spec)
> > +    // In the VideoMode, they are negative if the bit is set (NR-110497-TC 4.3.3 0x22 Set Video Mode)
> > +
> > +    // Horizontal sync
> > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesHorizontalSyncPositive) == 0) {
> > +      VideoMode->Flags |= VideoModeFlagsHorizontalSyncInverted;
> > +    }
> > +    // Vertical sync
> > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesVerticalSyncPositive) == 0) {
> > +      VideoMode->Flags |= VideoModeFlagsVerticalSyncInverted;
> > +    }
> > +    // Interlace
> > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesInterlaced) == EdidDetailedTimingsFeaturesInterlaced) {
> > +      VideoMode->Flags |= VideoModeFlagsInterlaced;
> > +    }
> > +
> > +    DEBUG ((DEBUG_INFO, "Read mode %dx%d from detailed timings\n", VideoMode->HActive, VideoMode->VActive));
> > +    return TRUE;
> > +  }
> > +  return FALSE;
> > +}
> > +
> > +/**
> > +Check if a particular video mode is in either the Established or Standard Timings section of the EDID.
> > +
> > +@param  EDID        Pointer to the 128-byte EDID
> > +@param  hRes        Horizontal resolution
> > +@param  vRes        Vertical resolution
> > +@param  refresh     Refresh rate
> > +@retval TRUE        The requested mode is present in the EDID
> > +
> > +**/
> > +STATIC BOOLEAN
> > +IsModeInEdid (
> > +    IN CONST VOID *EDID,
> > +    IN UINT16 HRes,
> > +    IN UINT16 VRes,
> > +    IN UINT16 Refresh
> > +    )
> > +{
> > +  UINT16 EdidHRes;
> > +  UINT16 EdidVRes;
> > +  UINT8 EdidRefresh;
> > +  BOOLEAN ModeSupported;
> > +
> > +  ModeSupported = IsModeInEstablishedTimings (EDID, HRes, VRes, Refresh);
> > +
> > +  if (ModeSupported == FALSE) {
> > +    // Check if the mode is in the Standard Timings section of the EDID
> > +    UINT8 i;
> > +    for (i = 0; i < EDID_NUMBER_OF_STANDARD_TIMINGS; i++) {
> > +      if (TRUE == ReadStandardTiming (EDID, i, &EdidHRes, &EdidVRes, &EdidRefresh)) {
> > +        if ((HRes == EdidHRes) && (VRes == EdidVRes) && (Refresh == EdidRefresh)) {
> > +          ModeSupported = TRUE;
> > +          break;
> > +        }
> > +      }
> > +    }
> > +  }
> > +  return ModeSupported;
> > +}
> > +
> > +/**
> > +Returns the (index)'th entry from the list of pre-calculated video timings that is also present in the EDID,
> > +or, video mode data corresponding to any detailed timings present in the EDID.
> > +
> > +Like QueryVideoMode, finds the number (and contents) of video modes available by repeatedly calling this function
> > +with an increasing index value, until it returns FALSE
> > +@param  index       The caller wants the _index_'th video mode
> > +@param  EDID        Pointer to the 128-byte EDID
> > +@param  edidSize    Size in bytes of the EDID
> > +@param  videoMode   Video timings extracted from the modeData structure
> > +@retval EFI_SUCCESS The requested mode is present in the EDID
> > +@retval EFI_INVALID_PARAMETER The requested mode is not present in the EDID
> > +**/
> > +EFI_STATUS
> > +DlEdidGetSupportedVideoMode (
> > +    IN UINT32 Index,
> > +    IN CONST VOID *EDID,
> > +    IN UINT32 EdidSize,
> > +    OUT CONST struct VideoMode **VideoMode
> > +    )
> > +{
> > +  UINTN SupportedVideoModesFoundInEdid;
> > +  EFI_STATUS Status;
> > +
> > +  SupportedVideoModesFoundInEdid = 0;
> > +  Status = EFI_INVALID_PARAMETER;
> > +
> > +  // If we didn't manage to find an EDID earlier, just use one of the hard-coded video modes
> > +  if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> > +    if (Index >= DlVideoModeGetNumSupportedVideoModes ()) {
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +    else {
> > +      *VideoMode = DlVideoModeGetSupportedVideoMode (Index);
> > +      DEBUG ((DEBUG_WARN, "No monitor EDID loaded - returning mode from default list (%dx%d)\n", (*VideoMode)-
> >HActive, (*VideoMode)->VActive));
> > +      return EFI_SUCCESS;
> > +    }
> > +  }
> > +
> > +  UINT16 ModeNumber;
> > +  for (ModeNumber = 0; ModeNumber < DlVideoModeGetNumSupportedVideoModes (); ModeNumber++) {
> > +
> > +    CONST struct VideoMode *SupportedVideoMode = DlVideoModeGetSupportedVideoMode (ModeNumber);
> > +    ASSERT (SupportedVideoMode);
> > +
> > +    if (IsModeInEdid (EDID, SupportedVideoMode->HActive, SupportedVideoMode->VActive,
> DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE)) {
> > +      if (Index == SupportedVideoModesFoundInEdid) {
> > +        *VideoMode = SupportedVideoMode;
> > +        Status = EFI_SUCCESS;
> > +        break;
> > +      }
> > +      SupportedVideoModesFoundInEdid++;
> > +    }
> > +  }
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    // Have a look in the detailed timings
> > +    UINTN DetailedTimingNumber;
> > +    STATIC struct VideoMode TmpVideoMode;
> > +    DetailedTimingNumber = Index - SupportedVideoModesFoundInEdid;
> > +
> > +    if (DetailedTimingNumber < EDID_NUMBER_OF_DETAILED_TIMINGS) {
> > +      if (ReadDetailedTiming (EDID, (UINT8)DetailedTimingNumber, &TmpVideoMode)) {
> > +        *VideoMode = &TmpVideoMode;
> > +        Status = EFI_SUCCESS;
> > +      }
> > +    }
> > +  }
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > + * Like GetSupportedEdidVideoMode, but will return a fallback fixed mode of 640x480@60Hz
> > + * for index 0 if no suitable modes found in EDID.
> > + * @param index
> > + * @param EDID
> > + * @param edidSize
> > + * @param videoMode
> > + * @return EFI_SUCCESS
> > + */
> > +EFI_STATUS
> > +DlEdidGetSupportedVideoModeWithFallback (
> > +    IN UINT32 Index,
> > +    IN CONST VOID *EDID,
> > +    IN UINT32 EdidSize,
> > +    OUT CONST struct VideoMode **VideoMode
> > +    )
> > +{
> > +  EFI_STATUS Status;
> > +  Status = DlEdidGetSupportedVideoMode (Index, EDID, EdidSize, VideoMode);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    // Special case - if we didn't find any matching video modes in the EDID, fall back to 640x480@60Hz
> > +    if (Index == 0) {
> > +      *VideoMode = DlVideoModeGetSupportedVideoMode (0);
> > +      DEBUG ((DEBUG_WARN, "No video modes supported by driver found in monitor EDID received from DL device - falling
> back to %dx%d\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
> > +      Status = EFI_SUCCESS;
> > +    }
> > +  }
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +Count the number of video modes that we have timing information for that are present in the EDID
> > +@param  EDID        Pointer to the 128-byte EDID
> > +@param  edidSize
> > +@retval             The number of modes in the EDID
> > +
> > +**/
> > +UINT32
> > +DlEdidGetNumSupportedModesInEdid (
> > +    IN CONST VOID *EDID,
> > +    IN UINT32 EdidSize
> > +    )
> > +{
> > +  UINT32 MaxMode;
> > +
> > +  if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> > +    return DlVideoModeGetNumSupportedVideoModes ();
> > +  }
> > +
> > +  for (MaxMode = 0; ; MaxMode++) {
> > +    CONST struct VideoMode *videoMode;
> > +    if (EFI_ERROR (DlEdidGetSupportedVideoMode (MaxMode, EDID, EdidSize, &videoMode))) {
> > +      break;
> > +    }
> > +  }
> > +  DEBUG ((DEBUG_INFO, "Found %d video modes supported by driver in monitor EDID.\n", MaxMode));
> > +  return MaxMode;
> > +}
> > +
> > +
> > +
> > +/**
> > + * Read the EDID from the connected monitor, store it in the local data structure
> > + * @param UsbDisplayLinkDev
> > + * @retval EFI_OUT_OF_RESOURCES - Could not allocate memory
> > + * @retval EFI_SUCCESS
> > + */
> > +EFI_STATUS
> > +DlReadEdid (
> > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > +    )
> > +{
> > +  EFI_STATUS Status;
> > +  BOOLEAN EdidFound;
> > +  EFI_EDID_OVERRIDE_PROTOCOL* EdidOverride;
> > +
> > +  //
> > +  // setup EDID information
> > +  //
> > +  UsbDisplayLinkDev->EdidDiscovered.Edid = (UINT8 *)NULL;
> > +  UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = 0;
> > +
> > +  EdidFound = FALSE;
> > +
> > +  //
> > +  // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
> > +  //
> > +  Status = gBS->LocateProtocol (&gEfiEdidOverrideProtocolGuid, NULL, (VOID**)&EdidOverride);
> > +
> > +  if (!EFI_ERROR (Status)) {
> > +    UINT32 EdidAttributes = 0xff;
> > +    UINTN EdidDataSize = 0;
> > +    UINT8* EdidDataBlock = (UINT8*)NULL;
> > +
> > +    // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
> > +    EdidDataBlock = (UINT8*)AllocatePool (EDID_BLOCK_SIZE * 2);
> > +
> > +    if (NULL == EdidDataBlock) {
> > +      return EFI_OUT_OF_RESOURCES;
> > +    }
> > +
> > +    Status = EdidOverride->GetEdid (
> > +      EdidOverride,
> > +      &UsbDisplayLinkDev->Handle,
> > +      &EdidAttributes,
> > +      &EdidDataSize,
> > +      &EdidDataBlock);
> > +
> > +    if (!EFI_ERROR (Status) && EdidAttributes == 0 && EdidDataSize != 0) {
> > +      UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> > +      UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> > +      EdidFound = TRUE;
> > +    }
> > +    else {
> > +      FreePool (EdidDataBlock);
> > +      EdidDataBlock = NULL;
> > +    }
> > +  }
> > +
> > +  if (EdidFound != TRUE) {
> > +    UINTN EdidDataSize = 0;
> > +    UINT8* EdidDataBlock = (UINT8*)NULL;
> > +
> > +    if (ReadEdidData (UsbDisplayLinkDev, &EdidDataBlock, &EdidDataSize) == EFI_SUCCESS) {
> > +
> > +      if (IsEdidChecksumCorrect (EdidDataBlock)) {
> > +        UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> > +        UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> > +        EdidFound = TRUE;
> > +      } else {
> > +        DEBUG ((DEBUG_WARN, "Monitor EDID received from DisplayLink device had an invalid checksum. Corrupted?\n"));
> > +      }
> > +    }
> > +  }
> > +
> > +  if (EdidFound == FALSE) {
> > +    DEBUG ((DEBUG_WARN, "No valid monitor EDID received from DisplayLink device. Cannot detect resolutions supported by
> monitor.\n"));
> > +  }
> > +
> > +  // Set the EDID active.
> > +  // In an error case this will be set 0/NULL, which flags to the parsing code that there is no EDID.
> > +  UsbDisplayLinkDev->EdidActive.SizeOfEdid = UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid;
> > +  UsbDisplayLinkDev->EdidActive.Edid = UsbDisplayLinkDev->EdidDiscovered.Edid;
> > +
> > +  return EFI_SUCCESS;
> > +}
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> > new file mode 100644
> > index 000000000000..a1b8a0512d1a
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> > @@ -0,0 +1,129 @@
> > +/** @file Edid.h
> > + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> > + * Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#ifndef EDID_H
> > +#define EDID_H
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +#define EDID_HEADER_SIZE                          ((UINTN)8)
> > +#define EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES  ((UINTN)3)
> > +#define EDID_NUMBER_OF_STANDARD_TIMINGS           ((UINTN)8)
> > +#define EDID_NUMBER_OF_DETAILED_TIMINGS           ((UINTN)4)
> > +
> > +
> > +typedef struct {
> > +  UINT16  HRes;
> > +  UINT16  VRes;
> > +  UINT16  Refresh;
> > +} EDID_TIMING;
> > +
> > +
> > +EFI_STATUS
> > +DlEdidGetSupportedVideoMode (
> > +    UINT32 ModeNumber,
> > +    CONST VOID *EDID,
> > +    UINT32 EdidSize,
> > +    CONST struct VideoMode **VideoMode
> > +    );
> > +
> > +EFI_STATUS
> > +DlEdidGetSupportedVideoModeWithFallback (
> > +    UINT32 ModeNumber,
> > +    CONST VOID *EDID,
> > +    UINT32 EdidSize,
> > +    CONST struct VideoMode **VideoMode
> > +    );
> > +
> > +UINT32
> > +DlEdidGetNumSupportedModesInEdid (
> > +    CONST VOID *EDID,
> > +    UINT32 EdidSize
> > +    );
> > +
> > +EFI_STATUS
> > +DlReadEdid (
> > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > +);
> > +
> > +// EDID Detailed timings section - Features
> > +enum EdidDetailedTimingsFeatures {
> > +  EdidDetailedTimingsFeaturesInterlaced              = 0x80,
> > +  EdidDetailedTimingsFeaturesStereoModeMask          = 0x60,
> > +  EdidDetailedTimingsFeaturesSyncSchemeMask          = 0x18,
> > +  EdidDetailedTimingsFeaturesHorizontalSyncPositive  = 0x02,
> > +  EdidDetailedTimingsFeaturesVerticalSyncPositive    = 0x04,
> > +};
> > +
> > +// NR-110497-TC-7ZM Section 4.3.3 0x22 Set Video Mode - Flags
> > +enum VideoModeFlags {
> > +  VideoModeFlagsInterlaced             = 0x0001,
> > +  VideoModeFlagsHorizontalSyncInverted = 0x0100,
> > +  VideoModeFlagsVerticalSyncInverted   = 0x0200,
> > +};
> > +
> > +struct StandardTimingIdentification {
> > +  UINT8 HorizontalActivePixels;           // X resolution, from 256->2288 in increments of 8 pixels
> > +  UINT8 ImageAspectRatioAndrefresh;   // Bits 7,6 Aspect ratio - 0=16:10 1=4:3 2=5:4 3=16:9
> > +                                          // Bits 5,0 Refresh rate Range 60->1213Hz
> > +};
> > +
> > +struct DetailedTimingIdentification {
> > +  UINT16 PixelClock;                  // wPixelClock in VideoMode struct
> > +  UINT8  HActiveLo;                   // wHActive
> > +  UINT8  HBlankingLo;                 // wHBlanking
> > +  UINT8  HActiveHiBlankingHi;
> > +  UINT8  VActiveLo;                   // wVActive
> > +  UINT8  VBlankingLo;                 // wVBlanking
> > +  UINT8  VActiveHiBlankingHi;
> > +  UINT8  HSyncOffsetLo;               // wHSyncOffset, front porch
> > +  UINT8  HSyncWidthLo;                // wHSyncWidth
> > +  UINT8  VSyncOffsetLoSyncWidthLo;
> > +  UINT8  HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi;
> > +  UINT8  HImageSizeHi;
> > +  UINT8  VImageSizeHi;
> > +  UINT8  HImageSizeLoVImageSizeLo;
> > +  UINT8  HBorder;
> > +  UINT8  VBorder;
> > +  UINT8  Features;
> > +};
> > +
> > +struct Edid {
> > +  UINT8  Header[EDID_HEADER_SIZE];           //EDID header "00 FF FF FF FF FF FF 00"
> > +  UINT16 ManufactureName;                  //EISA 3-character ID
> > +  UINT16 ProductCode;                      //Vendor assigned code
> > +  UINT32 SerialNumber;                     //32-bit serial number
> > +  UINT8  WeekOfManufacture;                //Week number
> > +  UINT8  YearOfManufacture;                //Year
> > +  UINT8  EdidVersion;                      //EDID Structure Version
> > +  UINT8  EdidRevision;                     //EDID Structure Revision
> > +  UINT8  VideoInputDefinition;
> > +  UINT8  MaxHorizontalImageSize;           //cm
> > +  UINT8  MaxVerticalImageSize;             //cm
> > +  UINT8  DisplayTransferCharacteristic;
> > +  UINT8  FeatureSupport;
> > +  UINT8  RedGreenLowBits;                  //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
> > +  UINT8  BlueWhiteLowBits;                 //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
> > +  UINT8  RedX;                             //Red-x Bits 9 - 2
> > +  UINT8  RedY;                             //Red-y Bits 9 - 2
> > +  UINT8  GreenX;                           //Green-x Bits 9 - 2
> > +  UINT8  GreenY;                           //Green-y Bits 9 - 2
> > +  UINT8  BlueX;                            //Blue-x Bits 9 - 2
> > +  UINT8  BlueY;                            //Blue-y Bits 9 - 2
> > +  UINT8  WhiteX;                           //White-x Bits 9 - 2
> > +  UINT8  WhiteY;                           //White-x Bits 9 - 2
> > +  UINT8  EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES];
> > +  struct StandardTimingIdentification  standardTimingIdentifications[EDID_NUMBER_OF_STANDARD_TIMINGS];
> > +  struct DetailedTimingIdentification  detailedTimingDescriptions[EDID_NUMBER_OF_DETAILED_TIMINGS];
> > +  UINT8  ExtensionFlag;                    //Number of (optional) 128-byte EDID extension blocks to follow
> > +  UINT8  Checksum;
> > +};
> > +
> > +#endif // EDID_H
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> > new file mode 100644
> > index 000000000000..3e483afdba72
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> > @@ -0,0 +1,578 @@
> > +/**
> > + * @file Gop.c
> > + * @brief UEFI GOP protocol API implementation for USB DisplayLink driver.
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +#include "Edid.h"
> > +
> > +
> > +/**
> > + *
> > + * @param This            Pointer to the instance of the GOP protocol
> > + * @param BltOperation
> > + * @param SourceX
> > + * @param SourceY
> > + * @param Width
> > + * @param Height
> > + * @param DestinationX
> > + * @param DestinationY
> > + * @return
> > + */
> > +STATIC EFI_STATUS
> > +CheckBounds (
> > +    IN EFI_GRAPHICS_OUTPUT_PROTOCOL* This,
> > +    IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> > +    IN UINTN SourceX,
> > +    IN UINTN SourceY,
> > +    IN UINTN Width,
> > +    IN UINTN Height,
> > +    IN UINTN DestinationX,
> > +    IN UINTN DestinationY
> > +    )
> > +{
> > +  USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> > +  EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> > +
> > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> > +  Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> > +
> > +  CONST EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* ScreenMode = Gop->Mode->Info;
> > +
> > +  if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
> > +    if (SourceY + Height > ScreenMode->VerticalResolution) {
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    if (SourceX + Width > ScreenMode->HorizontalResolution) {
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +  }
> > +
> > +  if (BltOperation == EfiBltBufferToVideo
> > +    || BltOperation == EfiBltVideoToVideo
> > +    || BltOperation == EfiBltVideoFill) {
> > +    if (DestinationY + Height > ScreenMode->VerticalResolution) {
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +
> > +    if (DestinationX + Width > ScreenMode->HorizontalResolution) {
> > +      return EFI_INVALID_PARAMETER;
> > +    }
> > +  }
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + * Update the local copy of the Frame Buffer. This local copy is periodically transmitted to the
> > + * DisplayLink device (via DlGopSendScreenUpdate)
> > + * @param UsbDisplayLinkDev
> > + * @param BltBuffer
> > + * @param BltOperation
> > + * @param SourceX
> > + * @param SourceY
> > + * @param DestinationX
> > + * @param DestinationY
> > + * @param Width
> > + * @param Height
> > + * @param BltBufferStride
> > + * @param PixelsPerScanLine
> > + */
> > +STATIC VOID
> > +BuildBackBuffer (
> > +  IN  USB_DISPLAYLINK_DEV                     *UsbDisplayLinkDev,
> > +  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer, OPTIONAL
> > +  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
> > +  IN  UINTN                                   SourceX,
> > +  IN  UINTN                                   SourceY,
> > +  IN  UINTN                                   DestinationX,
> > +  IN  UINTN                                   DestinationY,
> > +  IN  UINTN                                   Width,
> > +  IN  UINTN                                   Height,
> > +  IN  UINTN                                   BltBufferStride,
> > +  IN  UINTN                                   PixelsPerScanLine
> > +)
> > +{
> > +  UINTN H;
> > +  UINTN W;
> > +  switch (BltOperation) {
> > +  case EfiBltVideoToBltBuffer:
> > +  {
> > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> > +    Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)((UINT8 *)BltBuffer + (DestinationY * BltBufferStride) + DestinationX * sizeof
> (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> > +    SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> > +
> > +    for (H = 0; H < Height; H++) {
> > +      for (W = 0; W < Width; W++) {
> > +        Blt[W] = *SrcB++;
> > +      }
> > +      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> > +      SrcB += PixelsPerScanLine - Width;
> > +    }
> > +  }
> > +  break;
> > +
> > +  case EfiBltBufferToVideo:
> > +  {
> > +    // Update the store of the area of the screen that is "dirty" - that we need to send in the next screen update.
> > +    if (DestinationY < UsbDisplayLinkDev->LastY1) {
> > +      UsbDisplayLinkDev->LastY1 = DestinationY;
> > +    }
> > +    if ((DestinationY + Height) > UsbDisplayLinkDev->LastY2) {
> > +      UsbDisplayLinkDev->LastY2 = DestinationY + Height;
> > +    }
> > +
> > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> > +    Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)(((UINT8 *)BltBuffer) + (SourceY * BltBufferStride) + SourceX * sizeof *Blt);
> > +    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> > +
> > +    for (H = 0; H < Height; H++) {
> > +      for (W = 0; W < Width; W++) {
> > +        *DstB++ = Blt[W];
> > +      }
> > +      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> > +      DstB += PixelsPerScanLine - Width;
> > +    }
> > +  }
> > +  break;
> > +
> > +  case EfiBltVideoToVideo:
> > +  {
> > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> > +    SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> > +    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> > +
> > +    for (H = 0; H < Height; H++) {
> > +      for (W = 0; W < Width; W++) {
> > +        *DstB++ = *SrcB++;
> > +      }
> > +      SrcB += PixelsPerScanLine - Width;
> > +      DstB += PixelsPerScanLine - Width;
> > +    }
> > +  }
> > +  break;
> > +
> > +  case EfiBltVideoFill:
> > +  {
> > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> > +    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> > +    for (H = 0; H < Height; H++) {
> > +      for (W = 0; W < Width; W++) {
> > +        *DstB++ = *BltBuffer;
> > +      }
> > +      DstB += PixelsPerScanLine - Width;
> > +    }
> > +  }
> > +  break;
> > +  default: break;
> > +  }
> > +}
> > +
> > +/**
> > + * Display a colour bar pattern on the DisplayLink device.
> > + * @param UsbDisplayLinkDev
> > + * @param PatternNumber
> > + * @return
> > + */
> > +EFI_STATUS
> > +DlGopSendTestPattern (
> > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > +    IN UINTN PatternNumber)
> > +{
> > +  EFI_STATUS Status;
> > +  UINTN DataLen;
> > +  UINT8 *DstBuf;
> > +  UINT32 USBStatus;
> > +
> > +  Status = EFI_SUCCESS;
> > +  DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per
> pixel
> > +  DstBuf = AllocateZeroPool (DataLen);
> > +
> > +  if (DstBuf == NULL) {
> > +    DEBUG ((DEBUG_ERROR, "SendTestPattern Failed to allocate memory\n"));
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  //DEBUG ((DEBUG_ERROR, "Called DlGopSendTestPattern %d\n", PatternNumber));
> > +
> > +  CONST UINT8 RedPixel[3] = { 0xFF, 0x00, 0x00 };
> > +  CONST UINT8 GreenPixel[3] = { 0x00, 0xFF, 0x00 };
> > +  CONST UINT8 BluePixel[3] = { 0x00, 0x00, 0xFF };
> > +  CONST UINT8 YellowPixel[3] = { 0xFF, 0xFF, 0x00 };
> > +  CONST UINT8 MagentaPixel[3] = { 0xFF, 0x00, 0xFF };
> > +  CONST UINT8 CyanPixel[3] = { 0x00, 0xFF, 0xFF };
> > +
> > +  UINTN Row;
> > +  UINTN Column;
> > +  for (Row = 0; Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution; Row++) {
> > +    for (Column = 0; Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution; Column++) {
> > +
> > +      if (0 == PatternNumber) {
> > +        if (Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution / 3) {
> > +          CopyMem (&DstBuf[Column * 3], RedPixel, sizeof (RedPixel));
> > +        }
> > +        else if (Row < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution * 2) / 3)
> > +        {
> > +          CopyMem (&DstBuf[Column * 3], GreenPixel, sizeof (GreenPixel));
> > +        }
> > +        else {
> > +          CopyMem (&DstBuf[Column * 3], BluePixel, sizeof (BluePixel));
> > +        }
> > +      }
> > +      else {
> > +        if (Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution / 3) {
> > +          CopyMem (&DstBuf[Column * 3], YellowPixel, sizeof (RedPixel));
> > +        }
> > +        else if (Column < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 2) / 3)
> > +        {
> > +          CopyMem (&DstBuf[Column * 3], MagentaPixel, sizeof (GreenPixel));
> > +        }
> > +        else {
> > +          CopyMem (&DstBuf[Column * 3], CyanPixel, sizeof (BluePixel));
> > +        }
> > +      }
> > +    }
> > +    DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, DataLen, &USBStatus);
> > +  }
> > +  // Payload with length of 1 to terminate the frame
> > +  DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, 1, &USBStatus);
> > +  FreePool (DstBuf);
> > +
> > +  return Status;
> > +}
> > +
> > +
> > +/**
> > + * Transfer the latest copy of the Blt buffer over USB to the DisplayLink device
> > + * @param UsbDisplayLinkDev
> > + * @return
> > + */
> > +EFI_STATUS
> > +DlGopSendScreenUpdate (
> > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > +    )
> > +{
> > +  EFI_STATUS Status;
> > +  UINT32 USBStatus;
> > +  Status = EFI_SUCCESS;
> > +
> > +  // If it has been a while since we sent an update, send a full screen.
> > +  // This allows us to update a hot-plugged monitor quickly.
> > +  if (UsbDisplayLinkDev->TimeSinceLastScreenUpdate > DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD) {
> > +    UsbDisplayLinkDev->LastY1 = 0;
> > +    UsbDisplayLinkDev->LastY2 = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution - 1;
> > +  }
> > +
> > +  // If there has been no BLT since the last update/poll, drop out quietly.
> > +  if (UsbDisplayLinkDev->LastY2 < UsbDisplayLinkDev->LastY1) {
> > +    UsbDisplayLinkDev->TimeSinceLastScreenUpdate += (DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 1000);  // Convert
> us to ms
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  UsbDisplayLinkDev->TimeSinceLastScreenUpdate = 0;
> > +
> > +  EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> > +
> > +  UINTN DataLen;
> > +  UINTN Width;
> > +  UINTN Height;
> > +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcPtr;
> > +  UINT8* DstPtr;
> > +  UINT8 DstBuffer[1920 * 3]; // Get rid of the magic numbers at some point
> > +                             // Could also use a buffer allocated at runtime to store the line, stored in the USB_DISPLAYLINK_DEV
> structure.
> > +  UINTN H;
> > +
> > +  DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per
> pixel
> > +  Width = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution;
> > +  Height = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution;
> > +  SrcPtr = UsbDisplayLinkDev->Screen;
> > +  DstPtr = DstBuffer;
> > +
> > +  for (H = 0; H < Height; H++) {
> > +    DstPtr = DstBuffer;
> > +
> > +    UINTN W;
> > +    for (W = 0; W < Width; W++) {
> > +      // Need to swap round the RGB values
> > +      DstPtr[0] = ((UINT8 *)SrcPtr)[2];
> > +      DstPtr[1] = ((UINT8 *)SrcPtr)[1];
> > +      DstPtr[2] = ((UINT8 *)SrcPtr)[0];
> > +      SrcPtr++;
> > +      DstPtr += 3;
> > +    }
> > +
> > +    Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, DataLen, &USBStatus);
> > +
> > +    // USBStatus values defined in usbio.h, e.g. EFI_USB_ERR_TIMEOUT 0x40
> > +    if (EFI_ERROR (Status)) {
> > +      DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB
> status x%x\n", H, DataLen, Status, USBStatus));
> > +      break;
> > +    }
> > +    // Need an extra DlUsbBulkWrite if the data length is divisible by USB MaxPacketSize. This spare data will just get written
> into the (invisible) stride area.
> > +    // Note that the API doesn't let us do a bulk write of 0.
> > +    if ((DataLen & (UsbDisplayLinkDev->BulkOutEndpointDescriptor.MaxPacketSize - 1)) == 0) {
> > +      Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 2, &USBStatus);
> > +      if (EFI_ERROR (Status)) {
> > +        DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB
> status x%x\n", H, DataLen, Status, USBStatus));
> > +        break;
> > +      }
> > +    }
> > +  }
> > +
> > +  if (!EFI_ERROR (Status)) {
> > +    // If we've successfully transmitted the frame, reset the values that store which area of the screen has been BLTted to.
> > +    // If we haven't succeeded, this will mean we'll try to resend it after the next poll period.
> > +    UsbDisplayLinkDev->LastY2 = 0;
> > +    UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> > +  }
> > +
> > +  // Payload with length of 1 to terminate the frame
> > +  // We need to do this even if we had an error, to indicate to the DL device that it should now expect a new frame.
> > +  DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 1, &USBStatus);
> > +
> > +  gBS->RestoreTPL (OriginalTPL);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > + * Calculate the video refresh rate from the video timing parameters (pixel clock etc)
> > + * @param videoMode
> > + * @return
> > + */
> > +#ifndef MDEPKG_NDEBUG
> > +STATIC inline UINT16
> > +CalculateRefreshRate (
> > +    IN CONST struct VideoMode *VideoMode)
> > +{
> > +  UINT16 RefreshRate;
> > +  UINT16 Rmod;
> > +  UINT16 Rate10Hz;
> > +
> > +  RefreshRate = (VideoMode->PixelClock * 10000) / ((VideoMode->HActive + VideoMode->HBlanking) * (VideoMode->VActive
> + VideoMode->VBlanking));
> > +  Rmod = RefreshRate % 10;
> > +  Rate10Hz = RefreshRate - Rmod;
> > +
> > +  if (Rmod >= 5) {
> > +    Rate10Hz += 10;
> > +  }
> > +  return Rate10Hz;
> > +}
> > +#endif // MDEPKG_NDEBUG
> > +/*
> ***************************************************************************************************** */
> > +/*
> ***************************************************************************************************** */
> > +/* ******************        START OF FUNCTIONS WHICH IMPLEMENT GOP INTERFACE         ****************** */
> > +/*
> ***************************************************************************************************** */
> > +/*
> ***************************************************************************************************** */
> > +
> > +
> > +/**
> > + *
> > + * @param Gop          Pointer to the instance of the GOP protocol
> > + * @param ModeNumber
> > + * @param SizeOfInfo
> > + * @param Info
> > + * @return
> > + */
> > +EFI_STATUS
> > +EFIAPI
> > +DisplayLinkQueryMode (
> > +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *Gop,
> > +  IN  UINT32                                ModeNumber,
> > +  OUT UINTN                                 *SizeOfInfo,
> > +  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
> > +)
> > +{
> > +  USB_DISPLAYLINK_DEV *Dev;
> > +  CONST struct VideoMode *VideoMode;
> > +  EFI_STATUS Status;
> > +
> > +  Dev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> > +  Status = EFI_INVALID_PARAMETER;
> > +
> > +  if ((SizeOfInfo == NULL) || (Info == NULL)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  // Get a video mode from the EDID
> > +  Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, Dev->EdidActive.Edid, Dev->EdidActive.SizeOfEdid,
> &VideoMode);
> > +
> > +  if (!EFI_ERROR (Status)) {
> > +
> > +    *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof
> (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> > +    if (*Info == NULL) {
> > +      return EFI_OUT_OF_RESOURCES;
> > +    }
> > +
> > +    DEBUG ((DEBUG_INFO, "BIOS querying mode number %d - returning %dx%d @ %dHz\n", ModeNumber, VideoMode-
> >HActive, VideoMode->VActive, CalculateRefreshRate (VideoMode)));
> > +
> > +    *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> > +
> > +    (*Info)->Version = 0;
> > +    (*Info)->HorizontalResolution = VideoMode->HActive;
> > +    (*Info)->VerticalResolution = VideoMode->VActive;
> > +    (*Info)->PixelFormat = PixelBltOnly;
> > +    (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;
> > +    (*Info)->PixelInformation.RedMask = 0;
> > +    (*Info)->PixelInformation.GreenMask = 0;
> > +    (*Info)->PixelInformation.BlueMask = 0;
> > +    (*Info)->PixelInformation.ReservedMask = 0;
> > +  }
> > +  return Status;
> > +}
> > +
> > +/**
> > + *
> > + * @param Gop         Pointer to the instance of the GOP protocol
> > + * @param ModeNumber
> > + * @return
> > + */
> > +EFI_STATUS
> > +EFIAPI
> > +DisplayLinkSetMode (
> > +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *Gop,
> > +  IN  UINT32                        ModeNumber
> > +)
> > +{
> > +  USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> > +  EFI_STATUS Status;
> > +  CONST struct VideoMode *VideoMode;
> > +
> > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> > +
> > +  // Prevent the DisplayLinkPeriodicTimer from interrupting us (bug 28877).
> > +  // When the driver is manually loaded, the TPL is TPL_NOTIFY (16) which prevents the interrupt from the timer.
> > +  // When the GOP driver is sideloaded, the TPL of this call is TPL_APPLICATION (4) and the timer can interrupt us.
> > +  Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> > +
> > +  // Get a video mode from the EDID
> > +  Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, UsbDisplayLinkDev->EdidActive.Edid,
> UsbDisplayLinkDev->EdidActive.SizeOfEdid, &VideoMode);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  Gop->Mode->Info->Version = 0;
> > +  Gop->Mode->Info->HorizontalResolution = VideoMode->HActive;
> > +  Gop->Mode->Info->VerticalResolution = VideoMode->VActive;
> > +  Gop->Mode->Info->PixelFormat = PixelBltOnly;
> > +  Gop->Mode->Info->PixelsPerScanLine = Gop->Mode->Info->HorizontalResolution;
> > +  Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> > +  Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> > +  Gop->Mode->FrameBufferSize = 0;
> > +
> > +  //
> > +  // Allocate the back buffer
> > +  //
> > +  if (UsbDisplayLinkDev->Screen != NULL) {
> > +    FreePool (UsbDisplayLinkDev->Screen);
> > +  }
> > +
> > +  UsbDisplayLinkDev->Screen = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)AllocateZeroPool (
> > +    Gop->Mode->Info->HorizontalResolution *
> > +    Gop->Mode->Info->VerticalResolution *
> > +    sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> > +
> > +  if (UsbDisplayLinkDev->Screen == NULL) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  DEBUG ((DEBUG_INFO, "Video mode %d selected by BIOS - %d x %d.\n", ModeNumber, VideoMode->HActive, VideoMode-
> >VActive));
> > +  // Wait until we are sure that we can set the video mode before we tell the firmware
> > +  Status = DlUsbSendControlWriteMessage (UsbDisplayLinkDev, SET_VIDEO_MODE, 0, VideoMode, sizeof (struct
> VideoMode));
> > +
> > +  if (Status != EFI_SUCCESS) {
> > +    // Flag up that we haven't set the video mode correctly yet.
> > +    DEBUG ((DEBUG_ERROR, "Failed to send USB message to DisplayLink device to set monitor video mode. Monitor
> connected correctly?\n"));
> > +    Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> > +    FreePool (UsbDisplayLinkDev->Screen);
> > +    UsbDisplayLinkDev->Screen = NULL;
> > +  } else {
> > +    BuildBackBuffer (
> > +      UsbDisplayLinkDev,
> > +      UsbDisplayLinkDev->Screen,
> > +      EfiBltBufferToVideo,
> > +      0, 0,
> > +      0, 0,
> > +      Gop->Mode->Info->HorizontalResolution,
> > +      Gop->Mode->Info->VerticalResolution,
> > +      Gop->Mode->Info->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
> > +      Gop->Mode->Info->HorizontalResolution);
> > +    // unlock the DisplayLinkPeriodicTimer
> > +    Gop->Mode->Mode = ModeNumber;
> > +  }
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > + * Implementation of the GOP protocol Blt API function
> > + * @param This            Pointer to the instance of the GOP protocol
> > + * @param BltBuffer
> > + * @param BltOperation
> > + * @param SourceX
> > + * @param SourceY
> > + * @param DestinationX
> > + * @param DestinationY
> > + * @param Width
> > + * @param Height
> > + * @param Delta
> > + * @return
> > + */
> > +EFI_STATUS
> > +EFIAPI
> > +DisplayLinkBlt (
> > +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
> > +  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer, OPTIONAL
> > +  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
> > +  IN  UINTN                                   SourceX,
> > +  IN  UINTN                                   SourceY,
> > +  IN  UINTN                                   DestinationX,
> > +  IN  UINTN                                   DestinationY,
> > +  IN  UINTN                                   Width,
> > +  IN  UINTN                                   Height,
> > +  IN  UINTN                                   Delta         OPTIONAL
> > +)
> > +{
> > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> > +
> > +  // Drop out if we haven't set the video mode up yet
> > +  if (This->Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  if (Width == 0 || Height == 0) {
> > +    return EFI_INVALID_PARAMETER;
> > +  }
> > +
> > +  // Lock so we make an atomic write the frame buffer.
> > +  // We would not want a timer based event (Cursor, ...) to come in while we are doing this operation.
> > +  EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> > +
> > +  CONST UINTN BltBufferStride = (Delta == 0) ? Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) : Delta;
> > +  CONST EFI_STATUS boundsCheckStatus = CheckBounds (This, BltOperation, SourceX, SourceY, Width, Height, DestinationX,
> DestinationY);
> > +  if (EFI_ERROR (boundsCheckStatus)) {
> > +    gBS->RestoreTPL (OriginalTPL);
> > +    return boundsCheckStatus;
> > +  }
> > +
> > +  BuildBackBuffer (UsbDisplayLinkDev, BltBuffer, BltOperation, SourceX, SourceY, DestinationX, DestinationY, Width, Height,
> BltBufferStride, This->Mode->Info->PixelsPerScanLine);
> > +
> > +  gBS->RestoreTPL (OriginalTPL);
> > +  return EFI_SUCCESS;
> > +}
> > +
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> > new file mode 100644
> > index 000000000000..c12a80a6e1ab
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> > @@ -0,0 +1,145 @@
> > +/**
> > + * @file UsbDescriptors.c
> > + * @brief Functions to read USB Interface and Capabilities descriptors
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +#include "UsbDescriptors.h"
> > +
> > +/**
> > + *
> > + * @param UsbIo
> > + * @param descriptorType
> > + * @param index
> > + * @param Buffer
> > + * @param Length
> > + * @param UsbStatus
> > + * @return
> > + */
> > +STATIC EFI_STATUS
> > +ReadDescriptor (
> > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > +    UINT8 DescriptorType,
> > +    UINT8 Index,
> > +    VOID* Buffer,
> > +    UINT16 Length,
> > +    UINT32* UsbStatus)
> > +{
> > +  EFI_STATUS Status;
> > +
> > +  UINT8 Header[2];
> > +  ZeroMem (Header, sizeof (Header));
> > +
> > +  EFI_USB_DEVICE_REQUEST Request;
> > +  ZeroMem (&Request, sizeof (Request));
> > +  Request.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_STANDARD | USB_TARGET_DEVICE;
> > +  Request.Request = USB_REQ_GET_DESCRIPTOR;
> > +  Request.Index = 0;
> > +  Request.Value = DescriptorType << 8 | Index;
> > +  Request.Length = sizeof (Header);
> > +
> > +  // Read the descriptor header to see how many bytes it contains
> > +  Status = UsbIo->UsbControlTransfer (
> > +      UsbIo,
> > +      &Request,
> > +      EfiUsbDataIn,
> > +      DISPLAYLINK_USB_CTRL_TIMEOUT,
> > +      Header,
> > +      sizeof (Header),
> > +      UsbStatus);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "Failed to read length of descriptor type x%x, index %u (code %r, USB status x%x)\n",
> > +          DescriptorType, Index, Status, *UsbStatus));
> > +    return Status;
> > +  }
> > +  CONST UINT16 TotalLength = Header[0];
> > +
> > +  // Now we know the size of it, we can read the entire descriptor
> > +  Request.Length = TotalLength;
> > +
> > +  Status = UsbIo->UsbControlTransfer (
> > +      UsbIo,
> > +      &Request,
> > +      EfiUsbDataIn,
> > +      DISPLAYLINK_USB_CTRL_TIMEOUT,
> > +      Buffer,
> > +      TotalLength,
> > +      UsbStatus);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +  Perform a USB control transfer to read the DisplayLink vendor descriptor.
> > +
> > +  @param UsbIo   Pointer to the instance of the USBIO protocol
> > +  @param Buffer  Pointer to the buffer where descriptor should be written
> > +  @param Length  Length of buffer (and the maximum amount of descriptor data that shall be read)
> > +
> > +  @retval EFI_SUCCESS  The descriptor has been copied into Buffer
> > +  @retval Other        The descriptor could not be read
> > +**/
> > +EFI_STATUS
> > +ReadCapabilitiesDescriptor (
> > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > +    OUT VOID* Buffer,
> > +    IN UINT16 Length)
> > +{
> > +  UINT32 UsbStatus;
> > +  EFI_STATUS Status;
> > +
> > +  Status = ReadDescriptor (
> > +      UsbIo,
> > +      DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY,
> > +      0,
> > +      Buffer,
> > +      Length,
> > +      &UsbStatus);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "Could not read capabilities descriptor from DL device (code %r, USB status x%x). Unrecognised
> firmware version?\n", Status, UsbStatus));
> > +  }
> > +
> > +  return Status;
> > +}
> > +
> > +
> > +/**
> > + An alternative to the UBSIO protocol function EFI_USB_IO_GET_INTERFACE_DESCRIPTOR.
> > + This version allows you to specify an index.
> > + * @param UsbIo                 Pointer to the instance of the USBIO protocol
> > + * @param interfaceDescriptor   Where the descriptor should be written
> > + * @param index                 The index of the descriptor required (the standard USBIO function doesn't let you do this)
> > + * @return
> > + */
> > +EFI_STATUS
> > +UsbDisplayLinkGetInterfaceDescriptor (
> > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > +    OUT EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> > +    UINT8 Index
> > +    )
> > +{
> > +  UINT32 UsbStatus;
> > +  EFI_STATUS Status;
> > +
> > +  Status = ReadDescriptor (
> > +      UsbIo,
> > +      USB_DESC_TYPE_INTERFACE,
> > +      Index,
> > +      InterfaceDescriptor,
> > +      sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
> > +      &UsbStatus);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "USB control transfer failed while reading interface descriptor (code %r, USB status x%x)\n",
> Status, UsbStatus));
> > +  }
> > +
> > +  return Status;
> > +}
> > +
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> > new file mode 100644
> > index 000000000000..cdc01aad193a
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> > @@ -0,0 +1,109 @@
> > +/**
> > + * @file UsbDescriptors.h
> > + * @brief Functions to read USB Interface and Capabilities descriptors
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#ifndef USB_DESCRIPTORS_H_
> > +#define USB_DESCRIPTORS_H_
> > +
> > +  /**
> > +  Type of the Direct Framebuffer capability descriptor.
> > +  This is a vendor specific USB descriptor for DisplayLink.
> > +  @see NR-140082 Section 3.5
> > +  **/
> > +#define DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY 0x5e
> > +
> > +  /**
> > +  Identifiers for capabllity keys
> > +  @see NR-140082 Section 3.2
> > +  **/
> > +
> > +  /**
> > +  Key for Capabilities 1 - See section 3.2.1
> > +  **/
> > +#define CAPABILITIES1_KEY 0x0
> > +
> > +  /**
> > +  Lengths for capabllity fields
> > +  **/
> > +#define CAPABILITIES1_LENGTH 0x4
> > +
> > +  /**
> > +  Bits for the capability bitmask Capabilities1
> > +  **/
> > +
> > +  /**
> > +  This is the first capability defined for the protocol.
> > +  It represents the mode of operation as of initial release.
> > +  If a device ever breaks compatibility with this initial release,
> > +  it will cease
> > +  to support CapabilityBaseProtocol.
> > +  **/
> > +#define CAPABILITIES1_BASE_PROTOCOL (1 << 0)
> > +
> > +  /**
> > +  Idealised VendorDescriptor which is the result
> > +  of parsing vendor descriptor from device.
> > +  **/
> > +  typedef struct {
> > +    UINT32 Capabilities1;
> > +  } VendorDescriptor;
> > +
> > +#pragma pack(push, 1)
> > +  typedef struct {
> > +    UINT16 Key; /** Really of type enum DescrptorKeys */
> > +    UINT8 Length;
> > +    UINT8 Value[];
> > +  } DescriptorKLV;
> > +
> > +  typedef struct {
> > +    UINT8 Length;
> > +    UINT8 Type;
> > +    UINT16 CapabilityVersion;
> > +    UINT8 CapabilityLength;
> > +    UINT8 Klv[];
> > +  } VendorDescriptorGeneric;
> > +#pragma pack(pop)
> > +
> > +
> > +EFI_STATUS UsbDisplayLinkGetInterfaceDescriptor (
> > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > +    EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> > +    UINT8 index
> > +    );
> > +
> > +EFI_STATUS ReadCapabilitiesDescriptor (IN EFI_USB_IO_PROTOCOL *UsbIo, VOID* Buffer, UINT16 Length);
> > +
> > +/**
> > +Parse data in buffer to a VendorDescriptor, if possible.
> > +
> > +@param Data      Buffer
> > +@param Length    Length of buffer
> > +
> > +@retval EFI_SUCCESS      The descriptor was parsed successfully
> > +@retval EFI_UNSUPPORTED  Simple Pointer Protocol is not installed on Controller.
> > +**/
> > +EFI_STATUS
> > +UsbDisplayLinkParseCapabilitiesDescriptor (
> > +  CONST IN VOID* Data,
> > +  IN UINTN Length,
> > +  OUT VendorDescriptor* Descriptor
> > +);
> > +
> > +/**
> > +Decide if binding may proceed, given capabilities
> > +
> > +@retval TRUE   Binding may proceed
> > +@retval FALSE  Binding is not possible
> > +**/
> > +BOOLEAN
> > +UsbDisplayLinkCapabilitiesSufficientToBind (
> > +  CONST IN VendorDescriptor* Descriptor
> > +);
> > +
> > +#endif // USB_DESCRIPTORS_H_
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> > new file mode 100644
> > index 000000000000..997a3e307f38
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> > @@ -0,0 +1,1082 @@
> > +/**
> > + * @file UsbDisplayLink.c
> > + * @brief USB DisplayLink Driver that manages USB DisplayLink device and produces Graphics Output Protocol
> > + * This file implements the functions of the Driver Binding / Start / Stop / Unload interface
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +#include <Library/UefiRuntimeServicesTableLib.h>
> > +#include <Library/PrintLib.h>
> > +#include <Protocol/HiiFont.h>
> > +
> > +#include "Edid.h"
> > +#include "UsbDescriptors.h"
> > +
> > +//
> > +// Functions of Driver Binding Protocol
> > +//
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingSupported (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> > +  IN EFI_HANDLE                     Controller,
> > +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> > +);
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingStart (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> > +  IN EFI_HANDLE                     Controller,
> > +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> > +);
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingStop (
> > +  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
> > +  IN  EFI_HANDLE                    Controller,
> > +  IN  UINTN                         NumberOfChildren,
> > +  IN  EFI_HANDLE                    *ChildHandleBuffer
> > +);
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingEntryPoint (
> > +  IN EFI_HANDLE           ImageHandle,
> > +  IN EFI_SYSTEM_TABLE     *SystemTable
> > +);
> > +
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> > +  IN EFI_HANDLE           ImageHandle,
> > +  IN EFI_SYSTEM_TABLE     *SystemTable,
> > +  IN EFI_HANDLE           DriverBindingHandle
> > +);
> > +
> > +
> > +// Generated with https://www.guidgen.com/ - "B70E5A79-C6D6-4267-B02E-9108C989E287"
> > +EFI_GUID gEfiDlGopVariableGuid = { 0xB70E5A79, 0xC6D6, 0x4267,{ 0xB0, 0x2E, 0x91, 0x08, 0xC9, 0x89, 0xE2, 0x87 } };
> > +
> > +
> > +EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding = {
> > +  UsbDisplayLinkDriverBindingSupported,
> > +  UsbDisplayLinkDriverBindingStart,
> > +  UsbDisplayLinkDriverBindingStop,
> > +  INF_DRIVER_VERSION,
> > +  NULL,
> > +  NULL
> > +};
> > +
> > +
> > +/**
> > + * Reads integer environment variable with default fallback.
> > + * @param variableName   variable name to read
> > + * @param defaultValue   default value to return if requested not found
> > + */
> > +STATIC UINT32
> > +ReadEnvironmentInt (
> > +    CHAR16 *VariableName,
> > +    UINT32 DefaultValue
> > +    )
> > +{
> > +  UINT32 Result;
> > +  UINTN DataSize;
> > +  DataSize = sizeof (Result);
> > +  CONST EFI_STATUS Status = gRT->GetVariable (VariableName, &gEfiDlGopVariableGuid, (UINT32*)NULL, &DataSize,
> &Result);
> > +  if (!EFI_ERROR (Status) && (sizeof (Result) == DataSize)) {
> > +    return Result;
> > +  }
> > +  return DefaultValue;
> > +}
> > +
> > +/**
> > +* Reads boolean environment variable with default fallback.
> > +* @param variableName   variable name to read
> > +* @param defaultValue   default value to return if requested not found
> > +*/
> > +STATIC BOOLEAN
> > +ReadEnvironmentBool (
> > +    CHAR16 *VariableName,
> > +    BOOLEAN DefaultValue
> > +    )
> > +{
> > +  return ReadEnvironmentInt (VariableName, DefaultValue ? 1 : 0) == 1;
> > +}
> > +
> > +
> > +/**
> > +*
> > +* @param UsbDisplayLinkDev
> > +* @return
> > +*/
> > +STATIC EFI_STATUS
> > +InitializeUsbDisplayLinkDevice (
> > +  IN OUT USB_DISPLAYLINK_DEV *UsbDisplayLinkDev
> > +)
> > +{
> > +  EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> > +  Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> > +  Gop->QueryMode = DisplayLinkQueryMode;
> > +  Gop->SetMode = DisplayLinkSetMode;
> > +  Gop->Blt = DisplayLinkBlt;
> > +
> > +  //
> > +  // Allocate buffer for Graphics Output Protocol mode information
> > +  //
> > +  Gop->Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE*)AllocatePool (sizeof
> (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
> > +  if (Gop->Mode == NULL) {
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +  Gop->Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof
> (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> > +  if (Gop->Mode->Info == NULL) {
> > +    FreePool (Gop->Mode);
> > +    Gop->Mode = NULL;
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  Gop->Mode->MaxMode = MAX(1, DlEdidGetNumSupportedModesInEdid (UsbDisplayLinkDev->EdidActive.Edid,
> UsbDisplayLinkDev->EdidActive.SizeOfEdid));
> > +
> > +  Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> > +  Gop->Mode->Info->Version = 0;
> > +  // Initialising the horizontal resolution prevents certain BIOSs from hanging on boot, but
> > +  // it is not yet clear why. See bug 28194.
> > +  Gop->Mode->Info->HorizontalResolution = DlVideoModeGetSupportedVideoMode (0)->HActive;
> > +  Gop->Mode->Info->VerticalResolution = 0;
> > +  Gop->Mode->Info->PixelFormat = PixelBltOnly;
> > +  Gop->Mode->Info->PixelsPerScanLine = 0;
> > +  Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> > +  Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> > +  Gop->Mode->FrameBufferSize = 0;
> > +
> > +  // Prevent DlGopSendScreenUpdate from running until we are sure that the video mode is set
> > +  UsbDisplayLinkDev->LastY2 = 0;
> > +  UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > +  Look for alternate settings for the UsbIo handle's interface
> > +  which offer protocol DL_PROTOCOL_DIRECT_FB.
> > +
> > +  @retval -1                     Not found
> > +  @retval Other                  The alternate setting
> > +**/
> > +STATIC INTN
> > +GetDirectFbAltSetting (
> > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > +    IN UINT8 ParentInterfaceNumber
> > +    )
> > +{
> > +  EFI_STATUS Status;
> > +  INTN AltSettingIndex;
> > +  UINT16 InterfaceIndex;
> > +
> > +  AltSettingIndex = -1;
> > +
> > +  for (InterfaceIndex = 0; InterfaceIndex <= 0xFF; InterfaceIndex++) {
> > +    EFI_USB_INTERFACE_DESCRIPTOR interfaceDescriptor;
> > +    Status = UsbDisplayLinkGetInterfaceDescriptor (UsbIo, &interfaceDescriptor, (UINT8)InterfaceIndex);
> > +    if (EFI_ERROR (Status)) {
> > +      break;
> > +    }
> > +
> > +    if (interfaceDescriptor.InterfaceNumber == ParentInterfaceNumber &&
> > +       (interfaceDescriptor.InterfaceClass == CLASS_VENDOR) &&
> > +        interfaceDescriptor.InterfaceProtocol == INTERFACE_PROTOCOL_DIRECT_FB) {
> > +      AltSettingIndex = interfaceDescriptor.AlternateSetting;
> > +      break;
> > +    }
> > +  }
> > +  return AltSettingIndex;
> > +}
> > +
> > +/**
> > + *
> > + * @param UsbIo
> > + * @param altSettingIndex
> > + * @return
> > + */
> > +STATIC EFI_STATUS
> > +SelectAltSetting (
> > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > +    IN UINTN AltSettingIndex)
> > +{
> > +  // Set alternate setting 1 on the interface
> > +  EFI_STATUS Status;
> > +  UINT32 UsbStatus;
> > +  EFI_USB_DEVICE_REQUEST Request;
> > +  ZeroMem (&Request, sizeof (Request));
> > +  Request.RequestType = USB_REQ_TYPE_STANDARD | USB_TARGET_INTERFACE;
> > +  Request.Request = USB_REQ_SET_INTERFACE;
> > +  Request.Index = DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO;
> > +  Request.Value = (UINT16)AltSettingIndex;
> > +
> > +  Status = UsbIo->UsbControlTransfer (
> > +    UsbIo,
> > +    &Request,
> > +    EfiUsbNoData,
> > +    DISPLAYLINK_USB_CTRL_TIMEOUT,
> > +    NULL,
> > +    0,
> > +    &UsbStatus);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    Status = EFI_UNSUPPORTED;
> > +    DEBUG ((DEBUG_ERROR, "USB control transfer failed while attempting to select alt setting %d on interface (code %r, USB
> status x%x). DisplayLink device has unsupported firmware version?\n", AltSettingIndex, Status, UsbStatus));
> > +  }
> > +  return Status;
> > +}
> > +
> > +
> > +/**
> > +  Report whether the driver can support the device attached via UsbIo
> > +  by seeing what if any capabilities it reports.
> > +
> > +  @retval TRUE     Device has sufficient capabilities for this driver.
> > +  @retval FALSE    Device lacks sufficient capabilities.
> > +**/
> > +STATIC BOOLEAN
> > +CapabilitiesSupported (
> > +    IN EFI_USB_IO_PROTOCOL *UsbIo
> > +    )
> > +{
> > +  UINT8 Buffer[256];
> > +  EFI_STATUS Status;
> > +
> > +  Status = ReadCapabilitiesDescriptor (UsbIo, Buffer, sizeof (Buffer));
> > +  if (EFI_ERROR (Status)) {
> > +    return FALSE;
> > +  }
> > +
> > +  VendorDescriptor descriptor;
> > +  Status = UsbDisplayLinkParseCapabilitiesDescriptor (Buffer, sizeof (Buffer), &descriptor);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "Failed to parse capabilities descriptor (code %r)\n", Status));
> > +    return FALSE;
> > +  }
> > +
> > +  return UsbDisplayLinkCapabilitiesSufficientToBind (&descriptor);
> > +}
> > +
> > +
> > +/**
> > + *
> > + * @param UsbIo
> > + * @param InterfaceDescriptor
> > + * @param altSettingIndex
> > + * @return
> > + */
> > +STATIC BOOLEAN
> > +IsDLDirectFbCapableInterface (
> > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > +    IN EFI_USB_INTERFACE_DESCRIPTOR  *InterfaceDescriptor,
> > +    IN INTN *AltSettingIndex)
> > +{
> > +  EFI_STATUS Status;
> > +  EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
> > +
> > +  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DeviceDescriptor);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    return FALSE;
> > +  }
> > +
> > +  if (DeviceDescriptor.IdVendor != VENDOR_DISPLAYLINK) {
> > +    return FALSE;
> > +  }
> > +
> > +  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, InterfaceDescriptor);
> > +  if (EFI_ERROR (Status)) {
> > +    return FALSE;
> > +  }
> > +
> > +  // We can assume that the interface that we want to talk to - the NIVO interface - is number 0
> > +  if (InterfaceDescriptor->InterfaceNumber != DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO) {
> > +    return FALSE;
> > +  }
> > +
> > +  // Check if we have an interface (alt setting) descriptor with the correct interface protocol
> > +  *AltSettingIndex = GetDirectFbAltSetting (UsbIo, InterfaceDescriptor->InterfaceNumber);
> > +
> > +  if (*AltSettingIndex == -1) {
> > +    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to find setting on device which supports GOP functionality. Check
> firmware / device version?\n"));
> > +    return FALSE;
> > +  }
> > +
> > +  // Now check that the capabilities that we need are properly supported
> > +  if (CapabilitiesSupported (UsbIo) == FALSE) {
> > +    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: DL device detected, but it doesn't support the required GOP features. Check
> firmware / device version?\n"));
> > +    return FALSE;
> > +  }
> > +
> > +  return TRUE;
> > +}
> > +
> > +
> > +/**
> > + * Prints a block of text in the framebuffer (helper function).
> > + * @param X   x coordinate
> > + * @param Y   y coordinate
> > + */
> > +STATIC VOID
> > +DisplayLinkPrintTextToScreenInternal (
> > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> > +  UINTN X,
> > +  UINTN Y,
> > +  IN CHAR16 *Buffer
> > +  )
> > +{
> > +  EFI_STATUS Status;
> > +  EFI_HII_FONT_PROTOCOL *HiiFont;
> > +  EFI_IMAGE_OUTPUT *Blt;
> > +  EFI_FONT_DISPLAY_INFO FontInfo;
> > +  EFI_HII_OUT_FLAGS Flags;
> > +
> > +  Blt = (EFI_IMAGE_OUTPUT*)NULL;
> > +
> > +  Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **)&HiiFont);
> > +  if (!EFI_ERROR (Status)) {
> > +    Blt = (EFI_IMAGE_OUTPUT*)AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
> > +    Blt->Width = (UINT16)GraphicsOutput->Mode->Info->HorizontalResolution;
> > +    Blt->Height = (UINT16)GraphicsOutput->Mode->Info->VerticalResolution;
> > +    Blt->Image.Screen = GraphicsOutput;
> > +
> > +    ZeroMem (&FontInfo, sizeof (EFI_FONT_DISPLAY_INFO));
> > +    FontInfo.ForegroundColor.Red = 0;
> > +    FontInfo.ForegroundColor.Green = 0;
> > +    FontInfo.ForegroundColor.Blue = 0;
> > +    FontInfo.BackgroundColor.Red = 0xff;
> > +    FontInfo.BackgroundColor.Green = 0xff;
> > +    FontInfo.BackgroundColor.Blue = 0xff;
> > +
> > +    Flags = EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_OUT_FLAG_CLIP |
> > +            EFI_HII_OUT_FLAG_CLIP_CLEAN_X | EFI_HII_OUT_FLAG_CLIP_CLEAN_Y |
> > +            EFI_HII_IGNORE_LINE_BREAK | EFI_HII_DIRECT_TO_SCREEN;
> > +
> > +    Status = HiiFont->StringToImage (
> > +                           HiiFont,
> > +                           Flags,
> > +                           Buffer,
> > +                           &FontInfo,
> > +                           &Blt,
> > +                           X,
> > +                           Y,
> > +                           (EFI_HII_ROW_INFO**)NULL,
> > +                           (UINTN*)NULL,
> > +                           (UINTN*)NULL);
> > +  }
> > +
> > +  if (Blt != NULL) {
> > +    FreePool (Blt);
> > +  }
> > +}
> > +
> > +
> > +/**
> > +* Prints a block of text in the framebuffer.
> > +* @param X       x coordinate
> > +* @param Y       y coordinate
> > +* @param Format  string format similar to stdlib's vsnprintf
> > +* @param ...     arguments
> > +*/
> > +VOID
> > +EFIAPI
> > +DlGopPrintTextToScreen (
> > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> > +  UINTN X,
> > +  UINTN Y,
> > +  IN CONST CHAR16 *Format,
> > +  ...
> > +  )
> > +{
> > +  VA_LIST Marker;
> > +  CHAR16 *Buffer;
> > +  UINTN BufferSize;
> > +
> > +  ASSERT (Format != NULL);
> > +  ASSERT (((UINTN) Format & BIT0) == 0);
> > +
> > +  VA_START(Marker, Format);
> > +
> > +  BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);
> > +
> > +  Buffer = (CHAR16*)AllocatePool (BufferSize);
> > +  ASSERT (Buffer != NULL);
> > +
> > +  UnicodeVSPrint (Buffer, BufferSize, Format, Marker);
> > +
> > +  VA_END(Marker);
> > +
> > +  DisplayLinkPrintTextToScreenInternal (GraphicsOutput, X, Y, Buffer);
> > +
> > +  FreePool (Buffer);
> > +}
> > +
> > +
> > +/**
> > + * Sometimes platforms only write to the first GOP device that they find. Enabling this function allows us to copy the pixels
> from this device.
> > + * @param UsbDisplayLinkDev
> > + */
> > +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > +STATIC VOID
> > +DisplayLinkCopyFromPrimaryGopDevice (
> > +  IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > +  )
> > +{
> > +  UINTN HandleCount;
> > +  EFI_HANDLE *HandleBuffer;
> > +  UINTN HandleIndex;
> > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
> > +
> > +  gBS->LocateHandleBuffer (
> > +    ByProtocol,
> > +    &gEfiGraphicsOutputProtocolGuid,
> > +    NULL,
> > +    &HandleCount,
> > +    &HandleBuffer);
> > +
> > +  for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
> > +    gBS->HandleProtocol (HandleBuffer[HandleIndex], &gEfiGraphicsOutputProtocolGuid, (VOID**)&Gop);
> > +    if (Gop != &UsbDisplayLinkDev->GraphicsOutputProtocol && Gop->Mode->FrameBufferBase !=
> (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
> > +
> > +    // See if we need to do a screen update - calculate a really noddy hash to see if any screen updates have happened.
> > +    STATIC UINT32 prevframeBufferHash = 0; // 4 bytes per pixel
> > +    UINT32 currFrameBufferHash = 0;
> > +    UINTN i;
> > +    for (i = 0; i < (Gop->Mode->Info->HorizontalResolution * Gop->Mode->Info->VerticalResolution); i++) {
> > +      currFrameBufferHash += ((UINT32*)(UINTN)Gop->Mode->FrameBufferBase)[i];
> > +    }
> > +
> > +    if (currFrameBufferHash != prevframeBufferHash) {
> > +      prevframeBufferHash = currFrameBufferHash;
> > +
> > +      DisplayLinkBlt (
> > +        &UsbDisplayLinkDev->GraphicsOutputProtocol,
> > +        (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(UINTN)Gop->Mode->FrameBufferBase,
> > +        EfiBltBufferToVideo,
> > +        0,
> > +        0,
> > +        0,
> > +        0,
> > +        Gop->Mode->Info->HorizontalResolution,
> > +        Gop->Mode->Info->VerticalResolution,
> > +        0);
> > +      }
> > +      break;
> > +    }
> > +  }
> > +
> > +  FreePool (HandleBuffer);
> > +}
> > +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > +
> > +
> > +/**
> > + * Exit from boot services: signal handler.
> > + */
> > +STATIC VOID
> > +EFIAPI
> > +DisplayLinkDriverExitBootServices (
> > +  IN EFI_EVENT  Event,
> > +  IN VOID       *Context
> > +  )
> > +{
> > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> > +  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> > +
> > +  gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> > +}
> > +
> > +/**
> > + * Periodic screen update: timer callback.
> > + */
> > +VOID
> > +EFIAPI
> > +DisplayLinkPeriodicTimer (
> > +    IN EFI_EVENT Event,
> > +    IN VOID* Context
> > +    )
> > +{
> > +  EFI_STATUS Status;
> > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> > +
> > +  Status = EFI_SUCCESS;
> > +  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> > +
> > +  // Drop out if we haven't set the video mode up yet
> > +  if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> > +    // Restart the one-shot timer to poll the status again.
> > +    Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> > +    if (EFI_ERROR (Status)) {
> > +      DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> > +    }
> > +    return;
> > +  }
> > +
> > +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > +  DisplayLinkCopyFromPrimaryGopDevice (UsbDisplayLinkDev);
> > +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > +
> > +  if (UsbDisplayLinkDev->ShowBandwidth) {
> > +    STATIC UINTN Count = 0;
> > +
> > +    if (Count++ % 50 == 0) {
> > +      DlGopPrintTextToScreen (&UsbDisplayLinkDev->GraphicsOutputProtocol, 32, 48, (CONST CHAR16*)L"  Bandwidth: %d
> MB/s    ", UsbDisplayLinkDev->DataSent * 10000000 / DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 50 / 1024 / 1024);
> > +      UsbDisplayLinkDev->DataSent = 0;
> > +    }
> > +  }
> > +
> > +  if (UsbDisplayLinkDev->ShowTestPattern)
> > +  {
> > +    if (UsbDisplayLinkDev->ShowTestPattern == 5) {
> > +      DlGopSendTestPattern (UsbDisplayLinkDev, 0);
> > +    } else if (UsbDisplayLinkDev->ShowTestPattern >= 10) {
> > +      DlGopSendTestPattern (UsbDisplayLinkDev, 1);
> > +      UsbDisplayLinkDev->ShowTestPattern = 0;
> > +    }
> > +    UsbDisplayLinkDev->ShowTestPattern++;
> > +
> > +  }
> > +
> > +  // Send the latest version of the frame buffer to the DL device over USB
> > +  DlGopSendScreenUpdate (UsbDisplayLinkDev);
> > +
> > +  // Restart the timer now we've finished
> > +  Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> > +  }
> > +}
> > +
> > +/*
> ******************************************************************************************************
> */
> > +/*
> ******************************************************************************************************
> */
> > +/* ******************   START OF FUNCTIONS WHICH IMPLEMENT DRIVER BINDING INTERFACE    ******************
> */
> > +/*
> ******************************************************************************************************
> */
> > +/*
> ******************************************************************************************************
> */
> > +
> > +/**
> > +  Check whether USB DisplayLink driver supports this device.
> > +
> > +  @param  This                   The USB DisplayLink driver 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
> > +UsbDisplayLinkDriverBindingSupported (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> > +  IN EFI_HANDLE                     Controller,
> > +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> > +  )
> > +{
> > +  EFI_STATUS          Status;
> > +  EFI_USB_IO_PROTOCOL *UsbIo;
> > +
> > +  Status = gBS->OpenProtocol (
> > +                  Controller,
> > +                  &gEfiUsbIoProtocolGuid,
> > +                  (VOID **) &UsbIo,
> > +                  This->DriverBindingHandle,
> > +                  Controller,
> > +                  EFI_OPEN_PROTOCOL_BY_DRIVER);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    return Status;
> > +  }
> > +
> > +  //
> > +  // Use the USB I/O Protocol interface to check whether Controller is
> > +  // a DisplayLink device that can be managed by this driver.
> > +  //
> > +  Status = EFI_UNSUPPORTED;
> > +  EFI_USB_INTERFACE_DESCRIPTOR DummyInterfaceDescriptor;
> > +  INTN DummyAltSettingIndex;
> > +
> > +  if (IsDLDirectFbCapableInterface (UsbIo, &DummyInterfaceDescriptor, &DummyAltSettingIndex)){
> > +    Status = EFI_SUCCESS;
> > +  }
> > +
> > +  gBS->CloseProtocol (
> > +        Controller,
> > +        &gEfiUsbIoProtocolGuid,
> > +        This->DriverBindingHandle,
> > +        Controller);
> > +
> > +  return Status;
> > +}
> > +
> > +
> > +/**
> > +  Starts the DisplayLink device with this driver.
> > +
> > +  This function consumes USB I/O Protocol, intializes USB DisplayLink device,
> > +  installs Graphics Output Protocol
> > +  Transfer to manage the USB DisplayLink device.
> > +
> > +  @param  This                  The USB DisplayLink 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           This driver supports this device.
> > +  @retval EFI_UNSUPPORTED       This driver does not support this device.
> > +  @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
> > +  @retval EFI_OUT_OF_RESOURCES  Can't allocate memory resources.
> > +  @retval EFI_ALREADY_STARTED   This driver has been started.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingStart (
> > +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> > +  IN EFI_HANDLE                   Controller,
> > +  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
> > +  )
> > +{
> > +  EFI_STATUS                      Status;
> > +  USB_DISPLAYLINK_DEV             *UsbDisplayLinkDev;
> > +  UINT8                           EndpointNumber;
> > +  EFI_USB_ENDPOINT_DESCRIPTOR     EndpointDescriptor;
> > +  UINT8                           Index;
> > +  BOOLEAN                         FoundOut;
> > +  BOOLEAN                         FoundIn;
> > +  EFI_TPL                         OriginalTPL;
> > +  INTN                            altSettingIndex;
> > +
> > +  OriginalTPL = gBS->RaiseTPL (TPL_CALLBACK);
> > +
> > +  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)AllocateZeroPool (sizeof (USB_DISPLAYLINK_DEV));
> > +  if (UsbDisplayLinkDev == NULL) {
> > +    DEBUG ((DEBUG_ERROR, "Device initialialisation - Failed to allocate memory for device.\n"));
> > +    gBS->RestoreTPL (OriginalTPL);
> > +    return EFI_OUT_OF_RESOURCES;
> > +  }
> > +
> > +  UsbDisplayLinkDev->Signature = USB_DISPLAYLINK_DEV_SIGNATURE;
> > +
> > +  UsbDisplayLinkDev->ShowBandwidth = ReadEnvironmentBool (L"DisplayLinkShowBandwidth", FALSE);
> > +  UsbDisplayLinkDev->ShowTestPattern = ReadEnvironmentBool (L"DisplayLinkShowTestPatterns", FALSE);
> > +
> > +  //
> > +  // Open USB I/O Protocol
> > +  //
> > +  Status = gBS->OpenProtocol (
> > +      Controller,
> > +      &gEfiUsbIoProtocolGuid,
> > +      (VOID **) &UsbDisplayLinkDev->UsbIo,
> > +      This->DriverBindingHandle,
> > +      Controller,
> > +      EFI_OPEN_PROTOCOL_BY_DRIVER);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "Failed to open usbio protocol. Is USB correctly supported on this platform?.\n"));
> > +    Status = EFI_UNSUPPORTED;
> > +    goto ErrorExit2;
> > +  }
> > +
> > +  if (!IsDLDirectFbCapableInterface (UsbDisplayLinkDev->UsbIo, &UsbDisplayLinkDev->InterfaceDescriptor, &altSettingIndex))
> {
> > +    Status = EFI_UNSUPPORTED;
> > +    goto ErrorExit4;
> > +  }
> > +
> > +  Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, altSettingIndex);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to select alternate setting.\n"));
> > +    Status = EFI_UNSUPPORTED;
> > +    goto ErrorExit4;
> > +  }
> > +
> > +  //
> > +  // Parse endpoint descriptor
> > +  //
> > +  EndpointNumber = UsbDisplayLinkDev->InterfaceDescriptor.NumEndpoints;
> > +
> > +  //
> > +  // Traverse endpoints to find bulk endpoint
> > +  //
> > +  FoundOut = FALSE;
> > +  FoundIn = FALSE;
> > +  for (Index = 0; Index < EndpointNumber; Index++) {
> > +    UsbDisplayLinkDev->UsbIo->UsbGetEndpointDescriptor (
> > +             UsbDisplayLinkDev->UsbIo,
> > +             Index,
> > +             &EndpointDescriptor);
> > +
> > +    if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_BULK) {
> > +      if (!FoundOut && (EndpointDescriptor.EndpointAddress & BIT7) == 0) {
> > +        CopyMem (&UsbDisplayLinkDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> > +        FoundOut = TRUE;
> > +      } else if (!FoundIn && (EndpointDescriptor.EndpointAddress & BIT7) == BIT7) {
> > +        CopyMem (&UsbDisplayLinkDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> > +        FoundIn = TRUE;
> > +      }
> > +    }
> > +  }
> > +
> > +  if (FoundOut == FALSE) {
> > +    Status = EFI_UNSUPPORTED;
> > +    DEBUG ((DEBUG_ERROR, "No endpoints found.  Num endpoints searched = %d.\n", EndpointNumber));
> > +    goto ErrorExit4;
> > +  }
> > +
> > +  Status = DlReadEdid (UsbDisplayLinkDev);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "Failed to read monitor EDID from DisplayLink device (code %r)\n", Status));
> > +    goto ErrorExit7;
> > +  }
> > +
> > +  Status = InitializeUsbDisplayLinkDevice (UsbDisplayLinkDev);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "Failed to initialise DisplayLink device (code %r)\n", Status));
> > +    goto ErrorExit7;
> > +  }
> > +
> > +  Status = gBS->InstallMultipleProtocolInterfaces (
> > +      &Controller,
> > +      &gEfiGraphicsOutputProtocolGuid,
> > +      &UsbDisplayLinkDev->GraphicsOutputProtocol,
> > +      &gEfiEdidDiscoveredProtocolGuid,
> > +      &UsbDisplayLinkDev->EdidDiscovered,
> > +      &gEfiEdidActiveProtocolGuid,
> > +      &UsbDisplayLinkDev->EdidActive,
> > +      NULL);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "Failed to install Graphics Output and EDID protocol interfaces - driver not installed correctly -
>  %r\n", Status));
> > +    goto ErrorExit8;
> > +  }
> > +
> > +  UsbDisplayLinkDev->ControllerNameTable = (EFI_UNICODE_STRING_TABLE*)NULL;
> > +
> > +  AddUnicodeString2 (
> > +    "eng",
> > +    mUsbDisplayLinkComponentName.SupportedLanguages,
> > +    &UsbDisplayLinkDev->ControllerNameTable,
> > +    (CONST CHAR16*)L"Generic Usb DisplayLink",
> > +    TRUE);
> > +
> > +  AddUnicodeString2 (
> > +    "en",
> > +    mUsbDisplayLinkComponentName2.SupportedLanguages,
> > +    &UsbDisplayLinkDev->ControllerNameTable,
> > +    (CONST CHAR16*)L"Generic Usb DisplayLink",
> > +    FALSE);
> > +
> > +  //
> > +  // Setup a periodic timer
> > +  //
> > +  Status = gBS->CreateEvent (
> > +                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
> > +                  TPL_CALLBACK,
> > +                  DisplayLinkPeriodicTimer,
> > +                  UsbDisplayLinkDev,
> > +                  &UsbDisplayLinkDev->TimerEvent);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    Status = EFI_OUT_OF_RESOURCES;
> > +    DEBUG ((DEBUG_ERROR, "Failed to create screeen update polling event.\n"));
> > +    goto ErrorExit8;
> > +  }
> > +
> > +  // Start one-shot timer. The rendering operations can take quite a long time, so we
> > +  // don't want another timer event to happen until we have finished; so we'll restart
> > +  // the timer from DisplayLinkPeriodicTimer, the event handler function.
> > +  Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> > +  if (EFI_ERROR (Status)) {
> > +    Status = EFI_OUT_OF_RESOURCES;
> > +    DEBUG ((DEBUG_ERROR, "Failed to create screen update polling timer.\n"));
> > +    goto ErrorExit8;
> > +  }
> > +
> > +  Status = gBS->CreateEventEx (
> > +                  EVT_NOTIFY_SIGNAL,
> > +                  TPL_NOTIFY,
> > +                  DisplayLinkDriverExitBootServices,
> > +                  UsbDisplayLinkDev,
> > +                  &gEfiEventExitBootServicesGuid,
> > +                  &UsbDisplayLinkDev->DriverExitBootServicesEvent);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    Status = EFI_OUT_OF_RESOURCES;
> > +    DEBUG ((DEBUG_ERROR, "Failed to create event for bootexit.\n"));
> > +    goto ErrorExit8;
> > +  }
> > +
> > +  gBS->RestoreTPL (OriginalTPL);
> > +
> > +  DEBUG ((DEBUG_INFO, "DisplayLink GOP driver successfully bound to device.\n"));
> > +
> > +  return EFI_SUCCESS;
> > +
> > +  //
> > +  // Error handler
> > +  //
> > + ErrorExit8:
> > + ErrorExit7:
> > + ErrorExit4:
> > +  gBS->CloseProtocol (
> > +   Controller,
> > +   &gEfiUsbIoProtocolGuid,
> > +   This->DriverBindingHandle,
> > +   Controller);
> > +
> > + ErrorExit2:
> > +  if (UsbDisplayLinkDev != NULL) {
> > +    FreePool (UsbDisplayLinkDev);
> > +    UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)NULL;
> > +  }
> > +
> > +  DEBUG ((DEBUG_ERROR, "Exiting - Failed to initialise driver.\n"));
> > +
> > +  gBS->RestoreTPL (OriginalTPL);
> > +  return Status;
> > +}
> > +
> > +/**
> > +Entrypoint of USB DisplayLink Driver.
> > +
> > +This function is the entrypoint of a combined USB DisplayLink GOP Driver. It installs Driver Binding
> > +Protocols together with Component Name Protocols.
> > +
> > +@param  ImageHandle       The firmware allocated handle for the EFI image.
> > +@param  SystemTable       A pointer to the EFI System Table.
> > +@param  DriverBindingHandle  The Driver binding handle
> > +
> > +@retval EFI_SUCCESS       The entry point is executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> > +  IN EFI_HANDLE           ImageHandle,
> > +  IN EFI_SYSTEM_TABLE     *SystemTable,
> > +  IN EFI_HANDLE           DriverBindingHandle
> > +)
> > +{
> > +  EFI_STATUS Status;
> > +
> > +  Status = EfiLibInstallDriverBindingComponentName2 (
> > +    ImageHandle,
> > +    SystemTable,
> > +    &gUsbDisplayLinkDriverBinding,
> > +    DriverBindingHandle,
> > +    &mUsbDisplayLinkComponentName,
> > +    &mUsbDisplayLinkComponentName2);
> > +
> > +  ASSERT_EFI_ERROR (Status);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > +
> > +
> > +/**
> > +Entrypoint of USB DisplayLink Driver.
> > +
> > +This function is the entrypoint of USB DisplayLink Driver. It installs Driver Binding
> > +Protocols together with Component Name Protocols.
> > +
> > +@param  ImageHandle       The firmware allocated handle for the EFI image.
> > +@param  SystemTable       A pointer to the EFI System Table.
> > +
> > +@retval EFI_SUCCESS       The entry point is executed successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingEntryPoint (
> > +  IN EFI_HANDLE           ImageHandle,
> > +  IN EFI_SYSTEM_TABLE     *SystemTable
> > +)
> > +{
> > +  return UsbDisplayLinkDriverCombinedGopBindingEntryPoint (ImageHandle, SystemTable, ImageHandle);
> > +}
> > +
> > +
> > +/**
> > +Unloads an image.
> > +@param  ImageHandle           Handle that identifies the image to be unloaded.
> > +@retval EFI_SUCCESS           The image has been unloaded.
> > +@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverCombinedGopUnload (
> > +  IN EFI_HANDLE  ImageHandle
> > +)
> > +{
> > +  EFI_STATUS  Status = EFI_SUCCESS;
> > +  EFI_STATUS  handleDisconnectStatus;
> > +  EFI_HANDLE  *HandleBuffer;
> > +  UINTN       HandleCount;
> > +  UINTN       Index;
> > +
> > +  //
> > +  // Retrieve array of all handles in the handle database
> > +  //
> > +  handleDisconnectStatus = gBS->LocateHandleBuffer (
> > +    AllHandles,
> > +    NULL,
> > +    NULL,
> > +    &HandleCount,
> > +    &HandleBuffer
> > +  );
> > +  if (! EFI_ERROR (handleDisconnectStatus)) {
> > +    //
> > +    // Disconnect the current driver from handles in the handle database
> > +    //
> > +    for (Index = 0; Index < HandleCount; Index++) {
> > +      Status = gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
> > +    }
> > +    //
> > +    // Free the array of handles
> > +    //
> > +    if (HandleBuffer != NULL)
> > +    {
> > +      FreePool (HandleBuffer);
> > +    }
> > +  }
> > +
> > +  // Even if we didn't manage to disconnect the handles, try to uninstall the protocols
> > +  //
> > +  // Uninstall protocols installed in the driver entry point
> > +  //
> > +  Status = gBS->UninstallMultipleProtocolInterfaces (
> > +    ImageHandle,
> > +    &gEfiDriverBindingProtocolGuid,
> > +    &gUsbDisplayLinkDriverBinding,
> > +    &gEfiComponentNameProtocolGuid,
> > +    &mUsbDisplayLinkComponentName,
> > +    &gEfiComponentName2ProtocolGuid,
> > +    &mUsbDisplayLinkComponentName2,
> > +    NULL
> > +  );
> > +
> > +  if (EFI_ERROR (handleDisconnectStatus))
> > +  {
> > +    return handleDisconnectStatus;
> > +  }
> > +  return Status;
> > +}
> > +
> > +
> > +/**
> > +  Stop the USB DisplayLink device handled by this driver.
> > +
> > +  @param  This                   The USB DisplayLink 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_UNSUPPORTED        Simple Pointer Protocol is not installed on Controller.
> > +  @retval Others                 Fail to uninstall protocols attached on the device.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +UsbDisplayLinkDriverBindingStop (
> > +  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
> > +  IN  EFI_HANDLE                    Controller,
> > +  IN  UINTN                         NumberOfChildren,
> > +  IN  EFI_HANDLE                    *ChildHandleBuffer
> > +  )
> > +{
> > +  EFI_STATUS                        Status;
> > +  USB_DISPLAYLINK_DEV               *UsbDisplayLinkDev;
> > +  EFI_GRAPHICS_OUTPUT_PROTOCOL      *GraphicsOutputProtocol;
> > +
> > +  Status = gBS->OpenProtocol (
> > +                  Controller,
> > +                  &gEfiGraphicsOutputProtocolGuid,
> > +                  (VOID **) &GraphicsOutputProtocol,
> > +                  This->DriverBindingHandle,
> > +                  Controller,
> > +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    return EFI_UNSUPPORTED;
> > +  }
> > +
> > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> > +
> > +  // Reset the video mode to clear the display. Don't drop out if there is a problem, just press on.
> > +  // Note that this will also clear the frame buffer, as the screen buffer will be re-allocated with AllocateZeroPool.
> > +  if ((GraphicsOutputProtocol->Mode != NULL) &&
> > +      (GraphicsOutputProtocol->Mode->Mode != GRAPHICS_OUTPUT_INVALID_MODE_NUMBER)) {
> > +    Status = DisplayLinkSetMode (GraphicsOutputProtocol, GraphicsOutputProtocol->Mode->Mode);
> > +    if (EFI_ERROR (Status)) {
> > +      DEBUG ((DEBUG_WARN, "Driver stop - Problem resetting video mode - %r.\n", Status));
> > +    }
> > +  }
> > +
> > +  // Reset the alt setting on the interface (to the DL3 alt setting)
> > +  Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, 0);
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_WARN, "Error resetting USB interface alternate setting - %r.\n", Status));
> > +  }
> > +
> > +  Status = gBS->UninstallMultipleProtocolInterfaces (
> > +                  Controller,
> > +                  &gEfiGraphicsOutputProtocolGuid,
> > +                  &UsbDisplayLinkDev->GraphicsOutputProtocol,
> > +                  &gEfiEdidDiscoveredProtocolGuid,
> > +                  &UsbDisplayLinkDev->EdidDiscovered,
> > +                  &gEfiEdidActiveProtocolGuid,
> > +                  &UsbDisplayLinkDev->EdidActive,
> > +                  NULL);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_WARN, "Error uninstalling Graphics Output and EDID protocol interfaces - %r.\n", Status));
> > +    return Status;
> > +  }
> > +
> > +  gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> > +
> > +  gBS->CloseProtocol (
> > +         Controller,
> > +         &gEfiUsbIoProtocolGuid,
> > +         This->DriverBindingHandle,
> > +         Controller);
> > +
> > +  //
> > +  // Free all resources.
> > +  //
> > +  if (UsbDisplayLinkDev->ControllerNameTable != NULL) {
> > +    FreeUnicodeStringTable (UsbDisplayLinkDev->ControllerNameTable);
> > +  }
> > +
> > +  if (UsbDisplayLinkDev->Screen != NULL) {
> > +    FreePool (UsbDisplayLinkDev->Screen);
> > +    UsbDisplayLinkDev->Screen = NULL;
> > +  }
> > +
> > +  if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode) {
> > +    if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info) {
> > +      FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info);
> > +      UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info = NULL;
> > +    }
> > +    FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode);
> > +    UsbDisplayLinkDev->GraphicsOutputProtocol.Mode = NULL;
> > +  }
> > +
> > +  FreePool (UsbDisplayLinkDev);
> > +
> > +  return EFI_SUCCESS;
> > +
> > +}
> > +
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> > new file mode 100644
> > index 000000000000..497a2621bc2c
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> > @@ -0,0 +1,278 @@
> > +/**
> > + * @file UsbDisplayLink.h
> > + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#ifndef _EFI_USB_DISPLAYLINK_H_
> > +#define _EFI_USB_DISPLAYLINK_H_
> > +
> > +#include <Uefi/UefiBaseType.h>
> > +#include <Uefi/UefiSpec.h>
> > +
> > +#include <Protocol/EdidActive.h>
> > +#include <Protocol/EdidDiscovered.h>
> > +#include <Protocol/EdidOverride.h>
> > +#include <Protocol/GraphicsOutput.h>
> > +#include <Protocol/UsbIo.h>
> > +
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/ReportStatusCodeLib.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/UefiLib.h>
> > +
> > +#define VENDOR_DISPLAYLINK      0x17e9
> > +#define CLASS_VENDOR            0xFF
> > +
> > +#define DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO ((UINTN)0)
> > +
> > +#define INTERFACE_PROTOCOL_DIRECT_FB    4
> > +
> > +#define USB_TRANSFER_LENGTH           (64 * 1024)
> > +#define DISPLAYLINK_MODE_DATA_LENGTH  (146)
> > +#define DISPLAYLINK_USB_CTRL_TIMEOUT  (1000)
> > +#define DISPLAYLINK_USB_BULK_TIMEOUT  (1)
> > +
> > +#define DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD  ((UINTN)1000000) // 0.1s in us
> > +#define DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD   ((UINTN)30000) // 3s in ticks
> > +
> > +#define DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE ((UINT16)60)
> > +
> > +// Requests to read values from the firmware
> > +#define EDID_BLOCK_SIZE 128
> > +#define EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK ((UINT16)(0x64))
> > +
> > +/** Structures ported from firmware - protocol.h */
> > +enum ID {
> > +  // VideoCommands
> > +  GET_OUTPUT_EDID = 0,
> > +  SET_VIDEO_MODE = 1
> > +};
> > +
> > +typedef struct {
> > +  UINT32                     HorizontalResolution;
> > +  UINT32                     VerticalResolution;
> > +  UINT32                     ColorDepth;
> > +  UINT32                     RefreshRate;
> > +  UINT8                      Commands[DISPLAYLINK_MODE_DATA_LENGTH];
> > +} DISPLAYLINK_MODE_DATA;
> > +
> > +#define GRAPHICS_OUTPUT_INVALID_MODE_NUMBER 0xffff
> > +
> > +/**
> > + *  Device instance of USB display.
> > + */
> > +typedef struct {
> > +  UINT64                        Signature;
> > +  EFI_HANDLE                    Handle;
> > +  EFI_USB_IO_PROTOCOL           *UsbIo;
> > +  EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
> > +  EFI_USB_ENDPOINT_DESCRIPTOR   BulkOutEndpointDescriptor;
> > +  EFI_USB_ENDPOINT_DESCRIPTOR   BulkInEndpointDescriptor;
> > +  EFI_GRAPHICS_OUTPUT_PROTOCOL  GraphicsOutputProtocol;
> > +  EFI_EDID_DISCOVERED_PROTOCOL  EdidDiscovered;
> > +  EFI_EDID_ACTIVE_PROTOCOL      EdidActive;
> > +  EFI_UNICODE_STRING_TABLE      *ControllerNameTable;
> > +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Screen;
> > +  UINTN                         DataSent;                       /** Debug - used to track the bandwidth */
> > +  EFI_EVENT                     TimerEvent;
> > +  EFI_EVENT                     DriverExitBootServicesEvent;
> > +  BOOLEAN                       ShowBandwidth;                 /** Debugging - show the bandwidth on the screen */
> > +  BOOLEAN                       ShowTestPattern;               /** Show a colourbar pattern instead of the BLTd contents of the
> framebuffer */
> > +  UINTN                         LastY1;                        /** Used to track if we can do a partial screen update */
> > +  UINTN                         LastY2;
> > +  UINTN                         LastWidth;
> > +  UINTN                         TimeSinceLastScreenUpdate;     /** Do a full screen update every (x) seconds */
> > +} USB_DISPLAYLINK_DEV;
> > +
> > +#define USB_DISPLAYLINK_DEV_SIGNATURE SIGNATURE_32 ('d', 'l', 'i', 'n')
> > +
> > +struct VideoMode {
> > +  UINT8  Reserved1;          /* Reserved - must be 0. */
> > +  UINT8  Reserved2;          /* Reserved - must be 2. */
> > +
> > +  // Values matching the EDID Detailed Timing Descriptor spec
> > +  UINT16 PixelClock;
> > +  UINT16 HActive;
> > +  UINT16 HBlanking;
> > +  UINT16 HSyncOffset;  // Horizontal Front Porch
> > +  UINT16 HSyncWidth;
> > +  UINT16 VActive;
> > +  UINT16 VBlanking;
> > +  UINT16 VSyncOffset;  // Vertical Front Porch
> > +  UINT16 VSyncWidth;
> > +  // End of Edid Detailed Timing Descriptor
> > +
> > +  UINT16 Flags               /*ModeFlags*/;
> > +  UINT16 Accumulate;
> > +  UINT16 Reserved3;         /* Reserved - must be 0. */
> > +  UINT16 Reserved4;         /* Reserved - must be 0. */
> > +  UINT16 InsetLeft;
> > +  UINT16 InsetTop;
> > +  UINT16 InsetRight;
> > +  UINT16 InsetBottom;
> > +  UINT32 FillValue;
> > +  UINT32 Reserved5;        /* Reserved - must be 0. */
> > +  UINT8  Vic;
> > +  UINT8  ActiveFormat;
> > +  UINT16 Reserved6;
> > +};
> > +
> > +#define USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(a) \
> > +  CR(a, USB_DISPLAYLINK_DEV, GraphicsOutputProtocol, USB_DISPLAYLINK_DEV_SIGNATURE)
> > +
> > +//
> > +// Global Variables
> > +//
> > +extern EFI_DRIVER_BINDING_PROTOCOL   gUsbDisplayLinkDriverBinding;
> > +extern EFI_COMPONENT_NAME_PROTOCOL   mUsbDisplayLinkComponentName;
> > +extern EFI_COMPONENT_NAME2_PROTOCOL  mUsbDisplayLinkComponentName2;
> > +
> > +
> > +/* ******************************************* */
> > +/* ********  GOP interface functions  ******** */
> > +/* ******************************************* */
> > +
> > +/**
> > + * Implementation of the GOP protocol QueryMode API function
> > + * @param This         Instance of the GOP protocol
> > + * @param ModeNumber
> > + * @param SizeOfInfo
> > + * @param Info
> > + * @return
> > + */
> > +EFI_STATUS
> > +  EFIAPI
> > +  DisplayLinkQueryMode (
> > +    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
> > +    IN  UINT32                                ModeNumber,
> > +    OUT UINTN                                 *SizeOfInfo,
> > +    OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
> > +  );
> > +
> > +
> > +/**
> > + * Implementation of the GOP protocol SetMode API function
> > + * @param This
> > + * @param ModeNumber
> > + * @return
> > + */
> > +EFI_STATUS
> > +  EFIAPI
> > +  DisplayLinkSetMode (
> > +    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *This,
> > +    IN  UINT32                        ModeNumber
> > +  );
> > +
> > +/**
> > + * Implementation of the GOP protocol Blt API function
> > + * @param This
> > + * @param BltBuffer
> > + * @param BltOperation
> > + * @param SourceX
> > + * @param SourceY
> > + * @param DestinationX
> > + * @param DestinationY
> > + * @param Width
> > + * @param Height
> > + * @param Delta
> > + * @return
> > + */
> > +EFI_STATUS
> > +  EFIAPI
> > +  DisplayLinkBlt (
> > +    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
> > +    IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer, OPTIONAL
> > +    IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
> > +    IN  UINTN                                   SourceX,
> > +    IN  UINTN                                   SourceY,
> > +    IN  UINTN                                   DestinationX,
> > +    IN  UINTN                                   DestinationY,
> > +    IN  UINTN                                   Width,
> > +    IN  UINTN                                   Height,
> > +    IN  UINTN                                   Delta         OPTIONAL
> > +  );
> > +
> > +/* *************************** */
> > +/* **  GOP helper functions ** */
> > +/* *************************** */
> > +
> > +VOID
> > +EFIAPI
> > +DlGopPrintTextToScreen (
> > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> > +  UINTN X,
> > +  UINTN Y,
> > +  IN CONST CHAR16 *Format,
> > +  ...
> > +);
> > +
> > +EFI_STATUS
> > +DlGopSendTestPattern (
> > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > +  UINTN PatternNumber
> > +);
> > +
> > +EFI_STATUS
> > +DlGopSendScreenUpdate (
> > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > +);
> > +
> > +
> > +/* ******************************************* */
> > +/* ********  USB interface functions  ******** */
> > +/* ******************************************* */
> > +
> > +EFI_STATUS
> > +DlUsbSendControlWriteMessage (
> > +  IN USB_DISPLAYLINK_DEV *Device,
> > +  IN UINT8 Request,
> > +  IN UINT16 Value,
> > +  IN CONST VOID *ControlMsg,
> > +  IN UINT16 ControlMsgLen
> > +);
> > +
> > +EFI_STATUS
> > +DlUsbSendControlReadMessage (
> > +  IN USB_DISPLAYLINK_DEV *Device,
> > +  IN UINT8 Request,
> > +  IN UINT16 Value,
> > +  OUT VOID *ControlMsg,
> > +  IN UINT16 ControlMsgLen
> > +);
> > +
> > +EFI_STATUS
> > +DlUsbBulkWrite (
> > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > +  CONST UINT8* Buffer,
> > +  UINTN DataLen,
> > +  UINT32 *USBStatus
> > +);
> > +
> > +UINTN
> > +DlUsbBulkRead (
> > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > +  UINT8* Buffer,
> > +  UINTN BufferLen
> > +);
> > +
> > +/* ******************************************* */
> > +/* ********   Video Mode functions    ******** */
> > +/* ******************************************* */
> > +
> > +// Pre-calculated video modes
> > +UINT32
> > +DlVideoModeGetNumSupportedVideoModes ();
> > +
> > +CONST struct VideoMode *
> > +DlVideoModeGetSupportedVideoMode (
> > +  UINT32 index
> > +);
> > +
> > +#endif
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> > new file mode 100644
> > index 000000000000..252293da39d4
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> > @@ -0,0 +1,180 @@
> > +/**
> > + * @file UsbTransfer.c
> > + * @brief Wrapper of UEFI USB bulk and control transfer interface for USB DisplayLink driver.
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +/**
> > + * Write the data to the DisplayLink device using the USBIO protocol.
> > + * @param UsbDisplayLinkDev
> > + * @param Buffer
> > + * @param DataLen
> > + * @param USBStatus
> > + * @return
> > +  * EFI_SUCCESS   The bulk transfer has been successfully executed.
> > +  * EFI_INVALID_PARAMETER   If DeviceEndpoint is not valid.
> > +  * EFI_INVALID_PARAMETER   Data is NULL.
> > +  * EFI_INVALID_PARAMETER   DataLength is NULL.
> > +  * EFI_INVALID_PARAMETER   Status is NULL.
> > +  * EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
> > +  * EFI_TIMEOUT   The bulk transfer cannot be completed within Timeout timeframe.
> > +  * EFI_DEVICE_ERROR  The transfer failed other than timeout, and the transfer status is returned in Status.
> > + */
> > +EFI_STATUS
> > +DlUsbBulkWrite (
> > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > +    IN CONST UINT8* Buffer,
> > +    IN UINTN DataLen,
> > +    OUT UINT32 *USBStatus
> > +    )
> > +{
> > +  EFI_STATUS Status;
> > +  Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> > +    UsbDisplayLinkDev->UsbIo,
> > +    UsbDisplayLinkDev->BulkOutEndpointDescriptor.EndpointAddress,
> > +    (VOID*)Buffer,
> > +    &DataLen,
> > +    DISPLAYLINK_USB_BULK_TIMEOUT,
> > +    USBStatus);
> > +
> > +  return Status;
> > +}
> > +
> > +/**
> > +* Read data from the DisplayLink device using the USBIO protocol.
> > +* @param UsbDisplayLinkDev
> > +* @param Buffer
> > +* @param BufferLen
> > +* @return 0 if an error occurred or 0 bytes were read, otherwise the number of bytes read
> > + */
> > +UINTN
> > +DlUsbBulkRead (
> > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > +    IN UINT8* Buffer,
> > +    IN UINTN BufferLen
> > +    )
> > +{
> > +  UINT32 Result;
> > +  UINTN ReadLen;
> > +  EFI_STATUS Status;
> > +
> > +  ReadLen = BufferLen;
> > +
> > +  Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> > +    UsbDisplayLinkDev->UsbIo,
> > +    UsbDisplayLinkDev->BulkInEndpointDescriptor.EndpointAddress,
> > +    Buffer,
> > +    &ReadLen,
> > +    DISPLAYLINK_USB_BULK_TIMEOUT,
> > +    &Result);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    return 0;
> > +  }
> > +
> > +  return ReadLen;
> > +}
> > +
> > +
> > +/**
> > +Send a control message (e.g set video mode) message to the DisplayLink device.
> > +
> > +@param  Device                   USB device handle.
> > +@param  request                  Request type, e.g. SET_VIDEO_MODE
> > +@param  value
> > +@param  controlMsg               Pointer to the message to send.
> > +@param  controlMsgLen            Length of the message.
> > +
> > +@retval EFI_SUCCESS            Successfully sent message.
> > +
> > +**/
> > +EFI_STATUS
> > +DlUsbSendControlWriteMessage (
> > +  IN USB_DISPLAYLINK_DEV *Device,
> > +  IN UINT8 Request,
> > +  IN UINT16 Value,
> > +  IN CONST VOID *ControlMsg,
> > +  IN UINT16 ControlMsgLen
> > +  )
> > +{
> > +  EFI_STATUS             Status;
> > +  UINT32                 UsbStatus;
> > +  EFI_USB_DEVICE_REQUEST UsbRequest;
> > +
> > +  ZeroMem (&Request, sizeof (Request));
> > +  UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE;
> > +  UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> > +  UsbRequest.Request = Request;
> > +  UsbRequest.Value = Value;
> > +  UsbRequest.Length = ControlMsgLen;
> > +
> > +  Status = Device->UsbIo->UsbControlTransfer (
> > +    Device->UsbIo,
> > +    &UsbRequest,
> > +    EfiUsbDataOut,
> > +    DISPLAYLINK_USB_CTRL_TIMEOUT,
> > +    (VOID *)ControlMsg,
> > +    ControlMsgLen,
> > +    &UsbStatus);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "USB write control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> > +    Status = EFI_DEVICE_ERROR;
> > +  }
> > +  return Status;
> > +}
> > +
> > +
> > +/**
> > +Request data from the DisplayLink device (e.g. the monitor EDID)
> > +
> > +@param  Device                   USB device handle.
> > +@param  request                  Request type, e.g. GET_OUTPUT_EDID
> > +@param  value
> > +@param  controlMsg               Pointer to the message to send.
> > +@param  controlMsgLen            Length of the message.
> > +
> > +@retval EFI_SUCCESS            Successfully sent message.
> > +
> > +**/
> > +EFI_STATUS
> > +DlUsbSendControlReadMessage (
> > +  IN USB_DISPLAYLINK_DEV *Device,
> > +  IN UINT8 Request,
> > +  IN UINT16 Value,
> > +  OUT VOID *ControlMsg,
> > +  IN UINT16 ControlMsgLen
> > +  )
> > +{
> > +  EFI_STATUS             Status;
> > +  UINT32                 UsbStatus;
> > +  EFI_USB_DEVICE_REQUEST UsbRequest;
> > +
> > +  ZeroMem (&UsbRequest, sizeof (UsbRequest));
> > +  UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE | USB_ENDPOINT_DIR_IN;
> > +  UsbRequest.Request = Request;
> > +  UsbRequest.Value = Value;
> > +  UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> > +  UsbRequest.Length = ControlMsgLen;
> > +
> > +  Status = Device->UsbIo->UsbControlTransfer (
> > +    Device->UsbIo,
> > +    &UsbRequest,
> > +    EfiUsbDataIn,
> > +    DISPLAYLINK_USB_CTRL_TIMEOUT,
> > +    (VOID *)ControlMsg,
> > +    ControlMsgLen,
> > +    &UsbStatus);
> > +
> > +  if (EFI_ERROR (Status)) {
> > +    DEBUG ((DEBUG_ERROR, "USB read control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> > +    Status = EFI_DEVICE_ERROR;
> > +  }
> > +  return Status;
> > +}
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> > new file mode 100644
> > index 000000000000..6218c093147c
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> > @@ -0,0 +1,254 @@
> > +/**
> > + * @file VideoModes.c
> > + * @brief Pre-calculated video timings sent to the DisplayLink device when a video mode is selected
> > + *
> > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > + *
> > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > + *
> > +**/
> > +
> > +#include "UsbDisplayLink.h"
> > +
> > +
> > +// Supported video modes - must be in order of pixel count (i.e. hres x vres)
> > +
> > +STATIC CONST struct VideoMode ModeData[] = {
> > +  {
> > +     // 640 x 480 @ 60Hz
> > +    .Reserved2 = 2,
> > +    .PixelClock = 2517,
> > +    .HActive = 640,
> > +    .HBlanking = 160,
> > +    .HSyncOffset = 16,
> > +    .HSyncWidth = 96,
> > +    .VActive = 480,
> > +    .VBlanking = 45,
> > +    .VSyncOffset = 10,
> > +    .VSyncWidth = 2,
> > +    .Flags = 0x00000300,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  },
> > +  {
> > +    // 800 x 600 @ 60Hz
> > +    .Reserved2 = 2,
> > +    .PixelClock = 4000,
> > +    .HActive = 800,
> > +    .HBlanking = 256,
> > +    .HSyncOffset = 40,
> > +    .HSyncWidth = 128,
> > +    .VActive = 600,
> > +    .VBlanking = 28,
> > +    .VSyncOffset = 1,
> > +    .VSyncWidth = 3,
> > +    .Flags = 0x00000000,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  },
> > +  {
> > +    // 1024x768 @ 60Hz
> > +    .Reserved1 = 0,
> > +    .Reserved2 = 2,
> > +    .PixelClock = 6500,
> > +    .HActive = 1024,
> > +    .HBlanking = 320,
> > +    .HSyncOffset = 24,
> > +    .HSyncWidth = 136,
> > +    .VActive = 768,
> > +    .VBlanking = 38,
> > +    .VSyncOffset = 3,
> > +    .VSyncWidth = 6,
> > +    .Flags = 0x00000300,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  },
> > +  {
> > +    // 1360x768 @ 60Hz
> > +    .Reserved1 = 0,
> > +    .Reserved2 = 2,
> > +    .PixelClock = 8550,
> > +    .HActive = 1360,
> > +    .HBlanking = 432,
> > +    .HSyncOffset = 64,
> > +    .HSyncWidth = 112,
> > +    .VActive = 768,
> > +    .VBlanking = 27,
> > +    .VSyncOffset = 3,
> > +    .VSyncWidth = 6,
> > +    .Flags = 0x00000000,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  },
> > +  {
> > +    // 1280x960 @ 60Hz
> > +    .Reserved1 = 0,
> > +    .Reserved2 = 2,
> > +    .PixelClock = 10800,
> > +    .HActive = 1280,
> > +    .HBlanking = 520,
> > +    .HSyncOffset = 96,
> > +    .HSyncWidth = 112,
> > +    .VActive = 960,
> > +    .VBlanking = 40,
> > +    .VSyncOffset = 1,
> > +    .VSyncWidth = 3,
> > +    .Flags = 0x00000000,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  },
> > +  {
> > +    // 1280x1024 @ 60Hz
> > +    .Reserved1 = 0,
> > +    .Reserved2 = 2,
> > +    .PixelClock = 10800,
> > +    .HActive = 1280,
> > +    .HBlanking = 408,
> > +    .HSyncOffset = 48,
> > +    .HSyncWidth = 112,
> > +    .VActive = 1024,
> > +    .VBlanking = 42,
> > +    .VSyncOffset = 1,
> > +    .VSyncWidth = 3,
> > +    .Flags = 0x00000000,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  },
> > +  {
> > +    // 1600x900 @ 60Hz
> > +    .Reserved2 = 2,
> > +    .PixelClock = 11825,
> > +    .HActive = 1600,
> > +    .HBlanking = 512,
> > +    .HSyncOffset = 88,
> > +    .HSyncWidth = 168,
> > +    .VActive = 900,
> > +    .VBlanking = 34,
> > +    .VSyncOffset = 3,
> > +    .VSyncWidth = 5,
> > +    .Flags = 0x00000500,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  },
> > +  {
> > +    // 1400x1050 @ 60Hz
> > +    .Reserved1 = 0,
> > +    .Reserved2 = 2,
> > +    .PixelClock = 12175,
> > +    .HActive = 1400,
> > +    .HBlanking = 464,
> > +    .HSyncOffset = 88,
> > +    .HSyncWidth = 144,
> > +    .VActive = 1050,
> > +    .VBlanking = 39,
> > +    .VSyncOffset = 3,
> > +    .VSyncWidth = 4,
> > +    .Flags = 0x00000100,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  },
> > +  {
> > +    // 1600x1200 @ 60Hz
> > +    .Reserved1 = 0,
> > +    .Reserved2 = 2,
> > +    .PixelClock = 16200,
> > +    .HActive = 1600,
> > +    .HBlanking = 560,
> > +    .HSyncOffset = 64,
> > +    .HSyncWidth = 192,
> > +    .VActive = 1200,
> > +    .VBlanking = 50,
> > +    .VSyncOffset = 1,
> > +    .VSyncWidth = 3,
> > +    .Flags = 0x00000000,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  },
> > +  {
> > +    // 1920 x 1080
> > +    .Reserved2 = 2,
> > +    .PixelClock = 14850,
> > +    .HActive = 1920,
> > +    .HBlanking = 280,
> > +    .HSyncOffset = 88,
> > +    .HSyncWidth = 44,
> > +    .VActive = 1080,
> > +    .VBlanking = 45,
> > +    .VSyncOffset = 4,
> > +    .VSyncWidth = 5,
> > +    .Flags = 0x00000000,
> > +    .Accumulate = 1,
> > +    .Reserved3 = 0,
> > +    .Reserved4 = 0,
> > +    .Reserved5 = 0x00000000,
> > +    .Vic = 0,
> > +    .ActiveFormat = 0,
> > +  }
> > +};
> > +
> > +STATIC CONST UINT32 NumSupportedVideoModes = (sizeof (ModeData) / sizeof (struct VideoMode));
> > +
> > +/**
> > +Find the number of pre-calculated video modes that we support.
> > +
> > +@retval Number of modes.
> > +
> > +**/
> > +UINT32 DlVideoModeGetNumSupportedVideoModes ()
> > +{
> > +  return NumSupportedVideoModes;
> > +}
> > +
> > +/**
> > +Get one of the pre-calculated video modes
> > +
> > +@param  index      The video mode that we want.
> > +
> > +@retval NULL       The index was out of range.
> > +
> > +**/
> > +CONST struct VideoMode *DlVideoModeGetSupportedVideoMode (
> > +    UINT32 Index
> > +    )
> > +{
> > +  if (Index >= NumSupportedVideoModes) {
> > +    return NULL;
> > +  }
> > +  return &ModeData[Index];
> > +}
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> > new file mode 100644
> > index 000000000000..955331ba6076
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> > @@ -0,0 +1,61 @@
> > +#/** @file
> > +#
> > +#  Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > +#
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +#**/
> > +
> > +[Defines]
> > +  PLATFORM_NAME                  = DisplayLinkPkg
> > +  PLATFORM_GUID                  = ad3b37b0-f798-4f97-9b3f-0c6f43d7c993
> > +  PLATFORM_VERSION               = 0.1
> > +  DSC_SPECIFICATION              = 0x0001001C
> > +  OUTPUT_DIRECTORY               = Build/DisplayLink
> > +  SUPPORTED_ARCHITECTURES        = X64|IA32|AARCH64|ARM
> > +  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
> > +  SKUID_IDENTIFIER               = DEFAULT
> > +
> > +[LibraryClasses]
> > +  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
> > +  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> > +  DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
> > +  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
> > +  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> > +  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> > +  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
> > +  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
> > +  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
> > +  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
> > +  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
> > +  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
> > +  UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
> > +
> > +[LibraryClasses.common.UEFI_DRIVER]
> > +  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
> > +
> > +[LibraryClasses.AARCH64]
> > +  NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> > +  NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> > +
> > +[LibraryClasses.ARM]
> > +  NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> > +  NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> > +
> > +[PcdsFixedAtBuild]
> > +!ifdef $(DEBUG_ENABLE_OUTPUT)
> > +  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x3f
> > +  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80080043  # Flags to control amount of debug output - see
> https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging
> > +  gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x07
> > +!endif
> > +
> > +[Components]
> > +  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > +
> > +[BuildOptions]
> > +  *_*_*_CC_FLAGS               = -D DISABLE_NEW_DEPRECATED_INTERFACES -D
> INF_DRIVER_VERSION=$(INF_DRIVER_VERSION)
> > +  GCC:RELEASE_*_*_CC_FLAGS     = -DMDEPKG_NDEBUG
> > +  MSFT:RELEASE_*_*_CC_FLAGS    = /D MDEPKG_NDEBUG
> > +!ifdef $(COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE)
> > +  *_*_*_CC_FLAGS = -D COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > +!endif
> > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> > new file mode 100644
> > index 000000000000..40061f1eb46d
> > --- /dev/null
> > +++ b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> > @@ -0,0 +1,77 @@
> > +# DISPLAYLINK DRIVERS
> > +This package contains a GOP driver for Universal USB-connected docks containing the
> > +DisplayLink DL-6xxx chip or newer.
> > +
> > +[DisplayLink Website](http://www.displaylink.com)
> > +
> > +[Products](https://www.displaylink.com/products/universal-docking-stations)
> > +
> > +# INDEX
> > +
> > +* [Resolutions Supported](#resolutions-supported)
> > +* [Frame rates](#frame-rates)
> > +* [Multiple monitor outputs](#multiple-monitor-outputs)
> > +* [Multiple DisplayLink devices](#multiple-displaylink-devices)
> > +* [Behaviour with no monitor connected](#behaviour-with-no-monitor-connected)
> > +
> > +# Resolutions supported
> > +
> > +The driver supports the following resolutions:
> > +
> > +640 x 480 @ 60Hz
> > +
> > +800 x 600 @ 60Hz
> > +
> > +1024x768 @ 60Hz
> > +
> > +1360x768 @ 60Hz
> > +
> > +1280x960 @ 60Hz
> > +
> > +1280x1024 @ 60Hz
> > +
> > +1600x900 @ 60Hz
> > +
> > +1400x1050 @ 60Hz
> > +
> > +1600x1200 @ 60Hz
> > +
> > +1920x1080 @ 60Hz
> > +
> > +
> > +Note that the list of resolutions advertised by the driver may be smaller than
> > +this if a connected monitor does not support a particular resolution. The driver
> > +interrogates connected monitors to see which modes can be supported.It is the
> > +responsibility of the BIOS to select the video mode from this list which most
> > +closely matches its requirements. In some cases this may lead to the BIOS
> > +scaling its display.
> > +
> > +# Frame rates
> > +
> > +The driver is limited to a maximum of ten frames per second. Some slower systems
> > +at higher screen resolutions may perform at a lower rate than this.
> > +
> > +# Multiple monitor outputs
> > +
> > +If multiple monitors are connected to the DisplayLinkdevice, the display will be
> > +duplicated (cloned) across all outputs at the same resolution. The resolution
> > +used will be limited by the capability of the monitor with the
> > +lowest specification.
> > +
> > +# Multiple DisplayLink devices
> > +
> > +The driver will support the connection of multiple DisplayLink devices. The
> > +exact behaviourof the system with multiple devices connected is defined by the
> > +rest of the BIOS; usually, the BIOS causes the displays to be duplicated
> > +(cloned) across all devices. Note that the system performance and frame rate
> > +will be affected by the number of DisplayLink devices connected.
> > +
> > +# Behaviour with no monitor connected
> > +
> > +The driver uses the EDID (Extended Display Identification Data) protocol to
> > +detect the list of resolutions that a monitor will support.In some monitors this
> > +may take some time, and occasionally no EDID information will be returned at
> > +all. In this case the driver will not be able to detect that there is a monitor
> > +connected. To improve the user experience in these cases, the driver will behave
> > +as if there is a monitor connected, and will fall back to presenting the full
> > +range of supported resolutions to the BIOS.
> > diff --git a/Maintainers.txt b/Maintainers.txt
> > index 876ae5612ad8..47aac133abb1 100644
> > --- a/Maintainers.txt
> > +++ b/Maintainers.txt
> > @@ -47,6 +47,11 @@ Drivers/OptionRomPkg
> >  W: https://github.com/tianocore/tianocore.github.io/wiki/OptionRomPkg
> >  M: Ray Ni <ray.ni@intel.com>
> >
> > +Drivers/DisplayLink
> > +M: Leif Lindholm <leif.lindholm@linaro.org>
> > +M: Ard Bieshuevel <ard.bieshuevel@linaro.org>
> > +R: Andy Hayes <andy.hayes@displaylink.com>
> > +
> >  Platform
> >  M: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >  M: Leif Lindholm <leif.lindholm@linaro.org>
> > --
> > 2.20.1
> >

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips
  2019-09-13  7:57     ` Ni, Ray
@ 2019-09-19 16:42       ` Leif Lindholm
  0 siblings, 0 replies; 6+ messages in thread
From: Leif Lindholm @ 2019-09-19 16:42 UTC (permalink / raw)
  To: Ni, Ray; +Cc: Andy Hayes, Kinney, Michael D, devel@edk2.groups.io

Hi Ray,

On Fri, Sep 13, 2019 at 07:57:08AM +0000, Ni, Ray wrote:
> Leif, Mike,
> I have two general comments regarding the edk2-platforms/Drivers directory:
> 1. should we change it to "Driver" because the other two don't carry a "s"?
> 2. Where should OptionRomPkg go? "Platform" and "Silicon" both
> contains vendor sub-directories. Now "Driver" contains vendor
> sub-directory as well. But OptionRomPkg is in the root of
> "Driver". Do we need to put it as a future task to separate the
> OptionRomPkg according to vendors? or create "Driver/Intel" and put
> OptionRomPkg there?

I agree we should look into reworking this. We've gone through the
initial effort of importing OpenPlatformPkg, bringing Intel platforms
across from -devel branches, and moving non-industry-standard items
across from edk2. It would make sense to revisit the directory layout
now we have some more content to relate to.

Best Regards,

Leif

> (sorry I thought I sent the mail long time ago.)
> 
> Thanks,
> Ray
> 
> > -----Original Message-----
> > From: Leif Lindholm <leif.lindholm@linaro.org>
> > Sent: Friday, August 30, 2019 8:27 AM
> > To: Andy Hayes <andy.hayes@displaylink.com>
> > Cc: devel@edk2.groups.io; Kinney, Michael D <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>
> > Subject: Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on
> > DisplayLink chips
> > 
> > Hi Andy,
> > 
> > This looks fine to me - all my feedback has been addressed.
> > Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
> > 
> > Ray - did you have any comments on this, or can I go ahead and commit?
> > 
> > Best Regards,
> > 
> > Leif
> > 
> > On Mon, Aug 19, 2019 at 02:32:00PM +0100, Andy Hayes wrote:
> > > Cc: Leif Lindholm <leif.lindholm@linaro.org>
> > > Cc: Michael D Kinney <michael.d.kinney@intel.com>
> > > Signed-off-by: Andy Hayes <andy.hayes@displaylink.com>
> > > ---
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c |  137 +++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c        |  235 +++++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf  |   65 ++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c                 |  598 +++++++++++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h                 |  129 +++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c                  |  578 +++++++++++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c       |  145 +++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h       |  109 ++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c       | 1082 ++++++++++++++++++++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h       |  278 +++++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c          |  180 ++++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c           |  254 +++++
> > >  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc                    |   61 ++
> > >  Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md                             |   77 ++
> > >  Maintainers.txt                                                          |    5 +
> > >  15 files changed, 3933 insertions(+)
> > >
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> > > new file mode 100644
> > > index 000000000000..4bfadd770b81
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.c
> > > @@ -0,0 +1,137 @@
> > > +/** @file CapabilityDescriptor.c
> > > + * @brief Definitions for reading USB capability descriptor DisplayLink dock
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#include "UsbDisplayLink.h"
> > > +#include "UsbDescriptors.h"
> > > +
> > > +/**
> > > + * Check that the Capability Descriptor is valid and hasn't been tampered with.
> > > + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> > > + * @param Length
> > > + * @param out
> > > + * @return
> > > + */
> > > +STATIC EFI_STATUS
> > > +ValidateHeader (
> > > +    CONST IN VOID* Data,
> > > +    IN UINTN Length,
> > > +    OUT CONST VendorDescriptorGeneric** Out
> > > +    )
> > > +{
> > > +  if (Length < sizeof (VendorDescriptorGeneric)) {
> > > +    DEBUG ((DEBUG_ERROR, "Data too short (%d bytes) for capability descriptor header section\n", Length));
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +  CONST VendorDescriptorGeneric* Desc = (VendorDescriptorGeneric*)Data;
> > > +  if (Desc->Length > Length) {
> > > +    DEBUG ((DEBUG_ERROR, "Capability descriptor: Descriptor (%d bytes) exceeds buffer (%d bytes)\n",
> > > +          Length, Desc->Length));
> > > +    return EFI_BUFFER_TOO_SMALL;
> > > +  }
> > > +  if (Desc->Type != DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY) {
> > > +    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid type (0x%08x)\n", Desc->Type));
> > > +    return EFI_UNSUPPORTED;
> > > +  }
> > > +  if (Desc->CapabilityVersion != 1) {
> > > +    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid version (%d)\n", Desc->CapabilityVersion));
> > > +    return EFI_INCOMPATIBLE_VERSION;
> > > +  }
> > > +  // Capability length must fit within remaining space
> > > +  if (Desc->CapabilityLength > (Desc->Length - (sizeof (Desc->Length) + sizeof (Desc->Type)))) {
> > > +    DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid CapabilityLength (%d)\n", Desc->CapabilityLength));
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +  *Out = Desc;
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +
> > > +/**
> > > + * Check that the connected DisplayLink device supports the functionality that this driver requires, e.g. video formats
> > > + * @param Data Binary data of the Capability Descriptor received from the DisplayLink device
> > > + * @param Length
> > > + * @param Output
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +UsbDisplayLinkParseCapabilitiesDescriptor (
> > > +    CONST IN VOID* Data,
> > > +    IN UINTN Length,
> > > +    OUT VendorDescriptor* Output
> > > +    )
> > > +{
> > > +  CONST VendorDescriptorGeneric* Desc;
> > > +  EFI_STATUS Status;
> > > +
> > > +  Desc = NULL;
> > > +  Status = ValidateHeader (Data, Length, &Desc);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    return Status;
> > > +  }
> > > +
> > > +  // Default capabilities
> > > +  Output->Capabilities1 = 0;
> > > +
> > > +  CONST UINTN CapsHeaderLength = sizeof (Desc->CapabilityVersion) + sizeof (Desc->CapabilityLength);
> > > +  ASSERT (CapsHeaderLength < MAX_UINT8);
> > > +
> > > +  UINTN DataRemaining;
> > > +  UINTN Offset;
> > > +
> > > +  DataRemaining = Desc->CapabilityLength - CapsHeaderLength;
> > > +  Offset = 0;
> > > +
> > > +  while (DataRemaining >= sizeof (DescriptorKLV)) {
> > > +    CONST DescriptorKLV* KeyHeader = (CONST DescriptorKLV*)(Desc->Klv + Offset);
> > > +    CONST UINTN KeyValueSize = sizeof (DescriptorKLV) + KeyHeader->Length;
> > > +    if (KeyValueSize > DataRemaining) {
> > > +      DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid value Length (%d)\n", Desc->CapabilityLength));
> > > +      return EFI_INVALID_PARAMETER;
> > > +    }
> > > +
> > > +    switch (KeyHeader->Key) {
> > > +      case CAPABILITIES1_KEY: {
> > > +        if (KeyHeader->Length != CAPABILITIES1_LENGTH) {
> > > +          DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid length (%d) for Capabilities 1\n", KeyHeader->Length));
> > > +          return EFI_INVALID_PARAMETER;
> > > +        }
> > > +        Output->Capabilities1 = *(UINT32*)KeyHeader->Value;
> > > +        break;
> > > +      default:
> > > +        // Ignore unknown types
> > > +        break;
> > > +      }
> > > +    }
> > > +    DataRemaining -= KeyValueSize;
> > > +    Offset += KeyValueSize;
> > > +  }
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +
> > > +/**
> > > + * Check that the DisplayLink device supports the basic level of functionality to display GOP pixels.
> > > + * @param Descriptor The USB descriptor received from the DisplayLink device
> > > + * @return True we can bind, False we can't
> > > + */
> > > +BOOLEAN
> > > +UsbDisplayLinkCapabilitiesSufficientToBind (
> > > +    CONST IN VendorDescriptor* Descriptor
> > > +    )
> > > +{
> > > +  BOOLEAN Sufficient;
> > > +  Sufficient = (BOOLEAN)(Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL);
> > > +
> > > +  if (Sufficient == FALSE) {
> > > +    DEBUG ((DEBUG_ERROR, "DisplayLink device does not report support for base capabilites - reports x%x, required x%x\n",
> > Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL));
> > > +  }
> > > +  return Sufficient;
> > > +}
> > > +
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> > > new file mode 100644
> > > index 000000000000..74498f339eb7
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c
> > > @@ -0,0 +1,235 @@
> > > +/**
> > > + * @file ComponentName.c
> > > + * @brief UEFI Component Name protocol implementation for USB DisplayLink driver.
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#include "UsbDisplayLink.h"
> > > +
> > > +
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkComponentNameGetDriverName (
> > > +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> > > +  IN  CHAR8                        *Language,
> > > +  OUT CHAR16                       **DriverName
> > > +);
> > > +
> > > +
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkComponentNameGetControllerName (
> > > +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> > > +  IN  EFI_HANDLE                                      ControllerHandle,
> > > +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> > > +  IN  CHAR8                                           *Language,
> > > +  OUT CHAR16                                          **ControllerName
> > > +);
> > > +
> > > +
> > > +//
> > > +// EFI Component Name Protocol
> > > +//
> > > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  mUsbDisplayLinkComponentName = {
> > > +  UsbDisplayLinkComponentNameGetDriverName,
> > > +  UsbDisplayLinkComponentNameGetControllerName,
> > > +  "eng"
> > > +};
> > > +
> > > +//
> > > +// EFI Component Name 2 Protocol
> > > +//
> > > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplayLinkComponentName2 = {
> > > +  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbDisplayLinkComponentNameGetDriverName,
> > > +  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbDisplayLinkComponentNameGetControllerName,
> > > +  "en"
> > > +};
> > > +
> > > +
> > > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbDisplayLinkDriverNameTable[] = {
> > > +  { (CHAR8*)"eng;en", (CHAR16*)L"DisplayLink USB GOP Driver" },
> > > +  { (CHAR8*)NULL , (CHAR16*)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                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> > > +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> > > +  @param  Language              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            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
> > > +UsbDisplayLinkComponentNameGetDriverName (
> > > +  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
> > > +  IN  CHAR8                        *Language,
> > > +  OUT CHAR16                       **DriverName
> > > +  )
> > > +{
> > > +  return LookupUnicodeString2 (
> > > +           Language,
> > > +           This->SupportedLanguages,
> > > +           mUsbDisplayLinkDriverNameTable,
> > > +           DriverName,
> > > +           (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> > > +}
> > > +
> > > +/**
> > > +  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                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
> > > +                                EFI_COMPONENT_NAME_PROTOCOL instance.
> > > +  @param  ControllerHandle      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           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              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        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 not a valid EFI_HANDLE.
> > > +  @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
> > > +UsbDisplayLinkComponentNameGetControllerName (
> > > +  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
> > > +  IN  EFI_HANDLE                                      ControllerHandle,
> > > +  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
> > > +  IN  CHAR8                                           *Language,
> > > +  OUT CHAR16                                          **ControllerName
> > > +  )
> > > +{
> > > +  EFI_STATUS                   Status;
> > > +  USB_DISPLAYLINK_DEV          *UsbDisplayLinkDev;
> > > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol;
> > > +  EFI_USB_IO_PROTOCOL          *UsbIoProtocol;
> > > +
> > > +  //
> > > +  // This is a device driver, so ChildHandle must be NULL.
> > > +  //
> > > +  if (ChildHandle != NULL) {
> > > +    return EFI_UNSUPPORTED;
> > > +  }
> > > +
> > > +  //
> > > +  // Check Controller's handle
> > > +  //
> > > +  Status = gBS->OpenProtocol  (
> > > +                  ControllerHandle,
> > > +                  &gEfiUsbIoProtocolGuid,
> > > +                  (VOID **) &UsbIoProtocol,
> > > +                  gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> > > +                  ControllerHandle,
> > > +                  EFI_OPEN_PROTOCOL_BY_DRIVER);
> > > +
> > > +  if (!EFI_ERROR (Status)) {
> > > +    gBS->CloseProtocol  (
> > > +           ControllerHandle,
> > > +           &gEfiUsbIoProtocolGuid,
> > > +           gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> > > +           ControllerHandle);
> > > +
> > > +    return EFI_UNSUPPORTED;
> > > +  }
> > > +
> > > +  if (Status != EFI_ALREADY_STARTED) {
> > > +    return EFI_UNSUPPORTED;
> > > +  }
> > > +  //
> > > +  // Get the device context
> > > +  //
> > > +  Status = gBS->OpenProtocol (
> > > +                  ControllerHandle,
> > > +                  &gEfiGraphicsOutputProtocolGuid,
> > > +                  (VOID**)&GraphicsOutputProtocol,
> > > +                  gUsbDisplayLinkDriverBinding.DriverBindingHandle,
> > > +                  ControllerHandle,
> > > +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    return Status;
> > > +  }
> > > +
> > > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> > > +
> > > +  return LookupUnicodeString2 (
> > > +           Language,
> > > +           This->SupportedLanguages,
> > > +           UsbDisplayLinkDev->ControllerNameTable,
> > > +           ControllerName,
> > > +           (BOOLEAN)(This == &mUsbDisplayLinkComponentName));
> > > +}
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > > new file mode 100644
> > > index 000000000000..0f458fedcc88
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > > @@ -0,0 +1,65 @@
> > > +#/** @file
> > > +# USB DisplayLink driver that implements blt and EDID commands
> > > +#
> > > +# USB DisplayLink driver consumes I/O Protocol and Device Path Protocol, and produces
> > > +# Graphics Output Protocol on DisplayLink devices.
> > > +# 1. DisplayLink reference
> > > +# 2. UEFI Specification, v2.1
> > > +#
> > > +#  Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > +#
> > > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +#
> > > +#**/
> > > +
> > > +
> > > +[Defines]
> > > +  INF_VERSION                    = 0x0001001B
> > > +  BASE_NAME                      = DisplayLinkGop
> > > +  FILE_GUID                      = 2D2E62AA-9ECF-43b7-8219-94E7FC713DFF
> > > +  MODULE_TYPE                    = UEFI_DRIVER
> > > +  VERSION_STRING                 = 1.0
> > > +  ENTRY_POINT                    = UsbDisplayLinkDriverBindingEntryPoint
> > > +  UNLOAD_IMAGE                   = UsbDisplayLinkDriverCombinedGopUnload
> > > +  INF_DRIVER_VERSION             = 0x00000001
> > > +
> > > +[Sources]
> > > +  CapabilityDescriptor.c
> > > +  ComponentName.c
> > > +  Edid.c
> > > +  Edid.h
> > > +  Gop.c
> > > +  UsbDescriptors.c
> > > +  UsbDescriptors.h
> > > +  UsbDisplayLink.c
> > > +  UsbDisplayLink.h
> > > +  UsbTransfer.c
> > > +  VideoModes.c
> > > +
> > > +[Packages]
> > > +  MdePkg/MdePkg.dec
> > > +
> > > +[LibraryClasses]
> > > +  BaseMemoryLib
> > > +  DebugLib
> > > +  MemoryAllocationLib
> > > +  ReportStatusCodeLib
> > > +  UefiBootServicesTableLib
> > > +  UefiDriverEntryPoint
> > > +  UefiLib
> > > +  UefiUsbLib
> > > +
> > > +[Protocols]
> > > +  gEfiUsbIoProtocolGuid                         ## TO_START
> > > +  gEfiEdidActiveProtocolGuid                    # PROTOCOL BY_START
> > > +  gEfiEdidDiscoveredProtocolGuid                # PROTOCOL BY_START
> > > +  gEfiEdidOverrideProtocolGuid                  # PROTOCOL TO_START
> > > +  gEfiHiiDatabaseProtocolGuid
> > > +  gEfiHiiFontProtocolGuid
> > > +
> > > +[Guids]
> > > +  gEfiEventExitBootServicesGuid
> > > +  gEfiGlobalVariableGuid
> > > +
> > > +[Pcd]
> > > +  gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize     ## CONSUMES
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> > > new file mode 100644
> > > index 000000000000..21f4b7d9c736
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c
> > > @@ -0,0 +1,598 @@
> > > +/** @file Edid.c
> > > + * @brief Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#include "UsbDisplayLink.h"
> > > +#include "Edid.h"
> > > +
> > > +CONST UINT8 ExpectedEdidHeader[EDID_HEADER_SIZE] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
> > > +
> > > +//
> > > +// Standard timing defined by VESA EDID
> > > +//
> > > +CONST EDID_TIMING EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES][8] = {
> > > +  //
> > > +  // Established Timing I
> > > +  //
> > > +  {
> > > +    { 800, 600, 60 },
> > > +    { 800, 600, 56 },
> > > +    { 640, 480, 75 },
> > > +    { 640, 480, 72 },
> > > +    { 640, 480, 67 },
> > > +    { 640, 480, 60 },
> > > +    { 720, 400, 88 },
> > > +    { 720, 400, 70 },
> > > +  },
> > > +  {
> > > +    //
> > > +    // Established Timing II
> > > +    //
> > > +    { 1280, 1024, 75 },
> > > +    { 1024,  768, 75 },
> > > +    { 1024,  768, 70 },
> > > +    { 1024,  768, 60 },
> > > +    { 1024,  768, 87 },
> > > +    { 832,   624, 75 },
> > > +    { 800,   600, 75 },
> > > +    { 800,   600, 72 },
> > > +  },
> > > +  //
> > > +  // Established Timing III
> > > +  //
> > > +  {
> > > +    { 1152, 870, 75 },
> > > +    { 0, 0, 0 },
> > > +    { 0, 0, 0 },
> > > +    { 0, 0, 0 },
> > > +    { 0, 0, 0 },
> > > +    { 0, 0, 0 },
> > > +    { 0, 0, 0 },
> > > +    { 0, 0, 0 },
> > > +  }
> > > +};
> > > +
> > > +/**
> > > + * Requests the monitor EDID data from the connected DisplayLink device
> > > + * @param UsbDisplayLinkDev
> > > + * @param EdidDataBlock
> > > + * @param EdidSize
> > > + * @retval EFI_DEVICE_ERROR - No EDID received, or EDID is corrupted
> > > + * @retval EFI_OUT_OF_RESOURCES - Cannot allocate memory
> > > + * @retval EFI_SUCCESS
> > > + *
> > > + */
> > > +STATIC EFI_STATUS
> > > +ReadEdidData (
> > > +  IN USB_DISPLAYLINK_DEV      *UsbDisplayLinkDev,
> > > +  OUT UINT8                    **EdidDataBlock,
> > > +  OUT UINTN                    *EdidSize
> > > +)
> > > +{
> > > +  EFI_STATUS Status;
> > > +
> > > +  UINT8 EdidDataRead[EDID_BLOCK_SIZE];
> > > +  UINT8 *EdidData = EdidDataRead;
> > > +  UINT8* ValidEdid;
> > > +
> > > +  Status = DlUsbSendControlReadMessage (UsbDisplayLinkDev, GET_OUTPUT_EDID, 0, EdidDataRead, sizeof (EdidDataRead));
> > > +
> > > +  if (EFI_ERROR (Status) || (EdidData[0] != 0)) {
> > > +    DEBUG ((DEBUG_ERROR, "No monitor EDID received from DisplayLink device - System error %r, EDID error %d. Monitor
> > connected correctly?\n", Status, EdidData[0]));
> > > +    return EFI_DEVICE_ERROR;
> > > +  } else {
> > > +    //
> > > +    // Search for the EDID signature
> > > +    //
> > > +    ValidEdid = &EdidData[0];
> > > +    CONST UINT64 Signature = 0x00ffffffffffff00ull;
> > > +    if (CompareMem (ValidEdid, &Signature, 8) != 0) {
> > > +      //
> > > +      // No EDID signature found
> > > +      //
> > > +      DEBUG ((DEBUG_ERROR, "Monitor EDID received from DisplayLink device did not have a valid signature - corrupted?\n"));
> > > +      Status = EFI_DEVICE_ERROR;
> > > +      return Status;
> > > +    }
> > > +  }
> > > +
> > > +  *EdidDataBlock = (UINT8*)AllocateCopyPool (
> > > +    EDID_BLOCK_SIZE,
> > > +    ValidEdid);
> > > +
> > > +  if (*EdidDataBlock == NULL) {
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  //
> > > +  // Currently only support EDID 1.x
> > > +  //
> > > +  *EdidSize = EDID_BLOCK_SIZE;
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +
> > > +/**
> > > +Calculates the mod256 checksum of the EDID and compares it with the one supplied at the end of the EDID
> > > +@param  EDID        Pointer to the 128-byte EDID
> > > +@retval TRUE        The EDID checksum is correct
> > > +**/
> > > +BOOLEAN
> > > +IsEdidChecksumCorrect (
> > > +    CONST VOID *EDID
> > > +    )
> > > +{
> > > +  CONST UINT8 EdidChecksum = ((UINT8 *)EDID)[EDID_BLOCK_SIZE - 1];
> > > +  UINT8 CalculatedChecksum;
> > > +
> > > +  CalculatedChecksum = 0;
> > > +
> > > +  UINTN i;
> > > +  for (i = 0; i < EDID_BLOCK_SIZE - 1; i++) {
> > > +    CalculatedChecksum += ((UINT8 *)EDID)[i];
> > > +  }
> > > +  CalculatedChecksum = 0 - CalculatedChecksum;
> > > +
> > > +  return (CalculatedChecksum == EdidChecksum);
> > > +}
> > > +
> > > +/**
> > > +Check if a particular video mode is in the Established Timings section of the EDID.
> > > +
> > > +@param  EDID        Pointer to the 128-byte EDID
> > > +@param  hRes        Horizontal resolution
> > > +@param  vRes        Vertical resolution
> > > +@param  refresh     Refresh rate
> > > +@retval TRUE        The requested mode is present in the Established Timings section
> > > +
> > > +**/
> > > +STATIC BOOLEAN
> > > +IsModeInEstablishedTimings (
> > > +    IN CONST VOID *EDID,
> > > +    IN UINT16 HRes,
> > > +    IN UINT16 VRes,
> > > +    IN UINT16 Refresh
> > > +    )
> > > +{
> > > +  CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> > > +  BOOLEAN ModeSupported;
> > > +
> > > +  ModeSupported = FALSE;
> > > +
> > > +  int EstByteNum;
> > > +  int BitNum;
> > > +  for (EstByteNum = 0; EstByteNum < EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES; EstByteNum++) {
> > > +    for (BitNum = 0; BitNum < 8; BitNum++) {
> > > +      if (pEDID->EstablishedTimings[EstByteNum] & (1 << BitNum)) { // The bit is set in the established timings of the EDID
> > > +
> > > +        if ((EstablishedTimings[EstByteNum][BitNum].HRes == HRes) && // The passed-in resolution matches the resolution
> > represented by the set bit
> > > +          (EstablishedTimings[EstByteNum][BitNum].VRes == VRes) &&
> > > +          (EstablishedTimings[EstByteNum][BitNum].Refresh == Refresh)) {
> > > +
> > > +          ModeSupported = TRUE;
> > > +          break;
> > > +        }
> > > +      }
> > > +    }
> > > +    if (ModeSupported == TRUE) {
> > > +      break;
> > > +    }
> > > +  }
> > > +  return ModeSupported;
> > > +}
> > > +
> > > +/**
> > > +Extract the resolutions and refresh rate from one of the entries in the Standard Timings section of the EDID.
> > > +
> > > +@param  EDID          Pointer to the 128-byte EDID
> > > +@param  timingNumber  The entry that we want to extract
> > > +@param  hRes          Output - Horizontal resolution
> > > +@param  vRes          Output - Vertical resolution
> > > +@param  refresh       Output - Refresh rate
> > > +@retval TRUE          The requested Standard Timings entry contains valid data
> > > +
> > > +**/
> > > +STATIC BOOLEAN ReadStandardTiming (
> > > +  CONST VOID *EDID,
> > > +  IN UINT8 TimingNumber,
> > > +  OUT UINT16 *HRes,
> > > +  OUT UINT16 *VRes,
> > > +  OUT UINT8 *Refresh)
> > > +{
> > > +  CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> > > +
> > > +  // See section 3.9.1 of the VESA EDID spec
> > > +
> > > +  if (((pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels) == 0x01) &&
> > > +    (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh) == 0x01) {
> > > +    *HRes = 0;
> > > +    *VRes = 0;
> > > +    *Refresh = 0;
> > > +    return FALSE;
> > > +  }
> > > +  *HRes = (pEDID->standardTimingIdentifications[TimingNumber].HorizontalActivePixels + 31) * 8;
> > > +
> > > +  UINT8 AspectRatio;
> > > +  AspectRatio = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh >> 6) & 0x3;
> > > +
> > > +  switch (AspectRatio) {
> > > +  case 0: *VRes = (*HRes * 10) / 16;
> > > +    break;
> > > +  case 1: *VRes = (*HRes * 3) / 4;
> > > +    break;
> > > +  case 2: *VRes = (*HRes * 4) / 5;
> > > +    break;
> > > +  case 3: *VRes = (*HRes * 9) / 16;
> > > +    break;
> > > +  default: break;
> > > +  }
> > > +
> > > +  // WORKAROUND - 1360x768 is not a perfect aspect ratio
> > > +  if ((*HRes == 1360) && (*VRes == 765)) {
> > > +    *VRes = 768;
> > > +  }
> > > +
> > > +  *Refresh = (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRatioAndrefresh & 0x1F) + 60;
> > > +
> > > +  return TRUE;
> > > +}
> > > +
> > > +/**
> > > +Extract the resolutions and refresh rate from one of the entries in the Detailed Timings section of the EDID.
> > > +
> > > +@param  EDID          Pointer to the 128-byte EDID
> > > +@param  timingNumber  The entry that we want to extract
> > > +@param  videoMode     Output - Filled in with details from the detailed timing
> > > +@retval TRUE          The requested Detailed Timings entry contains valid data
> > > +
> > > +**/
> > > +STATIC BOOLEAN
> > > +ReadDetailedTiming (
> > > +  IN CONST VOID *EDID,
> > > +  IN UINT8 TimingNumber,
> > > +  OUT struct VideoMode *VideoMode
> > > +  )
> > > +{
> > > +  if (TimingNumber >= EDID_NUMBER_OF_DETAILED_TIMINGS) {
> > > +    return FALSE;
> > > +  }
> > > +
> > > +  UINT16 NumValidDetailedTimingsFound;
> > > +  NumValidDetailedTimingsFound = 0;
> > > +
> > > +  // Spin through the detailed timings until we find a valid one - then check if this has the index that we want
> > > +  int BlockNumber;
> > > +  for (BlockNumber = 0; BlockNumber < EDID_NUMBER_OF_DETAILED_TIMINGS; BlockNumber++) {
> > > +    CONST struct Edid *pEDID = (CONST struct Edid *)EDID;
> > > +    CONST struct DetailedTimingIdentification *pTiming = &pEDID->detailedTimingDescriptions[BlockNumber];
> > > +
> > > +    if (((BlockNumber == 0) && (pTiming->PixelClock == EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK)) ||
> > > +      (pTiming->PixelClock == 0)) {
> > > +      // This is not a valid detailed timing descriptor
> > > +      continue;
> > > +    }
> > > +
> > > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesSyncSchemeMask) != EdidDetailedTimingsFeaturesSyncSchemeMask)
> > {
> > > +      DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported sync scheme found - not processing.\n"));
> > > +      continue;
> > > +    }
> > > +
> > > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesStereoModeMask) != 0) {
> > > +      DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported stereo mode found - not processing.\n"));
> > > +      continue;
> > > +    }
> > > +
> > > +    // We've found a supported detailed timing - now see if this is the requested one
> > > +    if (TimingNumber != NumValidDetailedTimingsFound) {
> > > +      NumValidDetailedTimingsFound++;
> > > +      continue;
> > > +    }
> > > +
> > > +    ZeroMem ((VOID *)VideoMode, sizeof (struct VideoMode));
> > > +
> > > +    // Bit manipulations copied from host software class EDIDTimingDescriptor
> > > +
> > > +    VideoMode->PixelClock = (UINT16)pTiming->PixelClock;
> > > +    VideoMode->HActive = pTiming->HActiveLo + ((pTiming->HActiveHiBlankingHi & 0xF0) << 4);
> > > +    VideoMode->VActive = pTiming->VActiveLo + ((pTiming->VActiveHiBlankingHi & 0xF0) << 4);
> > > +
> > > +    VideoMode->HBlanking = pTiming->HBlankingLo + ((pTiming->HActiveHiBlankingHi & 0x0F) << 8);
> > > +    VideoMode->VBlanking = pTiming->VBlankingLo + ((pTiming->VActiveHiBlankingHi & 0x0F) << 8);
> > > +
> > > +    VideoMode->HSyncOffset = pTiming->HSyncOffsetLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi
> > & 0xC0) << 2);  // Horizontal Front Porch
> > > +    VideoMode->HSyncWidth = pTiming->HSyncWidthLo + ((pTiming->HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi
> > & 0x30) << 4);
> > > +
> > > +    VideoMode->VSyncOffset = ((pTiming->VSyncOffsetLoSyncWidthLo & 0xF0) >> 4) + ((pTiming-
> > >HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x0C) << 2); // Vertical Front Porch
> > > +    VideoMode->VSyncWidth = (pTiming->VSyncOffsetLoSyncWidthLo & 0x0F) + ((pTiming-
> > >HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x03) << 4);
> > > +
> > > +    VideoMode->Reserved2 = 2;
> > > +    VideoMode->Accumulate = 1;
> > > +
> > > +    // Horizontal and vertical sync inversions - positive if bit set in descriptor (EDID spec)
> > > +    // In the VideoMode, they are negative if the bit is set (NR-110497-TC 4.3.3 0x22 Set Video Mode)
> > > +
> > > +    // Horizontal sync
> > > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesHorizontalSyncPositive) == 0) {
> > > +      VideoMode->Flags |= VideoModeFlagsHorizontalSyncInverted;
> > > +    }
> > > +    // Vertical sync
> > > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesVerticalSyncPositive) == 0) {
> > > +      VideoMode->Flags |= VideoModeFlagsVerticalSyncInverted;
> > > +    }
> > > +    // Interlace
> > > +    if ((pTiming->Features & EdidDetailedTimingsFeaturesInterlaced) == EdidDetailedTimingsFeaturesInterlaced) {
> > > +      VideoMode->Flags |= VideoModeFlagsInterlaced;
> > > +    }
> > > +
> > > +    DEBUG ((DEBUG_INFO, "Read mode %dx%d from detailed timings\n", VideoMode->HActive, VideoMode->VActive));
> > > +    return TRUE;
> > > +  }
> > > +  return FALSE;
> > > +}
> > > +
> > > +/**
> > > +Check if a particular video mode is in either the Established or Standard Timings section of the EDID.
> > > +
> > > +@param  EDID        Pointer to the 128-byte EDID
> > > +@param  hRes        Horizontal resolution
> > > +@param  vRes        Vertical resolution
> > > +@param  refresh     Refresh rate
> > > +@retval TRUE        The requested mode is present in the EDID
> > > +
> > > +**/
> > > +STATIC BOOLEAN
> > > +IsModeInEdid (
> > > +    IN CONST VOID *EDID,
> > > +    IN UINT16 HRes,
> > > +    IN UINT16 VRes,
> > > +    IN UINT16 Refresh
> > > +    )
> > > +{
> > > +  UINT16 EdidHRes;
> > > +  UINT16 EdidVRes;
> > > +  UINT8 EdidRefresh;
> > > +  BOOLEAN ModeSupported;
> > > +
> > > +  ModeSupported = IsModeInEstablishedTimings (EDID, HRes, VRes, Refresh);
> > > +
> > > +  if (ModeSupported == FALSE) {
> > > +    // Check if the mode is in the Standard Timings section of the EDID
> > > +    UINT8 i;
> > > +    for (i = 0; i < EDID_NUMBER_OF_STANDARD_TIMINGS; i++) {
> > > +      if (TRUE == ReadStandardTiming (EDID, i, &EdidHRes, &EdidVRes, &EdidRefresh)) {
> > > +        if ((HRes == EdidHRes) && (VRes == EdidVRes) && (Refresh == EdidRefresh)) {
> > > +          ModeSupported = TRUE;
> > > +          break;
> > > +        }
> > > +      }
> > > +    }
> > > +  }
> > > +  return ModeSupported;
> > > +}
> > > +
> > > +/**
> > > +Returns the (index)'th entry from the list of pre-calculated video timings that is also present in the EDID,
> > > +or, video mode data corresponding to any detailed timings present in the EDID.
> > > +
> > > +Like QueryVideoMode, finds the number (and contents) of video modes available by repeatedly calling this function
> > > +with an increasing index value, until it returns FALSE
> > > +@param  index       The caller wants the _index_'th video mode
> > > +@param  EDID        Pointer to the 128-byte EDID
> > > +@param  edidSize    Size in bytes of the EDID
> > > +@param  videoMode   Video timings extracted from the modeData structure
> > > +@retval EFI_SUCCESS The requested mode is present in the EDID
> > > +@retval EFI_INVALID_PARAMETER The requested mode is not present in the EDID
> > > +**/
> > > +EFI_STATUS
> > > +DlEdidGetSupportedVideoMode (
> > > +    IN UINT32 Index,
> > > +    IN CONST VOID *EDID,
> > > +    IN UINT32 EdidSize,
> > > +    OUT CONST struct VideoMode **VideoMode
> > > +    )
> > > +{
> > > +  UINTN SupportedVideoModesFoundInEdid;
> > > +  EFI_STATUS Status;
> > > +
> > > +  SupportedVideoModesFoundInEdid = 0;
> > > +  Status = EFI_INVALID_PARAMETER;
> > > +
> > > +  // If we didn't manage to find an EDID earlier, just use one of the hard-coded video modes
> > > +  if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> > > +    if (Index >= DlVideoModeGetNumSupportedVideoModes ()) {
> > > +      return EFI_INVALID_PARAMETER;
> > > +    }
> > > +    else {
> > > +      *VideoMode = DlVideoModeGetSupportedVideoMode (Index);
> > > +      DEBUG ((DEBUG_WARN, "No monitor EDID loaded - returning mode from default list (%dx%d)\n", (*VideoMode)-
> > >HActive, (*VideoMode)->VActive));
> > > +      return EFI_SUCCESS;
> > > +    }
> > > +  }
> > > +
> > > +  UINT16 ModeNumber;
> > > +  for (ModeNumber = 0; ModeNumber < DlVideoModeGetNumSupportedVideoModes (); ModeNumber++) {
> > > +
> > > +    CONST struct VideoMode *SupportedVideoMode = DlVideoModeGetSupportedVideoMode (ModeNumber);
> > > +    ASSERT (SupportedVideoMode);
> > > +
> > > +    if (IsModeInEdid (EDID, SupportedVideoMode->HActive, SupportedVideoMode->VActive,
> > DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE)) {
> > > +      if (Index == SupportedVideoModesFoundInEdid) {
> > > +        *VideoMode = SupportedVideoMode;
> > > +        Status = EFI_SUCCESS;
> > > +        break;
> > > +      }
> > > +      SupportedVideoModesFoundInEdid++;
> > > +    }
> > > +  }
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    // Have a look in the detailed timings
> > > +    UINTN DetailedTimingNumber;
> > > +    STATIC struct VideoMode TmpVideoMode;
> > > +    DetailedTimingNumber = Index - SupportedVideoModesFoundInEdid;
> > > +
> > > +    if (DetailedTimingNumber < EDID_NUMBER_OF_DETAILED_TIMINGS) {
> > > +      if (ReadDetailedTiming (EDID, (UINT8)DetailedTimingNumber, &TmpVideoMode)) {
> > > +        *VideoMode = &TmpVideoMode;
> > > +        Status = EFI_SUCCESS;
> > > +      }
> > > +    }
> > > +  }
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > + * Like GetSupportedEdidVideoMode, but will return a fallback fixed mode of 640x480@60Hz
> > > + * for index 0 if no suitable modes found in EDID.
> > > + * @param index
> > > + * @param EDID
> > > + * @param edidSize
> > > + * @param videoMode
> > > + * @return EFI_SUCCESS
> > > + */
> > > +EFI_STATUS
> > > +DlEdidGetSupportedVideoModeWithFallback (
> > > +    IN UINT32 Index,
> > > +    IN CONST VOID *EDID,
> > > +    IN UINT32 EdidSize,
> > > +    OUT CONST struct VideoMode **VideoMode
> > > +    )
> > > +{
> > > +  EFI_STATUS Status;
> > > +  Status = DlEdidGetSupportedVideoMode (Index, EDID, EdidSize, VideoMode);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    // Special case - if we didn't find any matching video modes in the EDID, fall back to 640x480@60Hz
> > > +    if (Index == 0) {
> > > +      *VideoMode = DlVideoModeGetSupportedVideoMode (0);
> > > +      DEBUG ((DEBUG_WARN, "No video modes supported by driver found in monitor EDID received from DL device - falling
> > back to %dx%d\n", (*VideoMode)->HActive, (*VideoMode)->VActive));
> > > +      Status = EFI_SUCCESS;
> > > +    }
> > > +  }
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > +Count the number of video modes that we have timing information for that are present in the EDID
> > > +@param  EDID        Pointer to the 128-byte EDID
> > > +@param  edidSize
> > > +@retval             The number of modes in the EDID
> > > +
> > > +**/
> > > +UINT32
> > > +DlEdidGetNumSupportedModesInEdid (
> > > +    IN CONST VOID *EDID,
> > > +    IN UINT32 EdidSize
> > > +    )
> > > +{
> > > +  UINT32 MaxMode;
> > > +
> > > +  if ((EDID == NULL) || (EdidSize != EDID_BLOCK_SIZE)) {
> > > +    return DlVideoModeGetNumSupportedVideoModes ();
> > > +  }
> > > +
> > > +  for (MaxMode = 0; ; MaxMode++) {
> > > +    CONST struct VideoMode *videoMode;
> > > +    if (EFI_ERROR (DlEdidGetSupportedVideoMode (MaxMode, EDID, EdidSize, &videoMode))) {
> > > +      break;
> > > +    }
> > > +  }
> > > +  DEBUG ((DEBUG_INFO, "Found %d video modes supported by driver in monitor EDID.\n", MaxMode));
> > > +  return MaxMode;
> > > +}
> > > +
> > > +
> > > +
> > > +/**
> > > + * Read the EDID from the connected monitor, store it in the local data structure
> > > + * @param UsbDisplayLinkDev
> > > + * @retval EFI_OUT_OF_RESOURCES - Could not allocate memory
> > > + * @retval EFI_SUCCESS
> > > + */
> > > +EFI_STATUS
> > > +DlReadEdid (
> > > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > > +    )
> > > +{
> > > +  EFI_STATUS Status;
> > > +  BOOLEAN EdidFound;
> > > +  EFI_EDID_OVERRIDE_PROTOCOL* EdidOverride;
> > > +
> > > +  //
> > > +  // setup EDID information
> > > +  //
> > > +  UsbDisplayLinkDev->EdidDiscovered.Edid = (UINT8 *)NULL;
> > > +  UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = 0;
> > > +
> > > +  EdidFound = FALSE;
> > > +
> > > +  //
> > > +  // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
> > > +  //
> > > +  Status = gBS->LocateProtocol (&gEfiEdidOverrideProtocolGuid, NULL, (VOID**)&EdidOverride);
> > > +
> > > +  if (!EFI_ERROR (Status)) {
> > > +    UINT32 EdidAttributes = 0xff;
> > > +    UINTN EdidDataSize = 0;
> > > +    UINT8* EdidDataBlock = (UINT8*)NULL;
> > > +
> > > +    // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
> > > +    EdidDataBlock = (UINT8*)AllocatePool (EDID_BLOCK_SIZE * 2);
> > > +
> > > +    if (NULL == EdidDataBlock) {
> > > +      return EFI_OUT_OF_RESOURCES;
> > > +    }
> > > +
> > > +    Status = EdidOverride->GetEdid (
> > > +      EdidOverride,
> > > +      &UsbDisplayLinkDev->Handle,
> > > +      &EdidAttributes,
> > > +      &EdidDataSize,
> > > +      &EdidDataBlock);
> > > +
> > > +    if (!EFI_ERROR (Status) && EdidAttributes == 0 && EdidDataSize != 0) {
> > > +      UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> > > +      UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> > > +      EdidFound = TRUE;
> > > +    }
> > > +    else {
> > > +      FreePool (EdidDataBlock);
> > > +      EdidDataBlock = NULL;
> > > +    }
> > > +  }
> > > +
> > > +  if (EdidFound != TRUE) {
> > > +    UINTN EdidDataSize = 0;
> > > +    UINT8* EdidDataBlock = (UINT8*)NULL;
> > > +
> > > +    if (ReadEdidData (UsbDisplayLinkDev, &EdidDataBlock, &EdidDataSize) == EFI_SUCCESS) {
> > > +
> > > +      if (IsEdidChecksumCorrect (EdidDataBlock)) {
> > > +        UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid = (UINT32)EdidDataSize;
> > > +        UsbDisplayLinkDev->EdidDiscovered.Edid = EdidDataBlock;
> > > +        EdidFound = TRUE;
> > > +      } else {
> > > +        DEBUG ((DEBUG_WARN, "Monitor EDID received from DisplayLink device had an invalid checksum. Corrupted?\n"));
> > > +      }
> > > +    }
> > > +  }
> > > +
> > > +  if (EdidFound == FALSE) {
> > > +    DEBUG ((DEBUG_WARN, "No valid monitor EDID received from DisplayLink device. Cannot detect resolutions supported by
> > monitor.\n"));
> > > +  }
> > > +
> > > +  // Set the EDID active.
> > > +  // In an error case this will be set 0/NULL, which flags to the parsing code that there is no EDID.
> > > +  UsbDisplayLinkDev->EdidActive.SizeOfEdid = UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid;
> > > +  UsbDisplayLinkDev->EdidActive.Edid = UsbDisplayLinkDev->EdidDiscovered.Edid;
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> > > new file mode 100644
> > > index 000000000000..a1b8a0512d1a
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h
> > > @@ -0,0 +1,129 @@
> > > +/** @file Edid.h
> > > + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> > > + * Reads and parses the EDID, checks if a requested video mode is in the supplied EDID
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#ifndef EDID_H
> > > +#define EDID_H
> > > +
> > > +#include "UsbDisplayLink.h"
> > > +
> > > +#define EDID_HEADER_SIZE                          ((UINTN)8)
> > > +#define EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES  ((UINTN)3)
> > > +#define EDID_NUMBER_OF_STANDARD_TIMINGS           ((UINTN)8)
> > > +#define EDID_NUMBER_OF_DETAILED_TIMINGS           ((UINTN)4)
> > > +
> > > +
> > > +typedef struct {
> > > +  UINT16  HRes;
> > > +  UINT16  VRes;
> > > +  UINT16  Refresh;
> > > +} EDID_TIMING;
> > > +
> > > +
> > > +EFI_STATUS
> > > +DlEdidGetSupportedVideoMode (
> > > +    UINT32 ModeNumber,
> > > +    CONST VOID *EDID,
> > > +    UINT32 EdidSize,
> > > +    CONST struct VideoMode **VideoMode
> > > +    );
> > > +
> > > +EFI_STATUS
> > > +DlEdidGetSupportedVideoModeWithFallback (
> > > +    UINT32 ModeNumber,
> > > +    CONST VOID *EDID,
> > > +    UINT32 EdidSize,
> > > +    CONST struct VideoMode **VideoMode
> > > +    );
> > > +
> > > +UINT32
> > > +DlEdidGetNumSupportedModesInEdid (
> > > +    CONST VOID *EDID,
> > > +    UINT32 EdidSize
> > > +    );
> > > +
> > > +EFI_STATUS
> > > +DlReadEdid (
> > > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > > +);
> > > +
> > > +// EDID Detailed timings section - Features
> > > +enum EdidDetailedTimingsFeatures {
> > > +  EdidDetailedTimingsFeaturesInterlaced              = 0x80,
> > > +  EdidDetailedTimingsFeaturesStereoModeMask          = 0x60,
> > > +  EdidDetailedTimingsFeaturesSyncSchemeMask          = 0x18,
> > > +  EdidDetailedTimingsFeaturesHorizontalSyncPositive  = 0x02,
> > > +  EdidDetailedTimingsFeaturesVerticalSyncPositive    = 0x04,
> > > +};
> > > +
> > > +// NR-110497-TC-7ZM Section 4.3.3 0x22 Set Video Mode - Flags
> > > +enum VideoModeFlags {
> > > +  VideoModeFlagsInterlaced             = 0x0001,
> > > +  VideoModeFlagsHorizontalSyncInverted = 0x0100,
> > > +  VideoModeFlagsVerticalSyncInverted   = 0x0200,
> > > +};
> > > +
> > > +struct StandardTimingIdentification {
> > > +  UINT8 HorizontalActivePixels;           // X resolution, from 256->2288 in increments of 8 pixels
> > > +  UINT8 ImageAspectRatioAndrefresh;   // Bits 7,6 Aspect ratio - 0=16:10 1=4:3 2=5:4 3=16:9
> > > +                                          // Bits 5,0 Refresh rate Range 60->1213Hz
> > > +};
> > > +
> > > +struct DetailedTimingIdentification {
> > > +  UINT16 PixelClock;                  // wPixelClock in VideoMode struct
> > > +  UINT8  HActiveLo;                   // wHActive
> > > +  UINT8  HBlankingLo;                 // wHBlanking
> > > +  UINT8  HActiveHiBlankingHi;
> > > +  UINT8  VActiveLo;                   // wVActive
> > > +  UINT8  VBlankingLo;                 // wVBlanking
> > > +  UINT8  VActiveHiBlankingHi;
> > > +  UINT8  HSyncOffsetLo;               // wHSyncOffset, front porch
> > > +  UINT8  HSyncWidthLo;                // wHSyncWidth
> > > +  UINT8  VSyncOffsetLoSyncWidthLo;
> > > +  UINT8  HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi;
> > > +  UINT8  HImageSizeHi;
> > > +  UINT8  VImageSizeHi;
> > > +  UINT8  HImageSizeLoVImageSizeLo;
> > > +  UINT8  HBorder;
> > > +  UINT8  VBorder;
> > > +  UINT8  Features;
> > > +};
> > > +
> > > +struct Edid {
> > > +  UINT8  Header[EDID_HEADER_SIZE];           //EDID header "00 FF FF FF FF FF FF 00"
> > > +  UINT16 ManufactureName;                  //EISA 3-character ID
> > > +  UINT16 ProductCode;                      //Vendor assigned code
> > > +  UINT32 SerialNumber;                     //32-bit serial number
> > > +  UINT8  WeekOfManufacture;                //Week number
> > > +  UINT8  YearOfManufacture;                //Year
> > > +  UINT8  EdidVersion;                      //EDID Structure Version
> > > +  UINT8  EdidRevision;                     //EDID Structure Revision
> > > +  UINT8  VideoInputDefinition;
> > > +  UINT8  MaxHorizontalImageSize;           //cm
> > > +  UINT8  MaxVerticalImageSize;             //cm
> > > +  UINT8  DisplayTransferCharacteristic;
> > > +  UINT8  FeatureSupport;
> > > +  UINT8  RedGreenLowBits;                  //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
> > > +  UINT8  BlueWhiteLowBits;                 //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
> > > +  UINT8  RedX;                             //Red-x Bits 9 - 2
> > > +  UINT8  RedY;                             //Red-y Bits 9 - 2
> > > +  UINT8  GreenX;                           //Green-x Bits 9 - 2
> > > +  UINT8  GreenY;                           //Green-y Bits 9 - 2
> > > +  UINT8  BlueX;                            //Blue-x Bits 9 - 2
> > > +  UINT8  BlueY;                            //Blue-y Bits 9 - 2
> > > +  UINT8  WhiteX;                           //White-x Bits 9 - 2
> > > +  UINT8  WhiteY;                           //White-x Bits 9 - 2
> > > +  UINT8  EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES];
> > > +  struct StandardTimingIdentification  standardTimingIdentifications[EDID_NUMBER_OF_STANDARD_TIMINGS];
> > > +  struct DetailedTimingIdentification  detailedTimingDescriptions[EDID_NUMBER_OF_DETAILED_TIMINGS];
> > > +  UINT8  ExtensionFlag;                    //Number of (optional) 128-byte EDID extension blocks to follow
> > > +  UINT8  Checksum;
> > > +};
> > > +
> > > +#endif // EDID_H
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> > > new file mode 100644
> > > index 000000000000..3e483afdba72
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c
> > > @@ -0,0 +1,578 @@
> > > +/**
> > > + * @file Gop.c
> > > + * @brief UEFI GOP protocol API implementation for USB DisplayLink driver.
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#include "UsbDisplayLink.h"
> > > +#include "Edid.h"
> > > +
> > > +
> > > +/**
> > > + *
> > > + * @param This            Pointer to the instance of the GOP protocol
> > > + * @param BltOperation
> > > + * @param SourceX
> > > + * @param SourceY
> > > + * @param Width
> > > + * @param Height
> > > + * @param DestinationX
> > > + * @param DestinationY
> > > + * @return
> > > + */
> > > +STATIC EFI_STATUS
> > > +CheckBounds (
> > > +    IN EFI_GRAPHICS_OUTPUT_PROTOCOL* This,
> > > +    IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
> > > +    IN UINTN SourceX,
> > > +    IN UINTN SourceY,
> > > +    IN UINTN Width,
> > > +    IN UINTN Height,
> > > +    IN UINTN DestinationX,
> > > +    IN UINTN DestinationY
> > > +    )
> > > +{
> > > +  USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> > > +  EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> > > +
> > > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> > > +  Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> > > +
> > > +  CONST EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* ScreenMode = Gop->Mode->Info;
> > > +
> > > +  if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
> > > +    if (SourceY + Height > ScreenMode->VerticalResolution) {
> > > +      return EFI_INVALID_PARAMETER;
> > > +    }
> > > +
> > > +    if (SourceX + Width > ScreenMode->HorizontalResolution) {
> > > +      return EFI_INVALID_PARAMETER;
> > > +    }
> > > +  }
> > > +
> > > +  if (BltOperation == EfiBltBufferToVideo
> > > +    || BltOperation == EfiBltVideoToVideo
> > > +    || BltOperation == EfiBltVideoFill) {
> > > +    if (DestinationY + Height > ScreenMode->VerticalResolution) {
> > > +      return EFI_INVALID_PARAMETER;
> > > +    }
> > > +
> > > +    if (DestinationX + Width > ScreenMode->HorizontalResolution) {
> > > +      return EFI_INVALID_PARAMETER;
> > > +    }
> > > +  }
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > + * Update the local copy of the Frame Buffer. This local copy is periodically transmitted to the
> > > + * DisplayLink device (via DlGopSendScreenUpdate)
> > > + * @param UsbDisplayLinkDev
> > > + * @param BltBuffer
> > > + * @param BltOperation
> > > + * @param SourceX
> > > + * @param SourceY
> > > + * @param DestinationX
> > > + * @param DestinationY
> > > + * @param Width
> > > + * @param Height
> > > + * @param BltBufferStride
> > > + * @param PixelsPerScanLine
> > > + */
> > > +STATIC VOID
> > > +BuildBackBuffer (
> > > +  IN  USB_DISPLAYLINK_DEV                     *UsbDisplayLinkDev,
> > > +  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer, OPTIONAL
> > > +  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
> > > +  IN  UINTN                                   SourceX,
> > > +  IN  UINTN                                   SourceY,
> > > +  IN  UINTN                                   DestinationX,
> > > +  IN  UINTN                                   DestinationY,
> > > +  IN  UINTN                                   Width,
> > > +  IN  UINTN                                   Height,
> > > +  IN  UINTN                                   BltBufferStride,
> > > +  IN  UINTN                                   PixelsPerScanLine
> > > +)
> > > +{
> > > +  UINTN H;
> > > +  UINTN W;
> > > +  switch (BltOperation) {
> > > +  case EfiBltVideoToBltBuffer:
> > > +  {
> > > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> > > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> > > +    Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)((UINT8 *)BltBuffer + (DestinationY * BltBufferStride) + DestinationX * sizeof
> > (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> > > +    SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> > > +
> > > +    for (H = 0; H < Height; H++) {
> > > +      for (W = 0; W < Width; W++) {
> > > +        Blt[W] = *SrcB++;
> > > +      }
> > > +      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> > > +      SrcB += PixelsPerScanLine - Width;
> > > +    }
> > > +  }
> > > +  break;
> > > +
> > > +  case EfiBltBufferToVideo:
> > > +  {
> > > +    // Update the store of the area of the screen that is "dirty" - that we need to send in the next screen update.
> > > +    if (DestinationY < UsbDisplayLinkDev->LastY1) {
> > > +      UsbDisplayLinkDev->LastY1 = DestinationY;
> > > +    }
> > > +    if ((DestinationY + Height) > UsbDisplayLinkDev->LastY2) {
> > > +      UsbDisplayLinkDev->LastY2 = DestinationY + Height;
> > > +    }
> > > +
> > > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt;
> > > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> > > +    Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)(((UINT8 *)BltBuffer) + (SourceY * BltBufferStride) + SourceX * sizeof *Blt);
> > > +    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> > > +
> > > +    for (H = 0; H < Height; H++) {
> > > +      for (W = 0; W < Width; W++) {
> > > +        *DstB++ = Blt[W];
> > > +      }
> > > +      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBufferStride);
> > > +      DstB += PixelsPerScanLine - Width;
> > > +    }
> > > +  }
> > > +  break;
> > > +
> > > +  case EfiBltVideoToVideo:
> > > +  {
> > > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB;
> > > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> > > +    SrcB = UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine + SourceX;
> > > +    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> > > +
> > > +    for (H = 0; H < Height; H++) {
> > > +      for (W = 0; W < Width; W++) {
> > > +        *DstB++ = *SrcB++;
> > > +      }
> > > +      SrcB += PixelsPerScanLine - Width;
> > > +      DstB += PixelsPerScanLine - Width;
> > > +    }
> > > +  }
> > > +  break;
> > > +
> > > +  case EfiBltVideoFill:
> > > +  {
> > > +    EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB;
> > > +    DstB = UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanLine + DestinationX;
> > > +    for (H = 0; H < Height; H++) {
> > > +      for (W = 0; W < Width; W++) {
> > > +        *DstB++ = *BltBuffer;
> > > +      }
> > > +      DstB += PixelsPerScanLine - Width;
> > > +    }
> > > +  }
> > > +  break;
> > > +  default: break;
> > > +  }
> > > +}
> > > +
> > > +/**
> > > + * Display a colour bar pattern on the DisplayLink device.
> > > + * @param UsbDisplayLinkDev
> > > + * @param PatternNumber
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +DlGopSendTestPattern (
> > > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > > +    IN UINTN PatternNumber)
> > > +{
> > > +  EFI_STATUS Status;
> > > +  UINTN DataLen;
> > > +  UINT8 *DstBuf;
> > > +  UINT32 USBStatus;
> > > +
> > > +  Status = EFI_SUCCESS;
> > > +  DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per
> > pixel
> > > +  DstBuf = AllocateZeroPool (DataLen);
> > > +
> > > +  if (DstBuf == NULL) {
> > > +    DEBUG ((DEBUG_ERROR, "SendTestPattern Failed to allocate memory\n"));
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  //DEBUG ((DEBUG_ERROR, "Called DlGopSendTestPattern %d\n", PatternNumber));
> > > +
> > > +  CONST UINT8 RedPixel[3] = { 0xFF, 0x00, 0x00 };
> > > +  CONST UINT8 GreenPixel[3] = { 0x00, 0xFF, 0x00 };
> > > +  CONST UINT8 BluePixel[3] = { 0x00, 0x00, 0xFF };
> > > +  CONST UINT8 YellowPixel[3] = { 0xFF, 0xFF, 0x00 };
> > > +  CONST UINT8 MagentaPixel[3] = { 0xFF, 0x00, 0xFF };
> > > +  CONST UINT8 CyanPixel[3] = { 0x00, 0xFF, 0xFF };
> > > +
> > > +  UINTN Row;
> > > +  UINTN Column;
> > > +  for (Row = 0; Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution; Row++) {
> > > +    for (Column = 0; Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution; Column++) {
> > > +
> > > +      if (0 == PatternNumber) {
> > > +        if (Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution / 3) {
> > > +          CopyMem (&DstBuf[Column * 3], RedPixel, sizeof (RedPixel));
> > > +        }
> > > +        else if (Row < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution * 2) / 3)
> > > +        {
> > > +          CopyMem (&DstBuf[Column * 3], GreenPixel, sizeof (GreenPixel));
> > > +        }
> > > +        else {
> > > +          CopyMem (&DstBuf[Column * 3], BluePixel, sizeof (BluePixel));
> > > +        }
> > > +      }
> > > +      else {
> > > +        if (Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution / 3) {
> > > +          CopyMem (&DstBuf[Column * 3], YellowPixel, sizeof (RedPixel));
> > > +        }
> > > +        else if (Column < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 2) / 3)
> > > +        {
> > > +          CopyMem (&DstBuf[Column * 3], MagentaPixel, sizeof (GreenPixel));
> > > +        }
> > > +        else {
> > > +          CopyMem (&DstBuf[Column * 3], CyanPixel, sizeof (BluePixel));
> > > +        }
> > > +      }
> > > +    }
> > > +    DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, DataLen, &USBStatus);
> > > +  }
> > > +  // Payload with length of 1 to terminate the frame
> > > +  DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, 1, &USBStatus);
> > > +  FreePool (DstBuf);
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +
> > > +/**
> > > + * Transfer the latest copy of the Blt buffer over USB to the DisplayLink device
> > > + * @param UsbDisplayLinkDev
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +DlGopSendScreenUpdate (
> > > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > > +    )
> > > +{
> > > +  EFI_STATUS Status;
> > > +  UINT32 USBStatus;
> > > +  Status = EFI_SUCCESS;
> > > +
> > > +  // If it has been a while since we sent an update, send a full screen.
> > > +  // This allows us to update a hot-plugged monitor quickly.
> > > +  if (UsbDisplayLinkDev->TimeSinceLastScreenUpdate > DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD) {
> > > +    UsbDisplayLinkDev->LastY1 = 0;
> > > +    UsbDisplayLinkDev->LastY2 = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution - 1;
> > > +  }
> > > +
> > > +  // If there has been no BLT since the last update/poll, drop out quietly.
> > > +  if (UsbDisplayLinkDev->LastY2 < UsbDisplayLinkDev->LastY1) {
> > > +    UsbDisplayLinkDev->TimeSinceLastScreenUpdate += (DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 1000);  // Convert
> > us to ms
> > > +    return EFI_SUCCESS;
> > > +  }
> > > +
> > > +  UsbDisplayLinkDev->TimeSinceLastScreenUpdate = 0;
> > > +
> > > +  EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> > > +
> > > +  UINTN DataLen;
> > > +  UINTN Width;
> > > +  UINTN Height;
> > > +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcPtr;
> > > +  UINT8* DstPtr;
> > > +  UINT8 DstBuffer[1920 * 3]; // Get rid of the magic numbers at some point
> > > +                             // Could also use a buffer allocated at runtime to store the line, stored in the USB_DISPLAYLINK_DEV
> > structure.
> > > +  UINTN H;
> > > +
> > > +  DataLen = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution * 3; // Send 1 line @ 24 bits per
> > pixel
> > > +  Width = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->HorizontalResolution;
> > > +  Height = UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->VerticalResolution;
> > > +  SrcPtr = UsbDisplayLinkDev->Screen;
> > > +  DstPtr = DstBuffer;
> > > +
> > > +  for (H = 0; H < Height; H++) {
> > > +    DstPtr = DstBuffer;
> > > +
> > > +    UINTN W;
> > > +    for (W = 0; W < Width; W++) {
> > > +      // Need to swap round the RGB values
> > > +      DstPtr[0] = ((UINT8 *)SrcPtr)[2];
> > > +      DstPtr[1] = ((UINT8 *)SrcPtr)[1];
> > > +      DstPtr[2] = ((UINT8 *)SrcPtr)[0];
> > > +      SrcPtr++;
> > > +      DstPtr += 3;
> > > +    }
> > > +
> > > +    Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, DataLen, &USBStatus);
> > > +
> > > +    // USBStatus values defined in usbio.h, e.g. EFI_USB_ERR_TIMEOUT 0x40
> > > +    if (EFI_ERROR (Status)) {
> > > +      DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB
> > status x%x\n", H, DataLen, Status, USBStatus));
> > > +      break;
> > > +    }
> > > +    // Need an extra DlUsbBulkWrite if the data length is divisible by USB MaxPacketSize. This spare data will just get written
> > into the (invisible) stride area.
> > > +    // Note that the API doesn't let us do a bulk write of 0.
> > > +    if ((DataLen & (UsbDisplayLinkDev->BulkOutEndpointDescriptor.MaxPacketSize - 1)) == 0) {
> > > +      Status = DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 2, &USBStatus);
> > > +      if (EFI_ERROR (Status)) {
> > > +        DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel data failed. Line %d len %d, failure code %r USB
> > status x%x\n", H, DataLen, Status, USBStatus));
> > > +        break;
> > > +      }
> > > +    }
> > > +  }
> > > +
> > > +  if (!EFI_ERROR (Status)) {
> > > +    // If we've successfully transmitted the frame, reset the values that store which area of the screen has been BLTted to.
> > > +    // If we haven't succeeded, this will mean we'll try to resend it after the next poll period.
> > > +    UsbDisplayLinkDev->LastY2 = 0;
> > > +    UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> > > +  }
> > > +
> > > +  // Payload with length of 1 to terminate the frame
> > > +  // We need to do this even if we had an error, to indicate to the DL device that it should now expect a new frame.
> > > +  DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 1, &USBStatus);
> > > +
> > > +  gBS->RestoreTPL (OriginalTPL);
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > + * Calculate the video refresh rate from the video timing parameters (pixel clock etc)
> > > + * @param videoMode
> > > + * @return
> > > + */
> > > +#ifndef MDEPKG_NDEBUG
> > > +STATIC inline UINT16
> > > +CalculateRefreshRate (
> > > +    IN CONST struct VideoMode *VideoMode)
> > > +{
> > > +  UINT16 RefreshRate;
> > > +  UINT16 Rmod;
> > > +  UINT16 Rate10Hz;
> > > +
> > > +  RefreshRate = (VideoMode->PixelClock * 10000) / ((VideoMode->HActive + VideoMode->HBlanking) * (VideoMode->VActive
> > + VideoMode->VBlanking));
> > > +  Rmod = RefreshRate % 10;
> > > +  Rate10Hz = RefreshRate - Rmod;
> > > +
> > > +  if (Rmod >= 5) {
> > > +    Rate10Hz += 10;
> > > +  }
> > > +  return Rate10Hz;
> > > +}
> > > +#endif // MDEPKG_NDEBUG
> > > +/*
> > ***************************************************************************************************** */
> > > +/*
> > ***************************************************************************************************** */
> > > +/* ******************        START OF FUNCTIONS WHICH IMPLEMENT GOP INTERFACE         ****************** */
> > > +/*
> > ***************************************************************************************************** */
> > > +/*
> > ***************************************************************************************************** */
> > > +
> > > +
> > > +/**
> > > + *
> > > + * @param Gop          Pointer to the instance of the GOP protocol
> > > + * @param ModeNumber
> > > + * @param SizeOfInfo
> > > + * @param Info
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +EFIAPI
> > > +DisplayLinkQueryMode (
> > > +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *Gop,
> > > +  IN  UINT32                                ModeNumber,
> > > +  OUT UINTN                                 *SizeOfInfo,
> > > +  OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
> > > +)
> > > +{
> > > +  USB_DISPLAYLINK_DEV *Dev;
> > > +  CONST struct VideoMode *VideoMode;
> > > +  EFI_STATUS Status;
> > > +
> > > +  Dev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> > > +  Status = EFI_INVALID_PARAMETER;
> > > +
> > > +  if ((SizeOfInfo == NULL) || (Info == NULL)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  // Get a video mode from the EDID
> > > +  Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, Dev->EdidActive.Edid, Dev->EdidActive.SizeOfEdid,
> > &VideoMode);
> > > +
> > > +  if (!EFI_ERROR (Status)) {
> > > +
> > > +    *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof
> > (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> > > +    if (*Info == NULL) {
> > > +      return EFI_OUT_OF_RESOURCES;
> > > +    }
> > > +
> > > +    DEBUG ((DEBUG_INFO, "BIOS querying mode number %d - returning %dx%d @ %dHz\n", ModeNumber, VideoMode-
> > >HActive, VideoMode->VActive, CalculateRefreshRate (VideoMode)));
> > > +
> > > +    *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> > > +
> > > +    (*Info)->Version = 0;
> > > +    (*Info)->HorizontalResolution = VideoMode->HActive;
> > > +    (*Info)->VerticalResolution = VideoMode->VActive;
> > > +    (*Info)->PixelFormat = PixelBltOnly;
> > > +    (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;
> > > +    (*Info)->PixelInformation.RedMask = 0;
> > > +    (*Info)->PixelInformation.GreenMask = 0;
> > > +    (*Info)->PixelInformation.BlueMask = 0;
> > > +    (*Info)->PixelInformation.ReservedMask = 0;
> > > +  }
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > + *
> > > + * @param Gop         Pointer to the instance of the GOP protocol
> > > + * @param ModeNumber
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +EFIAPI
> > > +DisplayLinkSetMode (
> > > +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *Gop,
> > > +  IN  UINT32                        ModeNumber
> > > +)
> > > +{
> > > +  USB_DISPLAYLINK_DEV *UsbDisplayLinkDev;
> > > +  EFI_STATUS Status;
> > > +  CONST struct VideoMode *VideoMode;
> > > +
> > > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop);
> > > +
> > > +  // Prevent the DisplayLinkPeriodicTimer from interrupting us (bug 28877).
> > > +  // When the driver is manually loaded, the TPL is TPL_NOTIFY (16) which prevents the interrupt from the timer.
> > > +  // When the GOP driver is sideloaded, the TPL of this call is TPL_APPLICATION (4) and the timer can interrupt us.
> > > +  Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> > > +
> > > +  // Get a video mode from the EDID
> > > +  Status = DlEdidGetSupportedVideoModeWithFallback (ModeNumber, UsbDisplayLinkDev->EdidActive.Edid,
> > UsbDisplayLinkDev->EdidActive.SizeOfEdid, &VideoMode);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    return Status;
> > > +  }
> > > +
> > > +  Gop->Mode->Info->Version = 0;
> > > +  Gop->Mode->Info->HorizontalResolution = VideoMode->HActive;
> > > +  Gop->Mode->Info->VerticalResolution = VideoMode->VActive;
> > > +  Gop->Mode->Info->PixelFormat = PixelBltOnly;
> > > +  Gop->Mode->Info->PixelsPerScanLine = Gop->Mode->Info->HorizontalResolution;
> > > +  Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> > > +  Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> > > +  Gop->Mode->FrameBufferSize = 0;
> > > +
> > > +  //
> > > +  // Allocate the back buffer
> > > +  //
> > > +  if (UsbDisplayLinkDev->Screen != NULL) {
> > > +    FreePool (UsbDisplayLinkDev->Screen);
> > > +  }
> > > +
> > > +  UsbDisplayLinkDev->Screen = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)AllocateZeroPool (
> > > +    Gop->Mode->Info->HorizontalResolution *
> > > +    Gop->Mode->Info->VerticalResolution *
> > > +    sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
> > > +
> > > +  if (UsbDisplayLinkDev->Screen == NULL) {
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  DEBUG ((DEBUG_INFO, "Video mode %d selected by BIOS - %d x %d.\n", ModeNumber, VideoMode->HActive, VideoMode-
> > >VActive));
> > > +  // Wait until we are sure that we can set the video mode before we tell the firmware
> > > +  Status = DlUsbSendControlWriteMessage (UsbDisplayLinkDev, SET_VIDEO_MODE, 0, VideoMode, sizeof (struct
> > VideoMode));
> > > +
> > > +  if (Status != EFI_SUCCESS) {
> > > +    // Flag up that we haven't set the video mode correctly yet.
> > > +    DEBUG ((DEBUG_ERROR, "Failed to send USB message to DisplayLink device to set monitor video mode. Monitor
> > connected correctly?\n"));
> > > +    Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> > > +    FreePool (UsbDisplayLinkDev->Screen);
> > > +    UsbDisplayLinkDev->Screen = NULL;
> > > +  } else {
> > > +    BuildBackBuffer (
> > > +      UsbDisplayLinkDev,
> > > +      UsbDisplayLinkDev->Screen,
> > > +      EfiBltBufferToVideo,
> > > +      0, 0,
> > > +      0, 0,
> > > +      Gop->Mode->Info->HorizontalResolution,
> > > +      Gop->Mode->Info->VerticalResolution,
> > > +      Gop->Mode->Info->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
> > > +      Gop->Mode->Info->HorizontalResolution);
> > > +    // unlock the DisplayLinkPeriodicTimer
> > > +    Gop->Mode->Mode = ModeNumber;
> > > +  }
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > + * Implementation of the GOP protocol Blt API function
> > > + * @param This            Pointer to the instance of the GOP protocol
> > > + * @param BltBuffer
> > > + * @param BltOperation
> > > + * @param SourceX
> > > + * @param SourceY
> > > + * @param DestinationX
> > > + * @param DestinationY
> > > + * @param Width
> > > + * @param Height
> > > + * @param Delta
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +EFIAPI
> > > +DisplayLinkBlt (
> > > +  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
> > > +  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer, OPTIONAL
> > > +  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
> > > +  IN  UINTN                                   SourceX,
> > > +  IN  UINTN                                   SourceY,
> > > +  IN  UINTN                                   DestinationX,
> > > +  IN  UINTN                                   DestinationY,
> > > +  IN  UINTN                                   Width,
> > > +  IN  UINTN                                   Height,
> > > +  IN  UINTN                                   Delta         OPTIONAL
> > > +)
> > > +{
> > > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> > > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(This);
> > > +
> > > +  // Drop out if we haven't set the video mode up yet
> > > +  if (This->Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> > > +    return EFI_SUCCESS;
> > > +  }
> > > +
> > > +  if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  if (Width == 0 || Height == 0) {
> > > +    return EFI_INVALID_PARAMETER;
> > > +  }
> > > +
> > > +  // Lock so we make an atomic write the frame buffer.
> > > +  // We would not want a timer based event (Cursor, ...) to come in while we are doing this operation.
> > > +  EFI_TPL OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
> > > +
> > > +  CONST UINTN BltBufferStride = (Delta == 0) ? Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) : Delta;
> > > +  CONST EFI_STATUS boundsCheckStatus = CheckBounds (This, BltOperation, SourceX, SourceY, Width, Height, DestinationX,
> > DestinationY);
> > > +  if (EFI_ERROR (boundsCheckStatus)) {
> > > +    gBS->RestoreTPL (OriginalTPL);
> > > +    return boundsCheckStatus;
> > > +  }
> > > +
> > > +  BuildBackBuffer (UsbDisplayLinkDev, BltBuffer, BltOperation, SourceX, SourceY, DestinationX, DestinationY, Width, Height,
> > BltBufferStride, This->Mode->Info->PixelsPerScanLine);
> > > +
> > > +  gBS->RestoreTPL (OriginalTPL);
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> > > new file mode 100644
> > > index 000000000000..c12a80a6e1ab
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c
> > > @@ -0,0 +1,145 @@
> > > +/**
> > > + * @file UsbDescriptors.c
> > > + * @brief Functions to read USB Interface and Capabilities descriptors
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#include "UsbDisplayLink.h"
> > > +#include "UsbDescriptors.h"
> > > +
> > > +/**
> > > + *
> > > + * @param UsbIo
> > > + * @param descriptorType
> > > + * @param index
> > > + * @param Buffer
> > > + * @param Length
> > > + * @param UsbStatus
> > > + * @return
> > > + */
> > > +STATIC EFI_STATUS
> > > +ReadDescriptor (
> > > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > > +    UINT8 DescriptorType,
> > > +    UINT8 Index,
> > > +    VOID* Buffer,
> > > +    UINT16 Length,
> > > +    UINT32* UsbStatus)
> > > +{
> > > +  EFI_STATUS Status;
> > > +
> > > +  UINT8 Header[2];
> > > +  ZeroMem (Header, sizeof (Header));
> > > +
> > > +  EFI_USB_DEVICE_REQUEST Request;
> > > +  ZeroMem (&Request, sizeof (Request));
> > > +  Request.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_STANDARD | USB_TARGET_DEVICE;
> > > +  Request.Request = USB_REQ_GET_DESCRIPTOR;
> > > +  Request.Index = 0;
> > > +  Request.Value = DescriptorType << 8 | Index;
> > > +  Request.Length = sizeof (Header);
> > > +
> > > +  // Read the descriptor header to see how many bytes it contains
> > > +  Status = UsbIo->UsbControlTransfer (
> > > +      UsbIo,
> > > +      &Request,
> > > +      EfiUsbDataIn,
> > > +      DISPLAYLINK_USB_CTRL_TIMEOUT,
> > > +      Header,
> > > +      sizeof (Header),
> > > +      UsbStatus);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "Failed to read length of descriptor type x%x, index %u (code %r, USB status x%x)\n",
> > > +          DescriptorType, Index, Status, *UsbStatus));
> > > +    return Status;
> > > +  }
> > > +  CONST UINT16 TotalLength = Header[0];
> > > +
> > > +  // Now we know the size of it, we can read the entire descriptor
> > > +  Request.Length = TotalLength;
> > > +
> > > +  Status = UsbIo->UsbControlTransfer (
> > > +      UsbIo,
> > > +      &Request,
> > > +      EfiUsbDataIn,
> > > +      DISPLAYLINK_USB_CTRL_TIMEOUT,
> > > +      Buffer,
> > > +      TotalLength,
> > > +      UsbStatus);
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > +  Perform a USB control transfer to read the DisplayLink vendor descriptor.
> > > +
> > > +  @param UsbIo   Pointer to the instance of the USBIO protocol
> > > +  @param Buffer  Pointer to the buffer where descriptor should be written
> > > +  @param Length  Length of buffer (and the maximum amount of descriptor data that shall be read)
> > > +
> > > +  @retval EFI_SUCCESS  The descriptor has been copied into Buffer
> > > +  @retval Other        The descriptor could not be read
> > > +**/
> > > +EFI_STATUS
> > > +ReadCapabilitiesDescriptor (
> > > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > > +    OUT VOID* Buffer,
> > > +    IN UINT16 Length)
> > > +{
> > > +  UINT32 UsbStatus;
> > > +  EFI_STATUS Status;
> > > +
> > > +  Status = ReadDescriptor (
> > > +      UsbIo,
> > > +      DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY,
> > > +      0,
> > > +      Buffer,
> > > +      Length,
> > > +      &UsbStatus);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "Could not read capabilities descriptor from DL device (code %r, USB status x%x). Unrecognised
> > firmware version?\n", Status, UsbStatus));
> > > +  }
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +
> > > +/**
> > > + An alternative to the UBSIO protocol function EFI_USB_IO_GET_INTERFACE_DESCRIPTOR.
> > > + This version allows you to specify an index.
> > > + * @param UsbIo                 Pointer to the instance of the USBIO protocol
> > > + * @param interfaceDescriptor   Where the descriptor should be written
> > > + * @param index                 The index of the descriptor required (the standard USBIO function doesn't let you do this)
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +UsbDisplayLinkGetInterfaceDescriptor (
> > > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > > +    OUT EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> > > +    UINT8 Index
> > > +    )
> > > +{
> > > +  UINT32 UsbStatus;
> > > +  EFI_STATUS Status;
> > > +
> > > +  Status = ReadDescriptor (
> > > +      UsbIo,
> > > +      USB_DESC_TYPE_INTERFACE,
> > > +      Index,
> > > +      InterfaceDescriptor,
> > > +      sizeof (EFI_USB_INTERFACE_DESCRIPTOR),
> > > +      &UsbStatus);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "USB control transfer failed while reading interface descriptor (code %r, USB status x%x)\n",
> > Status, UsbStatus));
> > > +  }
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> > > new file mode 100644
> > > index 000000000000..cdc01aad193a
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h
> > > @@ -0,0 +1,109 @@
> > > +/**
> > > + * @file UsbDescriptors.h
> > > + * @brief Functions to read USB Interface and Capabilities descriptors
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#ifndef USB_DESCRIPTORS_H_
> > > +#define USB_DESCRIPTORS_H_
> > > +
> > > +  /**
> > > +  Type of the Direct Framebuffer capability descriptor.
> > > +  This is a vendor specific USB descriptor for DisplayLink.
> > > +  @see NR-140082 Section 3.5
> > > +  **/
> > > +#define DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY 0x5e
> > > +
> > > +  /**
> > > +  Identifiers for capabllity keys
> > > +  @see NR-140082 Section 3.2
> > > +  **/
> > > +
> > > +  /**
> > > +  Key for Capabilities 1 - See section 3.2.1
> > > +  **/
> > > +#define CAPABILITIES1_KEY 0x0
> > > +
> > > +  /**
> > > +  Lengths for capabllity fields
> > > +  **/
> > > +#define CAPABILITIES1_LENGTH 0x4
> > > +
> > > +  /**
> > > +  Bits for the capability bitmask Capabilities1
> > > +  **/
> > > +
> > > +  /**
> > > +  This is the first capability defined for the protocol.
> > > +  It represents the mode of operation as of initial release.
> > > +  If a device ever breaks compatibility with this initial release,
> > > +  it will cease
> > > +  to support CapabilityBaseProtocol.
> > > +  **/
> > > +#define CAPABILITIES1_BASE_PROTOCOL (1 << 0)
> > > +
> > > +  /**
> > > +  Idealised VendorDescriptor which is the result
> > > +  of parsing vendor descriptor from device.
> > > +  **/
> > > +  typedef struct {
> > > +    UINT32 Capabilities1;
> > > +  } VendorDescriptor;
> > > +
> > > +#pragma pack(push, 1)
> > > +  typedef struct {
> > > +    UINT16 Key; /** Really of type enum DescrptorKeys */
> > > +    UINT8 Length;
> > > +    UINT8 Value[];
> > > +  } DescriptorKLV;
> > > +
> > > +  typedef struct {
> > > +    UINT8 Length;
> > > +    UINT8 Type;
> > > +    UINT16 CapabilityVersion;
> > > +    UINT8 CapabilityLength;
> > > +    UINT8 Klv[];
> > > +  } VendorDescriptorGeneric;
> > > +#pragma pack(pop)
> > > +
> > > +
> > > +EFI_STATUS UsbDisplayLinkGetInterfaceDescriptor (
> > > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > > +    EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor,
> > > +    UINT8 index
> > > +    );
> > > +
> > > +EFI_STATUS ReadCapabilitiesDescriptor (IN EFI_USB_IO_PROTOCOL *UsbIo, VOID* Buffer, UINT16 Length);
> > > +
> > > +/**
> > > +Parse data in buffer to a VendorDescriptor, if possible.
> > > +
> > > +@param Data      Buffer
> > > +@param Length    Length of buffer
> > > +
> > > +@retval EFI_SUCCESS      The descriptor was parsed successfully
> > > +@retval EFI_UNSUPPORTED  Simple Pointer Protocol is not installed on Controller.
> > > +**/
> > > +EFI_STATUS
> > > +UsbDisplayLinkParseCapabilitiesDescriptor (
> > > +  CONST IN VOID* Data,
> > > +  IN UINTN Length,
> > > +  OUT VendorDescriptor* Descriptor
> > > +);
> > > +
> > > +/**
> > > +Decide if binding may proceed, given capabilities
> > > +
> > > +@retval TRUE   Binding may proceed
> > > +@retval FALSE  Binding is not possible
> > > +**/
> > > +BOOLEAN
> > > +UsbDisplayLinkCapabilitiesSufficientToBind (
> > > +  CONST IN VendorDescriptor* Descriptor
> > > +);
> > > +
> > > +#endif // USB_DESCRIPTORS_H_
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> > > new file mode 100644
> > > index 000000000000..997a3e307f38
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c
> > > @@ -0,0 +1,1082 @@
> > > +/**
> > > + * @file UsbDisplayLink.c
> > > + * @brief USB DisplayLink Driver that manages USB DisplayLink device and produces Graphics Output Protocol
> > > + * This file implements the functions of the Driver Binding / Start / Stop / Unload interface
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#include "UsbDisplayLink.h"
> > > +
> > > +#include <Library/UefiRuntimeServicesTableLib.h>
> > > +#include <Library/PrintLib.h>
> > > +#include <Protocol/HiiFont.h>
> > > +
> > > +#include "Edid.h"
> > > +#include "UsbDescriptors.h"
> > > +
> > > +//
> > > +// Functions of Driver Binding Protocol
> > > +//
> > > +
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverBindingSupported (
> > > +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> > > +  IN EFI_HANDLE                     Controller,
> > > +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> > > +);
> > > +
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverBindingStart (
> > > +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> > > +  IN EFI_HANDLE                     Controller,
> > > +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> > > +);
> > > +
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverBindingStop (
> > > +  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
> > > +  IN  EFI_HANDLE                    Controller,
> > > +  IN  UINTN                         NumberOfChildren,
> > > +  IN  EFI_HANDLE                    *ChildHandleBuffer
> > > +);
> > > +
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverBindingEntryPoint (
> > > +  IN EFI_HANDLE           ImageHandle,
> > > +  IN EFI_SYSTEM_TABLE     *SystemTable
> > > +);
> > > +
> > > +
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> > > +  IN EFI_HANDLE           ImageHandle,
> > > +  IN EFI_SYSTEM_TABLE     *SystemTable,
> > > +  IN EFI_HANDLE           DriverBindingHandle
> > > +);
> > > +
> > > +
> > > +// Generated with https://www.guidgen.com/ - "B70E5A79-C6D6-4267-B02E-9108C989E287"
> > > +EFI_GUID gEfiDlGopVariableGuid = { 0xB70E5A79, 0xC6D6, 0x4267,{ 0xB0, 0x2E, 0x91, 0x08, 0xC9, 0x89, 0xE2, 0x87 } };
> > > +
> > > +
> > > +EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding = {
> > > +  UsbDisplayLinkDriverBindingSupported,
> > > +  UsbDisplayLinkDriverBindingStart,
> > > +  UsbDisplayLinkDriverBindingStop,
> > > +  INF_DRIVER_VERSION,
> > > +  NULL,
> > > +  NULL
> > > +};
> > > +
> > > +
> > > +/**
> > > + * Reads integer environment variable with default fallback.
> > > + * @param variableName   variable name to read
> > > + * @param defaultValue   default value to return if requested not found
> > > + */
> > > +STATIC UINT32
> > > +ReadEnvironmentInt (
> > > +    CHAR16 *VariableName,
> > > +    UINT32 DefaultValue
> > > +    )
> > > +{
> > > +  UINT32 Result;
> > > +  UINTN DataSize;
> > > +  DataSize = sizeof (Result);
> > > +  CONST EFI_STATUS Status = gRT->GetVariable (VariableName, &gEfiDlGopVariableGuid, (UINT32*)NULL, &DataSize,
> > &Result);
> > > +  if (!EFI_ERROR (Status) && (sizeof (Result) == DataSize)) {
> > > +    return Result;
> > > +  }
> > > +  return DefaultValue;
> > > +}
> > > +
> > > +/**
> > > +* Reads boolean environment variable with default fallback.
> > > +* @param variableName   variable name to read
> > > +* @param defaultValue   default value to return if requested not found
> > > +*/
> > > +STATIC BOOLEAN
> > > +ReadEnvironmentBool (
> > > +    CHAR16 *VariableName,
> > > +    BOOLEAN DefaultValue
> > > +    )
> > > +{
> > > +  return ReadEnvironmentInt (VariableName, DefaultValue ? 1 : 0) == 1;
> > > +}
> > > +
> > > +
> > > +/**
> > > +*
> > > +* @param UsbDisplayLinkDev
> > > +* @return
> > > +*/
> > > +STATIC EFI_STATUS
> > > +InitializeUsbDisplayLinkDevice (
> > > +  IN OUT USB_DISPLAYLINK_DEV *UsbDisplayLinkDev
> > > +)
> > > +{
> > > +  EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop;
> > > +  Gop = &UsbDisplayLinkDev->GraphicsOutputProtocol;
> > > +  Gop->QueryMode = DisplayLinkQueryMode;
> > > +  Gop->SetMode = DisplayLinkSetMode;
> > > +  Gop->Blt = DisplayLinkBlt;
> > > +
> > > +  //
> > > +  // Allocate buffer for Graphics Output Protocol mode information
> > > +  //
> > > +  Gop->Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE*)AllocatePool (sizeof
> > (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
> > > +  if (Gop->Mode == NULL) {
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +  Gop->Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (sizeof
> > (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
> > > +  if (Gop->Mode->Info == NULL) {
> > > +    FreePool (Gop->Mode);
> > > +    Gop->Mode = NULL;
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  Gop->Mode->MaxMode = MAX(1, DlEdidGetNumSupportedModesInEdid (UsbDisplayLinkDev->EdidActive.Edid,
> > UsbDisplayLinkDev->EdidActive.SizeOfEdid));
> > > +
> > > +  Gop->Mode->Mode = GRAPHICS_OUTPUT_INVALID_MODE_NUMBER;
> > > +  Gop->Mode->Info->Version = 0;
> > > +  // Initialising the horizontal resolution prevents certain BIOSs from hanging on boot, but
> > > +  // it is not yet clear why. See bug 28194.
> > > +  Gop->Mode->Info->HorizontalResolution = DlVideoModeGetSupportedVideoMode (0)->HActive;
> > > +  Gop->Mode->Info->VerticalResolution = 0;
> > > +  Gop->Mode->Info->PixelFormat = PixelBltOnly;
> > > +  Gop->Mode->Info->PixelsPerScanLine = 0;
> > > +  Gop->Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
> > > +  Gop->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)NULL;
> > > +  Gop->Mode->FrameBufferSize = 0;
> > > +
> > > +  // Prevent DlGopSendScreenUpdate from running until we are sure that the video mode is set
> > > +  UsbDisplayLinkDev->LastY2 = 0;
> > > +  UsbDisplayLinkDev->LastY1 = (UINTN)-1;
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +/**
> > > +  Look for alternate settings for the UsbIo handle's interface
> > > +  which offer protocol DL_PROTOCOL_DIRECT_FB.
> > > +
> > > +  @retval -1                     Not found
> > > +  @retval Other                  The alternate setting
> > > +**/
> > > +STATIC INTN
> > > +GetDirectFbAltSetting (
> > > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > > +    IN UINT8 ParentInterfaceNumber
> > > +    )
> > > +{
> > > +  EFI_STATUS Status;
> > > +  INTN AltSettingIndex;
> > > +  UINT16 InterfaceIndex;
> > > +
> > > +  AltSettingIndex = -1;
> > > +
> > > +  for (InterfaceIndex = 0; InterfaceIndex <= 0xFF; InterfaceIndex++) {
> > > +    EFI_USB_INTERFACE_DESCRIPTOR interfaceDescriptor;
> > > +    Status = UsbDisplayLinkGetInterfaceDescriptor (UsbIo, &interfaceDescriptor, (UINT8)InterfaceIndex);
> > > +    if (EFI_ERROR (Status)) {
> > > +      break;
> > > +    }
> > > +
> > > +    if (interfaceDescriptor.InterfaceNumber == ParentInterfaceNumber &&
> > > +       (interfaceDescriptor.InterfaceClass == CLASS_VENDOR) &&
> > > +        interfaceDescriptor.InterfaceProtocol == INTERFACE_PROTOCOL_DIRECT_FB) {
> > > +      AltSettingIndex = interfaceDescriptor.AlternateSetting;
> > > +      break;
> > > +    }
> > > +  }
> > > +  return AltSettingIndex;
> > > +}
> > > +
> > > +/**
> > > + *
> > > + * @param UsbIo
> > > + * @param altSettingIndex
> > > + * @return
> > > + */
> > > +STATIC EFI_STATUS
> > > +SelectAltSetting (
> > > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > > +    IN UINTN AltSettingIndex)
> > > +{
> > > +  // Set alternate setting 1 on the interface
> > > +  EFI_STATUS Status;
> > > +  UINT32 UsbStatus;
> > > +  EFI_USB_DEVICE_REQUEST Request;
> > > +  ZeroMem (&Request, sizeof (Request));
> > > +  Request.RequestType = USB_REQ_TYPE_STANDARD | USB_TARGET_INTERFACE;
> > > +  Request.Request = USB_REQ_SET_INTERFACE;
> > > +  Request.Index = DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO;
> > > +  Request.Value = (UINT16)AltSettingIndex;
> > > +
> > > +  Status = UsbIo->UsbControlTransfer (
> > > +    UsbIo,
> > > +    &Request,
> > > +    EfiUsbNoData,
> > > +    DISPLAYLINK_USB_CTRL_TIMEOUT,
> > > +    NULL,
> > > +    0,
> > > +    &UsbStatus);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    Status = EFI_UNSUPPORTED;
> > > +    DEBUG ((DEBUG_ERROR, "USB control transfer failed while attempting to select alt setting %d on interface (code %r, USB
> > status x%x). DisplayLink device has unsupported firmware version?\n", AltSettingIndex, Status, UsbStatus));
> > > +  }
> > > +  return Status;
> > > +}
> > > +
> > > +
> > > +/**
> > > +  Report whether the driver can support the device attached via UsbIo
> > > +  by seeing what if any capabilities it reports.
> > > +
> > > +  @retval TRUE     Device has sufficient capabilities for this driver.
> > > +  @retval FALSE    Device lacks sufficient capabilities.
> > > +**/
> > > +STATIC BOOLEAN
> > > +CapabilitiesSupported (
> > > +    IN EFI_USB_IO_PROTOCOL *UsbIo
> > > +    )
> > > +{
> > > +  UINT8 Buffer[256];
> > > +  EFI_STATUS Status;
> > > +
> > > +  Status = ReadCapabilitiesDescriptor (UsbIo, Buffer, sizeof (Buffer));
> > > +  if (EFI_ERROR (Status)) {
> > > +    return FALSE;
> > > +  }
> > > +
> > > +  VendorDescriptor descriptor;
> > > +  Status = UsbDisplayLinkParseCapabilitiesDescriptor (Buffer, sizeof (Buffer), &descriptor);
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "Failed to parse capabilities descriptor (code %r)\n", Status));
> > > +    return FALSE;
> > > +  }
> > > +
> > > +  return UsbDisplayLinkCapabilitiesSufficientToBind (&descriptor);
> > > +}
> > > +
> > > +
> > > +/**
> > > + *
> > > + * @param UsbIo
> > > + * @param InterfaceDescriptor
> > > + * @param altSettingIndex
> > > + * @return
> > > + */
> > > +STATIC BOOLEAN
> > > +IsDLDirectFbCapableInterface (
> > > +    IN EFI_USB_IO_PROTOCOL *UsbIo,
> > > +    IN EFI_USB_INTERFACE_DESCRIPTOR  *InterfaceDescriptor,
> > > +    IN INTN *AltSettingIndex)
> > > +{
> > > +  EFI_STATUS Status;
> > > +  EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor;
> > > +
> > > +  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DeviceDescriptor);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    return FALSE;
> > > +  }
> > > +
> > > +  if (DeviceDescriptor.IdVendor != VENDOR_DISPLAYLINK) {
> > > +    return FALSE;
> > > +  }
> > > +
> > > +  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, InterfaceDescriptor);
> > > +  if (EFI_ERROR (Status)) {
> > > +    return FALSE;
> > > +  }
> > > +
> > > +  // We can assume that the interface that we want to talk to - the NIVO interface - is number 0
> > > +  if (InterfaceDescriptor->InterfaceNumber != DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO) {
> > > +    return FALSE;
> > > +  }
> > > +
> > > +  // Check if we have an interface (alt setting) descriptor with the correct interface protocol
> > > +  *AltSettingIndex = GetDirectFbAltSetting (UsbIo, InterfaceDescriptor->InterfaceNumber);
> > > +
> > > +  if (*AltSettingIndex == -1) {
> > > +    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to find setting on device which supports GOP functionality. Check
> > firmware / device version?\n"));
> > > +    return FALSE;
> > > +  }
> > > +
> > > +  // Now check that the capabilities that we need are properly supported
> > > +  if (CapabilitiesSupported (UsbIo) == FALSE) {
> > > +    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: DL device detected, but it doesn't support the required GOP features. Check
> > firmware / device version?\n"));
> > > +    return FALSE;
> > > +  }
> > > +
> > > +  return TRUE;
> > > +}
> > > +
> > > +
> > > +/**
> > > + * Prints a block of text in the framebuffer (helper function).
> > > + * @param X   x coordinate
> > > + * @param Y   y coordinate
> > > + */
> > > +STATIC VOID
> > > +DisplayLinkPrintTextToScreenInternal (
> > > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> > > +  UINTN X,
> > > +  UINTN Y,
> > > +  IN CHAR16 *Buffer
> > > +  )
> > > +{
> > > +  EFI_STATUS Status;
> > > +  EFI_HII_FONT_PROTOCOL *HiiFont;
> > > +  EFI_IMAGE_OUTPUT *Blt;
> > > +  EFI_FONT_DISPLAY_INFO FontInfo;
> > > +  EFI_HII_OUT_FLAGS Flags;
> > > +
> > > +  Blt = (EFI_IMAGE_OUTPUT*)NULL;
> > > +
> > > +  Status = gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOID **)&HiiFont);
> > > +  if (!EFI_ERROR (Status)) {
> > > +    Blt = (EFI_IMAGE_OUTPUT*)AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
> > > +    Blt->Width = (UINT16)GraphicsOutput->Mode->Info->HorizontalResolution;
> > > +    Blt->Height = (UINT16)GraphicsOutput->Mode->Info->VerticalResolution;
> > > +    Blt->Image.Screen = GraphicsOutput;
> > > +
> > > +    ZeroMem (&FontInfo, sizeof (EFI_FONT_DISPLAY_INFO));
> > > +    FontInfo.ForegroundColor.Red = 0;
> > > +    FontInfo.ForegroundColor.Green = 0;
> > > +    FontInfo.ForegroundColor.Blue = 0;
> > > +    FontInfo.BackgroundColor.Red = 0xff;
> > > +    FontInfo.BackgroundColor.Green = 0xff;
> > > +    FontInfo.BackgroundColor.Blue = 0xff;
> > > +
> > > +    Flags = EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_OUT_FLAG_CLIP |
> > > +            EFI_HII_OUT_FLAG_CLIP_CLEAN_X | EFI_HII_OUT_FLAG_CLIP_CLEAN_Y |
> > > +            EFI_HII_IGNORE_LINE_BREAK | EFI_HII_DIRECT_TO_SCREEN;
> > > +
> > > +    Status = HiiFont->StringToImage (
> > > +                           HiiFont,
> > > +                           Flags,
> > > +                           Buffer,
> > > +                           &FontInfo,
> > > +                           &Blt,
> > > +                           X,
> > > +                           Y,
> > > +                           (EFI_HII_ROW_INFO**)NULL,
> > > +                           (UINTN*)NULL,
> > > +                           (UINTN*)NULL);
> > > +  }
> > > +
> > > +  if (Blt != NULL) {
> > > +    FreePool (Blt);
> > > +  }
> > > +}
> > > +
> > > +
> > > +/**
> > > +* Prints a block of text in the framebuffer.
> > > +* @param X       x coordinate
> > > +* @param Y       y coordinate
> > > +* @param Format  string format similar to stdlib's vsnprintf
> > > +* @param ...     arguments
> > > +*/
> > > +VOID
> > > +EFIAPI
> > > +DlGopPrintTextToScreen (
> > > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> > > +  UINTN X,
> > > +  UINTN Y,
> > > +  IN CONST CHAR16 *Format,
> > > +  ...
> > > +  )
> > > +{
> > > +  VA_LIST Marker;
> > > +  CHAR16 *Buffer;
> > > +  UINTN BufferSize;
> > > +
> > > +  ASSERT (Format != NULL);
> > > +  ASSERT (((UINTN) Format & BIT0) == 0);
> > > +
> > > +  VA_START(Marker, Format);
> > > +
> > > +  BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);
> > > +
> > > +  Buffer = (CHAR16*)AllocatePool (BufferSize);
> > > +  ASSERT (Buffer != NULL);
> > > +
> > > +  UnicodeVSPrint (Buffer, BufferSize, Format, Marker);
> > > +
> > > +  VA_END(Marker);
> > > +
> > > +  DisplayLinkPrintTextToScreenInternal (GraphicsOutput, X, Y, Buffer);
> > > +
> > > +  FreePool (Buffer);
> > > +}
> > > +
> > > +
> > > +/**
> > > + * Sometimes platforms only write to the first GOP device that they find. Enabling this function allows us to copy the pixels
> > from this device.
> > > + * @param UsbDisplayLinkDev
> > > + */
> > > +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > > +STATIC VOID
> > > +DisplayLinkCopyFromPrimaryGopDevice (
> > > +  IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > > +  )
> > > +{
> > > +  UINTN HandleCount;
> > > +  EFI_HANDLE *HandleBuffer;
> > > +  UINTN HandleIndex;
> > > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
> > > +
> > > +  gBS->LocateHandleBuffer (
> > > +    ByProtocol,
> > > +    &gEfiGraphicsOutputProtocolGuid,
> > > +    NULL,
> > > +    &HandleCount,
> > > +    &HandleBuffer);
> > > +
> > > +  for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
> > > +    gBS->HandleProtocol (HandleBuffer[HandleIndex], &gEfiGraphicsOutputProtocolGuid, (VOID**)&Gop);
> > > +    if (Gop != &UsbDisplayLinkDev->GraphicsOutputProtocol && Gop->Mode->FrameBufferBase !=
> > (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
> > > +
> > > +    // See if we need to do a screen update - calculate a really noddy hash to see if any screen updates have happened.
> > > +    STATIC UINT32 prevframeBufferHash = 0; // 4 bytes per pixel
> > > +    UINT32 currFrameBufferHash = 0;
> > > +    UINTN i;
> > > +    for (i = 0; i < (Gop->Mode->Info->HorizontalResolution * Gop->Mode->Info->VerticalResolution); i++) {
> > > +      currFrameBufferHash += ((UINT32*)(UINTN)Gop->Mode->FrameBufferBase)[i];
> > > +    }
> > > +
> > > +    if (currFrameBufferHash != prevframeBufferHash) {
> > > +      prevframeBufferHash = currFrameBufferHash;
> > > +
> > > +      DisplayLinkBlt (
> > > +        &UsbDisplayLinkDev->GraphicsOutputProtocol,
> > > +        (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(UINTN)Gop->Mode->FrameBufferBase,
> > > +        EfiBltBufferToVideo,
> > > +        0,
> > > +        0,
> > > +        0,
> > > +        0,
> > > +        Gop->Mode->Info->HorizontalResolution,
> > > +        Gop->Mode->Info->VerticalResolution,
> > > +        0);
> > > +      }
> > > +      break;
> > > +    }
> > > +  }
> > > +
> > > +  FreePool (HandleBuffer);
> > > +}
> > > +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > > +
> > > +
> > > +/**
> > > + * Exit from boot services: signal handler.
> > > + */
> > > +STATIC VOID
> > > +EFIAPI
> > > +DisplayLinkDriverExitBootServices (
> > > +  IN EFI_EVENT  Event,
> > > +  IN VOID       *Context
> > > +  )
> > > +{
> > > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> > > +  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> > > +
> > > +  gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> > > +}
> > > +
> > > +/**
> > > + * Periodic screen update: timer callback.
> > > + */
> > > +VOID
> > > +EFIAPI
> > > +DisplayLinkPeriodicTimer (
> > > +    IN EFI_EVENT Event,
> > > +    IN VOID* Context
> > > +    )
> > > +{
> > > +  EFI_STATUS Status;
> > > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev;
> > > +
> > > +  Status = EFI_SUCCESS;
> > > +  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)Context;
> > > +
> > > +  // Drop out if we haven't set the video mode up yet
> > > +  if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Mode == GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) {
> > > +    // Restart the one-shot timer to poll the status again.
> > > +    Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> > > +    if (EFI_ERROR (Status)) {
> > > +      DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> > > +    }
> > > +    return;
> > > +  }
> > > +
> > > +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > > +  DisplayLinkCopyFromPrimaryGopDevice (UsbDisplayLinkDev);
> > > +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > > +
> > > +  if (UsbDisplayLinkDev->ShowBandwidth) {
> > > +    STATIC UINTN Count = 0;
> > > +
> > > +    if (Count++ % 50 == 0) {
> > > +      DlGopPrintTextToScreen (&UsbDisplayLinkDev->GraphicsOutputProtocol, 32, 48, (CONST CHAR16*)L"  Bandwidth: %d
> > MB/s    ", UsbDisplayLinkDev->DataSent * 10000000 / DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD / 50 / 1024 / 1024);
> > > +      UsbDisplayLinkDev->DataSent = 0;
> > > +    }
> > > +  }
> > > +
> > > +  if (UsbDisplayLinkDev->ShowTestPattern)
> > > +  {
> > > +    if (UsbDisplayLinkDev->ShowTestPattern == 5) {
> > > +      DlGopSendTestPattern (UsbDisplayLinkDev, 0);
> > > +    } else if (UsbDisplayLinkDev->ShowTestPattern >= 10) {
> > > +      DlGopSendTestPattern (UsbDisplayLinkDev, 1);
> > > +      UsbDisplayLinkDev->ShowTestPattern = 0;
> > > +    }
> > > +    UsbDisplayLinkDev->ShowTestPattern++;
> > > +
> > > +  }
> > > +
> > > +  // Send the latest version of the frame buffer to the DL device over USB
> > > +  DlGopSendScreenUpdate (UsbDisplayLinkDev);
> > > +
> > > +  // Restart the timer now we've finished
> > > +  Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "Failed to create timer.\n"));
> > > +  }
> > > +}
> > > +
> > > +/*
> > ******************************************************************************************************
> > */
> > > +/*
> > ******************************************************************************************************
> > */
> > > +/* ******************   START OF FUNCTIONS WHICH IMPLEMENT DRIVER BINDING INTERFACE    ******************
> > */
> > > +/*
> > ******************************************************************************************************
> > */
> > > +/*
> > ******************************************************************************************************
> > */
> > > +
> > > +/**
> > > +  Check whether USB DisplayLink driver supports this device.
> > > +
> > > +  @param  This                   The USB DisplayLink driver 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
> > > +UsbDisplayLinkDriverBindingSupported (
> > > +  IN EFI_DRIVER_BINDING_PROTOCOL    *This,
> > > +  IN EFI_HANDLE                     Controller,
> > > +  IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
> > > +  )
> > > +{
> > > +  EFI_STATUS          Status;
> > > +  EFI_USB_IO_PROTOCOL *UsbIo;
> > > +
> > > +  Status = gBS->OpenProtocol (
> > > +                  Controller,
> > > +                  &gEfiUsbIoProtocolGuid,
> > > +                  (VOID **) &UsbIo,
> > > +                  This->DriverBindingHandle,
> > > +                  Controller,
> > > +                  EFI_OPEN_PROTOCOL_BY_DRIVER);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    return Status;
> > > +  }
> > > +
> > > +  //
> > > +  // Use the USB I/O Protocol interface to check whether Controller is
> > > +  // a DisplayLink device that can be managed by this driver.
> > > +  //
> > > +  Status = EFI_UNSUPPORTED;
> > > +  EFI_USB_INTERFACE_DESCRIPTOR DummyInterfaceDescriptor;
> > > +  INTN DummyAltSettingIndex;
> > > +
> > > +  if (IsDLDirectFbCapableInterface (UsbIo, &DummyInterfaceDescriptor, &DummyAltSettingIndex)){
> > > +    Status = EFI_SUCCESS;
> > > +  }
> > > +
> > > +  gBS->CloseProtocol (
> > > +        Controller,
> > > +        &gEfiUsbIoProtocolGuid,
> > > +        This->DriverBindingHandle,
> > > +        Controller);
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +
> > > +/**
> > > +  Starts the DisplayLink device with this driver.
> > > +
> > > +  This function consumes USB I/O Protocol, intializes USB DisplayLink device,
> > > +  installs Graphics Output Protocol
> > > +  Transfer to manage the USB DisplayLink device.
> > > +
> > > +  @param  This                  The USB DisplayLink 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           This driver supports this device.
> > > +  @retval EFI_UNSUPPORTED       This driver does not support this device.
> > > +  @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
> > > +  @retval EFI_OUT_OF_RESOURCES  Can't allocate memory resources.
> > > +  @retval EFI_ALREADY_STARTED   This driver has been started.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverBindingStart (
> > > +  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
> > > +  IN EFI_HANDLE                   Controller,
> > > +  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
> > > +  )
> > > +{
> > > +  EFI_STATUS                      Status;
> > > +  USB_DISPLAYLINK_DEV             *UsbDisplayLinkDev;
> > > +  UINT8                           EndpointNumber;
> > > +  EFI_USB_ENDPOINT_DESCRIPTOR     EndpointDescriptor;
> > > +  UINT8                           Index;
> > > +  BOOLEAN                         FoundOut;
> > > +  BOOLEAN                         FoundIn;
> > > +  EFI_TPL                         OriginalTPL;
> > > +  INTN                            altSettingIndex;
> > > +
> > > +  OriginalTPL = gBS->RaiseTPL (TPL_CALLBACK);
> > > +
> > > +  UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)AllocateZeroPool (sizeof (USB_DISPLAYLINK_DEV));
> > > +  if (UsbDisplayLinkDev == NULL) {
> > > +    DEBUG ((DEBUG_ERROR, "Device initialialisation - Failed to allocate memory for device.\n"));
> > > +    gBS->RestoreTPL (OriginalTPL);
> > > +    return EFI_OUT_OF_RESOURCES;
> > > +  }
> > > +
> > > +  UsbDisplayLinkDev->Signature = USB_DISPLAYLINK_DEV_SIGNATURE;
> > > +
> > > +  UsbDisplayLinkDev->ShowBandwidth = ReadEnvironmentBool (L"DisplayLinkShowBandwidth", FALSE);
> > > +  UsbDisplayLinkDev->ShowTestPattern = ReadEnvironmentBool (L"DisplayLinkShowTestPatterns", FALSE);
> > > +
> > > +  //
> > > +  // Open USB I/O Protocol
> > > +  //
> > > +  Status = gBS->OpenProtocol (
> > > +      Controller,
> > > +      &gEfiUsbIoProtocolGuid,
> > > +      (VOID **) &UsbDisplayLinkDev->UsbIo,
> > > +      This->DriverBindingHandle,
> > > +      Controller,
> > > +      EFI_OPEN_PROTOCOL_BY_DRIVER);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "Failed to open usbio protocol. Is USB correctly supported on this platform?.\n"));
> > > +    Status = EFI_UNSUPPORTED;
> > > +    goto ErrorExit2;
> > > +  }
> > > +
> > > +  if (!IsDLDirectFbCapableInterface (UsbDisplayLinkDev->UsbIo, &UsbDisplayLinkDev->InterfaceDescriptor, &altSettingIndex))
> > {
> > > +    Status = EFI_UNSUPPORTED;
> > > +    goto ErrorExit4;
> > > +  }
> > > +
> > > +  Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, altSettingIndex);
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to select alternate setting.\n"));
> > > +    Status = EFI_UNSUPPORTED;
> > > +    goto ErrorExit4;
> > > +  }
> > > +
> > > +  //
> > > +  // Parse endpoint descriptor
> > > +  //
> > > +  EndpointNumber = UsbDisplayLinkDev->InterfaceDescriptor.NumEndpoints;
> > > +
> > > +  //
> > > +  // Traverse endpoints to find bulk endpoint
> > > +  //
> > > +  FoundOut = FALSE;
> > > +  FoundIn = FALSE;
> > > +  for (Index = 0; Index < EndpointNumber; Index++) {
> > > +    UsbDisplayLinkDev->UsbIo->UsbGetEndpointDescriptor (
> > > +             UsbDisplayLinkDev->UsbIo,
> > > +             Index,
> > > +             &EndpointDescriptor);
> > > +
> > > +    if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_BULK) {
> > > +      if (!FoundOut && (EndpointDescriptor.EndpointAddress & BIT7) == 0) {
> > > +        CopyMem (&UsbDisplayLinkDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> > > +        FoundOut = TRUE;
> > > +      } else if (!FoundIn && (EndpointDescriptor.EndpointAddress & BIT7) == BIT7) {
> > > +        CopyMem (&UsbDisplayLinkDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor));
> > > +        FoundIn = TRUE;
> > > +      }
> > > +    }
> > > +  }
> > > +
> > > +  if (FoundOut == FALSE) {
> > > +    Status = EFI_UNSUPPORTED;
> > > +    DEBUG ((DEBUG_ERROR, "No endpoints found.  Num endpoints searched = %d.\n", EndpointNumber));
> > > +    goto ErrorExit4;
> > > +  }
> > > +
> > > +  Status = DlReadEdid (UsbDisplayLinkDev);
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "Failed to read monitor EDID from DisplayLink device (code %r)\n", Status));
> > > +    goto ErrorExit7;
> > > +  }
> > > +
> > > +  Status = InitializeUsbDisplayLinkDevice (UsbDisplayLinkDev);
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "Failed to initialise DisplayLink device (code %r)\n", Status));
> > > +    goto ErrorExit7;
> > > +  }
> > > +
> > > +  Status = gBS->InstallMultipleProtocolInterfaces (
> > > +      &Controller,
> > > +      &gEfiGraphicsOutputProtocolGuid,
> > > +      &UsbDisplayLinkDev->GraphicsOutputProtocol,
> > > +      &gEfiEdidDiscoveredProtocolGuid,
> > > +      &UsbDisplayLinkDev->EdidDiscovered,
> > > +      &gEfiEdidActiveProtocolGuid,
> > > +      &UsbDisplayLinkDev->EdidActive,
> > > +      NULL);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "Failed to install Graphics Output and EDID protocol interfaces - driver not installed correctly -
> >  %r\n", Status));
> > > +    goto ErrorExit8;
> > > +  }
> > > +
> > > +  UsbDisplayLinkDev->ControllerNameTable = (EFI_UNICODE_STRING_TABLE*)NULL;
> > > +
> > > +  AddUnicodeString2 (
> > > +    "eng",
> > > +    mUsbDisplayLinkComponentName.SupportedLanguages,
> > > +    &UsbDisplayLinkDev->ControllerNameTable,
> > > +    (CONST CHAR16*)L"Generic Usb DisplayLink",
> > > +    TRUE);
> > > +
> > > +  AddUnicodeString2 (
> > > +    "en",
> > > +    mUsbDisplayLinkComponentName2.SupportedLanguages,
> > > +    &UsbDisplayLinkDev->ControllerNameTable,
> > > +    (CONST CHAR16*)L"Generic Usb DisplayLink",
> > > +    FALSE);
> > > +
> > > +  //
> > > +  // Setup a periodic timer
> > > +  //
> > > +  Status = gBS->CreateEvent (
> > > +                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
> > > +                  TPL_CALLBACK,
> > > +                  DisplayLinkPeriodicTimer,
> > > +                  UsbDisplayLinkDev,
> > > +                  &UsbDisplayLinkDev->TimerEvent);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    Status = EFI_OUT_OF_RESOURCES;
> > > +    DEBUG ((DEBUG_ERROR, "Failed to create screeen update polling event.\n"));
> > > +    goto ErrorExit8;
> > > +  }
> > > +
> > > +  // Start one-shot timer. The rendering operations can take quite a long time, so we
> > > +  // don't want another timer event to happen until we have finished; so we'll restart
> > > +  // the timer from DisplayLinkPeriodicTimer, the event handler function.
> > > +  Status = gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelative, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD);
> > > +  if (EFI_ERROR (Status)) {
> > > +    Status = EFI_OUT_OF_RESOURCES;
> > > +    DEBUG ((DEBUG_ERROR, "Failed to create screen update polling timer.\n"));
> > > +    goto ErrorExit8;
> > > +  }
> > > +
> > > +  Status = gBS->CreateEventEx (
> > > +                  EVT_NOTIFY_SIGNAL,
> > > +                  TPL_NOTIFY,
> > > +                  DisplayLinkDriverExitBootServices,
> > > +                  UsbDisplayLinkDev,
> > > +                  &gEfiEventExitBootServicesGuid,
> > > +                  &UsbDisplayLinkDev->DriverExitBootServicesEvent);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    Status = EFI_OUT_OF_RESOURCES;
> > > +    DEBUG ((DEBUG_ERROR, "Failed to create event for bootexit.\n"));
> > > +    goto ErrorExit8;
> > > +  }
> > > +
> > > +  gBS->RestoreTPL (OriginalTPL);
> > > +
> > > +  DEBUG ((DEBUG_INFO, "DisplayLink GOP driver successfully bound to device.\n"));
> > > +
> > > +  return EFI_SUCCESS;
> > > +
> > > +  //
> > > +  // Error handler
> > > +  //
> > > + ErrorExit8:
> > > + ErrorExit7:
> > > + ErrorExit4:
> > > +  gBS->CloseProtocol (
> > > +   Controller,
> > > +   &gEfiUsbIoProtocolGuid,
> > > +   This->DriverBindingHandle,
> > > +   Controller);
> > > +
> > > + ErrorExit2:
> > > +  if (UsbDisplayLinkDev != NULL) {
> > > +    FreePool (UsbDisplayLinkDev);
> > > +    UsbDisplayLinkDev = (USB_DISPLAYLINK_DEV*)NULL;
> > > +  }
> > > +
> > > +  DEBUG ((DEBUG_ERROR, "Exiting - Failed to initialise driver.\n"));
> > > +
> > > +  gBS->RestoreTPL (OriginalTPL);
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > +Entrypoint of USB DisplayLink Driver.
> > > +
> > > +This function is the entrypoint of a combined USB DisplayLink GOP Driver. It installs Driver Binding
> > > +Protocols together with Component Name Protocols.
> > > +
> > > +@param  ImageHandle       The firmware allocated handle for the EFI image.
> > > +@param  SystemTable       A pointer to the EFI System Table.
> > > +@param  DriverBindingHandle  The Driver binding handle
> > > +
> > > +@retval EFI_SUCCESS       The entry point is executed successfully.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverCombinedGopBindingEntryPoint (
> > > +  IN EFI_HANDLE           ImageHandle,
> > > +  IN EFI_SYSTEM_TABLE     *SystemTable,
> > > +  IN EFI_HANDLE           DriverBindingHandle
> > > +)
> > > +{
> > > +  EFI_STATUS Status;
> > > +
> > > +  Status = EfiLibInstallDriverBindingComponentName2 (
> > > +    ImageHandle,
> > > +    SystemTable,
> > > +    &gUsbDisplayLinkDriverBinding,
> > > +    DriverBindingHandle,
> > > +    &mUsbDisplayLinkComponentName,
> > > +    &mUsbDisplayLinkComponentName2);
> > > +
> > > +  ASSERT_EFI_ERROR (Status);
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > +
> > > +
> > > +/**
> > > +Entrypoint of USB DisplayLink Driver.
> > > +
> > > +This function is the entrypoint of USB DisplayLink Driver. It installs Driver Binding
> > > +Protocols together with Component Name Protocols.
> > > +
> > > +@param  ImageHandle       The firmware allocated handle for the EFI image.
> > > +@param  SystemTable       A pointer to the EFI System Table.
> > > +
> > > +@retval EFI_SUCCESS       The entry point is executed successfully.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverBindingEntryPoint (
> > > +  IN EFI_HANDLE           ImageHandle,
> > > +  IN EFI_SYSTEM_TABLE     *SystemTable
> > > +)
> > > +{
> > > +  return UsbDisplayLinkDriverCombinedGopBindingEntryPoint (ImageHandle, SystemTable, ImageHandle);
> > > +}
> > > +
> > > +
> > > +/**
> > > +Unloads an image.
> > > +@param  ImageHandle           Handle that identifies the image to be unloaded.
> > > +@retval EFI_SUCCESS           The image has been unloaded.
> > > +@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverCombinedGopUnload (
> > > +  IN EFI_HANDLE  ImageHandle
> > > +)
> > > +{
> > > +  EFI_STATUS  Status = EFI_SUCCESS;
> > > +  EFI_STATUS  handleDisconnectStatus;
> > > +  EFI_HANDLE  *HandleBuffer;
> > > +  UINTN       HandleCount;
> > > +  UINTN       Index;
> > > +
> > > +  //
> > > +  // Retrieve array of all handles in the handle database
> > > +  //
> > > +  handleDisconnectStatus = gBS->LocateHandleBuffer (
> > > +    AllHandles,
> > > +    NULL,
> > > +    NULL,
> > > +    &HandleCount,
> > > +    &HandleBuffer
> > > +  );
> > > +  if (! EFI_ERROR (handleDisconnectStatus)) {
> > > +    //
> > > +    // Disconnect the current driver from handles in the handle database
> > > +    //
> > > +    for (Index = 0; Index < HandleCount; Index++) {
> > > +      Status = gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
> > > +    }
> > > +    //
> > > +    // Free the array of handles
> > > +    //
> > > +    if (HandleBuffer != NULL)
> > > +    {
> > > +      FreePool (HandleBuffer);
> > > +    }
> > > +  }
> > > +
> > > +  // Even if we didn't manage to disconnect the handles, try to uninstall the protocols
> > > +  //
> > > +  // Uninstall protocols installed in the driver entry point
> > > +  //
> > > +  Status = gBS->UninstallMultipleProtocolInterfaces (
> > > +    ImageHandle,
> > > +    &gEfiDriverBindingProtocolGuid,
> > > +    &gUsbDisplayLinkDriverBinding,
> > > +    &gEfiComponentNameProtocolGuid,
> > > +    &mUsbDisplayLinkComponentName,
> > > +    &gEfiComponentName2ProtocolGuid,
> > > +    &mUsbDisplayLinkComponentName2,
> > > +    NULL
> > > +  );
> > > +
> > > +  if (EFI_ERROR (handleDisconnectStatus))
> > > +  {
> > > +    return handleDisconnectStatus;
> > > +  }
> > > +  return Status;
> > > +}
> > > +
> > > +
> > > +/**
> > > +  Stop the USB DisplayLink device handled by this driver.
> > > +
> > > +  @param  This                   The USB DisplayLink 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_UNSUPPORTED        Simple Pointer Protocol is not installed on Controller.
> > > +  @retval Others                 Fail to uninstall protocols attached on the device.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +EFIAPI
> > > +UsbDisplayLinkDriverBindingStop (
> > > +  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
> > > +  IN  EFI_HANDLE                    Controller,
> > > +  IN  UINTN                         NumberOfChildren,
> > > +  IN  EFI_HANDLE                    *ChildHandleBuffer
> > > +  )
> > > +{
> > > +  EFI_STATUS                        Status;
> > > +  USB_DISPLAYLINK_DEV               *UsbDisplayLinkDev;
> > > +  EFI_GRAPHICS_OUTPUT_PROTOCOL      *GraphicsOutputProtocol;
> > > +
> > > +  Status = gBS->OpenProtocol (
> > > +                  Controller,
> > > +                  &gEfiGraphicsOutputProtocolGuid,
> > > +                  (VOID **) &GraphicsOutputProtocol,
> > > +                  This->DriverBindingHandle,
> > > +                  Controller,
> > > +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    return EFI_UNSUPPORTED;
> > > +  }
> > > +
> > > +  UsbDisplayLinkDev = USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(GraphicsOutputProtocol);
> > > +
> > > +  // Reset the video mode to clear the display. Don't drop out if there is a problem, just press on.
> > > +  // Note that this will also clear the frame buffer, as the screen buffer will be re-allocated with AllocateZeroPool.
> > > +  if ((GraphicsOutputProtocol->Mode != NULL) &&
> > > +      (GraphicsOutputProtocol->Mode->Mode != GRAPHICS_OUTPUT_INVALID_MODE_NUMBER)) {
> > > +    Status = DisplayLinkSetMode (GraphicsOutputProtocol, GraphicsOutputProtocol->Mode->Mode);
> > > +    if (EFI_ERROR (Status)) {
> > > +      DEBUG ((DEBUG_WARN, "Driver stop - Problem resetting video mode - %r.\n", Status));
> > > +    }
> > > +  }
> > > +
> > > +  // Reset the alt setting on the interface (to the DL3 alt setting)
> > > +  Status = SelectAltSetting (UsbDisplayLinkDev->UsbIo, 0);
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_WARN, "Error resetting USB interface alternate setting - %r.\n", Status));
> > > +  }
> > > +
> > > +  Status = gBS->UninstallMultipleProtocolInterfaces (
> > > +                  Controller,
> > > +                  &gEfiGraphicsOutputProtocolGuid,
> > > +                  &UsbDisplayLinkDev->GraphicsOutputProtocol,
> > > +                  &gEfiEdidDiscoveredProtocolGuid,
> > > +                  &UsbDisplayLinkDev->EdidDiscovered,
> > > +                  &gEfiEdidActiveProtocolGuid,
> > > +                  &UsbDisplayLinkDev->EdidActive,
> > > +                  NULL);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_WARN, "Error uninstalling Graphics Output and EDID protocol interfaces - %r.\n", Status));
> > > +    return Status;
> > > +  }
> > > +
> > > +  gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent);
> > > +
> > > +  gBS->CloseProtocol (
> > > +         Controller,
> > > +         &gEfiUsbIoProtocolGuid,
> > > +         This->DriverBindingHandle,
> > > +         Controller);
> > > +
> > > +  //
> > > +  // Free all resources.
> > > +  //
> > > +  if (UsbDisplayLinkDev->ControllerNameTable != NULL) {
> > > +    FreeUnicodeStringTable (UsbDisplayLinkDev->ControllerNameTable);
> > > +  }
> > > +
> > > +  if (UsbDisplayLinkDev->Screen != NULL) {
> > > +    FreePool (UsbDisplayLinkDev->Screen);
> > > +    UsbDisplayLinkDev->Screen = NULL;
> > > +  }
> > > +
> > > +  if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode) {
> > > +    if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info) {
> > > +      FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info);
> > > +      UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info = NULL;
> > > +    }
> > > +    FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode);
> > > +    UsbDisplayLinkDev->GraphicsOutputProtocol.Mode = NULL;
> > > +  }
> > > +
> > > +  FreePool (UsbDisplayLinkDev);
> > > +
> > > +  return EFI_SUCCESS;
> > > +
> > > +}
> > > +
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> > > new file mode 100644
> > > index 000000000000..497a2621bc2c
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h
> > > @@ -0,0 +1,278 @@
> > > +/**
> > > + * @file UsbDisplayLink.h
> > > + * @brief Helper routine and corresponding data struct used by USB DisplayLink Driver.
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#ifndef _EFI_USB_DISPLAYLINK_H_
> > > +#define _EFI_USB_DISPLAYLINK_H_
> > > +
> > > +#include <Uefi/UefiBaseType.h>
> > > +#include <Uefi/UefiSpec.h>
> > > +
> > > +#include <Protocol/EdidActive.h>
> > > +#include <Protocol/EdidDiscovered.h>
> > > +#include <Protocol/EdidOverride.h>
> > > +#include <Protocol/GraphicsOutput.h>
> > > +#include <Protocol/UsbIo.h>
> > > +
> > > +#include <Library/BaseMemoryLib.h>
> > > +#include <Library/DebugLib.h>
> > > +#include <Library/MemoryAllocationLib.h>
> > > +#include <Library/ReportStatusCodeLib.h>
> > > +#include <Library/UefiBootServicesTableLib.h>
> > > +#include <Library/UefiLib.h>
> > > +
> > > +#define VENDOR_DISPLAYLINK      0x17e9
> > > +#define CLASS_VENDOR            0xFF
> > > +
> > > +#define DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO ((UINTN)0)
> > > +
> > > +#define INTERFACE_PROTOCOL_DIRECT_FB    4
> > > +
> > > +#define USB_TRANSFER_LENGTH           (64 * 1024)
> > > +#define DISPLAYLINK_MODE_DATA_LENGTH  (146)
> > > +#define DISPLAYLINK_USB_CTRL_TIMEOUT  (1000)
> > > +#define DISPLAYLINK_USB_BULK_TIMEOUT  (1)
> > > +
> > > +#define DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD  ((UINTN)1000000) // 0.1s in us
> > > +#define DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD   ((UINTN)30000) // 3s in ticks
> > > +
> > > +#define DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE ((UINT16)60)
> > > +
> > > +// Requests to read values from the firmware
> > > +#define EDID_BLOCK_SIZE 128
> > > +#define EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK ((UINT16)(0x64))
> > > +
> > > +/** Structures ported from firmware - protocol.h */
> > > +enum ID {
> > > +  // VideoCommands
> > > +  GET_OUTPUT_EDID = 0,
> > > +  SET_VIDEO_MODE = 1
> > > +};
> > > +
> > > +typedef struct {
> > > +  UINT32                     HorizontalResolution;
> > > +  UINT32                     VerticalResolution;
> > > +  UINT32                     ColorDepth;
> > > +  UINT32                     RefreshRate;
> > > +  UINT8                      Commands[DISPLAYLINK_MODE_DATA_LENGTH];
> > > +} DISPLAYLINK_MODE_DATA;
> > > +
> > > +#define GRAPHICS_OUTPUT_INVALID_MODE_NUMBER 0xffff
> > > +
> > > +/**
> > > + *  Device instance of USB display.
> > > + */
> > > +typedef struct {
> > > +  UINT64                        Signature;
> > > +  EFI_HANDLE                    Handle;
> > > +  EFI_USB_IO_PROTOCOL           *UsbIo;
> > > +  EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
> > > +  EFI_USB_ENDPOINT_DESCRIPTOR   BulkOutEndpointDescriptor;
> > > +  EFI_USB_ENDPOINT_DESCRIPTOR   BulkInEndpointDescriptor;
> > > +  EFI_GRAPHICS_OUTPUT_PROTOCOL  GraphicsOutputProtocol;
> > > +  EFI_EDID_DISCOVERED_PROTOCOL  EdidDiscovered;
> > > +  EFI_EDID_ACTIVE_PROTOCOL      EdidActive;
> > > +  EFI_UNICODE_STRING_TABLE      *ControllerNameTable;
> > > +  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Screen;
> > > +  UINTN                         DataSent;                       /** Debug - used to track the bandwidth */
> > > +  EFI_EVENT                     TimerEvent;
> > > +  EFI_EVENT                     DriverExitBootServicesEvent;
> > > +  BOOLEAN                       ShowBandwidth;                 /** Debugging - show the bandwidth on the screen */
> > > +  BOOLEAN                       ShowTestPattern;               /** Show a colourbar pattern instead of the BLTd contents of the
> > framebuffer */
> > > +  UINTN                         LastY1;                        /** Used to track if we can do a partial screen update */
> > > +  UINTN                         LastY2;
> > > +  UINTN                         LastWidth;
> > > +  UINTN                         TimeSinceLastScreenUpdate;     /** Do a full screen update every (x) seconds */
> > > +} USB_DISPLAYLINK_DEV;
> > > +
> > > +#define USB_DISPLAYLINK_DEV_SIGNATURE SIGNATURE_32 ('d', 'l', 'i', 'n')
> > > +
> > > +struct VideoMode {
> > > +  UINT8  Reserved1;          /* Reserved - must be 0. */
> > > +  UINT8  Reserved2;          /* Reserved - must be 2. */
> > > +
> > > +  // Values matching the EDID Detailed Timing Descriptor spec
> > > +  UINT16 PixelClock;
> > > +  UINT16 HActive;
> > > +  UINT16 HBlanking;
> > > +  UINT16 HSyncOffset;  // Horizontal Front Porch
> > > +  UINT16 HSyncWidth;
> > > +  UINT16 VActive;
> > > +  UINT16 VBlanking;
> > > +  UINT16 VSyncOffset;  // Vertical Front Porch
> > > +  UINT16 VSyncWidth;
> > > +  // End of Edid Detailed Timing Descriptor
> > > +
> > > +  UINT16 Flags               /*ModeFlags*/;
> > > +  UINT16 Accumulate;
> > > +  UINT16 Reserved3;         /* Reserved - must be 0. */
> > > +  UINT16 Reserved4;         /* Reserved - must be 0. */
> > > +  UINT16 InsetLeft;
> > > +  UINT16 InsetTop;
> > > +  UINT16 InsetRight;
> > > +  UINT16 InsetBottom;
> > > +  UINT32 FillValue;
> > > +  UINT32 Reserved5;        /* Reserved - must be 0. */
> > > +  UINT8  Vic;
> > > +  UINT8  ActiveFormat;
> > > +  UINT16 Reserved6;
> > > +};
> > > +
> > > +#define USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(a) \
> > > +  CR(a, USB_DISPLAYLINK_DEV, GraphicsOutputProtocol, USB_DISPLAYLINK_DEV_SIGNATURE)
> > > +
> > > +//
> > > +// Global Variables
> > > +//
> > > +extern EFI_DRIVER_BINDING_PROTOCOL   gUsbDisplayLinkDriverBinding;
> > > +extern EFI_COMPONENT_NAME_PROTOCOL   mUsbDisplayLinkComponentName;
> > > +extern EFI_COMPONENT_NAME2_PROTOCOL  mUsbDisplayLinkComponentName2;
> > > +
> > > +
> > > +/* ******************************************* */
> > > +/* ********  GOP interface functions  ******** */
> > > +/* ******************************************* */
> > > +
> > > +/**
> > > + * Implementation of the GOP protocol QueryMode API function
> > > + * @param This         Instance of the GOP protocol
> > > + * @param ModeNumber
> > > + * @param SizeOfInfo
> > > + * @param Info
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +  EFIAPI
> > > +  DisplayLinkQueryMode (
> > > +    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
> > > +    IN  UINT32                                ModeNumber,
> > > +    OUT UINTN                                 *SizeOfInfo,
> > > +    OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
> > > +  );
> > > +
> > > +
> > > +/**
> > > + * Implementation of the GOP protocol SetMode API function
> > > + * @param This
> > > + * @param ModeNumber
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +  EFIAPI
> > > +  DisplayLinkSetMode (
> > > +    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL  *This,
> > > +    IN  UINT32                        ModeNumber
> > > +  );
> > > +
> > > +/**
> > > + * Implementation of the GOP protocol Blt API function
> > > + * @param This
> > > + * @param BltBuffer
> > > + * @param BltOperation
> > > + * @param SourceX
> > > + * @param SourceY
> > > + * @param DestinationX
> > > + * @param DestinationY
> > > + * @param Width
> > > + * @param Height
> > > + * @param Delta
> > > + * @return
> > > + */
> > > +EFI_STATUS
> > > +  EFIAPI
> > > +  DisplayLinkBlt (
> > > +    IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
> > > +    IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer, OPTIONAL
> > > +    IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
> > > +    IN  UINTN                                   SourceX,
> > > +    IN  UINTN                                   SourceY,
> > > +    IN  UINTN                                   DestinationX,
> > > +    IN  UINTN                                   DestinationY,
> > > +    IN  UINTN                                   Width,
> > > +    IN  UINTN                                   Height,
> > > +    IN  UINTN                                   Delta         OPTIONAL
> > > +  );
> > > +
> > > +/* *************************** */
> > > +/* **  GOP helper functions ** */
> > > +/* *************************** */
> > > +
> > > +VOID
> > > +EFIAPI
> > > +DlGopPrintTextToScreen (
> > > +  EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput,
> > > +  UINTN X,
> > > +  UINTN Y,
> > > +  IN CONST CHAR16 *Format,
> > > +  ...
> > > +);
> > > +
> > > +EFI_STATUS
> > > +DlGopSendTestPattern (
> > > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > > +  UINTN PatternNumber
> > > +);
> > > +
> > > +EFI_STATUS
> > > +DlGopSendScreenUpdate (
> > > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
> > > +);
> > > +
> > > +
> > > +/* ******************************************* */
> > > +/* ********  USB interface functions  ******** */
> > > +/* ******************************************* */
> > > +
> > > +EFI_STATUS
> > > +DlUsbSendControlWriteMessage (
> > > +  IN USB_DISPLAYLINK_DEV *Device,
> > > +  IN UINT8 Request,
> > > +  IN UINT16 Value,
> > > +  IN CONST VOID *ControlMsg,
> > > +  IN UINT16 ControlMsgLen
> > > +);
> > > +
> > > +EFI_STATUS
> > > +DlUsbSendControlReadMessage (
> > > +  IN USB_DISPLAYLINK_DEV *Device,
> > > +  IN UINT8 Request,
> > > +  IN UINT16 Value,
> > > +  OUT VOID *ControlMsg,
> > > +  IN UINT16 ControlMsgLen
> > > +);
> > > +
> > > +EFI_STATUS
> > > +DlUsbBulkWrite (
> > > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > > +  CONST UINT8* Buffer,
> > > +  UINTN DataLen,
> > > +  UINT32 *USBStatus
> > > +);
> > > +
> > > +UINTN
> > > +DlUsbBulkRead (
> > > +  USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > > +  UINT8* Buffer,
> > > +  UINTN BufferLen
> > > +);
> > > +
> > > +/* ******************************************* */
> > > +/* ********   Video Mode functions    ******** */
> > > +/* ******************************************* */
> > > +
> > > +// Pre-calculated video modes
> > > +UINT32
> > > +DlVideoModeGetNumSupportedVideoModes ();
> > > +
> > > +CONST struct VideoMode *
> > > +DlVideoModeGetSupportedVideoMode (
> > > +  UINT32 index
> > > +);
> > > +
> > > +#endif
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> > > new file mode 100644
> > > index 000000000000..252293da39d4
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c
> > > @@ -0,0 +1,180 @@
> > > +/**
> > > + * @file UsbTransfer.c
> > > + * @brief Wrapper of UEFI USB bulk and control transfer interface for USB DisplayLink driver.
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#include "UsbDisplayLink.h"
> > > +
> > > +/**
> > > + * Write the data to the DisplayLink device using the USBIO protocol.
> > > + * @param UsbDisplayLinkDev
> > > + * @param Buffer
> > > + * @param DataLen
> > > + * @param USBStatus
> > > + * @return
> > > +  * EFI_SUCCESS   The bulk transfer has been successfully executed.
> > > +  * EFI_INVALID_PARAMETER   If DeviceEndpoint is not valid.
> > > +  * EFI_INVALID_PARAMETER   Data is NULL.
> > > +  * EFI_INVALID_PARAMETER   DataLength is NULL.
> > > +  * EFI_INVALID_PARAMETER   Status is NULL.
> > > +  * EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
> > > +  * EFI_TIMEOUT   The bulk transfer cannot be completed within Timeout timeframe.
> > > +  * EFI_DEVICE_ERROR  The transfer failed other than timeout, and the transfer status is returned in Status.
> > > + */
> > > +EFI_STATUS
> > > +DlUsbBulkWrite (
> > > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > > +    IN CONST UINT8* Buffer,
> > > +    IN UINTN DataLen,
> > > +    OUT UINT32 *USBStatus
> > > +    )
> > > +{
> > > +  EFI_STATUS Status;
> > > +  Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> > > +    UsbDisplayLinkDev->UsbIo,
> > > +    UsbDisplayLinkDev->BulkOutEndpointDescriptor.EndpointAddress,
> > > +    (VOID*)Buffer,
> > > +    &DataLen,
> > > +    DISPLAYLINK_USB_BULK_TIMEOUT,
> > > +    USBStatus);
> > > +
> > > +  return Status;
> > > +}
> > > +
> > > +/**
> > > +* Read data from the DisplayLink device using the USBIO protocol.
> > > +* @param UsbDisplayLinkDev
> > > +* @param Buffer
> > > +* @param BufferLen
> > > +* @return 0 if an error occurred or 0 bytes were read, otherwise the number of bytes read
> > > + */
> > > +UINTN
> > > +DlUsbBulkRead (
> > > +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev,
> > > +    IN UINT8* Buffer,
> > > +    IN UINTN BufferLen
> > > +    )
> > > +{
> > > +  UINT32 Result;
> > > +  UINTN ReadLen;
> > > +  EFI_STATUS Status;
> > > +
> > > +  ReadLen = BufferLen;
> > > +
> > > +  Status = UsbDisplayLinkDev->UsbIo->UsbBulkTransfer (
> > > +    UsbDisplayLinkDev->UsbIo,
> > > +    UsbDisplayLinkDev->BulkInEndpointDescriptor.EndpointAddress,
> > > +    Buffer,
> > > +    &ReadLen,
> > > +    DISPLAYLINK_USB_BULK_TIMEOUT,
> > > +    &Result);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    return 0;
> > > +  }
> > > +
> > > +  return ReadLen;
> > > +}
> > > +
> > > +
> > > +/**
> > > +Send a control message (e.g set video mode) message to the DisplayLink device.
> > > +
> > > +@param  Device                   USB device handle.
> > > +@param  request                  Request type, e.g. SET_VIDEO_MODE
> > > +@param  value
> > > +@param  controlMsg               Pointer to the message to send.
> > > +@param  controlMsgLen            Length of the message.
> > > +
> > > +@retval EFI_SUCCESS            Successfully sent message.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +DlUsbSendControlWriteMessage (
> > > +  IN USB_DISPLAYLINK_DEV *Device,
> > > +  IN UINT8 Request,
> > > +  IN UINT16 Value,
> > > +  IN CONST VOID *ControlMsg,
> > > +  IN UINT16 ControlMsgLen
> > > +  )
> > > +{
> > > +  EFI_STATUS             Status;
> > > +  UINT32                 UsbStatus;
> > > +  EFI_USB_DEVICE_REQUEST UsbRequest;
> > > +
> > > +  ZeroMem (&Request, sizeof (Request));
> > > +  UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE;
> > > +  UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> > > +  UsbRequest.Request = Request;
> > > +  UsbRequest.Value = Value;
> > > +  UsbRequest.Length = ControlMsgLen;
> > > +
> > > +  Status = Device->UsbIo->UsbControlTransfer (
> > > +    Device->UsbIo,
> > > +    &UsbRequest,
> > > +    EfiUsbDataOut,
> > > +    DISPLAYLINK_USB_CTRL_TIMEOUT,
> > > +    (VOID *)ControlMsg,
> > > +    ControlMsgLen,
> > > +    &UsbStatus);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "USB write control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> > > +    Status = EFI_DEVICE_ERROR;
> > > +  }
> > > +  return Status;
> > > +}
> > > +
> > > +
> > > +/**
> > > +Request data from the DisplayLink device (e.g. the monitor EDID)
> > > +
> > > +@param  Device                   USB device handle.
> > > +@param  request                  Request type, e.g. GET_OUTPUT_EDID
> > > +@param  value
> > > +@param  controlMsg               Pointer to the message to send.
> > > +@param  controlMsgLen            Length of the message.
> > > +
> > > +@retval EFI_SUCCESS            Successfully sent message.
> > > +
> > > +**/
> > > +EFI_STATUS
> > > +DlUsbSendControlReadMessage (
> > > +  IN USB_DISPLAYLINK_DEV *Device,
> > > +  IN UINT8 Request,
> > > +  IN UINT16 Value,
> > > +  OUT VOID *ControlMsg,
> > > +  IN UINT16 ControlMsgLen
> > > +  )
> > > +{
> > > +  EFI_STATUS             Status;
> > > +  UINT32                 UsbStatus;
> > > +  EFI_USB_DEVICE_REQUEST UsbRequest;
> > > +
> > > +  ZeroMem (&UsbRequest, sizeof (UsbRequest));
> > > +  UsbRequest.RequestType = USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFACE | USB_ENDPOINT_DIR_IN;
> > > +  UsbRequest.Request = Request;
> > > +  UsbRequest.Value = Value;
> > > +  UsbRequest.Index = Device->InterfaceDescriptor.InterfaceNumber;
> > > +  UsbRequest.Length = ControlMsgLen;
> > > +
> > > +  Status = Device->UsbIo->UsbControlTransfer (
> > > +    Device->UsbIo,
> > > +    &UsbRequest,
> > > +    EfiUsbDataIn,
> > > +    DISPLAYLINK_USB_CTRL_TIMEOUT,
> > > +    (VOID *)ControlMsg,
> > > +    ControlMsgLen,
> > > +    &UsbStatus);
> > > +
> > > +  if (EFI_ERROR (Status)) {
> > > +    DEBUG ((DEBUG_ERROR, "USB read control transfer failed - %r (USB status x%x).\n", Status, UsbStatus));
> > > +    Status = EFI_DEVICE_ERROR;
> > > +  }
> > > +  return Status;
> > > +}
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> > > new file mode 100644
> > > index 000000000000..6218c093147c
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c
> > > @@ -0,0 +1,254 @@
> > > +/**
> > > + * @file VideoModes.c
> > > + * @brief Pre-calculated video timings sent to the DisplayLink device when a video mode is selected
> > > + *
> > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > + *
> > > + * SPDX-License-Identifier: BSD-2-Clause-Patent
> > > + *
> > > +**/
> > > +
> > > +#include "UsbDisplayLink.h"
> > > +
> > > +
> > > +// Supported video modes - must be in order of pixel count (i.e. hres x vres)
> > > +
> > > +STATIC CONST struct VideoMode ModeData[] = {
> > > +  {
> > > +     // 640 x 480 @ 60Hz
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 2517,
> > > +    .HActive = 640,
> > > +    .HBlanking = 160,
> > > +    .HSyncOffset = 16,
> > > +    .HSyncWidth = 96,
> > > +    .VActive = 480,
> > > +    .VBlanking = 45,
> > > +    .VSyncOffset = 10,
> > > +    .VSyncWidth = 2,
> > > +    .Flags = 0x00000300,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  },
> > > +  {
> > > +    // 800 x 600 @ 60Hz
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 4000,
> > > +    .HActive = 800,
> > > +    .HBlanking = 256,
> > > +    .HSyncOffset = 40,
> > > +    .HSyncWidth = 128,
> > > +    .VActive = 600,
> > > +    .VBlanking = 28,
> > > +    .VSyncOffset = 1,
> > > +    .VSyncWidth = 3,
> > > +    .Flags = 0x00000000,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  },
> > > +  {
> > > +    // 1024x768 @ 60Hz
> > > +    .Reserved1 = 0,
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 6500,
> > > +    .HActive = 1024,
> > > +    .HBlanking = 320,
> > > +    .HSyncOffset = 24,
> > > +    .HSyncWidth = 136,
> > > +    .VActive = 768,
> > > +    .VBlanking = 38,
> > > +    .VSyncOffset = 3,
> > > +    .VSyncWidth = 6,
> > > +    .Flags = 0x00000300,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  },
> > > +  {
> > > +    // 1360x768 @ 60Hz
> > > +    .Reserved1 = 0,
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 8550,
> > > +    .HActive = 1360,
> > > +    .HBlanking = 432,
> > > +    .HSyncOffset = 64,
> > > +    .HSyncWidth = 112,
> > > +    .VActive = 768,
> > > +    .VBlanking = 27,
> > > +    .VSyncOffset = 3,
> > > +    .VSyncWidth = 6,
> > > +    .Flags = 0x00000000,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  },
> > > +  {
> > > +    // 1280x960 @ 60Hz
> > > +    .Reserved1 = 0,
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 10800,
> > > +    .HActive = 1280,
> > > +    .HBlanking = 520,
> > > +    .HSyncOffset = 96,
> > > +    .HSyncWidth = 112,
> > > +    .VActive = 960,
> > > +    .VBlanking = 40,
> > > +    .VSyncOffset = 1,
> > > +    .VSyncWidth = 3,
> > > +    .Flags = 0x00000000,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  },
> > > +  {
> > > +    // 1280x1024 @ 60Hz
> > > +    .Reserved1 = 0,
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 10800,
> > > +    .HActive = 1280,
> > > +    .HBlanking = 408,
> > > +    .HSyncOffset = 48,
> > > +    .HSyncWidth = 112,
> > > +    .VActive = 1024,
> > > +    .VBlanking = 42,
> > > +    .VSyncOffset = 1,
> > > +    .VSyncWidth = 3,
> > > +    .Flags = 0x00000000,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  },
> > > +  {
> > > +    // 1600x900 @ 60Hz
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 11825,
> > > +    .HActive = 1600,
> > > +    .HBlanking = 512,
> > > +    .HSyncOffset = 88,
> > > +    .HSyncWidth = 168,
> > > +    .VActive = 900,
> > > +    .VBlanking = 34,
> > > +    .VSyncOffset = 3,
> > > +    .VSyncWidth = 5,
> > > +    .Flags = 0x00000500,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  },
> > > +  {
> > > +    // 1400x1050 @ 60Hz
> > > +    .Reserved1 = 0,
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 12175,
> > > +    .HActive = 1400,
> > > +    .HBlanking = 464,
> > > +    .HSyncOffset = 88,
> > > +    .HSyncWidth = 144,
> > > +    .VActive = 1050,
> > > +    .VBlanking = 39,
> > > +    .VSyncOffset = 3,
> > > +    .VSyncWidth = 4,
> > > +    .Flags = 0x00000100,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  },
> > > +  {
> > > +    // 1600x1200 @ 60Hz
> > > +    .Reserved1 = 0,
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 16200,
> > > +    .HActive = 1600,
> > > +    .HBlanking = 560,
> > > +    .HSyncOffset = 64,
> > > +    .HSyncWidth = 192,
> > > +    .VActive = 1200,
> > > +    .VBlanking = 50,
> > > +    .VSyncOffset = 1,
> > > +    .VSyncWidth = 3,
> > > +    .Flags = 0x00000000,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  },
> > > +  {
> > > +    // 1920 x 1080
> > > +    .Reserved2 = 2,
> > > +    .PixelClock = 14850,
> > > +    .HActive = 1920,
> > > +    .HBlanking = 280,
> > > +    .HSyncOffset = 88,
> > > +    .HSyncWidth = 44,
> > > +    .VActive = 1080,
> > > +    .VBlanking = 45,
> > > +    .VSyncOffset = 4,
> > > +    .VSyncWidth = 5,
> > > +    .Flags = 0x00000000,
> > > +    .Accumulate = 1,
> > > +    .Reserved3 = 0,
> > > +    .Reserved4 = 0,
> > > +    .Reserved5 = 0x00000000,
> > > +    .Vic = 0,
> > > +    .ActiveFormat = 0,
> > > +  }
> > > +};
> > > +
> > > +STATIC CONST UINT32 NumSupportedVideoModes = (sizeof (ModeData) / sizeof (struct VideoMode));
> > > +
> > > +/**
> > > +Find the number of pre-calculated video modes that we support.
> > > +
> > > +@retval Number of modes.
> > > +
> > > +**/
> > > +UINT32 DlVideoModeGetNumSupportedVideoModes ()
> > > +{
> > > +  return NumSupportedVideoModes;
> > > +}
> > > +
> > > +/**
> > > +Get one of the pre-calculated video modes
> > > +
> > > +@param  index      The video mode that we want.
> > > +
> > > +@retval NULL       The index was out of range.
> > > +
> > > +**/
> > > +CONST struct VideoMode *DlVideoModeGetSupportedVideoMode (
> > > +    UINT32 Index
> > > +    )
> > > +{
> > > +  if (Index >= NumSupportedVideoModes) {
> > > +    return NULL;
> > > +  }
> > > +  return &ModeData[Index];
> > > +}
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> > > new file mode 100644
> > > index 000000000000..955331ba6076
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc
> > > @@ -0,0 +1,61 @@
> > > +#/** @file
> > > +#
> > > +#  Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
> > > +#
> > > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +#
> > > +#**/
> > > +
> > > +[Defines]
> > > +  PLATFORM_NAME                  = DisplayLinkPkg
> > > +  PLATFORM_GUID                  = ad3b37b0-f798-4f97-9b3f-0c6f43d7c993
> > > +  PLATFORM_VERSION               = 0.1
> > > +  DSC_SPECIFICATION              = 0x0001001C
> > > +  OUTPUT_DIRECTORY               = Build/DisplayLink
> > > +  SUPPORTED_ARCHITECTURES        = X64|IA32|AARCH64|ARM
> > > +  BUILD_TARGETS                  = DEBUG|RELEASE|NOOPT
> > > +  SKUID_IDENTIFIER               = DEFAULT
> > > +
> > > +[LibraryClasses]
> > > +  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
> > > +  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> > > +  DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
> > > +  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
> > > +  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> > > +  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> > > +  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
> > > +  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
> > > +  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
> > > +  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
> > > +  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
> > > +  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
> > > +  UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
> > > +
> > > +[LibraryClasses.common.UEFI_DRIVER]
> > > +  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
> > > +
> > > +[LibraryClasses.AARCH64]
> > > +  NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> > > +  NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> > > +
> > > +[LibraryClasses.ARM]
> > > +  NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
> > > +  NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf
> > > +
> > > +[PcdsFixedAtBuild]
> > > +!ifdef $(DEBUG_ENABLE_OUTPUT)
> > > +  gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x3f
> > > +  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80080043  # Flags to control amount of debug output - see
> > https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging
> > > +  gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x07
> > > +!endif
> > > +
> > > +[Components]
> > > +  Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf
> > > +
> > > +[BuildOptions]
> > > +  *_*_*_CC_FLAGS               = -D DISABLE_NEW_DEPRECATED_INTERFACES -D
> > INF_DRIVER_VERSION=$(INF_DRIVER_VERSION)
> > > +  GCC:RELEASE_*_*_CC_FLAGS     = -DMDEPKG_NDEBUG
> > > +  MSFT:RELEASE_*_*_CC_FLAGS    = /D MDEPKG_NDEBUG
> > > +!ifdef $(COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE)
> > > +  *_*_*_CC_FLAGS = -D COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE
> > > +!endif
> > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> > > new file mode 100644
> > > index 000000000000..40061f1eb46d
> > > --- /dev/null
> > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md
> > > @@ -0,0 +1,77 @@
> > > +# DISPLAYLINK DRIVERS
> > > +This package contains a GOP driver for Universal USB-connected docks containing the
> > > +DisplayLink DL-6xxx chip or newer.
> > > +
> > > +[DisplayLink Website](http://www.displaylink.com)
> > > +
> > > +[Products](https://www.displaylink.com/products/universal-docking-stations)
> > > +
> > > +# INDEX
> > > +
> > > +* [Resolutions Supported](#resolutions-supported)
> > > +* [Frame rates](#frame-rates)
> > > +* [Multiple monitor outputs](#multiple-monitor-outputs)
> > > +* [Multiple DisplayLink devices](#multiple-displaylink-devices)
> > > +* [Behaviour with no monitor connected](#behaviour-with-no-monitor-connected)
> > > +
> > > +# Resolutions supported
> > > +
> > > +The driver supports the following resolutions:
> > > +
> > > +640 x 480 @ 60Hz
> > > +
> > > +800 x 600 @ 60Hz
> > > +
> > > +1024x768 @ 60Hz
> > > +
> > > +1360x768 @ 60Hz
> > > +
> > > +1280x960 @ 60Hz
> > > +
> > > +1280x1024 @ 60Hz
> > > +
> > > +1600x900 @ 60Hz
> > > +
> > > +1400x1050 @ 60Hz
> > > +
> > > +1600x1200 @ 60Hz
> > > +
> > > +1920x1080 @ 60Hz
> > > +
> > > +
> > > +Note that the list of resolutions advertised by the driver may be smaller than
> > > +this if a connected monitor does not support a particular resolution. The driver
> > > +interrogates connected monitors to see which modes can be supported.It is the
> > > +responsibility of the BIOS to select the video mode from this list which most
> > > +closely matches its requirements. In some cases this may lead to the BIOS
> > > +scaling its display.
> > > +
> > > +# Frame rates
> > > +
> > > +The driver is limited to a maximum of ten frames per second. Some slower systems
> > > +at higher screen resolutions may perform at a lower rate than this.
> > > +
> > > +# Multiple monitor outputs
> > > +
> > > +If multiple monitors are connected to the DisplayLinkdevice, the display will be
> > > +duplicated (cloned) across all outputs at the same resolution. The resolution
> > > +used will be limited by the capability of the monitor with the
> > > +lowest specification.
> > > +
> > > +# Multiple DisplayLink devices
> > > +
> > > +The driver will support the connection of multiple DisplayLink devices. The
> > > +exact behaviourof the system with multiple devices connected is defined by the
> > > +rest of the BIOS; usually, the BIOS causes the displays to be duplicated
> > > +(cloned) across all devices. Note that the system performance and frame rate
> > > +will be affected by the number of DisplayLink devices connected.
> > > +
> > > +# Behaviour with no monitor connected
> > > +
> > > +The driver uses the EDID (Extended Display Identification Data) protocol to
> > > +detect the list of resolutions that a monitor will support.In some monitors this
> > > +may take some time, and occasionally no EDID information will be returned at
> > > +all. In this case the driver will not be able to detect that there is a monitor
> > > +connected. To improve the user experience in these cases, the driver will behave
> > > +as if there is a monitor connected, and will fall back to presenting the full
> > > +range of supported resolutions to the BIOS.
> > > diff --git a/Maintainers.txt b/Maintainers.txt
> > > index 876ae5612ad8..47aac133abb1 100644
> > > --- a/Maintainers.txt
> > > +++ b/Maintainers.txt
> > > @@ -47,6 +47,11 @@ Drivers/OptionRomPkg
> > >  W: https://github.com/tianocore/tianocore.github.io/wiki/OptionRomPkg
> > >  M: Ray Ni <ray.ni@intel.com>
> > >
> > > +Drivers/DisplayLink
> > > +M: Leif Lindholm <leif.lindholm@linaro.org>
> > > +M: Ard Bieshuevel <ard.bieshuevel@linaro.org>
> > > +R: Andy Hayes <andy.hayes@displaylink.com>
> > > +
> > >  Platform
> > >  M: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > >  M: Leif Lindholm <leif.lindholm@linaro.org>
> > > --
> > > 2.20.1
> > >

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [edk2-devel] [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips
  2019-08-30 15:27   ` [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips Leif Lindholm
  2019-09-09  8:06     ` [External] " Andy Hayes
  2019-09-13  7:57     ` Ni, Ray
@ 2019-10-04 19:54     ` Laszlo Ersek
  2 siblings, 0 replies; 6+ messages in thread
From: Laszlo Ersek @ 2019-10-04 19:54 UTC (permalink / raw)
  To: Andy Hayes
  Cc: devel, leif.lindholm, Michael D Kinney, Ni, Ray,
	Michael A Rothman

Hello Andy,

I've got a question about your edk2-platforms commit 9df63499ea01 (i.e.,
this patch):

On 08/30/19 17:27, Leif Lindholm wrote:
> On Mon, Aug 19, 2019 at 02:32:00PM +0100, Andy Hayes wrote:

[...]

>> diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c

[...]

>> +EFI_STATUS
>> +DlReadEdid (
>> +    IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev
>> +    )
>> +{

[...]

>> +    Status = EdidOverride->GetEdid (
>> +      EdidOverride,
>> +      &UsbDisplayLinkDev->Handle,
>> +      &EdidAttributes,
>> +      &EdidDataSize,
>> +      &EdidDataBlock);

In UEFI v2.8, EFI_EDID_OVERRIDE_PROTOCOL_GET_EDID's "ChildHandle"
parameter is specified as follows, in *natural language*:

  ChildHandle -- A child handle that represents a possible video output
                 device.

Accordingly, the function *prototype* should specify the parameter as:

  IN EFI_HANDLE ChildHandle

However, the spec in fact mandates:

  IN EFI_HANDLE *ChildHandle

there.

This is most likely a typo in the prototype, and should be fixed (so
that the prototype match the natural language description). I've
reported the following spec ticket about it:

  https://mantis.uefi.org/mantis/view.php?id=2018

Here's the problem.

It looks like most GetEdid() calls in existence conform to the *spirit*
of the spec, and not to the *letter* thereof; in other words, they pass
an EFI_HANDLE for ChildHandle. Furthermore, the
EFI_EDID_OVERRIDE_PROTOCOL implementations underneath also conform to
the spirit, and not the letter of the spec, and they consume ChildHandle
as an EFI_HANDLE. (They do not de-reference ChildHandle for getting the
actual handle.)

In other words, fixing the typo in the spec would simply adopt existing
practice, and no code would have to be changed for spec conformance.

Except... the code quoted above.

The code above conforms to the *letter* of the spec, and passes an
(EFI_HANDLE*), as ChildHandle. If the typo is fixed in the spec, the
call site in DlReadEdid() would have to be modified.

Can you please confirm wheter:

- the EdidOverride->GetEdid() call is reached in practice (= it is not
dead code),

- the underlying EFI_EDID_OVERRIDE_PROTOCOL actually consumes
ChildHandle (for which it first has to de-reference it)?

My hope is that either the above call site is dead code en-bloc, or the
underlying protocol implementation ignores the ChildHandle parameter.
Then we can fix both the spec and the DlReadEdid() function.

Thanks!
Laszlo

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-10-04 19:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20190819133200.14577-1-andy.hayes@displaylink.com>
     [not found] ` <20190819133200.14577-2-andy.hayes@displaylink.com>
2019-08-30 15:27   ` [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips Leif Lindholm
2019-09-09  8:06     ` [External] " Andy Hayes
2019-09-09 11:00       ` Leif Lindholm
2019-09-13  7:57     ` Ni, Ray
2019-09-19 16:42       ` Leif Lindholm
2019-10-04 19:54     ` [edk2-devel] " Laszlo Ersek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox