From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 134.134.136.24, mailfrom: ray.ni@intel.com) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by groups.io with SMTP; Fri, 13 Sep 2019 00:57:33 -0700 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 13 Sep 2019 00:57:32 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.64,492,1559545200"; d="scan'208";a="187752060" Received: from fmsmsx106.amr.corp.intel.com ([10.18.124.204]) by orsmga003.jf.intel.com with ESMTP; 13 Sep 2019 00:57:31 -0700 Received: from fmsmsx609.amr.corp.intel.com (10.18.126.89) by FMSMSX106.amr.corp.intel.com (10.18.124.204) with Microsoft SMTP Server (TLS) id 14.3.439.0; Fri, 13 Sep 2019 00:57:11 -0700 Received: from fmsmsx609.amr.corp.intel.com (10.18.126.89) by fmsmsx609.amr.corp.intel.com (10.18.126.89) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1713.5; Fri, 13 Sep 2019 00:57:10 -0700 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by fmsmsx609.amr.corp.intel.com (10.18.126.89) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.1.1713.5 via Frontend Transport; Fri, 13 Sep 2019 00:57:10 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.32]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.53]) with mapi id 14.03.0439.000; Fri, 13 Sep 2019 15:57:08 +0800 From: "Ni, Ray" To: Leif Lindholm , Andy Hayes , "Kinney, Michael D" CC: "devel@edk2.groups.io" Subject: Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips Thread-Topic: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: Added GOP driver for USB docking stations based on DisplayLink chips Thread-Index: AQHVX0d3SResWXr9S0WOnSoytbWQf6cT98Fg Date: Fri, 13 Sep 2019 07:57:08 +0000 Message-ID: <734D49CCEBEEF84792F5B80ED585239D5C2D5107@SHSMSX104.ccr.corp.intel.com> References: <20190819133200.14577-1-andy.hayes@displaylink.com> <20190819133200.14577-2-andy.hayes@displaylink.com> <20190830152717.GV29255@bivouac.eciton.net> In-Reply-To: <20190830152717.GV29255@bivouac.eciton.net> Accept-Language: en-US, zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiNjE4NTg5NjQtNzk4My00NWI1LWEyZDMtMzYzYWY3NWIyMDkyIiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoiREdGRDJOXC96WWNWYndKUG5XemRNc3l5MnlTYW1qOHZvYUtkaDRHRUhzakFhdUVQbmhaRCtITmY2SGE2N2pIYmkifQ== x-ctpclassification: CTP_NT dlp-product: dlpe-windows dlp-version: 11.2.0.6 dlp-reaction: no-action x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Return-Path: ray.ni@intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Leif, Mike, I have two general comments regarding the edk2-platforms/Drivers directory: 1. should we change it to "Driver" because the other two don't carry a "s"? 2. Where should OptionRomPkg go? "Platform" and "Silicon" both contains ven= dor sub-directories. Now "Driver" contains vendor sub-directory as well. Bu= t OptionRomPkg is in the root of "Driver". Do we need to put it as a future= task to separate the OptionRomPkg according to vendors? or create "Driver/= Intel" and put OptionRomPkg there? (sorry I thought I sent the mail long time ago.) Thanks, Ray > -----Original Message----- > From: Leif Lindholm > Sent: Friday, August 30, 2019 8:27 AM > To: Andy Hayes > Cc: devel@edk2.groups.io; Kinney, Michael D ;= Ni, Ray > Subject: Re: [edk2-platforms: PATCH 1/1] DisplayLinkPkg: DisplayLinkGop: = Added GOP driver for USB docking stations based on > DisplayLink chips >=20 > Hi Andy, >=20 > This looks fine to me - all my feedback has been addressed. > Reviewed-by: Leif Lindholm >=20 > Ray - did you have any comments on this, or can I go ahead and commit? >=20 > Best Regards, >=20 > Leif >=20 > On Mon, Aug 19, 2019 at 02:32:00PM +0100, Andy Hayes wrote: > > Cc: Leif Lindholm > > Cc: Michael D Kinney > > Signed-off-by: Andy Hayes > > --- > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor= .c | 137 +++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c = | 235 +++++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.in= f | 65 ++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c = | 598 +++++++++++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h = | 129 +++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c = | 578 +++++++++++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c = | 145 +++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h = | 109 ++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c = | 1082 ++++++++++++++++++++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h = | 278 +++++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c = | 180 ++++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c = | 254 +++++ > > Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc = | 61 ++ > > Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md = | 77 ++ > > Maintainers.txt = | 5 + > > 15 files changed, 3933 insertions(+) > > > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Capabili= tyDescriptor.c > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescriptor.= c > > new file mode 100644 > > index 000000000000..4bfadd770b81 > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/CapabilityDescr= iptor.c > > @@ -0,0 +1,137 @@ > > +/** @file CapabilityDescriptor.c > > + * @brief Definitions for reading USB capability descriptor DisplayLin= k dock > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#include "UsbDisplayLink.h" > > +#include "UsbDescriptors.h" > > + > > +/** > > + * Check that the Capability Descriptor is valid and hasn't been tampe= red with. > > + * @param Data Binary data of the Capability Descriptor received from = the DisplayLink device > > + * @param Length > > + * @param out > > + * @return > > + */ > > +STATIC EFI_STATUS > > +ValidateHeader ( > > + CONST IN VOID* Data, > > + IN UINTN Length, > > + OUT CONST VendorDescriptorGeneric** Out > > + ) > > +{ > > + if (Length < sizeof (VendorDescriptorGeneric)) { > > + DEBUG ((DEBUG_ERROR, "Data too short (%d bytes) for capability des= criptor header section\n", Length)); > > + return EFI_INVALID_PARAMETER; > > + } > > + CONST VendorDescriptorGeneric* Desc =3D (VendorDescriptorGeneric*)Da= ta; > > + if (Desc->Length > Length) { > > + DEBUG ((DEBUG_ERROR, "Capability descriptor: Descriptor (%d bytes)= exceeds buffer (%d bytes)\n", > > + Length, Desc->Length)); > > + return EFI_BUFFER_TOO_SMALL; > > + } > > + if (Desc->Type !=3D DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY) { > > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid type (0x%08x)= \n", Desc->Type)); > > + return EFI_UNSUPPORTED; > > + } > > + if (Desc->CapabilityVersion !=3D 1) { > > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid version (%d)\= n", Desc->CapabilityVersion)); > > + return EFI_INCOMPATIBLE_VERSION; > > + } > > + // Capability length must fit within remaining space > > + if (Desc->CapabilityLength > (Desc->Length - (sizeof (Desc->Length) = + sizeof (Desc->Type)))) { > > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid CapabilityLen= gth (%d)\n", Desc->CapabilityLength)); > > + return EFI_INVALID_PARAMETER; > > + } > > + *Out =3D Desc; > > + return EFI_SUCCESS; > > +} > > + > > + > > +/** > > + * Check that the connected DisplayLink device supports the functional= ity that this driver requires, e.g. video formats > > + * @param Data Binary data of the Capability Descriptor received from = the DisplayLink device > > + * @param Length > > + * @param Output > > + * @return > > + */ > > +EFI_STATUS > > +UsbDisplayLinkParseCapabilitiesDescriptor ( > > + CONST IN VOID* Data, > > + IN UINTN Length, > > + OUT VendorDescriptor* Output > > + ) > > +{ > > + CONST VendorDescriptorGeneric* Desc; > > + EFI_STATUS Status; > > + > > + Desc =3D NULL; > > + Status =3D ValidateHeader (Data, Length, &Desc); > > + > > + if (EFI_ERROR (Status)) { > > + return Status; > > + } > > + > > + // Default capabilities > > + Output->Capabilities1 =3D 0; > > + > > + CONST UINTN CapsHeaderLength =3D sizeof (Desc->CapabilityVersion) + = sizeof (Desc->CapabilityLength); > > + ASSERT (CapsHeaderLength < MAX_UINT8); > > + > > + UINTN DataRemaining; > > + UINTN Offset; > > + > > + DataRemaining =3D Desc->CapabilityLength - CapsHeaderLength; > > + Offset =3D 0; > > + > > + while (DataRemaining >=3D sizeof (DescriptorKLV)) { > > + CONST DescriptorKLV* KeyHeader =3D (CONST DescriptorKLV*)(Desc->Kl= v + Offset); > > + CONST UINTN KeyValueSize =3D sizeof (DescriptorKLV) + KeyHeader->L= ength; > > + if (KeyValueSize > DataRemaining) { > > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid value Lengt= h (%d)\n", Desc->CapabilityLength)); > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + switch (KeyHeader->Key) { > > + case CAPABILITIES1_KEY: { > > + if (KeyHeader->Length !=3D CAPABILITIES1_LENGTH) { > > + DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid length = (%d) for Capabilities 1\n", KeyHeader->Length)); > > + return EFI_INVALID_PARAMETER; > > + } > > + Output->Capabilities1 =3D *(UINT32*)KeyHeader->Value; > > + break; > > + default: > > + // Ignore unknown types > > + break; > > + } > > + } > > + DataRemaining -=3D KeyValueSize; > > + Offset +=3D KeyValueSize; > > + } > > + return EFI_SUCCESS; > > +} > > + > > + > > +/** > > + * Check that the DisplayLink device supports the basic level of funct= ionality to display GOP pixels. > > + * @param Descriptor The USB descriptor received from the DisplayLink = device > > + * @return True we can bind, False we can't > > + */ > > +BOOLEAN > > +UsbDisplayLinkCapabilitiesSufficientToBind ( > > + CONST IN VendorDescriptor* Descriptor > > + ) > > +{ > > + BOOLEAN Sufficient; > > + Sufficient =3D (BOOLEAN)(Descriptor->Capabilities1 & CAPABILITIES1_B= ASE_PROTOCOL); > > + > > + if (Sufficient =3D=3D FALSE) { > > + DEBUG ((DEBUG_ERROR, "DisplayLink device does not report support f= or base capabilites - reports x%x, required x%x\n", > Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL)); > > + } > > + return Sufficient; > > +} > > + > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Componen= tName.c > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c > > new file mode 100644 > > index 000000000000..74498f339eb7 > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/ComponentName.c > > @@ -0,0 +1,235 @@ > > +/** > > + * @file ComponentName.c > > + * @brief UEFI Component Name protocol implementation for USB DisplayL= ink driver. > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#include "UsbDisplayLink.h" > > + > > + > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkComponentNameGetDriverName ( > > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > > + IN CHAR8 *Language, > > + OUT CHAR16 **DriverName > > +); > > + > > + > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkComponentNameGetControllerName ( > > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > > + IN EFI_HANDLE ControllerHandle= , > > + IN EFI_HANDLE ChildHandle = OPTIONAL, > > + IN CHAR8 *Language, > > + OUT CHAR16 **ControllerName > > +); > > + > > + > > +// > > +// EFI Component Name Protocol > > +// > > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL mUsbDisplay= LinkComponentName =3D { > > + UsbDisplayLinkComponentNameGetDriverName, > > + UsbDisplayLinkComponentNameGetControllerName, > > + "eng" > > +}; > > + > > +// > > +// EFI Component Name 2 Protocol > > +// > > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplay= LinkComponentName2 =3D { > > + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UsbDisplayLinkComponentNameGet= DriverName, > > + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UsbDisplayLinkComponentNam= eGetControllerName, > > + "en" > > +}; > > + > > + > > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUsbDisplayLink= DriverNameTable[] =3D { > > + { (CHAR8*)"eng;en", (CHAR16*)L"DisplayLink USB GOP Driver" }, > > + { (CHAR8*)NULL , (CHAR16*)NULL } > > +}; > > + > > +/** > > + Retrieves a Unicode string that is the user readable name of the dri= ver. > > + > > + This function retrieves the user readable name of a driver in the fo= rm of a > > + Unicode string. If the driver specified by This has a user readable = name in > > + the language specified by Language, then a pointer to the driver nam= e is > > + returned in DriverName, and EFI_SUCCESS is returned. If the driver s= pecified > > + by This does not support the language specified by Language, > > + then EFI_UNSUPPORTED is returned. > > + > > + @param This A pointer to the EFI_COMPONENT_NAME2_P= ROTOCOL or > > + EFI_COMPONENT_NAME_PROTOCOL instance. > > + @param Language A pointer to a Null-terminated ASCII s= tring > > + array indicating the language. This is= the > > + language of the driver name that the c= aller is > > + requesting, and it must match one of t= he > > + languages specified in SupportedLangua= ges. The > > + number of languages supported by a dri= ver is up > > + to the driver writer. Language is spec= ified > > + in RFC 4646 or ISO 639-2 language code= format. > > + @param DriverName A pointer to the Unicode string to ret= urn. > > + This Unicode string is the name of the > > + driver specified by This in the langua= ge > > + specified by Language. > > + > > + @retval EFI_SUCCESS The Unicode string for the Driver spec= ified by > > + This and the language specified by Lan= guage was > > + returned in DriverName. > > + @retval EFI_INVALID_PARAMETER Language is NULL. > > + @retval EFI_INVALID_PARAMETER DriverName is NULL. > > + @retval EFI_UNSUPPORTED The driver specified by This does not = support > > + the language specified by Language. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkComponentNameGetDriverName ( > > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > > + IN CHAR8 *Language, > > + OUT CHAR16 **DriverName > > + ) > > +{ > > + return LookupUnicodeString2 ( > > + Language, > > + This->SupportedLanguages, > > + mUsbDisplayLinkDriverNameTable, > > + DriverName, > > + (BOOLEAN)(This =3D=3D &mUsbDisplayLinkComponentName)); > > +} > > + > > +/** > > + Retrieves a Unicode string that is the user readable name of the con= troller > > + that is being managed by a driver. > > + > > + This function retrieves the user readable name of the controller spe= cified by > > + ControllerHandle and ChildHandle in the form of a Unicode string. If= the > > + driver specified by This has a user readable name in the language sp= ecified by > > + Language, then a pointer to the controller name is returned in Contr= ollerName, > > + and EFI_SUCCESS is returned. If the driver specified by This is not= currently > > + managing the controller specified by ControllerHandle and ChildHandl= e, > > + then EFI_UNSUPPORTED is returned. If the driver specified by This d= oes not > > + support the language specified by Language, then EFI_UNSUPPORTED is = returned. > > + > > + @param This A pointer to the EFI_COMPONENT_NAME2_P= ROTOCOL or > > + EFI_COMPONENT_NAME_PROTOCOL instance. > > + @param ControllerHandle The handle of a controller that the dr= iver > > + specified by This is managing. This h= andle > > + specifies the controller whose name is= to be > > + returned. > > + @param ChildHandle The handle of the child controller to = retrieve > > + the name of. This is an optional para= meter that > > + may be NULL. It will be NULL for devi= ce > > + drivers. It will also be NULL for a b= us drivers > > + that wish to retrieve the name of the = bus > > + controller. It will not be NULL for a= bus > > + driver that wishes to retrieve the nam= e of a > > + child controller. > > + @param Language A pointer to a Null-terminated ASCII s= tring > > + array indicating the language. This i= s the > > + language of the driver name that the c= aller is > > + requesting, and it must match one of t= he > > + languages specified in SupportedLangua= ges. The > > + number of languages supported by a dri= ver is up > > + to the driver writer. Language is spec= ified in > > + RFC 4646 or ISO 639-2 language code fo= rmat. > > + @param ControllerName A pointer to the Unicode string to ret= urn. > > + This Unicode string is the name of the > > + controller specified by ControllerHand= le and > > + ChildHandle in the language specified = by > > + Language from the point of view of the= driver > > + specified by This. > > + > > + @retval EFI_SUCCESS The Unicode string for the user readab= le name in > > + the language specified by Language for= the > > + driver specified by This was returned = in > > + DriverName. > > + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HA= NDLE. > > + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not = a valid > > + EFI_HANDLE. > > + @retval EFI_INVALID_PARAMETER Language is NULL. > > + @retval EFI_INVALID_PARAMETER ControllerName is NULL. > > + @retval EFI_UNSUPPORTED The driver specified by This is not cu= rrently > > + managing the controller specified by > > + ControllerHandle and ChildHandle. > > + @retval EFI_UNSUPPORTED The driver specified by This does not = support > > + the language specified by Language. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkComponentNameGetControllerName ( > > + IN EFI_COMPONENT_NAME_PROTOCOL *This, > > + IN EFI_HANDLE ControllerHandle= , > > + IN EFI_HANDLE ChildHandle = OPTIONAL, > > + IN CHAR8 *Language, > > + OUT CHAR16 **ControllerName > > + ) > > +{ > > + EFI_STATUS Status; > > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev; > > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol; > > + EFI_USB_IO_PROTOCOL *UsbIoProtocol; > > + > > + // > > + // This is a device driver, so ChildHandle must be NULL. > > + // > > + if (ChildHandle !=3D NULL) { > > + return EFI_UNSUPPORTED; > > + } > > + > > + // > > + // Check Controller's handle > > + // > > + Status =3D gBS->OpenProtocol ( > > + ControllerHandle, > > + &gEfiUsbIoProtocolGuid, > > + (VOID **) &UsbIoProtocol, > > + gUsbDisplayLinkDriverBinding.DriverBindingHandle, > > + ControllerHandle, > > + EFI_OPEN_PROTOCOL_BY_DRIVER); > > + > > + if (!EFI_ERROR (Status)) { > > + gBS->CloseProtocol ( > > + ControllerHandle, > > + &gEfiUsbIoProtocolGuid, > > + gUsbDisplayLinkDriverBinding.DriverBindingHandle, > > + ControllerHandle); > > + > > + return EFI_UNSUPPORTED; > > + } > > + > > + if (Status !=3D EFI_ALREADY_STARTED) { > > + return EFI_UNSUPPORTED; > > + } > > + // > > + // Get the device context > > + // > > + Status =3D gBS->OpenProtocol ( > > + ControllerHandle, > > + &gEfiGraphicsOutputProtocolGuid, > > + (VOID**)&GraphicsOutputProtocol, > > + gUsbDisplayLinkDriverBinding.DriverBindingHandle, > > + ControllerHandle, > > + EFI_OPEN_PROTOCOL_GET_PROTOCOL); > > + > > + if (EFI_ERROR (Status)) { > > + return Status; > > + } > > + > > + UsbDisplayLinkDev =3D USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTO= COL(GraphicsOutputProtocol); > > + > > + return LookupUnicodeString2 ( > > + Language, > > + This->SupportedLanguages, > > + UsbDisplayLinkDev->ControllerNameTable, > > + ControllerName, > > + (BOOLEAN)(This =3D=3D &mUsbDisplayLinkComponentName)); > > +} > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayL= inkGopDxe.inf > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.inf > > new file mode 100644 > > index 000000000000..0f458fedcc88 > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopD= xe.inf > > @@ -0,0 +1,65 @@ > > +#/** @file > > +# USB DisplayLink driver that implements blt and EDID commands > > +# > > +# USB DisplayLink driver consumes I/O Protocol and Device Path Protoco= l, and produces > > +# Graphics Output Protocol on DisplayLink devices. > > +# 1. DisplayLink reference > > +# 2. UEFI Specification, v2.1 > > +# > > +# Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > +# > > +# SPDX-License-Identifier: BSD-2-Clause-Patent > > +# > > +#**/ > > + > > + > > +[Defines] > > + INF_VERSION =3D 0x0001001B > > + BASE_NAME =3D DisplayLinkGop > > + FILE_GUID =3D 2D2E62AA-9ECF-43b7-8219-94E7FC713= DFF > > + MODULE_TYPE =3D UEFI_DRIVER > > + VERSION_STRING =3D 1.0 > > + ENTRY_POINT =3D UsbDisplayLinkDriverBindingEntryP= oint > > + UNLOAD_IMAGE =3D UsbDisplayLinkDriverCombinedGopUn= load > > + INF_DRIVER_VERSION =3D 0x00000001 > > + > > +[Sources] > > + CapabilityDescriptor.c > > + ComponentName.c > > + Edid.c > > + Edid.h > > + Gop.c > > + UsbDescriptors.c > > + UsbDescriptors.h > > + UsbDisplayLink.c > > + UsbDisplayLink.h > > + UsbTransfer.c > > + VideoModes.c > > + > > +[Packages] > > + MdePkg/MdePkg.dec > > + > > +[LibraryClasses] > > + BaseMemoryLib > > + DebugLib > > + MemoryAllocationLib > > + ReportStatusCodeLib > > + UefiBootServicesTableLib > > + UefiDriverEntryPoint > > + UefiLib > > + UefiUsbLib > > + > > +[Protocols] > > + gEfiUsbIoProtocolGuid ## TO_START > > + gEfiEdidActiveProtocolGuid # PROTOCOL BY_START > > + gEfiEdidDiscoveredProtocolGuid # PROTOCOL BY_START > > + gEfiEdidOverrideProtocolGuid # PROTOCOL TO_START > > + gEfiHiiDatabaseProtocolGuid > > + gEfiHiiFontProtocolGuid > > + > > +[Guids] > > + gEfiEventExitBootServicesGuid > > + gEfiGlobalVariableGuid > > + > > +[Pcd] > > + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize ## CONSUME= S > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c > > new file mode 100644 > > index 000000000000..21f4b7d9c736 > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.c > > @@ -0,0 +1,598 @@ > > +/** @file Edid.c > > + * @brief Reads and parses the EDID, checks if a requested video mode = is in the supplied EDID > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#include "UsbDisplayLink.h" > > +#include "Edid.h" > > + > > +CONST UINT8 ExpectedEdidHeader[EDID_HEADER_SIZE] =3D { 0x00, 0xFF, 0xF= F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 }; > > + > > +// > > +// Standard timing defined by VESA EDID > > +// > > +CONST EDID_TIMING EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMING= S_BYTES][8] =3D { > > + // > > + // Established Timing I > > + // > > + { > > + { 800, 600, 60 }, > > + { 800, 600, 56 }, > > + { 640, 480, 75 }, > > + { 640, 480, 72 }, > > + { 640, 480, 67 }, > > + { 640, 480, 60 }, > > + { 720, 400, 88 }, > > + { 720, 400, 70 }, > > + }, > > + { > > + // > > + // Established Timing II > > + // > > + { 1280, 1024, 75 }, > > + { 1024, 768, 75 }, > > + { 1024, 768, 70 }, > > + { 1024, 768, 60 }, > > + { 1024, 768, 87 }, > > + { 832, 624, 75 }, > > + { 800, 600, 75 }, > > + { 800, 600, 72 }, > > + }, > > + // > > + // Established Timing III > > + // > > + { > > + { 1152, 870, 75 }, > > + { 0, 0, 0 }, > > + { 0, 0, 0 }, > > + { 0, 0, 0 }, > > + { 0, 0, 0 }, > > + { 0, 0, 0 }, > > + { 0, 0, 0 }, > > + { 0, 0, 0 }, > > + } > > +}; > > + > > +/** > > + * Requests the monitor EDID data from the connected DisplayLink devic= e > > + * @param UsbDisplayLinkDev > > + * @param EdidDataBlock > > + * @param EdidSize > > + * @retval EFI_DEVICE_ERROR - No EDID received, or EDID is corrupted > > + * @retval EFI_OUT_OF_RESOURCES - Cannot allocate memory > > + * @retval EFI_SUCCESS > > + * > > + */ > > +STATIC EFI_STATUS > > +ReadEdidData ( > > + IN USB_DISPLAYLINK_DEV *UsbDisplayLinkDev, > > + OUT UINT8 **EdidDataBlock, > > + OUT UINTN *EdidSize > > +) > > +{ > > + EFI_STATUS Status; > > + > > + UINT8 EdidDataRead[EDID_BLOCK_SIZE]; > > + UINT8 *EdidData =3D EdidDataRead; > > + UINT8* ValidEdid; > > + > > + Status =3D DlUsbSendControlReadMessage (UsbDisplayLinkDev, GET_OUTPU= T_EDID, 0, EdidDataRead, sizeof (EdidDataRead)); > > + > > + if (EFI_ERROR (Status) || (EdidData[0] !=3D 0)) { > > + DEBUG ((DEBUG_ERROR, "No monitor EDID received from DisplayLink de= vice - System error %r, EDID error %d. Monitor > connected correctly?\n", Status, EdidData[0])); > > + return EFI_DEVICE_ERROR; > > + } else { > > + // > > + // Search for the EDID signature > > + // > > + ValidEdid =3D &EdidData[0]; > > + CONST UINT64 Signature =3D 0x00ffffffffffff00ull; > > + if (CompareMem (ValidEdid, &Signature, 8) !=3D 0) { > > + // > > + // No EDID signature found > > + // > > + DEBUG ((DEBUG_ERROR, "Monitor EDID received from DisplayLink dev= ice did not have a valid signature - corrupted?\n")); > > + Status =3D EFI_DEVICE_ERROR; > > + return Status; > > + } > > + } > > + > > + *EdidDataBlock =3D (UINT8*)AllocateCopyPool ( > > + EDID_BLOCK_SIZE, > > + ValidEdid); > > + > > + if (*EdidDataBlock =3D=3D NULL) { > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + // > > + // Currently only support EDID 1.x > > + // > > + *EdidSize =3D EDID_BLOCK_SIZE; > > + > > + return EFI_SUCCESS; > > +} > > + > > + > > +/** > > +Calculates the mod256 checksum of the EDID and compares it with the on= e supplied at the end of the EDID > > +@param EDID Pointer to the 128-byte EDID > > +@retval TRUE The EDID checksum is correct > > +**/ > > +BOOLEAN > > +IsEdidChecksumCorrect ( > > + CONST VOID *EDID > > + ) > > +{ > > + CONST UINT8 EdidChecksum =3D ((UINT8 *)EDID)[EDID_BLOCK_SIZE - 1]; > > + UINT8 CalculatedChecksum; > > + > > + CalculatedChecksum =3D 0; > > + > > + UINTN i; > > + for (i =3D 0; i < EDID_BLOCK_SIZE - 1; i++) { > > + CalculatedChecksum +=3D ((UINT8 *)EDID)[i]; > > + } > > + CalculatedChecksum =3D 0 - CalculatedChecksum; > > + > > + return (CalculatedChecksum =3D=3D EdidChecksum); > > +} > > + > > +/** > > +Check if a particular video mode is in the Established Timings section= of the EDID. > > + > > +@param EDID Pointer to the 128-byte EDID > > +@param hRes Horizontal resolution > > +@param vRes Vertical resolution > > +@param refresh Refresh rate > > +@retval TRUE The requested mode is present in the Established T= imings section > > + > > +**/ > > +STATIC BOOLEAN > > +IsModeInEstablishedTimings ( > > + IN CONST VOID *EDID, > > + IN UINT16 HRes, > > + IN UINT16 VRes, > > + IN UINT16 Refresh > > + ) > > +{ > > + CONST struct Edid *pEDID =3D (CONST struct Edid *)EDID; > > + BOOLEAN ModeSupported; > > + > > + ModeSupported =3D FALSE; > > + > > + int EstByteNum; > > + int BitNum; > > + for (EstByteNum =3D 0; EstByteNum < EDID_NUMBER_OF_ESTABLISHED_TIMIN= GS_BYTES; EstByteNum++) { > > + for (BitNum =3D 0; BitNum < 8; BitNum++) { > > + if (pEDID->EstablishedTimings[EstByteNum] & (1 << BitNum)) { // = The bit is set in the established timings of the EDID > > + > > + if ((EstablishedTimings[EstByteNum][BitNum].HRes =3D=3D HRes) = && // The passed-in resolution matches the resolution > represented by the set bit > > + (EstablishedTimings[EstByteNum][BitNum].VRes =3D=3D VRes) && > > + (EstablishedTimings[EstByteNum][BitNum].Refresh =3D=3D Refre= sh)) { > > + > > + ModeSupported =3D TRUE; > > + break; > > + } > > + } > > + } > > + if (ModeSupported =3D=3D TRUE) { > > + break; > > + } > > + } > > + return ModeSupported; > > +} > > + > > +/** > > +Extract the resolutions and refresh rate from one of the entries in th= e Standard Timings section of the EDID. > > + > > +@param EDID Pointer to the 128-byte EDID > > +@param timingNumber The entry that we want to extract > > +@param hRes Output - Horizontal resolution > > +@param vRes Output - Vertical resolution > > +@param refresh Output - Refresh rate > > +@retval TRUE The requested Standard Timings entry contains va= lid data > > + > > +**/ > > +STATIC BOOLEAN ReadStandardTiming ( > > + CONST VOID *EDID, > > + IN UINT8 TimingNumber, > > + OUT UINT16 *HRes, > > + OUT UINT16 *VRes, > > + OUT UINT8 *Refresh) > > +{ > > + CONST struct Edid *pEDID =3D (CONST struct Edid *)EDID; > > + > > + // See section 3.9.1 of the VESA EDID spec > > + > > + if (((pEDID->standardTimingIdentifications[TimingNumber].HorizontalA= ctivePixels) =3D=3D 0x01) && > > + (pEDID->standardTimingIdentifications[TimingNumber].ImageAspectRat= ioAndrefresh) =3D=3D 0x01) { > > + *HRes =3D 0; > > + *VRes =3D 0; > > + *Refresh =3D 0; > > + return FALSE; > > + } > > + *HRes =3D (pEDID->standardTimingIdentifications[TimingNumber].Horizo= ntalActivePixels + 31) * 8; > > + > > + UINT8 AspectRatio; > > + AspectRatio =3D (pEDID->standardTimingIdentifications[TimingNumber].= ImageAspectRatioAndrefresh >> 6) & 0x3; > > + > > + switch (AspectRatio) { > > + case 0: *VRes =3D (*HRes * 10) / 16; > > + break; > > + case 1: *VRes =3D (*HRes * 3) / 4; > > + break; > > + case 2: *VRes =3D (*HRes * 4) / 5; > > + break; > > + case 3: *VRes =3D (*HRes * 9) / 16; > > + break; > > + default: break; > > + } > > + > > + // WORKAROUND - 1360x768 is not a perfect aspect ratio > > + if ((*HRes =3D=3D 1360) && (*VRes =3D=3D 765)) { > > + *VRes =3D 768; > > + } > > + > > + *Refresh =3D (pEDID->standardTimingIdentifications[TimingNumber].Ima= geAspectRatioAndrefresh & 0x1F) + 60; > > + > > + return TRUE; > > +} > > + > > +/** > > +Extract the resolutions and refresh rate from one of the entries in th= e Detailed Timings section of the EDID. > > + > > +@param EDID Pointer to the 128-byte EDID > > +@param timingNumber The entry that we want to extract > > +@param videoMode Output - Filled in with details from the detaile= d timing > > +@retval TRUE The requested Detailed Timings entry contains va= lid data > > + > > +**/ > > +STATIC BOOLEAN > > +ReadDetailedTiming ( > > + IN CONST VOID *EDID, > > + IN UINT8 TimingNumber, > > + OUT struct VideoMode *VideoMode > > + ) > > +{ > > + if (TimingNumber >=3D EDID_NUMBER_OF_DETAILED_TIMINGS) { > > + return FALSE; > > + } > > + > > + UINT16 NumValidDetailedTimingsFound; > > + NumValidDetailedTimingsFound =3D 0; > > + > > + // Spin through the detailed timings until we find a valid one - the= n check if this has the index that we want > > + int BlockNumber; > > + for (BlockNumber =3D 0; BlockNumber < EDID_NUMBER_OF_DETAILED_TIMING= S; BlockNumber++) { > > + CONST struct Edid *pEDID =3D (CONST struct Edid *)EDID; > > + CONST struct DetailedTimingIdentification *pTiming =3D &pEDID->det= ailedTimingDescriptions[BlockNumber]; > > + > > + if (((BlockNumber =3D=3D 0) && (pTiming->PixelClock =3D=3D EDID_DE= TAILED_TIMING_INVALID_PIXEL_CLOCK)) || > > + (pTiming->PixelClock =3D=3D 0)) { > > + // This is not a valid detailed timing descriptor > > + continue; > > + } > > + > > + if ((pTiming->Features & EdidDetailedTimingsFeaturesSyncSchemeMask= ) !=3D EdidDetailedTimingsFeaturesSyncSchemeMask) > { > > + DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported sync = scheme found - not processing.\n")); > > + continue; > > + } > > + > > + if ((pTiming->Features & EdidDetailedTimingsFeaturesStereoModeMask= ) !=3D 0) { > > + DEBUG ((DEBUG_INFO, "EDID detailed timing with unsupported stere= o mode found - not processing.\n")); > > + continue; > > + } > > + > > + // We've found a supported detailed timing - now see if this is th= e requested one > > + if (TimingNumber !=3D NumValidDetailedTimingsFound) { > > + NumValidDetailedTimingsFound++; > > + continue; > > + } > > + > > + ZeroMem ((VOID *)VideoMode, sizeof (struct VideoMode)); > > + > > + // Bit manipulations copied from host software class EDIDTimingDes= criptor > > + > > + VideoMode->PixelClock =3D (UINT16)pTiming->PixelClock; > > + VideoMode->HActive =3D pTiming->HActiveLo + ((pTiming->HActiveHiBl= ankingHi & 0xF0) << 4); > > + VideoMode->VActive =3D pTiming->VActiveLo + ((pTiming->VActiveHiBl= ankingHi & 0xF0) << 4); > > + > > + VideoMode->HBlanking =3D pTiming->HBlankingLo + ((pTiming->HActive= HiBlankingHi & 0x0F) << 8); > > + VideoMode->VBlanking =3D pTiming->VBlankingLo + ((pTiming->VActive= HiBlankingHi & 0x0F) << 8); > > + > > + VideoMode->HSyncOffset =3D pTiming->HSyncOffsetLo + ((pTiming->HSy= ncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi > & 0xC0) << 2); // Horizontal Front Porch > > + VideoMode->HSyncWidth =3D pTiming->HSyncWidthLo + ((pTiming->HSync= OffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi > & 0x30) << 4); > > + > > + VideoMode->VSyncOffset =3D ((pTiming->VSyncOffsetLoSyncWidthLo & 0= xF0) >> 4) + ((pTiming- > >HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x0C) << 2); // Vert= ical Front Porch > > + VideoMode->VSyncWidth =3D (pTiming->VSyncOffsetLoSyncWidthLo & 0x0= F) + ((pTiming- > >HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi & 0x03) << 4); > > + > > + VideoMode->Reserved2 =3D 2; > > + VideoMode->Accumulate =3D 1; > > + > > + // Horizontal and vertical sync inversions - positive if bit set i= n descriptor (EDID spec) > > + // In the VideoMode, they are negative if the bit is set (NR-11049= 7-TC 4.3.3 0x22 Set Video Mode) > > + > > + // Horizontal sync > > + if ((pTiming->Features & EdidDetailedTimingsFeaturesHorizontalSync= Positive) =3D=3D 0) { > > + VideoMode->Flags |=3D VideoModeFlagsHorizontalSyncInverted; > > + } > > + // Vertical sync > > + if ((pTiming->Features & EdidDetailedTimingsFeaturesVerticalSyncPo= sitive) =3D=3D 0) { > > + VideoMode->Flags |=3D VideoModeFlagsVerticalSyncInverted; > > + } > > + // Interlace > > + if ((pTiming->Features & EdidDetailedTimingsFeaturesInterlaced) = =3D=3D EdidDetailedTimingsFeaturesInterlaced) { > > + VideoMode->Flags |=3D VideoModeFlagsInterlaced; > > + } > > + > > + DEBUG ((DEBUG_INFO, "Read mode %dx%d from detailed timings\n", Vid= eoMode->HActive, VideoMode->VActive)); > > + return TRUE; > > + } > > + return FALSE; > > +} > > + > > +/** > > +Check if a particular video mode is in either the Established or Stand= ard Timings section of the EDID. > > + > > +@param EDID Pointer to the 128-byte EDID > > +@param hRes Horizontal resolution > > +@param vRes Vertical resolution > > +@param refresh Refresh rate > > +@retval TRUE The requested mode is present in the EDID > > + > > +**/ > > +STATIC BOOLEAN > > +IsModeInEdid ( > > + IN CONST VOID *EDID, > > + IN UINT16 HRes, > > + IN UINT16 VRes, > > + IN UINT16 Refresh > > + ) > > +{ > > + UINT16 EdidHRes; > > + UINT16 EdidVRes; > > + UINT8 EdidRefresh; > > + BOOLEAN ModeSupported; > > + > > + ModeSupported =3D IsModeInEstablishedTimings (EDID, HRes, VRes, Refr= esh); > > + > > + if (ModeSupported =3D=3D FALSE) { > > + // Check if the mode is in the Standard Timings section of the EDI= D > > + UINT8 i; > > + for (i =3D 0; i < EDID_NUMBER_OF_STANDARD_TIMINGS; i++) { > > + if (TRUE =3D=3D ReadStandardTiming (EDID, i, &EdidHRes, &EdidVRe= s, &EdidRefresh)) { > > + if ((HRes =3D=3D EdidHRes) && (VRes =3D=3D EdidVRes) && (Refre= sh =3D=3D EdidRefresh)) { > > + ModeSupported =3D TRUE; > > + break; > > + } > > + } > > + } > > + } > > + return ModeSupported; > > +} > > + > > +/** > > +Returns the (index)'th entry from the list of pre-calculated video tim= ings that is also present in the EDID, > > +or, video mode data corresponding to any detailed timings present in t= he EDID. > > + > > +Like QueryVideoMode, finds the number (and contents) of video modes av= ailable by repeatedly calling this function > > +with an increasing index value, until it returns FALSE > > +@param index The caller wants the _index_'th video mode > > +@param EDID Pointer to the 128-byte EDID > > +@param edidSize Size in bytes of the EDID > > +@param videoMode Video timings extracted from the modeData structur= e > > +@retval EFI_SUCCESS The requested mode is present in the EDID > > +@retval EFI_INVALID_PARAMETER The requested mode is not present in the= EDID > > +**/ > > +EFI_STATUS > > +DlEdidGetSupportedVideoMode ( > > + IN UINT32 Index, > > + IN CONST VOID *EDID, > > + IN UINT32 EdidSize, > > + OUT CONST struct VideoMode **VideoMode > > + ) > > +{ > > + UINTN SupportedVideoModesFoundInEdid; > > + EFI_STATUS Status; > > + > > + SupportedVideoModesFoundInEdid =3D 0; > > + Status =3D EFI_INVALID_PARAMETER; > > + > > + // If we didn't manage to find an EDID earlier, just use one of the = hard-coded video modes > > + if ((EDID =3D=3D NULL) || (EdidSize !=3D EDID_BLOCK_SIZE)) { > > + if (Index >=3D DlVideoModeGetNumSupportedVideoModes ()) { > > + return EFI_INVALID_PARAMETER; > > + } > > + else { > > + *VideoMode =3D DlVideoModeGetSupportedVideoMode (Index); > > + DEBUG ((DEBUG_WARN, "No monitor EDID loaded - returning mode fro= m default list (%dx%d)\n", (*VideoMode)- > >HActive, (*VideoMode)->VActive)); > > + return EFI_SUCCESS; > > + } > > + } > > + > > + UINT16 ModeNumber; > > + for (ModeNumber =3D 0; ModeNumber < DlVideoModeGetNumSupportedVideoM= odes (); ModeNumber++) { > > + > > + CONST struct VideoMode *SupportedVideoMode =3D DlVideoModeGetSuppo= rtedVideoMode (ModeNumber); > > + ASSERT (SupportedVideoMode); > > + > > + if (IsModeInEdid (EDID, SupportedVideoMode->HActive, SupportedVide= oMode->VActive, > DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE)) { > > + if (Index =3D=3D SupportedVideoModesFoundInEdid) { > > + *VideoMode =3D SupportedVideoMode; > > + Status =3D EFI_SUCCESS; > > + break; > > + } > > + SupportedVideoModesFoundInEdid++; > > + } > > + } > > + > > + if (EFI_ERROR (Status)) { > > + // Have a look in the detailed timings > > + UINTN DetailedTimingNumber; > > + STATIC struct VideoMode TmpVideoMode; > > + DetailedTimingNumber =3D Index - SupportedVideoModesFoundInEdid; > > + > > + if (DetailedTimingNumber < EDID_NUMBER_OF_DETAILED_TIMINGS) { > > + if (ReadDetailedTiming (EDID, (UINT8)DetailedTimingNumber, &TmpV= ideoMode)) { > > + *VideoMode =3D &TmpVideoMode; > > + Status =3D EFI_SUCCESS; > > + } > > + } > > + } > > + > > + return Status; > > +} > > + > > +/** > > + * Like GetSupportedEdidVideoMode, but will return a fallback fixed mo= de of 640x480@60Hz > > + * for index 0 if no suitable modes found in EDID. > > + * @param index > > + * @param EDID > > + * @param edidSize > > + * @param videoMode > > + * @return EFI_SUCCESS > > + */ > > +EFI_STATUS > > +DlEdidGetSupportedVideoModeWithFallback ( > > + IN UINT32 Index, > > + IN CONST VOID *EDID, > > + IN UINT32 EdidSize, > > + OUT CONST struct VideoMode **VideoMode > > + ) > > +{ > > + EFI_STATUS Status; > > + Status =3D DlEdidGetSupportedVideoMode (Index, EDID, EdidSize, Video= Mode); > > + > > + if (EFI_ERROR (Status)) { > > + // Special case - if we didn't find any matching video modes in th= e EDID, fall back to 640x480@60Hz > > + if (Index =3D=3D 0) { > > + *VideoMode =3D DlVideoModeGetSupportedVideoMode (0); > > + DEBUG ((DEBUG_WARN, "No video modes supported by driver found in= monitor EDID received from DL device - falling > back to %dx%d\n", (*VideoMode)->HActive, (*VideoMode)->VActive)); > > + Status =3D EFI_SUCCESS; > > + } > > + } > > + > > + return Status; > > +} > > + > > +/** > > +Count the number of video modes that we have timing information for th= at are present in the EDID > > +@param EDID Pointer to the 128-byte EDID > > +@param edidSize > > +@retval The number of modes in the EDID > > + > > +**/ > > +UINT32 > > +DlEdidGetNumSupportedModesInEdid ( > > + IN CONST VOID *EDID, > > + IN UINT32 EdidSize > > + ) > > +{ > > + UINT32 MaxMode; > > + > > + if ((EDID =3D=3D NULL) || (EdidSize !=3D EDID_BLOCK_SIZE)) { > > + return DlVideoModeGetNumSupportedVideoModes (); > > + } > > + > > + for (MaxMode =3D 0; ; MaxMode++) { > > + CONST struct VideoMode *videoMode; > > + if (EFI_ERROR (DlEdidGetSupportedVideoMode (MaxMode, EDID, EdidSiz= e, &videoMode))) { > > + break; > > + } > > + } > > + DEBUG ((DEBUG_INFO, "Found %d video modes supported by driver in mon= itor EDID.\n", MaxMode)); > > + return MaxMode; > > +} > > + > > + > > + > > +/** > > + * Read the EDID from the connected monitor, store it in the local dat= a structure > > + * @param UsbDisplayLinkDev > > + * @retval EFI_OUT_OF_RESOURCES - Could not allocate memory > > + * @retval EFI_SUCCESS > > + */ > > +EFI_STATUS > > +DlReadEdid ( > > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev > > + ) > > +{ > > + EFI_STATUS Status; > > + BOOLEAN EdidFound; > > + EFI_EDID_OVERRIDE_PROTOCOL* EdidOverride; > > + > > + // > > + // setup EDID information > > + // > > + UsbDisplayLinkDev->EdidDiscovered.Edid =3D (UINT8 *)NULL; > > + UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid =3D 0; > > + > > + EdidFound =3D FALSE; > > + > > + // > > + // Find EDID Override protocol firstly, this protocol is installed b= y platform if needed. > > + // > > + Status =3D gBS->LocateProtocol (&gEfiEdidOverrideProtocolGuid, NULL,= (VOID**)&EdidOverride); > > + > > + if (!EFI_ERROR (Status)) { > > + UINT32 EdidAttributes =3D 0xff; > > + UINTN EdidDataSize =3D 0; > > + UINT8* EdidDataBlock =3D (UINT8*)NULL; > > + > > + // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to= avoid overflow > > + EdidDataBlock =3D (UINT8*)AllocatePool (EDID_BLOCK_SIZE * 2); > > + > > + if (NULL =3D=3D EdidDataBlock) { > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + Status =3D EdidOverride->GetEdid ( > > + EdidOverride, > > + &UsbDisplayLinkDev->Handle, > > + &EdidAttributes, > > + &EdidDataSize, > > + &EdidDataBlock); > > + > > + if (!EFI_ERROR (Status) && EdidAttributes =3D=3D 0 && EdidDataSize= !=3D 0) { > > + UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid =3D (UINT32)EdidDat= aSize; > > + UsbDisplayLinkDev->EdidDiscovered.Edid =3D EdidDataBlock; > > + EdidFound =3D TRUE; > > + } > > + else { > > + FreePool (EdidDataBlock); > > + EdidDataBlock =3D NULL; > > + } > > + } > > + > > + if (EdidFound !=3D TRUE) { > > + UINTN EdidDataSize =3D 0; > > + UINT8* EdidDataBlock =3D (UINT8*)NULL; > > + > > + if (ReadEdidData (UsbDisplayLinkDev, &EdidDataBlock, &EdidDataSize= ) =3D=3D EFI_SUCCESS) { > > + > > + if (IsEdidChecksumCorrect (EdidDataBlock)) { > > + UsbDisplayLinkDev->EdidDiscovered.SizeOfEdid =3D (UINT32)EdidD= ataSize; > > + UsbDisplayLinkDev->EdidDiscovered.Edid =3D EdidDataBlock; > > + EdidFound =3D TRUE; > > + } else { > > + DEBUG ((DEBUG_WARN, "Monitor EDID received from DisplayLink de= vice had an invalid checksum. Corrupted?\n")); > > + } > > + } > > + } > > + > > + if (EdidFound =3D=3D FALSE) { > > + DEBUG ((DEBUG_WARN, "No valid monitor EDID received from DisplayLi= nk device. Cannot detect resolutions supported by > monitor.\n")); > > + } > > + > > + // Set the EDID active. > > + // In an error case this will be set 0/NULL, which flags to the pars= ing code that there is no EDID. > > + UsbDisplayLinkDev->EdidActive.SizeOfEdid =3D UsbDisplayLinkDev->Edid= Discovered.SizeOfEdid; > > + UsbDisplayLinkDev->EdidActive.Edid =3D UsbDisplayLinkDev->EdidDiscov= ered.Edid; > > + > > + return EFI_SUCCESS; > > +} > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h > > new file mode 100644 > > index 000000000000..a1b8a0512d1a > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Edid.h > > @@ -0,0 +1,129 @@ > > +/** @file Edid.h > > + * @brief Helper routine and corresponding data struct used by USB Dis= playLink Driver. > > + * Reads and parses the EDID, checks if a requested video mode is in t= he supplied EDID > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#ifndef EDID_H > > +#define EDID_H > > + > > +#include "UsbDisplayLink.h" > > + > > +#define EDID_HEADER_SIZE ((UINTN)8) > > +#define EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES ((UINTN)3) > > +#define EDID_NUMBER_OF_STANDARD_TIMINGS ((UINTN)8) > > +#define EDID_NUMBER_OF_DETAILED_TIMINGS ((UINTN)4) > > + > > + > > +typedef struct { > > + UINT16 HRes; > > + UINT16 VRes; > > + UINT16 Refresh; > > +} EDID_TIMING; > > + > > + > > +EFI_STATUS > > +DlEdidGetSupportedVideoMode ( > > + UINT32 ModeNumber, > > + CONST VOID *EDID, > > + UINT32 EdidSize, > > + CONST struct VideoMode **VideoMode > > + ); > > + > > +EFI_STATUS > > +DlEdidGetSupportedVideoModeWithFallback ( > > + UINT32 ModeNumber, > > + CONST VOID *EDID, > > + UINT32 EdidSize, > > + CONST struct VideoMode **VideoMode > > + ); > > + > > +UINT32 > > +DlEdidGetNumSupportedModesInEdid ( > > + CONST VOID *EDID, > > + UINT32 EdidSize > > + ); > > + > > +EFI_STATUS > > +DlReadEdid ( > > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev > > +); > > + > > +// EDID Detailed timings section - Features > > +enum EdidDetailedTimingsFeatures { > > + EdidDetailedTimingsFeaturesInterlaced =3D 0x80, > > + EdidDetailedTimingsFeaturesStereoModeMask =3D 0x60, > > + EdidDetailedTimingsFeaturesSyncSchemeMask =3D 0x18, > > + EdidDetailedTimingsFeaturesHorizontalSyncPositive =3D 0x02, > > + EdidDetailedTimingsFeaturesVerticalSyncPositive =3D 0x04, > > +}; > > + > > +// NR-110497-TC-7ZM Section 4.3.3 0x22 Set Video Mode - Flags > > +enum VideoModeFlags { > > + VideoModeFlagsInterlaced =3D 0x0001, > > + VideoModeFlagsHorizontalSyncInverted =3D 0x0100, > > + VideoModeFlagsVerticalSyncInverted =3D 0x0200, > > +}; > > + > > +struct StandardTimingIdentification { > > + UINT8 HorizontalActivePixels; // X resolution, from 256->2= 288 in increments of 8 pixels > > + UINT8 ImageAspectRatioAndrefresh; // Bits 7,6 Aspect ratio - 0=3D1= 6:10 1=3D4:3 2=3D5:4 3=3D16:9 > > + // Bits 5,0 Refresh rate Ran= ge 60->1213Hz > > +}; > > + > > +struct DetailedTimingIdentification { > > + UINT16 PixelClock; // wPixelClock in VideoMode stru= ct > > + UINT8 HActiveLo; // wHActive > > + UINT8 HBlankingLo; // wHBlanking > > + UINT8 HActiveHiBlankingHi; > > + UINT8 VActiveLo; // wVActive > > + UINT8 VBlankingLo; // wVBlanking > > + UINT8 VActiveHiBlankingHi; > > + UINT8 HSyncOffsetLo; // wHSyncOffset, front porch > > + UINT8 HSyncWidthLo; // wHSyncWidth > > + UINT8 VSyncOffsetLoSyncWidthLo; > > + UINT8 HSyncOffsetHiHSyncWidthHiVSyncOffsetHiSyncWidthHi; > > + UINT8 HImageSizeHi; > > + UINT8 VImageSizeHi; > > + UINT8 HImageSizeLoVImageSizeLo; > > + UINT8 HBorder; > > + UINT8 VBorder; > > + UINT8 Features; > > +}; > > + > > +struct Edid { > > + UINT8 Header[EDID_HEADER_SIZE]; //EDID header "00 FF FF F= F FF FF FF 00" > > + UINT16 ManufactureName; //EISA 3-character ID > > + UINT16 ProductCode; //Vendor assigned code > > + UINT32 SerialNumber; //32-bit serial number > > + UINT8 WeekOfManufacture; //Week number > > + UINT8 YearOfManufacture; //Year > > + UINT8 EdidVersion; //EDID Structure Version > > + UINT8 EdidRevision; //EDID Structure Revision > > + UINT8 VideoInputDefinition; > > + UINT8 MaxHorizontalImageSize; //cm > > + UINT8 MaxVerticalImageSize; //cm > > + UINT8 DisplayTransferCharacteristic; > > + UINT8 FeatureSupport; > > + UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 G= y1Gy0 > > + UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 W= y1 Wy0 > > + UINT8 RedX; //Red-x Bits 9 - 2 > > + UINT8 RedY; //Red-y Bits 9 - 2 > > + UINT8 GreenX; //Green-x Bits 9 - 2 > > + UINT8 GreenY; //Green-y Bits 9 - 2 > > + UINT8 BlueX; //Blue-x Bits 9 - 2 > > + UINT8 BlueY; //Blue-y Bits 9 - 2 > > + UINT8 WhiteX; //White-x Bits 9 - 2 > > + UINT8 WhiteY; //White-x Bits 9 - 2 > > + UINT8 EstablishedTimings[EDID_NUMBER_OF_ESTABLISHED_TIMINGS_BYTES]; > > + struct StandardTimingIdentification standardTimingIdentifications[E= DID_NUMBER_OF_STANDARD_TIMINGS]; > > + struct DetailedTimingIdentification detailedTimingDescriptions[EDID= _NUMBER_OF_DETAILED_TIMINGS]; > > + UINT8 ExtensionFlag; //Number of (optional) 128-= byte EDID extension blocks to follow > > + UINT8 Checksum; > > +}; > > + > > +#endif // EDID_H > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c > > new file mode 100644 > > index 000000000000..3e483afdba72 > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/Gop.c > > @@ -0,0 +1,578 @@ > > +/** > > + * @file Gop.c > > + * @brief UEFI GOP protocol API implementation for USB DisplayLink dri= ver. > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#include "UsbDisplayLink.h" > > +#include "Edid.h" > > + > > + > > +/** > > + * > > + * @param This Pointer to the instance of the GOP protocol > > + * @param BltOperation > > + * @param SourceX > > + * @param SourceY > > + * @param Width > > + * @param Height > > + * @param DestinationX > > + * @param DestinationY > > + * @return > > + */ > > +STATIC EFI_STATUS > > +CheckBounds ( > > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL* This, > > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, > > + IN UINTN SourceX, > > + IN UINTN SourceY, > > + IN UINTN Width, > > + IN UINTN Height, > > + IN UINTN DestinationX, > > + IN UINTN DestinationY > > + ) > > +{ > > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev; > > + EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop; > > + > > + UsbDisplayLinkDev =3D USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTO= COL(This); > > + Gop =3D &UsbDisplayLinkDev->GraphicsOutputProtocol; > > + > > + CONST EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* ScreenMode =3D Gop->Mode= ->Info; > > + > > + if (BltOperation =3D=3D EfiBltVideoToBltBuffer || BltOperation =3D= =3D EfiBltVideoToVideo) { > > + if (SourceY + Height > ScreenMode->VerticalResolution) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + if (SourceX + Width > ScreenMode->HorizontalResolution) { > > + return EFI_INVALID_PARAMETER; > > + } > > + } > > + > > + if (BltOperation =3D=3D EfiBltBufferToVideo > > + || BltOperation =3D=3D EfiBltVideoToVideo > > + || BltOperation =3D=3D EfiBltVideoFill) { > > + if (DestinationY + Height > ScreenMode->VerticalResolution) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + if (DestinationX + Width > ScreenMode->HorizontalResolution) { > > + return EFI_INVALID_PARAMETER; > > + } > > + } > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + * Update the local copy of the Frame Buffer. This local copy is perio= dically transmitted to the > > + * DisplayLink device (via DlGopSendScreenUpdate) > > + * @param UsbDisplayLinkDev > > + * @param BltBuffer > > + * @param BltOperation > > + * @param SourceX > > + * @param SourceY > > + * @param DestinationX > > + * @param DestinationY > > + * @param Width > > + * @param Height > > + * @param BltBufferStride > > + * @param PixelsPerScanLine > > + */ > > +STATIC VOID > > +BuildBackBuffer ( > > + IN USB_DISPLAYLINK_DEV *UsbDisplayLinkDev, > > + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL > > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, > > + IN UINTN SourceX, > > + IN UINTN SourceY, > > + IN UINTN DestinationX, > > + IN UINTN DestinationY, > > + IN UINTN Width, > > + IN UINTN Height, > > + IN UINTN BltBufferStride, > > + IN UINTN PixelsPerScanLine > > +) > > +{ > > + UINTN H; > > + UINTN W; > > + switch (BltOperation) { > > + case EfiBltVideoToBltBuffer: > > + { > > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt; > > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB; > > + Blt =3D (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)((UINT8 *)BltBuffer + (Des= tinationY * BltBufferStride) + DestinationX * sizeof > (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); > > + SrcB =3D UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine += SourceX; > > + > > + for (H =3D 0; H < Height; H++) { > > + for (W =3D 0; W < Width; W++) { > > + Blt[W] =3D *SrcB++; > > + } > > + Blt =3D (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBuff= erStride); > > + SrcB +=3D PixelsPerScanLine - Width; > > + } > > + } > > + break; > > + > > + case EfiBltBufferToVideo: > > + { > > + // Update the store of the area of the screen that is "dirty" - th= at we need to send in the next screen update. > > + if (DestinationY < UsbDisplayLinkDev->LastY1) { > > + UsbDisplayLinkDev->LastY1 =3D DestinationY; > > + } > > + if ((DestinationY + Height) > UsbDisplayLinkDev->LastY2) { > > + UsbDisplayLinkDev->LastY2 =3D DestinationY + Height; > > + } > > + > > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Blt; > > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB; > > + Blt =3D (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)(((UINT8 *)BltBuffer) + (= SourceY * BltBufferStride) + SourceX * sizeof *Blt); > > + DstB =3D UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanL= ine + DestinationX; > > + > > + for (H =3D 0; H < Height; H++) { > > + for (W =3D 0; W < Width; W++) { > > + *DstB++ =3D Blt[W]; > > + } > > + Blt =3D (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(((UINT8*)Blt) + BltBuff= erStride); > > + DstB +=3D PixelsPerScanLine - Width; > > + } > > + } > > + break; > > + > > + case EfiBltVideoToVideo: > > + { > > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcB; > > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB; > > + SrcB =3D UsbDisplayLinkDev->Screen + SourceY * PixelsPerScanLine += SourceX; > > + DstB =3D UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanL= ine + DestinationX; > > + > > + for (H =3D 0; H < Height; H++) { > > + for (W =3D 0; W < Width; W++) { > > + *DstB++ =3D *SrcB++; > > + } > > + SrcB +=3D PixelsPerScanLine - Width; > > + DstB +=3D PixelsPerScanLine - Width; > > + } > > + } > > + break; > > + > > + case EfiBltVideoFill: > > + { > > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* DstB; > > + DstB =3D UsbDisplayLinkDev->Screen + DestinationY * PixelsPerScanL= ine + DestinationX; > > + for (H =3D 0; H < Height; H++) { > > + for (W =3D 0; W < Width; W++) { > > + *DstB++ =3D *BltBuffer; > > + } > > + DstB +=3D PixelsPerScanLine - Width; > > + } > > + } > > + break; > > + default: break; > > + } > > +} > > + > > +/** > > + * Display a colour bar pattern on the DisplayLink device. > > + * @param UsbDisplayLinkDev > > + * @param PatternNumber > > + * @return > > + */ > > +EFI_STATUS > > +DlGopSendTestPattern ( > > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev, > > + IN UINTN PatternNumber) > > +{ > > + EFI_STATUS Status; > > + UINTN DataLen; > > + UINT8 *DstBuf; > > + UINT32 USBStatus; > > + > > + Status =3D EFI_SUCCESS; > > + DataLen =3D UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->Ho= rizontalResolution * 3; // Send 1 line @ 24 bits per > pixel > > + DstBuf =3D AllocateZeroPool (DataLen); > > + > > + if (DstBuf =3D=3D NULL) { > > + DEBUG ((DEBUG_ERROR, "SendTestPattern Failed to allocate memory\n"= )); > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + //DEBUG ((DEBUG_ERROR, "Called DlGopSendTestPattern %d\n", PatternNu= mber)); > > + > > + CONST UINT8 RedPixel[3] =3D { 0xFF, 0x00, 0x00 }; > > + CONST UINT8 GreenPixel[3] =3D { 0x00, 0xFF, 0x00 }; > > + CONST UINT8 BluePixel[3] =3D { 0x00, 0x00, 0xFF }; > > + CONST UINT8 YellowPixel[3] =3D { 0xFF, 0xFF, 0x00 }; > > + CONST UINT8 MagentaPixel[3] =3D { 0xFF, 0x00, 0xFF }; > > + CONST UINT8 CyanPixel[3] =3D { 0x00, 0xFF, 0xFF }; > > + > > + UINTN Row; > > + UINTN Column; > > + for (Row =3D 0; Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode= ->Info->VerticalResolution; Row++) { > > + for (Column =3D 0; Column < UsbDisplayLinkDev->GraphicsOutputProto= col.Mode->Info->HorizontalResolution; Column++) { > > + > > + if (0 =3D=3D PatternNumber) { > > + if (Row < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info= ->VerticalResolution / 3) { > > + CopyMem (&DstBuf[Column * 3], RedPixel, sizeof (RedPixel)); > > + } > > + else if (Row < (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode= ->Info->VerticalResolution * 2) / 3) > > + { > > + CopyMem (&DstBuf[Column * 3], GreenPixel, sizeof (GreenPixel= )); > > + } > > + else { > > + CopyMem (&DstBuf[Column * 3], BluePixel, sizeof (BluePixel))= ; > > + } > > + } > > + else { > > + if (Column < UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->I= nfo->HorizontalResolution / 3) { > > + CopyMem (&DstBuf[Column * 3], YellowPixel, sizeof (RedPixel)= ); > > + } > > + else if (Column < (UsbDisplayLinkDev->GraphicsOutputProtocol.M= ode->Info->HorizontalResolution * 2) / 3) > > + { > > + CopyMem (&DstBuf[Column * 3], MagentaPixel, sizeof (GreenPix= el)); > > + } > > + else { > > + CopyMem (&DstBuf[Column * 3], CyanPixel, sizeof (BluePixel))= ; > > + } > > + } > > + } > > + DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, DataLen, &USBStatus); > > + } > > + // Payload with length of 1 to terminate the frame > > + DlUsbBulkWrite (UsbDisplayLinkDev, DstBuf, 1, &USBStatus); > > + FreePool (DstBuf); > > + > > + return Status; > > +} > > + > > + > > +/** > > + * Transfer the latest copy of the Blt buffer over USB to the DisplayL= ink device > > + * @param UsbDisplayLinkDev > > + * @return > > + */ > > +EFI_STATUS > > +DlGopSendScreenUpdate ( > > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT32 USBStatus; > > + Status =3D EFI_SUCCESS; > > + > > + // If it has been a while since we sent an update, send a full scree= n. > > + // This allows us to update a hot-plugged monitor quickly. > > + if (UsbDisplayLinkDev->TimeSinceLastScreenUpdate > DISPLAYLINK_FULL_= SCREEN_UPDATE_PERIOD) { > > + UsbDisplayLinkDev->LastY1 =3D 0; > > + UsbDisplayLinkDev->LastY2 =3D UsbDisplayLinkDev->GraphicsOutputPro= tocol.Mode->Info->HorizontalResolution - 1; > > + } > > + > > + // If there has been no BLT since the last update/poll, drop out qui= etly. > > + if (UsbDisplayLinkDev->LastY2 < UsbDisplayLinkDev->LastY1) { > > + UsbDisplayLinkDev->TimeSinceLastScreenUpdate +=3D (DISPLAYLINK_SCR= EEN_UPDATE_TIMER_PERIOD / 1000); // Convert > us to ms > > + return EFI_SUCCESS; > > + } > > + > > + UsbDisplayLinkDev->TimeSinceLastScreenUpdate =3D 0; > > + > > + EFI_TPL OriginalTPL =3D gBS->RaiseTPL (TPL_NOTIFY); > > + > > + UINTN DataLen; > > + UINTN Width; > > + UINTN Height; > > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL* SrcPtr; > > + UINT8* DstPtr; > > + UINT8 DstBuffer[1920 * 3]; // Get rid of the magic numbers at some p= oint > > + // Could also use a buffer allocated at r= untime to store the line, stored in the USB_DISPLAYLINK_DEV > structure. > > + UINTN H; > > + > > + DataLen =3D UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->Ho= rizontalResolution * 3; // Send 1 line @ 24 bits per > pixel > > + Width =3D UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->Hori= zontalResolution; > > + Height =3D UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info->Ver= ticalResolution; > > + SrcPtr =3D UsbDisplayLinkDev->Screen; > > + DstPtr =3D DstBuffer; > > + > > + for (H =3D 0; H < Height; H++) { > > + DstPtr =3D DstBuffer; > > + > > + UINTN W; > > + for (W =3D 0; W < Width; W++) { > > + // Need to swap round the RGB values > > + DstPtr[0] =3D ((UINT8 *)SrcPtr)[2]; > > + DstPtr[1] =3D ((UINT8 *)SrcPtr)[1]; > > + DstPtr[2] =3D ((UINT8 *)SrcPtr)[0]; > > + SrcPtr++; > > + DstPtr +=3D 3; > > + } > > + > > + Status =3D DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, DataLen, = &USBStatus); > > + > > + // USBStatus values defined in usbio.h, e.g. EFI_USB_ERR_TIMEOUT 0= x40 > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pixel= data failed. Line %d len %d, failure code %r USB > status x%x\n", H, DataLen, Status, USBStatus)); > > + break; > > + } > > + // Need an extra DlUsbBulkWrite if the data length is divisible by= USB MaxPacketSize. This spare data will just get written > into the (invisible) stride area. > > + // Note that the API doesn't let us do a bulk write of 0. > > + if ((DataLen & (UsbDisplayLinkDev->BulkOutEndpointDescriptor.MaxPa= cketSize - 1)) =3D=3D 0) { > > + Status =3D DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 2, &USB= Status); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Screen update - USB bulk transfer of pix= el data failed. Line %d len %d, failure code %r USB > status x%x\n", H, DataLen, Status, USBStatus)); > > + break; > > + } > > + } > > + } > > + > > + if (!EFI_ERROR (Status)) { > > + // If we've successfully transmitted the frame, reset the values t= hat store which area of the screen has been BLTted to. > > + // If we haven't succeeded, this will mean we'll try to resend it = after the next poll period. > > + UsbDisplayLinkDev->LastY2 =3D 0; > > + UsbDisplayLinkDev->LastY1 =3D (UINTN)-1; > > + } > > + > > + // Payload with length of 1 to terminate the frame > > + // We need to do this even if we had an error, to indicate to the DL= device that it should now expect a new frame. > > + DlUsbBulkWrite (UsbDisplayLinkDev, DstBuffer, 1, &USBStatus); > > + > > + gBS->RestoreTPL (OriginalTPL); > > + > > + return Status; > > +} > > + > > +/** > > + * Calculate the video refresh rate from the video timing parameters (= pixel clock etc) > > + * @param videoMode > > + * @return > > + */ > > +#ifndef MDEPKG_NDEBUG > > +STATIC inline UINT16 > > +CalculateRefreshRate ( > > + IN CONST struct VideoMode *VideoMode) > > +{ > > + UINT16 RefreshRate; > > + UINT16 Rmod; > > + UINT16 Rate10Hz; > > + > > + RefreshRate =3D (VideoMode->PixelClock * 10000) / ((VideoMode->HActi= ve + VideoMode->HBlanking) * (VideoMode->VActive > + VideoMode->VBlanking)); > > + Rmod =3D RefreshRate % 10; > > + Rate10Hz =3D RefreshRate - Rmod; > > + > > + if (Rmod >=3D 5) { > > + Rate10Hz +=3D 10; > > + } > > + return Rate10Hz; > > +} > > +#endif // MDEPKG_NDEBUG > > +/* > *************************************************************************= **************************** */ > > +/* > *************************************************************************= **************************** */ > > +/* ****************** START OF FUNCTIONS WHICH IMPLEMENT GOP IN= TERFACE ****************** */ > > +/* > *************************************************************************= **************************** */ > > +/* > *************************************************************************= **************************** */ > > + > > + > > +/** > > + * > > + * @param Gop Pointer to the instance of the GOP protocol > > + * @param ModeNumber > > + * @param SizeOfInfo > > + * @param Info > > + * @return > > + */ > > +EFI_STATUS > > +EFIAPI > > +DisplayLinkQueryMode ( > > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop, > > + IN UINT32 ModeNumber, > > + OUT UINTN *SizeOfInfo, > > + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info > > +) > > +{ > > + USB_DISPLAYLINK_DEV *Dev; > > + CONST struct VideoMode *VideoMode; > > + EFI_STATUS Status; > > + > > + Dev =3D USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(Gop); > > + Status =3D EFI_INVALID_PARAMETER; > > + > > + if ((SizeOfInfo =3D=3D NULL) || (Info =3D=3D NULL)) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // Get a video mode from the EDID > > + Status =3D DlEdidGetSupportedVideoModeWithFallback (ModeNumber, Dev-= >EdidActive.Edid, Dev->EdidActive.SizeOfEdid, > &VideoMode); > > + > > + if (!EFI_ERROR (Status)) { > > + > > + *Info =3D (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocatePool (siz= eof > (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); > > + if (*Info =3D=3D NULL) { > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + DEBUG ((DEBUG_INFO, "BIOS querying mode number %d - returning %dx%= d @ %dHz\n", ModeNumber, VideoMode- > >HActive, VideoMode->VActive, CalculateRefreshRate (VideoMode))); > > + > > + *SizeOfInfo =3D sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); > > + > > + (*Info)->Version =3D 0; > > + (*Info)->HorizontalResolution =3D VideoMode->HActive; > > + (*Info)->VerticalResolution =3D VideoMode->VActive; > > + (*Info)->PixelFormat =3D PixelBltOnly; > > + (*Info)->PixelsPerScanLine =3D (*Info)->HorizontalResolution; > > + (*Info)->PixelInformation.RedMask =3D 0; > > + (*Info)->PixelInformation.GreenMask =3D 0; > > + (*Info)->PixelInformation.BlueMask =3D 0; > > + (*Info)->PixelInformation.ReservedMask =3D 0; > > + } > > + return Status; > > +} > > + > > +/** > > + * > > + * @param Gop Pointer to the instance of the GOP protocol > > + * @param ModeNumber > > + * @return > > + */ > > +EFI_STATUS > > +EFIAPI > > +DisplayLinkSetMode ( > > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop, > > + IN UINT32 ModeNumber > > +) > > +{ > > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev; > > + EFI_STATUS Status; > > + CONST struct VideoMode *VideoMode; > > + > > + UsbDisplayLinkDev =3D USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTO= COL(Gop); > > + > > + // Prevent the DisplayLinkPeriodicTimer from interrupting us (bug 28= 877). > > + // When the driver is manually loaded, the TPL is TPL_NOTIFY (16) wh= ich prevents the interrupt from the timer. > > + // When the GOP driver is sideloaded, the TPL of this call is TPL_AP= PLICATION (4) and the timer can interrupt us. > > + Gop->Mode->Mode =3D GRAPHICS_OUTPUT_INVALID_MODE_NUMBER; > > + > > + // Get a video mode from the EDID > > + Status =3D DlEdidGetSupportedVideoModeWithFallback (ModeNumber, UsbD= isplayLinkDev->EdidActive.Edid, > UsbDisplayLinkDev->EdidActive.SizeOfEdid, &VideoMode); > > + > > + if (EFI_ERROR (Status)) { > > + return Status; > > + } > > + > > + Gop->Mode->Info->Version =3D 0; > > + Gop->Mode->Info->HorizontalResolution =3D VideoMode->HActive; > > + Gop->Mode->Info->VerticalResolution =3D VideoMode->VActive; > > + Gop->Mode->Info->PixelFormat =3D PixelBltOnly; > > + Gop->Mode->Info->PixelsPerScanLine =3D Gop->Mode->Info->HorizontalRe= solution; > > + Gop->Mode->SizeOfInfo =3D sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATI= ON); > > + Gop->Mode->FrameBufferBase =3D (EFI_PHYSICAL_ADDRESS)(UINTN)NULL; > > + Gop->Mode->FrameBufferSize =3D 0; > > + > > + // > > + // Allocate the back buffer > > + // > > + if (UsbDisplayLinkDev->Screen !=3D NULL) { > > + FreePool (UsbDisplayLinkDev->Screen); > > + } > > + > > + UsbDisplayLinkDev->Screen =3D (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)Alloca= teZeroPool ( > > + Gop->Mode->Info->HorizontalResolution * > > + Gop->Mode->Info->VerticalResolution * > > + sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); > > + > > + if (UsbDisplayLinkDev->Screen =3D=3D NULL) { > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + DEBUG ((DEBUG_INFO, "Video mode %d selected by BIOS - %d x %d.\n", M= odeNumber, VideoMode->HActive, VideoMode- > >VActive)); > > + // Wait until we are sure that we can set the video mode before we t= ell the firmware > > + Status =3D DlUsbSendControlWriteMessage (UsbDisplayLinkDev, SET_VIDE= O_MODE, 0, VideoMode, sizeof (struct > VideoMode)); > > + > > + if (Status !=3D EFI_SUCCESS) { > > + // Flag up that we haven't set the video mode correctly yet. > > + DEBUG ((DEBUG_ERROR, "Failed to send USB message to DisplayLink de= vice to set monitor video mode. Monitor > connected correctly?\n")); > > + Gop->Mode->Mode =3D GRAPHICS_OUTPUT_INVALID_MODE_NUMBER; > > + FreePool (UsbDisplayLinkDev->Screen); > > + UsbDisplayLinkDev->Screen =3D NULL; > > + } else { > > + BuildBackBuffer ( > > + UsbDisplayLinkDev, > > + UsbDisplayLinkDev->Screen, > > + EfiBltBufferToVideo, > > + 0, 0, > > + 0, 0, > > + Gop->Mode->Info->HorizontalResolution, > > + Gop->Mode->Info->VerticalResolution, > > + Gop->Mode->Info->HorizontalResolution * sizeof (EFI_GRAPHICS_OUT= PUT_BLT_PIXEL), > > + Gop->Mode->Info->HorizontalResolution); > > + // unlock the DisplayLinkPeriodicTimer > > + Gop->Mode->Mode =3D ModeNumber; > > + } > > + > > + return Status; > > +} > > + > > +/** > > + * Implementation of the GOP protocol Blt API function > > + * @param This Pointer to the instance of the GOP protocol > > + * @param BltBuffer > > + * @param BltOperation > > + * @param SourceX > > + * @param SourceY > > + * @param DestinationX > > + * @param DestinationY > > + * @param Width > > + * @param Height > > + * @param Delta > > + * @return > > + */ > > +EFI_STATUS > > +EFIAPI > > +DisplayLinkBlt ( > > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > > + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL > > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, > > + IN UINTN SourceX, > > + IN UINTN SourceY, > > + IN UINTN DestinationX, > > + IN UINTN DestinationY, > > + IN UINTN Width, > > + IN UINTN Height, > > + IN UINTN Delta OPTIONAL > > +) > > +{ > > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev; > > + UsbDisplayLinkDev =3D USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTO= COL(This); > > + > > + // Drop out if we haven't set the video mode up yet > > + if (This->Mode->Mode =3D=3D GRAPHICS_OUTPUT_INVALID_MODE_NUMBER) { > > + return EFI_SUCCESS; > > + } > > + > > + if ((BltOperation < 0) || (BltOperation >=3D EfiGraphicsOutputBltOpe= rationMax)) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + if (Width =3D=3D 0 || Height =3D=3D 0) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // Lock so we make an atomic write the frame buffer. > > + // We would not want a timer based event (Cursor, ...) to come in wh= ile we are doing this operation. > > + EFI_TPL OriginalTPL =3D gBS->RaiseTPL (TPL_NOTIFY); > > + > > + CONST UINTN BltBufferStride =3D (Delta =3D=3D 0) ? Width * sizeof (E= FI_GRAPHICS_OUTPUT_BLT_PIXEL) : Delta; > > + CONST EFI_STATUS boundsCheckStatus =3D CheckBounds (This, BltOperati= on, SourceX, SourceY, Width, Height, DestinationX, > DestinationY); > > + if (EFI_ERROR (boundsCheckStatus)) { > > + gBS->RestoreTPL (OriginalTPL); > > + return boundsCheckStatus; > > + } > > + > > + BuildBackBuffer (UsbDisplayLinkDev, BltBuffer, BltOperation, SourceX= , SourceY, DestinationX, DestinationY, Width, Height, > BltBufferStride, This->Mode->Info->PixelsPerScanLine); > > + > > + gBS->RestoreTPL (OriginalTPL); > > + return EFI_SUCCESS; > > +} > > + > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescr= iptors.c > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.c > > new file mode 100644 > > index 000000000000..c12a80a6e1ab > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.= c > > @@ -0,0 +1,145 @@ > > +/** > > + * @file UsbDescriptors.c > > + * @brief Functions to read USB Interface and Capabilities descriptors > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#include "UsbDisplayLink.h" > > +#include "UsbDescriptors.h" > > + > > +/** > > + * > > + * @param UsbIo > > + * @param descriptorType > > + * @param index > > + * @param Buffer > > + * @param Length > > + * @param UsbStatus > > + * @return > > + */ > > +STATIC EFI_STATUS > > +ReadDescriptor ( > > + IN EFI_USB_IO_PROTOCOL *UsbIo, > > + UINT8 DescriptorType, > > + UINT8 Index, > > + VOID* Buffer, > > + UINT16 Length, > > + UINT32* UsbStatus) > > +{ > > + EFI_STATUS Status; > > + > > + UINT8 Header[2]; > > + ZeroMem (Header, sizeof (Header)); > > + > > + EFI_USB_DEVICE_REQUEST Request; > > + ZeroMem (&Request, sizeof (Request)); > > + Request.RequestType =3D USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_STANDARD = | USB_TARGET_DEVICE; > > + Request.Request =3D USB_REQ_GET_DESCRIPTOR; > > + Request.Index =3D 0; > > + Request.Value =3D DescriptorType << 8 | Index; > > + Request.Length =3D sizeof (Header); > > + > > + // Read the descriptor header to see how many bytes it contains > > + Status =3D UsbIo->UsbControlTransfer ( > > + UsbIo, > > + &Request, > > + EfiUsbDataIn, > > + DISPLAYLINK_USB_CTRL_TIMEOUT, > > + Header, > > + sizeof (Header), > > + UsbStatus); > > + > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Failed to read length of descriptor type x%x= , index %u (code %r, USB status x%x)\n", > > + DescriptorType, Index, Status, *UsbStatus)); > > + return Status; > > + } > > + CONST UINT16 TotalLength =3D Header[0]; > > + > > + // Now we know the size of it, we can read the entire descriptor > > + Request.Length =3D TotalLength; > > + > > + Status =3D UsbIo->UsbControlTransfer ( > > + UsbIo, > > + &Request, > > + EfiUsbDataIn, > > + DISPLAYLINK_USB_CTRL_TIMEOUT, > > + Buffer, > > + TotalLength, > > + UsbStatus); > > + > > + return Status; > > +} > > + > > +/** > > + Perform a USB control transfer to read the DisplayLink vendor descri= ptor. > > + > > + @param UsbIo Pointer to the instance of the USBIO protocol > > + @param Buffer Pointer to the buffer where descriptor should be writ= ten > > + @param Length Length of buffer (and the maximum amount of descripto= r data that shall be read) > > + > > + @retval EFI_SUCCESS The descriptor has been copied into Buffer > > + @retval Other The descriptor could not be read > > +**/ > > +EFI_STATUS > > +ReadCapabilitiesDescriptor ( > > + IN EFI_USB_IO_PROTOCOL *UsbIo, > > + OUT VOID* Buffer, > > + IN UINT16 Length) > > +{ > > + UINT32 UsbStatus; > > + EFI_STATUS Status; > > + > > + Status =3D ReadDescriptor ( > > + UsbIo, > > + DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY, > > + 0, > > + Buffer, > > + Length, > > + &UsbStatus); > > + > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Could not read capabilities descriptor from = DL device (code %r, USB status x%x). Unrecognised > firmware version?\n", Status, UsbStatus)); > > + } > > + > > + return Status; > > +} > > + > > + > > +/** > > + An alternative to the UBSIO protocol function EFI_USB_IO_GET_INTERFAC= E_DESCRIPTOR. > > + This version allows you to specify an index. > > + * @param UsbIo Pointer to the instance of the USBIO p= rotocol > > + * @param interfaceDescriptor Where the descriptor should be written > > + * @param index The index of the descriptor required (= the standard USBIO function doesn't let you do this) > > + * @return > > + */ > > +EFI_STATUS > > +UsbDisplayLinkGetInterfaceDescriptor ( > > + IN EFI_USB_IO_PROTOCOL *UsbIo, > > + OUT EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor, > > + UINT8 Index > > + ) > > +{ > > + UINT32 UsbStatus; > > + EFI_STATUS Status; > > + > > + Status =3D ReadDescriptor ( > > + UsbIo, > > + USB_DESC_TYPE_INTERFACE, > > + Index, > > + InterfaceDescriptor, > > + sizeof (EFI_USB_INTERFACE_DESCRIPTOR), > > + &UsbStatus); > > + > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "USB control transfer failed while reading in= terface descriptor (code %r, USB status x%x)\n", > Status, UsbStatus)); > > + } > > + > > + return Status; > > +} > > + > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescr= iptors.h > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.h > > new file mode 100644 > > index 000000000000..cdc01aad193a > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDescriptors.= h > > @@ -0,0 +1,109 @@ > > +/** > > + * @file UsbDescriptors.h > > + * @brief Functions to read USB Interface and Capabilities descriptors > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#ifndef USB_DESCRIPTORS_H_ > > +#define USB_DESCRIPTORS_H_ > > + > > + /** > > + Type of the Direct Framebuffer capability descriptor. > > + This is a vendor specific USB descriptor for DisplayLink. > > + @see NR-140082 Section 3.5 > > + **/ > > +#define DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY 0x5e > > + > > + /** > > + Identifiers for capabllity keys > > + @see NR-140082 Section 3.2 > > + **/ > > + > > + /** > > + Key for Capabilities 1 - See section 3.2.1 > > + **/ > > +#define CAPABILITIES1_KEY 0x0 > > + > > + /** > > + Lengths for capabllity fields > > + **/ > > +#define CAPABILITIES1_LENGTH 0x4 > > + > > + /** > > + Bits for the capability bitmask Capabilities1 > > + **/ > > + > > + /** > > + This is the first capability defined for the protocol. > > + It represents the mode of operation as of initial release. > > + If a device ever breaks compatibility with this initial release, > > + it will cease > > + to support CapabilityBaseProtocol. > > + **/ > > +#define CAPABILITIES1_BASE_PROTOCOL (1 << 0) > > + > > + /** > > + Idealised VendorDescriptor which is the result > > + of parsing vendor descriptor from device. > > + **/ > > + typedef struct { > > + UINT32 Capabilities1; > > + } VendorDescriptor; > > + > > +#pragma pack(push, 1) > > + typedef struct { > > + UINT16 Key; /** Really of type enum DescrptorKeys */ > > + UINT8 Length; > > + UINT8 Value[]; > > + } DescriptorKLV; > > + > > + typedef struct { > > + UINT8 Length; > > + UINT8 Type; > > + UINT16 CapabilityVersion; > > + UINT8 CapabilityLength; > > + UINT8 Klv[]; > > + } VendorDescriptorGeneric; > > +#pragma pack(pop) > > + > > + > > +EFI_STATUS UsbDisplayLinkGetInterfaceDescriptor ( > > + IN EFI_USB_IO_PROTOCOL *UsbIo, > > + EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor, > > + UINT8 index > > + ); > > + > > +EFI_STATUS ReadCapabilitiesDescriptor (IN EFI_USB_IO_PROTOCOL *UsbIo, = VOID* Buffer, UINT16 Length); > > + > > +/** > > +Parse data in buffer to a VendorDescriptor, if possible. > > + > > +@param Data Buffer > > +@param Length Length of buffer > > + > > +@retval EFI_SUCCESS The descriptor was parsed successfully > > +@retval EFI_UNSUPPORTED Simple Pointer Protocol is not installed on C= ontroller. > > +**/ > > +EFI_STATUS > > +UsbDisplayLinkParseCapabilitiesDescriptor ( > > + CONST IN VOID* Data, > > + IN UINTN Length, > > + OUT VendorDescriptor* Descriptor > > +); > > + > > +/** > > +Decide if binding may proceed, given capabilities > > + > > +@retval TRUE Binding may proceed > > +@retval FALSE Binding is not possible > > +**/ > > +BOOLEAN > > +UsbDisplayLinkCapabilitiesSufficientToBind ( > > + CONST IN VendorDescriptor* Descriptor > > +); > > + > > +#endif // USB_DESCRIPTORS_H_ > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDispl= ayLink.c > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.c > > new file mode 100644 > > index 000000000000..997a3e307f38 > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.= c > > @@ -0,0 +1,1082 @@ > > +/** > > + * @file UsbDisplayLink.c > > + * @brief USB DisplayLink Driver that manages USB DisplayLink device a= nd produces Graphics Output Protocol > > + * This file implements the functions of the Driver Binding / Start / = Stop / Unload interface > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#include "UsbDisplayLink.h" > > + > > +#include > > +#include > > +#include > > + > > +#include "Edid.h" > > +#include "UsbDescriptors.h" > > + > > +// > > +// Functions of Driver Binding Protocol > > +// > > + > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverBindingSupported ( > > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > > + IN EFI_HANDLE Controller, > > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > > +); > > + > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverBindingStart ( > > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > > + IN EFI_HANDLE Controller, > > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > > +); > > + > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverBindingStop ( > > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > > + IN EFI_HANDLE Controller, > > + IN UINTN NumberOfChildren, > > + IN EFI_HANDLE *ChildHandleBuffer > > +); > > + > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverBindingEntryPoint ( > > + IN EFI_HANDLE ImageHandle, > > + IN EFI_SYSTEM_TABLE *SystemTable > > +); > > + > > + > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverCombinedGopBindingEntryPoint ( > > + IN EFI_HANDLE ImageHandle, > > + IN EFI_SYSTEM_TABLE *SystemTable, > > + IN EFI_HANDLE DriverBindingHandle > > +); > > + > > + > > +// Generated with https://www.guidgen.com/ - "B70E5A79-C6D6-4267-B02E-= 9108C989E287" > > +EFI_GUID gEfiDlGopVariableGuid =3D { 0xB70E5A79, 0xC6D6, 0x4267,{ 0xB0= , 0x2E, 0x91, 0x08, 0xC9, 0x89, 0xE2, 0x87 } }; > > + > > + > > +EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding =3D { > > + UsbDisplayLinkDriverBindingSupported, > > + UsbDisplayLinkDriverBindingStart, > > + UsbDisplayLinkDriverBindingStop, > > + INF_DRIVER_VERSION, > > + NULL, > > + NULL > > +}; > > + > > + > > +/** > > + * Reads integer environment variable with default fallback. > > + * @param variableName variable name to read > > + * @param defaultValue default value to return if requested not foun= d > > + */ > > +STATIC UINT32 > > +ReadEnvironmentInt ( > > + CHAR16 *VariableName, > > + UINT32 DefaultValue > > + ) > > +{ > > + UINT32 Result; > > + UINTN DataSize; > > + DataSize =3D sizeof (Result); > > + CONST EFI_STATUS Status =3D gRT->GetVariable (VariableName, &gEfiDlG= opVariableGuid, (UINT32*)NULL, &DataSize, > &Result); > > + if (!EFI_ERROR (Status) && (sizeof (Result) =3D=3D DataSize)) { > > + return Result; > > + } > > + return DefaultValue; > > +} > > + > > +/** > > +* Reads boolean environment variable with default fallback. > > +* @param variableName variable name to read > > +* @param defaultValue default value to return if requested not found > > +*/ > > +STATIC BOOLEAN > > +ReadEnvironmentBool ( > > + CHAR16 *VariableName, > > + BOOLEAN DefaultValue > > + ) > > +{ > > + return ReadEnvironmentInt (VariableName, DefaultValue ? 1 : 0) =3D= =3D 1; > > +} > > + > > + > > +/** > > +* > > +* @param UsbDisplayLinkDev > > +* @return > > +*/ > > +STATIC EFI_STATUS > > +InitializeUsbDisplayLinkDevice ( > > + IN OUT USB_DISPLAYLINK_DEV *UsbDisplayLinkDev > > +) > > +{ > > + EFI_GRAPHICS_OUTPUT_PROTOCOL* Gop; > > + Gop =3D &UsbDisplayLinkDev->GraphicsOutputProtocol; > > + Gop->QueryMode =3D DisplayLinkQueryMode; > > + Gop->SetMode =3D DisplayLinkSetMode; > > + Gop->Blt =3D DisplayLinkBlt; > > + > > + // > > + // Allocate buffer for Graphics Output Protocol mode information > > + // > > + Gop->Mode =3D (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE*)AllocatePool (size= of > (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)); > > + if (Gop->Mode =3D=3D NULL) { > > + return EFI_OUT_OF_RESOURCES; > > + } > > + Gop->Mode->Info =3D (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*)AllocateP= ool (sizeof > (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); > > + if (Gop->Mode->Info =3D=3D NULL) { > > + FreePool (Gop->Mode); > > + Gop->Mode =3D NULL; > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + Gop->Mode->MaxMode =3D MAX(1, DlEdidGetNumSupportedModesInEdid (UsbD= isplayLinkDev->EdidActive.Edid, > UsbDisplayLinkDev->EdidActive.SizeOfEdid)); > > + > > + Gop->Mode->Mode =3D GRAPHICS_OUTPUT_INVALID_MODE_NUMBER; > > + Gop->Mode->Info->Version =3D 0; > > + // Initialising the horizontal resolution prevents certain BIOSs fro= m hanging on boot, but > > + // it is not yet clear why. See bug 28194. > > + Gop->Mode->Info->HorizontalResolution =3D DlVideoModeGetSupportedVid= eoMode (0)->HActive; > > + Gop->Mode->Info->VerticalResolution =3D 0; > > + Gop->Mode->Info->PixelFormat =3D PixelBltOnly; > > + Gop->Mode->Info->PixelsPerScanLine =3D 0; > > + Gop->Mode->SizeOfInfo =3D sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATI= ON); > > + Gop->Mode->FrameBufferBase =3D (EFI_PHYSICAL_ADDRESS)(UINTN)NULL; > > + Gop->Mode->FrameBufferSize =3D 0; > > + > > + // Prevent DlGopSendScreenUpdate from running until we are sure that= the video mode is set > > + UsbDisplayLinkDev->LastY2 =3D 0; > > + UsbDisplayLinkDev->LastY1 =3D (UINTN)-1; > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Look for alternate settings for the UsbIo handle's interface > > + which offer protocol DL_PROTOCOL_DIRECT_FB. > > + > > + @retval -1 Not found > > + @retval Other The alternate setting > > +**/ > > +STATIC INTN > > +GetDirectFbAltSetting ( > > + IN EFI_USB_IO_PROTOCOL *UsbIo, > > + IN UINT8 ParentInterfaceNumber > > + ) > > +{ > > + EFI_STATUS Status; > > + INTN AltSettingIndex; > > + UINT16 InterfaceIndex; > > + > > + AltSettingIndex =3D -1; > > + > > + for (InterfaceIndex =3D 0; InterfaceIndex <=3D 0xFF; InterfaceIndex+= +) { > > + EFI_USB_INTERFACE_DESCRIPTOR interfaceDescriptor; > > + Status =3D UsbDisplayLinkGetInterfaceDescriptor (UsbIo, &interface= Descriptor, (UINT8)InterfaceIndex); > > + if (EFI_ERROR (Status)) { > > + break; > > + } > > + > > + if (interfaceDescriptor.InterfaceNumber =3D=3D ParentInterfaceNumb= er && > > + (interfaceDescriptor.InterfaceClass =3D=3D CLASS_VENDOR) && > > + interfaceDescriptor.InterfaceProtocol =3D=3D INTERFACE_PROTOCO= L_DIRECT_FB) { > > + AltSettingIndex =3D interfaceDescriptor.AlternateSetting; > > + break; > > + } > > + } > > + return AltSettingIndex; > > +} > > + > > +/** > > + * > > + * @param UsbIo > > + * @param altSettingIndex > > + * @return > > + */ > > +STATIC EFI_STATUS > > +SelectAltSetting ( > > + IN EFI_USB_IO_PROTOCOL *UsbIo, > > + IN UINTN AltSettingIndex) > > +{ > > + // Set alternate setting 1 on the interface > > + EFI_STATUS Status; > > + UINT32 UsbStatus; > > + EFI_USB_DEVICE_REQUEST Request; > > + ZeroMem (&Request, sizeof (Request)); > > + Request.RequestType =3D USB_REQ_TYPE_STANDARD | USB_TARGET_INTERFACE= ; > > + Request.Request =3D USB_REQ_SET_INTERFACE; > > + Request.Index =3D DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO; > > + Request.Value =3D (UINT16)AltSettingIndex; > > + > > + Status =3D UsbIo->UsbControlTransfer ( > > + UsbIo, > > + &Request, > > + EfiUsbNoData, > > + DISPLAYLINK_USB_CTRL_TIMEOUT, > > + NULL, > > + 0, > > + &UsbStatus); > > + > > + if (EFI_ERROR (Status)) { > > + Status =3D EFI_UNSUPPORTED; > > + DEBUG ((DEBUG_ERROR, "USB control transfer failed while attempting= to select alt setting %d on interface (code %r, USB > status x%x). DisplayLink device has unsupported firmware version?\n", Alt= SettingIndex, Status, UsbStatus)); > > + } > > + return Status; > > +} > > + > > + > > +/** > > + Report whether the driver can support the device attached via UsbIo > > + by seeing what if any capabilities it reports. > > + > > + @retval TRUE Device has sufficient capabilities for this driver. > > + @retval FALSE Device lacks sufficient capabilities. > > +**/ > > +STATIC BOOLEAN > > +CapabilitiesSupported ( > > + IN EFI_USB_IO_PROTOCOL *UsbIo > > + ) > > +{ > > + UINT8 Buffer[256]; > > + EFI_STATUS Status; > > + > > + Status =3D ReadCapabilitiesDescriptor (UsbIo, Buffer, sizeof (Buffer= )); > > + if (EFI_ERROR (Status)) { > > + return FALSE; > > + } > > + > > + VendorDescriptor descriptor; > > + Status =3D UsbDisplayLinkParseCapabilitiesDescriptor (Buffer, sizeof= (Buffer), &descriptor); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Failed to parse capabilities descriptor (cod= e %r)\n", Status)); > > + return FALSE; > > + } > > + > > + return UsbDisplayLinkCapabilitiesSufficientToBind (&descriptor); > > +} > > + > > + > > +/** > > + * > > + * @param UsbIo > > + * @param InterfaceDescriptor > > + * @param altSettingIndex > > + * @return > > + */ > > +STATIC BOOLEAN > > +IsDLDirectFbCapableInterface ( > > + IN EFI_USB_IO_PROTOCOL *UsbIo, > > + IN EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor, > > + IN INTN *AltSettingIndex) > > +{ > > + EFI_STATUS Status; > > + EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor; > > + > > + Status =3D UsbIo->UsbGetDeviceDescriptor (UsbIo, &DeviceDescriptor); > > + > > + if (EFI_ERROR (Status)) { > > + return FALSE; > > + } > > + > > + if (DeviceDescriptor.IdVendor !=3D VENDOR_DISPLAYLINK) { > > + return FALSE; > > + } > > + > > + Status =3D UsbIo->UsbGetInterfaceDescriptor (UsbIo, InterfaceDescrip= tor); > > + if (EFI_ERROR (Status)) { > > + return FALSE; > > + } > > + > > + // We can assume that the interface that we want to talk to - the NI= VO interface - is number 0 > > + if (InterfaceDescriptor->InterfaceNumber !=3D DISPLAYLINK_USB_INTERF= ACE_NUMBER_NIVO) { > > + return FALSE; > > + } > > + > > + // Check if we have an interface (alt setting) descriptor with the c= orrect interface protocol > > + *AltSettingIndex =3D GetDirectFbAltSetting (UsbIo, InterfaceDescript= or->InterfaceNumber); > > + > > + if (*AltSettingIndex =3D=3D -1) { > > + DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to find setting on d= evice which supports GOP functionality. Check > firmware / device version?\n")); > > + return FALSE; > > + } > > + > > + // Now check that the capabilities that we need are properly support= ed > > + if (CapabilitiesSupported (UsbIo) =3D=3D FALSE) { > > + DEBUG ((DEBUG_ERROR, "DisplayLink GOP: DL device detected, but it = doesn't support the required GOP features. Check > firmware / device version?\n")); > > + return FALSE; > > + } > > + > > + return TRUE; > > +} > > + > > + > > +/** > > + * Prints a block of text in the framebuffer (helper function). > > + * @param X x coordinate > > + * @param Y y coordinate > > + */ > > +STATIC VOID > > +DisplayLinkPrintTextToScreenInternal ( > > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, > > + UINTN X, > > + UINTN Y, > > + IN CHAR16 *Buffer > > + ) > > +{ > > + EFI_STATUS Status; > > + EFI_HII_FONT_PROTOCOL *HiiFont; > > + EFI_IMAGE_OUTPUT *Blt; > > + EFI_FONT_DISPLAY_INFO FontInfo; > > + EFI_HII_OUT_FLAGS Flags; > > + > > + Blt =3D (EFI_IMAGE_OUTPUT*)NULL; > > + > > + Status =3D gBS->LocateProtocol (&gEfiHiiFontProtocolGuid, NULL, (VOI= D **)&HiiFont); > > + if (!EFI_ERROR (Status)) { > > + Blt =3D (EFI_IMAGE_OUTPUT*)AllocateZeroPool (sizeof (EFI_IMAGE_OUT= PUT)); > > + Blt->Width =3D (UINT16)GraphicsOutput->Mode->Info->HorizontalResol= ution; > > + Blt->Height =3D (UINT16)GraphicsOutput->Mode->Info->VerticalResolu= tion; > > + Blt->Image.Screen =3D GraphicsOutput; > > + > > + ZeroMem (&FontInfo, sizeof (EFI_FONT_DISPLAY_INFO)); > > + FontInfo.ForegroundColor.Red =3D 0; > > + FontInfo.ForegroundColor.Green =3D 0; > > + FontInfo.ForegroundColor.Blue =3D 0; > > + FontInfo.BackgroundColor.Red =3D 0xff; > > + FontInfo.BackgroundColor.Green =3D 0xff; > > + FontInfo.BackgroundColor.Blue =3D 0xff; > > + > > + Flags =3D EFI_HII_IGNORE_IF_NO_GLYPH | EFI_HII_OUT_FLAG_CLIP | > > + EFI_HII_OUT_FLAG_CLIP_CLEAN_X | EFI_HII_OUT_FLAG_CLIP_CLEA= N_Y | > > + EFI_HII_IGNORE_LINE_BREAK | EFI_HII_DIRECT_TO_SCREEN; > > + > > + Status =3D HiiFont->StringToImage ( > > + HiiFont, > > + Flags, > > + Buffer, > > + &FontInfo, > > + &Blt, > > + X, > > + Y, > > + (EFI_HII_ROW_INFO**)NULL, > > + (UINTN*)NULL, > > + (UINTN*)NULL); > > + } > > + > > + if (Blt !=3D NULL) { > > + FreePool (Blt); > > + } > > +} > > + > > + > > +/** > > +* Prints a block of text in the framebuffer. > > +* @param X x coordinate > > +* @param Y y coordinate > > +* @param Format string format similar to stdlib's vsnprintf > > +* @param ... arguments > > +*/ > > +VOID > > +EFIAPI > > +DlGopPrintTextToScreen ( > > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, > > + UINTN X, > > + UINTN Y, > > + IN CONST CHAR16 *Format, > > + ... > > + ) > > +{ > > + VA_LIST Marker; > > + CHAR16 *Buffer; > > + UINTN BufferSize; > > + > > + ASSERT (Format !=3D NULL); > > + ASSERT (((UINTN) Format & BIT0) =3D=3D 0); > > + > > + VA_START(Marker, Format); > > + > > + BufferSize =3D (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeo= f (CHAR16); > > + > > + Buffer =3D (CHAR16*)AllocatePool (BufferSize); > > + ASSERT (Buffer !=3D NULL); > > + > > + UnicodeVSPrint (Buffer, BufferSize, Format, Marker); > > + > > + VA_END(Marker); > > + > > + DisplayLinkPrintTextToScreenInternal (GraphicsOutput, X, Y, Buffer); > > + > > + FreePool (Buffer); > > +} > > + > > + > > +/** > > + * Sometimes platforms only write to the first GOP device that they fi= nd. Enabling this function allows us to copy the pixels > from this device. > > + * @param UsbDisplayLinkDev > > + */ > > +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE > > +STATIC VOID > > +DisplayLinkCopyFromPrimaryGopDevice ( > > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev > > + ) > > +{ > > + UINTN HandleCount; > > + EFI_HANDLE *HandleBuffer; > > + UINTN HandleIndex; > > + EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop; > > + > > + gBS->LocateHandleBuffer ( > > + ByProtocol, > > + &gEfiGraphicsOutputProtocolGuid, > > + NULL, > > + &HandleCount, > > + &HandleBuffer); > > + > > + for (HandleIndex =3D 0; HandleIndex < HandleCount; HandleIndex++) { > > + gBS->HandleProtocol (HandleBuffer[HandleIndex], &gEfiGraphicsOutpu= tProtocolGuid, (VOID**)&Gop); > > + if (Gop !=3D &UsbDisplayLinkDev->GraphicsOutputProtocol && Gop->Mo= de->FrameBufferBase !=3D > (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) { > > + > > + // See if we need to do a screen update - calculate a really noddy= hash to see if any screen updates have happened. > > + STATIC UINT32 prevframeBufferHash =3D 0; // 4 bytes per pixel > > + UINT32 currFrameBufferHash =3D 0; > > + UINTN i; > > + for (i =3D 0; i < (Gop->Mode->Info->HorizontalResolution * Gop->Mo= de->Info->VerticalResolution); i++) { > > + currFrameBufferHash +=3D ((UINT32*)(UINTN)Gop->Mode->FrameBuffer= Base)[i]; > > + } > > + > > + if (currFrameBufferHash !=3D prevframeBufferHash) { > > + prevframeBufferHash =3D currFrameBufferHash; > > + > > + DisplayLinkBlt ( > > + &UsbDisplayLinkDev->GraphicsOutputProtocol, > > + (EFI_GRAPHICS_OUTPUT_BLT_PIXEL*)(UINTN)Gop->Mode->FrameBufferB= ase, > > + EfiBltBufferToVideo, > > + 0, > > + 0, > > + 0, > > + 0, > > + Gop->Mode->Info->HorizontalResolution, > > + Gop->Mode->Info->VerticalResolution, > > + 0); > > + } > > + break; > > + } > > + } > > + > > + FreePool (HandleBuffer); > > +} > > +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE > > + > > + > > +/** > > + * Exit from boot services: signal handler. > > + */ > > +STATIC VOID > > +EFIAPI > > +DisplayLinkDriverExitBootServices ( > > + IN EFI_EVENT Event, > > + IN VOID *Context > > + ) > > +{ > > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev; > > + UsbDisplayLinkDev =3D (USB_DISPLAYLINK_DEV*)Context; > > + > > + gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent); > > +} > > + > > +/** > > + * Periodic screen update: timer callback. > > + */ > > +VOID > > +EFIAPI > > +DisplayLinkPeriodicTimer ( > > + IN EFI_EVENT Event, > > + IN VOID* Context > > + ) > > +{ > > + EFI_STATUS Status; > > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev; > > + > > + Status =3D EFI_SUCCESS; > > + UsbDisplayLinkDev =3D (USB_DISPLAYLINK_DEV*)Context; > > + > > + // Drop out if we haven't set the video mode up yet > > + if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Mode =3D=3D GRAP= HICS_OUTPUT_INVALID_MODE_NUMBER) { > > + // Restart the one-shot timer to poll the status again. > > + Status =3D gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRela= tive, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Failed to create timer.\n")); > > + } > > + return; > > + } > > + > > +#ifdef COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE > > + DisplayLinkCopyFromPrimaryGopDevice (UsbDisplayLinkDev); > > +#endif // COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE > > + > > + if (UsbDisplayLinkDev->ShowBandwidth) { > > + STATIC UINTN Count =3D 0; > > + > > + if (Count++ % 50 =3D=3D 0) { > > + DlGopPrintTextToScreen (&UsbDisplayLinkDev->GraphicsOutputProtoc= ol, 32, 48, (CONST CHAR16*)L" Bandwidth: %d > MB/s ", UsbDisplayLinkDev->DataSent * 10000000 / DISPLAYLINK_SCREEN_UP= DATE_TIMER_PERIOD / 50 / 1024 / 1024); > > + UsbDisplayLinkDev->DataSent =3D 0; > > + } > > + } > > + > > + if (UsbDisplayLinkDev->ShowTestPattern) > > + { > > + if (UsbDisplayLinkDev->ShowTestPattern =3D=3D 5) { > > + DlGopSendTestPattern (UsbDisplayLinkDev, 0); > > + } else if (UsbDisplayLinkDev->ShowTestPattern >=3D 10) { > > + DlGopSendTestPattern (UsbDisplayLinkDev, 1); > > + UsbDisplayLinkDev->ShowTestPattern =3D 0; > > + } > > + UsbDisplayLinkDev->ShowTestPattern++; > > + > > + } > > + > > + // Send the latest version of the frame buffer to the DL device over= USB > > + DlGopSendScreenUpdate (UsbDisplayLinkDev); > > + > > + // Restart the timer now we've finished > > + Status =3D gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelati= ve, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Failed to create timer.\n")); > > + } > > +} > > + > > +/* > *************************************************************************= ***************************** > */ > > +/* > *************************************************************************= ***************************** > */ > > +/* ****************** START OF FUNCTIONS WHICH IMPLEMENT DRIVER BIND= ING INTERFACE ****************** > */ > > +/* > *************************************************************************= ***************************** > */ > > +/* > *************************************************************************= ***************************** > */ > > + > > +/** > > + Check whether USB DisplayLink driver supports this device. > > + > > + @param This The USB DisplayLink driver binding pr= otocol. > > + @param Controller The controller handle to check. > > + @param RemainingDevicePath The remaining device path. > > + > > + @retval EFI_SUCCESS The driver supports this controller. > > + @retval other This device isn't supported. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverBindingSupported ( > > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > > + IN EFI_HANDLE Controller, > > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > > + ) > > +{ > > + EFI_STATUS Status; > > + EFI_USB_IO_PROTOCOL *UsbIo; > > + > > + Status =3D gBS->OpenProtocol ( > > + Controller, > > + &gEfiUsbIoProtocolGuid, > > + (VOID **) &UsbIo, > > + This->DriverBindingHandle, > > + Controller, > > + EFI_OPEN_PROTOCOL_BY_DRIVER); > > + > > + if (EFI_ERROR (Status)) { > > + return Status; > > + } > > + > > + // > > + // Use the USB I/O Protocol interface to check whether Controller is > > + // a DisplayLink device that can be managed by this driver. > > + // > > + Status =3D EFI_UNSUPPORTED; > > + EFI_USB_INTERFACE_DESCRIPTOR DummyInterfaceDescriptor; > > + INTN DummyAltSettingIndex; > > + > > + if (IsDLDirectFbCapableInterface (UsbIo, &DummyInterfaceDescriptor, = &DummyAltSettingIndex)){ > > + Status =3D EFI_SUCCESS; > > + } > > + > > + gBS->CloseProtocol ( > > + Controller, > > + &gEfiUsbIoProtocolGuid, > > + This->DriverBindingHandle, > > + Controller); > > + > > + return Status; > > +} > > + > > + > > +/** > > + Starts the DisplayLink device with this driver. > > + > > + This function consumes USB I/O Protocol, intializes USB DisplayLink = device, > > + installs Graphics Output Protocol > > + Transfer to manage the USB DisplayLink device. > > + > > + @param This The USB DisplayLink driver binding ins= tance. > > + @param Controller Handle of device to bind driver to. > > + @param RemainingDevicePath Optional parameter use to pick a speci= fic child > > + device to start. > > + > > + @retval EFI_SUCCESS This driver supports this device. > > + @retval EFI_UNSUPPORTED This driver does not support this devi= ce. > > + @retval EFI_DEVICE_ERROR This driver cannot be started due to d= evice Error. > > + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. > > + @retval EFI_ALREADY_STARTED This driver has been started. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverBindingStart ( > > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > > + IN EFI_HANDLE Controller, > > + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath > > + ) > > +{ > > + EFI_STATUS Status; > > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev; > > + UINT8 EndpointNumber; > > + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; > > + UINT8 Index; > > + BOOLEAN FoundOut; > > + BOOLEAN FoundIn; > > + EFI_TPL OriginalTPL; > > + INTN altSettingIndex; > > + > > + OriginalTPL =3D gBS->RaiseTPL (TPL_CALLBACK); > > + > > + UsbDisplayLinkDev =3D (USB_DISPLAYLINK_DEV*)AllocateZeroPool (sizeof= (USB_DISPLAYLINK_DEV)); > > + if (UsbDisplayLinkDev =3D=3D NULL) { > > + DEBUG ((DEBUG_ERROR, "Device initialialisation - Failed to allocat= e memory for device.\n")); > > + gBS->RestoreTPL (OriginalTPL); > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + UsbDisplayLinkDev->Signature =3D USB_DISPLAYLINK_DEV_SIGNATURE; > > + > > + UsbDisplayLinkDev->ShowBandwidth =3D ReadEnvironmentBool (L"DisplayL= inkShowBandwidth", FALSE); > > + UsbDisplayLinkDev->ShowTestPattern =3D ReadEnvironmentBool (L"Displa= yLinkShowTestPatterns", FALSE); > > + > > + // > > + // Open USB I/O Protocol > > + // > > + Status =3D gBS->OpenProtocol ( > > + Controller, > > + &gEfiUsbIoProtocolGuid, > > + (VOID **) &UsbDisplayLinkDev->UsbIo, > > + This->DriverBindingHandle, > > + Controller, > > + EFI_OPEN_PROTOCOL_BY_DRIVER); > > + > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Failed to open usbio protocol. Is USB correc= tly supported on this platform?.\n")); > > + Status =3D EFI_UNSUPPORTED; > > + goto ErrorExit2; > > + } > > + > > + if (!IsDLDirectFbCapableInterface (UsbDisplayLinkDev->UsbIo, &UsbDis= playLinkDev->InterfaceDescriptor, &altSettingIndex)) > { > > + Status =3D EFI_UNSUPPORTED; > > + goto ErrorExit4; > > + } > > + > > + Status =3D SelectAltSetting (UsbDisplayLinkDev->UsbIo, altSettingInd= ex); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "DisplayLink GOP: Failed to select alternate = setting.\n")); > > + Status =3D EFI_UNSUPPORTED; > > + goto ErrorExit4; > > + } > > + > > + // > > + // Parse endpoint descriptor > > + // > > + EndpointNumber =3D UsbDisplayLinkDev->InterfaceDescriptor.NumEndpoin= ts; > > + > > + // > > + // Traverse endpoints to find bulk endpoint > > + // > > + FoundOut =3D FALSE; > > + FoundIn =3D FALSE; > > + for (Index =3D 0; Index < EndpointNumber; Index++) { > > + UsbDisplayLinkDev->UsbIo->UsbGetEndpointDescriptor ( > > + UsbDisplayLinkDev->UsbIo, > > + Index, > > + &EndpointDescriptor); > > + > > + if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) =3D=3D USB_END= POINT_BULK) { > > + if (!FoundOut && (EndpointDescriptor.EndpointAddress & BIT7) =3D= =3D 0) { > > + CopyMem (&UsbDisplayLinkDev->BulkOutEndpointDescriptor, &Endpo= intDescriptor, sizeof (EndpointDescriptor)); > > + FoundOut =3D TRUE; > > + } else if (!FoundIn && (EndpointDescriptor.EndpointAddress & BIT= 7) =3D=3D BIT7) { > > + CopyMem (&UsbDisplayLinkDev->BulkInEndpointDescriptor, &Endpoi= ntDescriptor, sizeof (EndpointDescriptor)); > > + FoundIn =3D TRUE; > > + } > > + } > > + } > > + > > + if (FoundOut =3D=3D FALSE) { > > + Status =3D EFI_UNSUPPORTED; > > + DEBUG ((DEBUG_ERROR, "No endpoints found. Num endpoints searched = =3D %d.\n", EndpointNumber)); > > + goto ErrorExit4; > > + } > > + > > + Status =3D DlReadEdid (UsbDisplayLinkDev); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Failed to read monitor EDID from DisplayLink= device (code %r)\n", Status)); > > + goto ErrorExit7; > > + } > > + > > + Status =3D InitializeUsbDisplayLinkDevice (UsbDisplayLinkDev); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Failed to initialise DisplayLink device (cod= e %r)\n", Status)); > > + goto ErrorExit7; > > + } > > + > > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > > + &Controller, > > + &gEfiGraphicsOutputProtocolGuid, > > + &UsbDisplayLinkDev->GraphicsOutputProtocol, > > + &gEfiEdidDiscoveredProtocolGuid, > > + &UsbDisplayLinkDev->EdidDiscovered, > > + &gEfiEdidActiveProtocolGuid, > > + &UsbDisplayLinkDev->EdidActive, > > + NULL); > > + > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "Failed to install Graphics Output and EDID p= rotocol interfaces - driver not installed correctly - > %r\n", Status)); > > + goto ErrorExit8; > > + } > > + > > + UsbDisplayLinkDev->ControllerNameTable =3D (EFI_UNICODE_STRING_TABLE= *)NULL; > > + > > + AddUnicodeString2 ( > > + "eng", > > + mUsbDisplayLinkComponentName.SupportedLanguages, > > + &UsbDisplayLinkDev->ControllerNameTable, > > + (CONST CHAR16*)L"Generic Usb DisplayLink", > > + TRUE); > > + > > + AddUnicodeString2 ( > > + "en", > > + mUsbDisplayLinkComponentName2.SupportedLanguages, > > + &UsbDisplayLinkDev->ControllerNameTable, > > + (CONST CHAR16*)L"Generic Usb DisplayLink", > > + FALSE); > > + > > + // > > + // Setup a periodic timer > > + // > > + Status =3D gBS->CreateEvent ( > > + EVT_TIMER | EVT_NOTIFY_SIGNAL, > > + TPL_CALLBACK, > > + DisplayLinkPeriodicTimer, > > + UsbDisplayLinkDev, > > + &UsbDisplayLinkDev->TimerEvent); > > + > > + if (EFI_ERROR (Status)) { > > + Status =3D EFI_OUT_OF_RESOURCES; > > + DEBUG ((DEBUG_ERROR, "Failed to create screeen update polling even= t.\n")); > > + goto ErrorExit8; > > + } > > + > > + // Start one-shot timer. The rendering operations can take quite a l= ong time, so we > > + // don't want another timer event to happen until we have finished; = so we'll restart > > + // the timer from DisplayLinkPeriodicTimer, the event handler functi= on. > > + Status =3D gBS->SetTimer (UsbDisplayLinkDev->TimerEvent, TimerRelati= ve, DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD); > > + if (EFI_ERROR (Status)) { > > + Status =3D EFI_OUT_OF_RESOURCES; > > + DEBUG ((DEBUG_ERROR, "Failed to create screen update polling timer= .\n")); > > + goto ErrorExit8; > > + } > > + > > + Status =3D gBS->CreateEventEx ( > > + EVT_NOTIFY_SIGNAL, > > + TPL_NOTIFY, > > + DisplayLinkDriverExitBootServices, > > + UsbDisplayLinkDev, > > + &gEfiEventExitBootServicesGuid, > > + &UsbDisplayLinkDev->DriverExitBootServicesEvent); > > + > > + if (EFI_ERROR (Status)) { > > + Status =3D EFI_OUT_OF_RESOURCES; > > + DEBUG ((DEBUG_ERROR, "Failed to create event for bootexit.\n")); > > + goto ErrorExit8; > > + } > > + > > + gBS->RestoreTPL (OriginalTPL); > > + > > + DEBUG ((DEBUG_INFO, "DisplayLink GOP driver successfully bound to de= vice.\n")); > > + > > + return EFI_SUCCESS; > > + > > + // > > + // Error handler > > + // > > + ErrorExit8: > > + ErrorExit7: > > + ErrorExit4: > > + gBS->CloseProtocol ( > > + Controller, > > + &gEfiUsbIoProtocolGuid, > > + This->DriverBindingHandle, > > + Controller); > > + > > + ErrorExit2: > > + if (UsbDisplayLinkDev !=3D NULL) { > > + FreePool (UsbDisplayLinkDev); > > + UsbDisplayLinkDev =3D (USB_DISPLAYLINK_DEV*)NULL; > > + } > > + > > + DEBUG ((DEBUG_ERROR, "Exiting - Failed to initialise driver.\n")); > > + > > + gBS->RestoreTPL (OriginalTPL); > > + return Status; > > +} > > + > > +/** > > +Entrypoint of USB DisplayLink Driver. > > + > > +This function is the entrypoint of a combined USB DisplayLink GOP Driv= er. It installs Driver Binding > > +Protocols together with Component Name Protocols. > > + > > +@param ImageHandle The firmware allocated handle for the EFI im= age. > > +@param SystemTable A pointer to the EFI System Table. > > +@param DriverBindingHandle The Driver binding handle > > + > > +@retval EFI_SUCCESS The entry point is executed successfully. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverCombinedGopBindingEntryPoint ( > > + IN EFI_HANDLE ImageHandle, > > + IN EFI_SYSTEM_TABLE *SystemTable, > > + IN EFI_HANDLE DriverBindingHandle > > +) > > +{ > > + EFI_STATUS Status; > > + > > + Status =3D EfiLibInstallDriverBindingComponentName2 ( > > + ImageHandle, > > + SystemTable, > > + &gUsbDisplayLinkDriverBinding, > > + DriverBindingHandle, > > + &mUsbDisplayLinkComponentName, > > + &mUsbDisplayLinkComponentName2); > > + > > + ASSERT_EFI_ERROR (Status); > > + > > + return EFI_SUCCESS; > > +} > > + > > + > > +/** > > +Entrypoint of USB DisplayLink Driver. > > + > > +This function is the entrypoint of USB DisplayLink Driver. It installs= Driver Binding > > +Protocols together with Component Name Protocols. > > + > > +@param ImageHandle The firmware allocated handle for the EFI im= age. > > +@param SystemTable A pointer to the EFI System Table. > > + > > +@retval EFI_SUCCESS The entry point is executed successfully. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverBindingEntryPoint ( > > + IN EFI_HANDLE ImageHandle, > > + IN EFI_SYSTEM_TABLE *SystemTable > > +) > > +{ > > + return UsbDisplayLinkDriverCombinedGopBindingEntryPoint (ImageHandle= , SystemTable, ImageHandle); > > +} > > + > > + > > +/** > > +Unloads an image. > > +@param ImageHandle Handle that identifies the image to be u= nloaded. > > +@retval EFI_SUCCESS The image has been unloaded. > > +@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. > > +**/ > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverCombinedGopUnload ( > > + IN EFI_HANDLE ImageHandle > > +) > > +{ > > + EFI_STATUS Status =3D EFI_SUCCESS; > > + EFI_STATUS handleDisconnectStatus; > > + EFI_HANDLE *HandleBuffer; > > + UINTN HandleCount; > > + UINTN Index; > > + > > + // > > + // Retrieve array of all handles in the handle database > > + // > > + handleDisconnectStatus =3D gBS->LocateHandleBuffer ( > > + AllHandles, > > + NULL, > > + NULL, > > + &HandleCount, > > + &HandleBuffer > > + ); > > + if (! EFI_ERROR (handleDisconnectStatus)) { > > + // > > + // Disconnect the current driver from handles in the handle databa= se > > + // > > + for (Index =3D 0; Index < HandleCount; Index++) { > > + Status =3D gBS->DisconnectController (HandleBuffer[Index], gImag= eHandle, NULL); > > + } > > + // > > + // Free the array of handles > > + // > > + if (HandleBuffer !=3D NULL) > > + { > > + FreePool (HandleBuffer); > > + } > > + } > > + > > + // Even if we didn't manage to disconnect the handles, try to uninst= all the protocols > > + // > > + // Uninstall protocols installed in the driver entry point > > + // > > + Status =3D gBS->UninstallMultipleProtocolInterfaces ( > > + ImageHandle, > > + &gEfiDriverBindingProtocolGuid, > > + &gUsbDisplayLinkDriverBinding, > > + &gEfiComponentNameProtocolGuid, > > + &mUsbDisplayLinkComponentName, > > + &gEfiComponentName2ProtocolGuid, > > + &mUsbDisplayLinkComponentName2, > > + NULL > > + ); > > + > > + if (EFI_ERROR (handleDisconnectStatus)) > > + { > > + return handleDisconnectStatus; > > + } > > + return Status; > > +} > > + > > + > > +/** > > + Stop the USB DisplayLink device handled by this driver. > > + > > + @param This The USB DisplayLink driver binding pr= otocol. > > + @param Controller The controller to release. > > + @param NumberOfChildren The number of handles in ChildHandleB= uffer. > > + @param ChildHandleBuffer The array of child handle. > > + > > + @retval EFI_SUCCESS The device was stopped. > > + @retval EFI_UNSUPPORTED Simple Pointer Protocol is not instal= led on Controller. > > + @retval Others Fail to uninstall protocols attached = on the device. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +UsbDisplayLinkDriverBindingStop ( > > + IN EFI_DRIVER_BINDING_PROTOCOL *This, > > + IN EFI_HANDLE Controller, > > + IN UINTN NumberOfChildren, > > + IN EFI_HANDLE *ChildHandleBuffer > > + ) > > +{ > > + EFI_STATUS Status; > > + USB_DISPLAYLINK_DEV *UsbDisplayLinkDev; > > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutputProtocol; > > + > > + Status =3D gBS->OpenProtocol ( > > + Controller, > > + &gEfiGraphicsOutputProtocolGuid, > > + (VOID **) &GraphicsOutputProtocol, > > + This->DriverBindingHandle, > > + Controller, > > + EFI_OPEN_PROTOCOL_GET_PROTOCOL); > > + > > + if (EFI_ERROR (Status)) { > > + return EFI_UNSUPPORTED; > > + } > > + > > + UsbDisplayLinkDev =3D USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTO= COL(GraphicsOutputProtocol); > > + > > + // Reset the video mode to clear the display. Don't drop out if ther= e is a problem, just press on. > > + // Note that this will also clear the frame buffer, as the screen bu= ffer will be re-allocated with AllocateZeroPool. > > + if ((GraphicsOutputProtocol->Mode !=3D NULL) && > > + (GraphicsOutputProtocol->Mode->Mode !=3D GRAPHICS_OUTPUT_INVALID= _MODE_NUMBER)) { > > + Status =3D DisplayLinkSetMode (GraphicsOutputProtocol, GraphicsOut= putProtocol->Mode->Mode); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_WARN, "Driver stop - Problem resetting video mode = - %r.\n", Status)); > > + } > > + } > > + > > + // Reset the alt setting on the interface (to the DL3 alt setting) > > + Status =3D SelectAltSetting (UsbDisplayLinkDev->UsbIo, 0); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_WARN, "Error resetting USB interface alternate setti= ng - %r.\n", Status)); > > + } > > + > > + Status =3D gBS->UninstallMultipleProtocolInterfaces ( > > + Controller, > > + &gEfiGraphicsOutputProtocolGuid, > > + &UsbDisplayLinkDev->GraphicsOutputProtocol, > > + &gEfiEdidDiscoveredProtocolGuid, > > + &UsbDisplayLinkDev->EdidDiscovered, > > + &gEfiEdidActiveProtocolGuid, > > + &UsbDisplayLinkDev->EdidActive, > > + NULL); > > + > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_WARN, "Error uninstalling Graphics Output and EDID p= rotocol interfaces - %r.\n", Status)); > > + return Status; > > + } > > + > > + gBS->CloseEvent (UsbDisplayLinkDev->TimerEvent); > > + > > + gBS->CloseProtocol ( > > + Controller, > > + &gEfiUsbIoProtocolGuid, > > + This->DriverBindingHandle, > > + Controller); > > + > > + // > > + // Free all resources. > > + // > > + if (UsbDisplayLinkDev->ControllerNameTable !=3D NULL) { > > + FreeUnicodeStringTable (UsbDisplayLinkDev->ControllerNameTable); > > + } > > + > > + if (UsbDisplayLinkDev->Screen !=3D NULL) { > > + FreePool (UsbDisplayLinkDev->Screen); > > + UsbDisplayLinkDev->Screen =3D NULL; > > + } > > + > > + if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode) { > > + if (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info) { > > + FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info); > > + UsbDisplayLinkDev->GraphicsOutputProtocol.Mode->Info =3D NULL; > > + } > > + FreePool (UsbDisplayLinkDev->GraphicsOutputProtocol.Mode); > > + UsbDisplayLinkDev->GraphicsOutputProtocol.Mode =3D NULL; > > + } > > + > > + FreePool (UsbDisplayLinkDev); > > + > > + return EFI_SUCCESS; > > + > > +} > > + > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDispl= ayLink.h > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.h > > new file mode 100644 > > index 000000000000..497a2621bc2c > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbDisplayLink.= h > > @@ -0,0 +1,278 @@ > > +/** > > + * @file UsbDisplayLink.h > > + * @brief Helper routine and corresponding data struct used by USB Dis= playLink Driver. > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#ifndef _EFI_USB_DISPLAYLINK_H_ > > +#define _EFI_USB_DISPLAYLINK_H_ > > + > > +#include > > +#include > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#define VENDOR_DISPLAYLINK 0x17e9 > > +#define CLASS_VENDOR 0xFF > > + > > +#define DISPLAYLINK_USB_INTERFACE_NUMBER_NIVO ((UINTN)0) > > + > > +#define INTERFACE_PROTOCOL_DIRECT_FB 4 > > + > > +#define USB_TRANSFER_LENGTH (64 * 1024) > > +#define DISPLAYLINK_MODE_DATA_LENGTH (146) > > +#define DISPLAYLINK_USB_CTRL_TIMEOUT (1000) > > +#define DISPLAYLINK_USB_BULK_TIMEOUT (1) > > + > > +#define DISPLAYLINK_SCREEN_UPDATE_TIMER_PERIOD ((UINTN)1000000) // 0.= 1s in us > > +#define DISPLAYLINK_FULL_SCREEN_UPDATE_PERIOD ((UINTN)30000) // 3s i= n ticks > > + > > +#define DISPLAYLINK_FIXED_VERTICAL_REFRESH_RATE ((UINT16)60) > > + > > +// Requests to read values from the firmware > > +#define EDID_BLOCK_SIZE 128 > > +#define EDID_DETAILED_TIMING_INVALID_PIXEL_CLOCK ((UINT16)(0x64)) > > + > > +/** Structures ported from firmware - protocol.h */ > > +enum ID { > > + // VideoCommands > > + GET_OUTPUT_EDID =3D 0, > > + SET_VIDEO_MODE =3D 1 > > +}; > > + > > +typedef struct { > > + UINT32 HorizontalResolution; > > + UINT32 VerticalResolution; > > + UINT32 ColorDepth; > > + UINT32 RefreshRate; > > + UINT8 Commands[DISPLAYLINK_MODE_DATA_LENGTH]; > > +} DISPLAYLINK_MODE_DATA; > > + > > +#define GRAPHICS_OUTPUT_INVALID_MODE_NUMBER 0xffff > > + > > +/** > > + * Device instance of USB display. > > + */ > > +typedef struct { > > + UINT64 Signature; > > + EFI_HANDLE Handle; > > + EFI_USB_IO_PROTOCOL *UsbIo; > > + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; > > + EFI_USB_ENDPOINT_DESCRIPTOR BulkOutEndpointDescriptor; > > + EFI_USB_ENDPOINT_DESCRIPTOR BulkInEndpointDescriptor; > > + EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutputProtocol; > > + EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered; > > + EFI_EDID_ACTIVE_PROTOCOL EdidActive; > > + EFI_UNICODE_STRING_TABLE *ControllerNameTable; > > + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Screen; > > + UINTN DataSent; /** De= bug - used to track the bandwidth */ > > + EFI_EVENT TimerEvent; > > + EFI_EVENT DriverExitBootServicesEvent; > > + BOOLEAN ShowBandwidth; /** Deb= ugging - show the bandwidth on the screen */ > > + BOOLEAN ShowTestPattern; /** Sho= w a colourbar pattern instead of the BLTd contents of the > framebuffer */ > > + UINTN LastY1; /** Use= d to track if we can do a partial screen update */ > > + UINTN LastY2; > > + UINTN LastWidth; > > + UINTN TimeSinceLastScreenUpdate; /** Do = a full screen update every (x) seconds */ > > +} USB_DISPLAYLINK_DEV; > > + > > +#define USB_DISPLAYLINK_DEV_SIGNATURE SIGNATURE_32 ('d', 'l', 'i', 'n'= ) > > + > > +struct VideoMode { > > + UINT8 Reserved1; /* Reserved - must be 0. */ > > + UINT8 Reserved2; /* Reserved - must be 2. */ > > + > > + // Values matching the EDID Detailed Timing Descriptor spec > > + UINT16 PixelClock; > > + UINT16 HActive; > > + UINT16 HBlanking; > > + UINT16 HSyncOffset; // Horizontal Front Porch > > + UINT16 HSyncWidth; > > + UINT16 VActive; > > + UINT16 VBlanking; > > + UINT16 VSyncOffset; // Vertical Front Porch > > + UINT16 VSyncWidth; > > + // End of Edid Detailed Timing Descriptor > > + > > + UINT16 Flags /*ModeFlags*/; > > + UINT16 Accumulate; > > + UINT16 Reserved3; /* Reserved - must be 0. */ > > + UINT16 Reserved4; /* Reserved - must be 0. */ > > + UINT16 InsetLeft; > > + UINT16 InsetTop; > > + UINT16 InsetRight; > > + UINT16 InsetBottom; > > + UINT32 FillValue; > > + UINT32 Reserved5; /* Reserved - must be 0. */ > > + UINT8 Vic; > > + UINT8 ActiveFormat; > > + UINT16 Reserved6; > > +}; > > + > > +#define USB_DISPLAYLINK_DEV_FROM_GRAPHICS_OUTPUT_PROTOCOL(a) \ > > + CR(a, USB_DISPLAYLINK_DEV, GraphicsOutputProtocol, USB_DISPLAYLINK_D= EV_SIGNATURE) > > + > > +// > > +// Global Variables > > +// > > +extern EFI_DRIVER_BINDING_PROTOCOL gUsbDisplayLinkDriverBinding; > > +extern EFI_COMPONENT_NAME_PROTOCOL mUsbDisplayLinkComponentName; > > +extern EFI_COMPONENT_NAME2_PROTOCOL mUsbDisplayLinkComponentName2; > > + > > + > > +/* ******************************************* */ > > +/* ******** GOP interface functions ******** */ > > +/* ******************************************* */ > > + > > +/** > > + * Implementation of the GOP protocol QueryMode API function > > + * @param This Instance of the GOP protocol > > + * @param ModeNumber > > + * @param SizeOfInfo > > + * @param Info > > + * @return > > + */ > > +EFI_STATUS > > + EFIAPI > > + DisplayLinkQueryMode ( > > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > > + IN UINT32 ModeNumber, > > + OUT UINTN *SizeOfInfo, > > + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info > > + ); > > + > > + > > +/** > > + * Implementation of the GOP protocol SetMode API function > > + * @param This > > + * @param ModeNumber > > + * @return > > + */ > > +EFI_STATUS > > + EFIAPI > > + DisplayLinkSetMode ( > > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > > + IN UINT32 ModeNumber > > + ); > > + > > +/** > > + * Implementation of the GOP protocol Blt API function > > + * @param This > > + * @param BltBuffer > > + * @param BltOperation > > + * @param SourceX > > + * @param SourceY > > + * @param DestinationX > > + * @param DestinationY > > + * @param Width > > + * @param Height > > + * @param Delta > > + * @return > > + */ > > +EFI_STATUS > > + EFIAPI > > + DisplayLinkBlt ( > > + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, > > + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL > > + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, > > + IN UINTN SourceX, > > + IN UINTN SourceY, > > + IN UINTN DestinationX, > > + IN UINTN DestinationY, > > + IN UINTN Width, > > + IN UINTN Height, > > + IN UINTN Delta OPTIONAL > > + ); > > + > > +/* *************************** */ > > +/* ** GOP helper functions ** */ > > +/* *************************** */ > > + > > +VOID > > +EFIAPI > > +DlGopPrintTextToScreen ( > > + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, > > + UINTN X, > > + UINTN Y, > > + IN CONST CHAR16 *Format, > > + ... > > +); > > + > > +EFI_STATUS > > +DlGopSendTestPattern ( > > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev, > > + UINTN PatternNumber > > +); > > + > > +EFI_STATUS > > +DlGopSendScreenUpdate ( > > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev > > +); > > + > > + > > +/* ******************************************* */ > > +/* ******** USB interface functions ******** */ > > +/* ******************************************* */ > > + > > +EFI_STATUS > > +DlUsbSendControlWriteMessage ( > > + IN USB_DISPLAYLINK_DEV *Device, > > + IN UINT8 Request, > > + IN UINT16 Value, > > + IN CONST VOID *ControlMsg, > > + IN UINT16 ControlMsgLen > > +); > > + > > +EFI_STATUS > > +DlUsbSendControlReadMessage ( > > + IN USB_DISPLAYLINK_DEV *Device, > > + IN UINT8 Request, > > + IN UINT16 Value, > > + OUT VOID *ControlMsg, > > + IN UINT16 ControlMsgLen > > +); > > + > > +EFI_STATUS > > +DlUsbBulkWrite ( > > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev, > > + CONST UINT8* Buffer, > > + UINTN DataLen, > > + UINT32 *USBStatus > > +); > > + > > +UINTN > > +DlUsbBulkRead ( > > + USB_DISPLAYLINK_DEV* UsbDisplayLinkDev, > > + UINT8* Buffer, > > + UINTN BufferLen > > +); > > + > > +/* ******************************************* */ > > +/* ******** Video Mode functions ******** */ > > +/* ******************************************* */ > > + > > +// Pre-calculated video modes > > +UINT32 > > +DlVideoModeGetNumSupportedVideoModes (); > > + > > +CONST struct VideoMode * > > +DlVideoModeGetSupportedVideoMode ( > > + UINT32 index > > +); > > + > > +#endif > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTrans= fer.c > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c > > new file mode 100644 > > index 000000000000..252293da39d4 > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/UsbTransfer.c > > @@ -0,0 +1,180 @@ > > +/** > > + * @file UsbTransfer.c > > + * @brief Wrapper of UEFI USB bulk and control transfer interface for = USB DisplayLink driver. > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#include "UsbDisplayLink.h" > > + > > +/** > > + * Write the data to the DisplayLink device using the USBIO protocol. > > + * @param UsbDisplayLinkDev > > + * @param Buffer > > + * @param DataLen > > + * @param USBStatus > > + * @return > > + * EFI_SUCCESS The bulk transfer has been successfully executed. > > + * EFI_INVALID_PARAMETER If DeviceEndpoint is not valid. > > + * EFI_INVALID_PARAMETER Data is NULL. > > + * EFI_INVALID_PARAMETER DataLength is NULL. > > + * EFI_INVALID_PARAMETER Status is NULL. > > + * EFI_OUT_OF_RESOURCES The request could not be completed due to a = lack of resources. > > + * EFI_TIMEOUT The bulk transfer cannot be completed within Timeout= timeframe. > > + * EFI_DEVICE_ERROR The transfer failed other than timeout, and the = transfer status is returned in Status. > > + */ > > +EFI_STATUS > > +DlUsbBulkWrite ( > > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev, > > + IN CONST UINT8* Buffer, > > + IN UINTN DataLen, > > + OUT UINT32 *USBStatus > > + ) > > +{ > > + EFI_STATUS Status; > > + Status =3D UsbDisplayLinkDev->UsbIo->UsbBulkTransfer ( > > + UsbDisplayLinkDev->UsbIo, > > + UsbDisplayLinkDev->BulkOutEndpointDescriptor.EndpointAddress, > > + (VOID*)Buffer, > > + &DataLen, > > + DISPLAYLINK_USB_BULK_TIMEOUT, > > + USBStatus); > > + > > + return Status; > > +} > > + > > +/** > > +* Read data from the DisplayLink device using the USBIO protocol. > > +* @param UsbDisplayLinkDev > > +* @param Buffer > > +* @param BufferLen > > +* @return 0 if an error occurred or 0 bytes were read, otherwise the n= umber of bytes read > > + */ > > +UINTN > > +DlUsbBulkRead ( > > + IN USB_DISPLAYLINK_DEV* UsbDisplayLinkDev, > > + IN UINT8* Buffer, > > + IN UINTN BufferLen > > + ) > > +{ > > + UINT32 Result; > > + UINTN ReadLen; > > + EFI_STATUS Status; > > + > > + ReadLen =3D BufferLen; > > + > > + Status =3D UsbDisplayLinkDev->UsbIo->UsbBulkTransfer ( > > + UsbDisplayLinkDev->UsbIo, > > + UsbDisplayLinkDev->BulkInEndpointDescriptor.EndpointAddress, > > + Buffer, > > + &ReadLen, > > + DISPLAYLINK_USB_BULK_TIMEOUT, > > + &Result); > > + > > + if (EFI_ERROR (Status)) { > > + return 0; > > + } > > + > > + return ReadLen; > > +} > > + > > + > > +/** > > +Send a control message (e.g set video mode) message to the DisplayLink= device. > > + > > +@param Device USB device handle. > > +@param request Request type, e.g. SET_VIDEO_MODE > > +@param value > > +@param controlMsg Pointer to the message to send. > > +@param controlMsgLen Length of the message. > > + > > +@retval EFI_SUCCESS Successfully sent message. > > + > > +**/ > > +EFI_STATUS > > +DlUsbSendControlWriteMessage ( > > + IN USB_DISPLAYLINK_DEV *Device, > > + IN UINT8 Request, > > + IN UINT16 Value, > > + IN CONST VOID *ControlMsg, > > + IN UINT16 ControlMsgLen > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT32 UsbStatus; > > + EFI_USB_DEVICE_REQUEST UsbRequest; > > + > > + ZeroMem (&Request, sizeof (Request)); > > + UsbRequest.RequestType =3D USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFAC= E; > > + UsbRequest.Index =3D Device->InterfaceDescriptor.InterfaceNumber; > > + UsbRequest.Request =3D Request; > > + UsbRequest.Value =3D Value; > > + UsbRequest.Length =3D ControlMsgLen; > > + > > + Status =3D Device->UsbIo->UsbControlTransfer ( > > + Device->UsbIo, > > + &UsbRequest, > > + EfiUsbDataOut, > > + DISPLAYLINK_USB_CTRL_TIMEOUT, > > + (VOID *)ControlMsg, > > + ControlMsgLen, > > + &UsbStatus); > > + > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "USB write control transfer failed - %r (USB = status x%x).\n", Status, UsbStatus)); > > + Status =3D EFI_DEVICE_ERROR; > > + } > > + return Status; > > +} > > + > > + > > +/** > > +Request data from the DisplayLink device (e.g. the monitor EDID) > > + > > +@param Device USB device handle. > > +@param request Request type, e.g. GET_OUTPUT_EDID > > +@param value > > +@param controlMsg Pointer to the message to send. > > +@param controlMsgLen Length of the message. > > + > > +@retval EFI_SUCCESS Successfully sent message. > > + > > +**/ > > +EFI_STATUS > > +DlUsbSendControlReadMessage ( > > + IN USB_DISPLAYLINK_DEV *Device, > > + IN UINT8 Request, > > + IN UINT16 Value, > > + OUT VOID *ControlMsg, > > + IN UINT16 ControlMsgLen > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT32 UsbStatus; > > + EFI_USB_DEVICE_REQUEST UsbRequest; > > + > > + ZeroMem (&UsbRequest, sizeof (UsbRequest)); > > + UsbRequest.RequestType =3D USB_REQ_TYPE_VENDOR | USB_TARGET_INTERFAC= E | USB_ENDPOINT_DIR_IN; > > + UsbRequest.Request =3D Request; > > + UsbRequest.Value =3D Value; > > + UsbRequest.Index =3D Device->InterfaceDescriptor.InterfaceNumber; > > + UsbRequest.Length =3D ControlMsgLen; > > + > > + Status =3D Device->UsbIo->UsbControlTransfer ( > > + Device->UsbIo, > > + &UsbRequest, > > + EfiUsbDataIn, > > + DISPLAYLINK_USB_CTRL_TIMEOUT, > > + (VOID *)ControlMsg, > > + ControlMsgLen, > > + &UsbStatus); > > + > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "USB read control transfer failed - %r (USB s= tatus x%x).\n", Status, UsbStatus)); > > + Status =3D EFI_DEVICE_ERROR; > > + } > > + return Status; > > +} > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoMod= es.c > b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c > > new file mode 100644 > > index 000000000000..6218c093147c > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/VideoModes.c > > @@ -0,0 +1,254 @@ > > +/** > > + * @file VideoModes.c > > + * @brief Pre-calculated video timings sent to the DisplayLink device = when a video mode is selected > > + * > > + * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-2-Clause-Patent > > + * > > +**/ > > + > > +#include "UsbDisplayLink.h" > > + > > + > > +// Supported video modes - must be in order of pixel count (i.e. hres = x vres) > > + > > +STATIC CONST struct VideoMode ModeData[] =3D { > > + { > > + // 640 x 480 @ 60Hz > > + .Reserved2 =3D 2, > > + .PixelClock =3D 2517, > > + .HActive =3D 640, > > + .HBlanking =3D 160, > > + .HSyncOffset =3D 16, > > + .HSyncWidth =3D 96, > > + .VActive =3D 480, > > + .VBlanking =3D 45, > > + .VSyncOffset =3D 10, > > + .VSyncWidth =3D 2, > > + .Flags =3D 0x00000300, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + }, > > + { > > + // 800 x 600 @ 60Hz > > + .Reserved2 =3D 2, > > + .PixelClock =3D 4000, > > + .HActive =3D 800, > > + .HBlanking =3D 256, > > + .HSyncOffset =3D 40, > > + .HSyncWidth =3D 128, > > + .VActive =3D 600, > > + .VBlanking =3D 28, > > + .VSyncOffset =3D 1, > > + .VSyncWidth =3D 3, > > + .Flags =3D 0x00000000, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + }, > > + { > > + // 1024x768 @ 60Hz > > + .Reserved1 =3D 0, > > + .Reserved2 =3D 2, > > + .PixelClock =3D 6500, > > + .HActive =3D 1024, > > + .HBlanking =3D 320, > > + .HSyncOffset =3D 24, > > + .HSyncWidth =3D 136, > > + .VActive =3D 768, > > + .VBlanking =3D 38, > > + .VSyncOffset =3D 3, > > + .VSyncWidth =3D 6, > > + .Flags =3D 0x00000300, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + }, > > + { > > + // 1360x768 @ 60Hz > > + .Reserved1 =3D 0, > > + .Reserved2 =3D 2, > > + .PixelClock =3D 8550, > > + .HActive =3D 1360, > > + .HBlanking =3D 432, > > + .HSyncOffset =3D 64, > > + .HSyncWidth =3D 112, > > + .VActive =3D 768, > > + .VBlanking =3D 27, > > + .VSyncOffset =3D 3, > > + .VSyncWidth =3D 6, > > + .Flags =3D 0x00000000, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + }, > > + { > > + // 1280x960 @ 60Hz > > + .Reserved1 =3D 0, > > + .Reserved2 =3D 2, > > + .PixelClock =3D 10800, > > + .HActive =3D 1280, > > + .HBlanking =3D 520, > > + .HSyncOffset =3D 96, > > + .HSyncWidth =3D 112, > > + .VActive =3D 960, > > + .VBlanking =3D 40, > > + .VSyncOffset =3D 1, > > + .VSyncWidth =3D 3, > > + .Flags =3D 0x00000000, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + }, > > + { > > + // 1280x1024 @ 60Hz > > + .Reserved1 =3D 0, > > + .Reserved2 =3D 2, > > + .PixelClock =3D 10800, > > + .HActive =3D 1280, > > + .HBlanking =3D 408, > > + .HSyncOffset =3D 48, > > + .HSyncWidth =3D 112, > > + .VActive =3D 1024, > > + .VBlanking =3D 42, > > + .VSyncOffset =3D 1, > > + .VSyncWidth =3D 3, > > + .Flags =3D 0x00000000, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + }, > > + { > > + // 1600x900 @ 60Hz > > + .Reserved2 =3D 2, > > + .PixelClock =3D 11825, > > + .HActive =3D 1600, > > + .HBlanking =3D 512, > > + .HSyncOffset =3D 88, > > + .HSyncWidth =3D 168, > > + .VActive =3D 900, > > + .VBlanking =3D 34, > > + .VSyncOffset =3D 3, > > + .VSyncWidth =3D 5, > > + .Flags =3D 0x00000500, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + }, > > + { > > + // 1400x1050 @ 60Hz > > + .Reserved1 =3D 0, > > + .Reserved2 =3D 2, > > + .PixelClock =3D 12175, > > + .HActive =3D 1400, > > + .HBlanking =3D 464, > > + .HSyncOffset =3D 88, > > + .HSyncWidth =3D 144, > > + .VActive =3D 1050, > > + .VBlanking =3D 39, > > + .VSyncOffset =3D 3, > > + .VSyncWidth =3D 4, > > + .Flags =3D 0x00000100, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + }, > > + { > > + // 1600x1200 @ 60Hz > > + .Reserved1 =3D 0, > > + .Reserved2 =3D 2, > > + .PixelClock =3D 16200, > > + .HActive =3D 1600, > > + .HBlanking =3D 560, > > + .HSyncOffset =3D 64, > > + .HSyncWidth =3D 192, > > + .VActive =3D 1200, > > + .VBlanking =3D 50, > > + .VSyncOffset =3D 1, > > + .VSyncWidth =3D 3, > > + .Flags =3D 0x00000000, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + }, > > + { > > + // 1920 x 1080 > > + .Reserved2 =3D 2, > > + .PixelClock =3D 14850, > > + .HActive =3D 1920, > > + .HBlanking =3D 280, > > + .HSyncOffset =3D 88, > > + .HSyncWidth =3D 44, > > + .VActive =3D 1080, > > + .VBlanking =3D 45, > > + .VSyncOffset =3D 4, > > + .VSyncWidth =3D 5, > > + .Flags =3D 0x00000000, > > + .Accumulate =3D 1, > > + .Reserved3 =3D 0, > > + .Reserved4 =3D 0, > > + .Reserved5 =3D 0x00000000, > > + .Vic =3D 0, > > + .ActiveFormat =3D 0, > > + } > > +}; > > + > > +STATIC CONST UINT32 NumSupportedVideoModes =3D (sizeof (ModeData) / si= zeof (struct VideoMode)); > > + > > +/** > > +Find the number of pre-calculated video modes that we support. > > + > > +@retval Number of modes. > > + > > +**/ > > +UINT32 DlVideoModeGetNumSupportedVideoModes () > > +{ > > + return NumSupportedVideoModes; > > +} > > + > > +/** > > +Get one of the pre-calculated video modes > > + > > +@param index The video mode that we want. > > + > > +@retval NULL The index was out of range. > > + > > +**/ > > +CONST struct VideoMode *DlVideoModeGetSupportedVideoMode ( > > + UINT32 Index > > + ) > > +{ > > + if (Index >=3D NumSupportedVideoModes) { > > + return NULL; > > + } > > + return &ModeData[Index]; > > +} > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc b/Dr= ivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc > > new file mode 100644 > > index 000000000000..955331ba6076 > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkPkg.dsc > > @@ -0,0 +1,61 @@ > > +#/** @file > > +# > > +# Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. > > +# > > +# SPDX-License-Identifier: BSD-2-Clause-Patent > > +# > > +#**/ > > + > > +[Defines] > > + PLATFORM_NAME =3D DisplayLinkPkg > > + PLATFORM_GUID =3D ad3b37b0-f798-4f97-9b3f-0c6f43d7c= 993 > > + PLATFORM_VERSION =3D 0.1 > > + DSC_SPECIFICATION =3D 0x0001001C > > + OUTPUT_DIRECTORY =3D Build/DisplayLink > > + SUPPORTED_ARCHITECTURES =3D X64|IA32|AARCH64|ARM > > + BUILD_TARGETS =3D DEBUG|RELEASE|NOOPT > > + SKUID_IDENTIFIER =3D DEFAULT > > + > > +[LibraryClasses] > > + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf > > + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf > > + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf > > + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/B= aseDebugPrintErrorLevelLib.inf > > + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf > > + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > > + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf > > + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeR= eportStatusCodeLib.inf > > + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/Uef= iBootServicesTableLib.inf > > + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverE= ntryPoint.inf > > + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf > > + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableL= ib/UefiRuntimeServicesTableLib.inf > > + UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf > > + > > +[LibraryClasses.common.UEFI_DRIVER] > > + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemor= yAllocationLib.inf > > + > > +[LibraryClasses.AARCH64] > > + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf > > + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf > > + > > +[LibraryClasses.ARM] > > + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf > > + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf > > + > > +[PcdsFixedAtBuild] > > +!ifdef $(DEBUG_ENABLE_OUTPUT) > > + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x3f > > + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80080043 # Flags= to control amount of debug output - see > https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Debugging > > + gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x07 > > +!endif > > + > > +[Components] > > + Drivers/DisplayLink/DisplayLinkPkg/DisplayLinkGop/DisplayLinkGopDxe.= inf > > + > > +[BuildOptions] > > + *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACE= S -D > INF_DRIVER_VERSION=3D$(INF_DRIVER_VERSION) > > + GCC:RELEASE_*_*_CC_FLAGS =3D -DMDEPKG_NDEBUG > > + MSFT:RELEASE_*_*_CC_FLAGS =3D /D MDEPKG_NDEBUG > > +!ifdef $(COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE) > > + *_*_*_CC_FLAGS =3D -D COPY_PIXELS_FROM_PRIMARY_GOP_DEVICE > > +!endif > > diff --git a/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md b/Drivers/Dis= playLink/DisplayLinkPkg/ReadMe.md > > new file mode 100644 > > index 000000000000..40061f1eb46d > > --- /dev/null > > +++ b/Drivers/DisplayLink/DisplayLinkPkg/ReadMe.md > > @@ -0,0 +1,77 @@ > > +# DISPLAYLINK DRIVERS > > +This package contains a GOP driver for Universal USB-connected docks c= ontaining the > > +DisplayLink DL-6xxx chip or newer. > > + > > +[DisplayLink Website](http://www.displaylink.com) > > + > > +[Products](https://www.displaylink.com/products/universal-docking-stat= ions) > > + > > +# INDEX > > + > > +* [Resolutions Supported](#resolutions-supported) > > +* [Frame rates](#frame-rates) > > +* [Multiple monitor outputs](#multiple-monitor-outputs) > > +* [Multiple DisplayLink devices](#multiple-displaylink-devices) > > +* [Behaviour with no monitor connected](#behaviour-with-no-monitor-con= nected) > > + > > +# Resolutions supported > > + > > +The driver supports the following resolutions: > > + > > +640 x 480 @ 60Hz > > + > > +800 x 600 @ 60Hz > > + > > +1024x768 @ 60Hz > > + > > +1360x768 @ 60Hz > > + > > +1280x960 @ 60Hz > > + > > +1280x1024 @ 60Hz > > + > > +1600x900 @ 60Hz > > + > > +1400x1050 @ 60Hz > > + > > +1600x1200 @ 60Hz > > + > > +1920x1080 @ 60Hz > > + > > + > > +Note that the list of resolutions advertised by the driver may be smal= ler than > > +this if a connected monitor does not support a particular resolution. = The driver > > +interrogates connected monitors to see which modes can be supported.It= is the > > +responsibility of the BIOS to select the video mode from this list whi= ch most > > +closely matches its requirements. In some cases this may lead to the B= IOS > > +scaling its display. > > + > > +# Frame rates > > + > > +The driver is limited to a maximum of ten frames per second. Some slow= er systems > > +at higher screen resolutions may perform at a lower rate than this. > > + > > +# Multiple monitor outputs > > + > > +If multiple monitors are connected to the DisplayLinkdevice, the displ= ay will be > > +duplicated (cloned) across all outputs at the same resolution. The res= olution > > +used will be limited by the capability of the monitor with the > > +lowest specification. > > + > > +# Multiple DisplayLink devices > > + > > +The driver will support the connection of multiple DisplayLink devices= . The > > +exact behaviourof the system with multiple devices connected is define= d by the > > +rest of the BIOS; usually, the BIOS causes the displays to be duplicat= ed > > +(cloned) across all devices. Note that the system performance and fram= e rate > > +will be affected by the number of DisplayLink devices connected. > > + > > +# Behaviour with no monitor connected > > + > > +The driver uses the EDID (Extended Display Identification Data) protoc= ol to > > +detect the list of resolutions that a monitor will support.In some mon= itors this > > +may take some time, and occasionally no EDID information will be retur= ned at > > +all. In this case the driver will not be able to detect that there is = a monitor > > +connected. To improve the user experience in these cases, the driver w= ill behave > > +as if there is a monitor connected, and will fall back to presenting t= he full > > +range of supported resolutions to the BIOS. > > diff --git a/Maintainers.txt b/Maintainers.txt > > index 876ae5612ad8..47aac133abb1 100644 > > --- a/Maintainers.txt > > +++ b/Maintainers.txt > > @@ -47,6 +47,11 @@ Drivers/OptionRomPkg > > W: https://github.com/tianocore/tianocore.github.io/wiki/OptionRomPkg > > M: Ray Ni > > > > +Drivers/DisplayLink > > +M: Leif Lindholm > > +M: Ard Bieshuevel > > +R: Andy Hayes > > + > > Platform > > M: Ard Biesheuvel > > M: Leif Lindholm > > -- > > 2.20.1 > >