From: "Ni, Ray" <ray.ni@intel.com>
To: Leif Lindholm <leif.lindholm@linaro.org>,
Andy Hayes <andy.hayes@displaylink.com>,
"Kinney, Michael D" <michael.d.kinney@intel.com>
Cc: "devel@edk2.groups.io" <devel@edk2.groups.io>
Subject: Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips
Date: Fri, 13 Sep 2019 07:57:08 +0000 [thread overview]
Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C2D5107@SHSMSX104.ccr.corp.intel.com> (raw)
In-Reply-To: <20190830152717.GV29255@bivouac.eciton.net>
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
> >
next prev parent reply other threads:[~2019-09-13 7:57 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
[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 [this message]
2019-09-19 16:42 ` Leif Lindholm
2019-10-04 19:54 ` [edk2-devel] " Laszlo Ersek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=734D49CCEBEEF84792F5B80ED585239D5C2D5107@SHSMSX104.ccr.corp.intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox