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

<div width="1" style="color:white;clear:both">_._,_._,_</div>
<hr>
Groups.io Links:<p>

You receive all messages sent to this group.


<p>

<a target="_blank" href="https://edk2.groups.io/g/devel/message/47031">View/Reply Online (#47031)</a> |


  


|


  
    <a target="_blank" href="https://groups.io/mt/34077395/1813853">Mute This Topic</a>
  

| <a href="https://edk2.groups.io/g/devel/post">New Topic</a><br>



<br>

<a href="https://edk2.groups.io/g/devel/editsub/1813853">Your Subscription</a> |
<a href="mailto:devel+owner@edk2.groups.io">Contact Group Owner</a> |

<a href="https://edk2.groups.io/g/devel/unsub">Unsubscribe</a>

 [edk2-devel-archive@redhat.com]<br>
<div width="1" style="color:white;clear:both">_._,_._,_</div>