Files
Andy Hayes 9df63499ea Drivers/DisplayLink: Add DisplayLinkPkg and GOP driver DisplayLinkGop
Add GOP driver for USB docking stations based on DisplayLink chips.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: Andy Hayes <andy.hayes@displaylink.com>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
2019-09-09 11:08:05 +01:00

138 lines
4.4 KiB
C

/** @file CapabilityDescriptor.c
* @brief Definitions for reading USB capability descriptor DisplayLink dock
*
* Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/
#include "UsbDisplayLink.h"
#include "UsbDescriptors.h"
/**
* Check that the Capability Descriptor is valid and hasn't been tampered with.
* @param Data Binary data of the Capability Descriptor received from the DisplayLink device
* @param Length
* @param out
* @return
*/
STATIC EFI_STATUS
ValidateHeader (
CONST IN VOID* Data,
IN UINTN Length,
OUT CONST VendorDescriptorGeneric** Out
)
{
if (Length < sizeof (VendorDescriptorGeneric)) {
DEBUG ((DEBUG_ERROR, "Data too short (%d bytes) for capability descriptor header section\n", Length));
return EFI_INVALID_PARAMETER;
}
CONST VendorDescriptorGeneric* Desc = (VendorDescriptorGeneric*)Data;
if (Desc->Length > Length) {
DEBUG ((DEBUG_ERROR, "Capability descriptor: Descriptor (%d bytes) exceeds buffer (%d bytes)\n",
Length, Desc->Length));
return EFI_BUFFER_TOO_SMALL;
}
if (Desc->Type != DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY) {
DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid type (0x%08x)\n", Desc->Type));
return EFI_UNSUPPORTED;
}
if (Desc->CapabilityVersion != 1) {
DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid version (%d)\n", Desc->CapabilityVersion));
return EFI_INCOMPATIBLE_VERSION;
}
// Capability length must fit within remaining space
if (Desc->CapabilityLength > (Desc->Length - (sizeof (Desc->Length) + sizeof (Desc->Type)))) {
DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid CapabilityLength (%d)\n", Desc->CapabilityLength));
return EFI_INVALID_PARAMETER;
}
*Out = Desc;
return EFI_SUCCESS;
}
/**
* Check that the connected DisplayLink device supports the functionality that this driver requires, e.g. video formats
* @param Data Binary data of the Capability Descriptor received from the DisplayLink device
* @param Length
* @param Output
* @return
*/
EFI_STATUS
UsbDisplayLinkParseCapabilitiesDescriptor (
CONST IN VOID* Data,
IN UINTN Length,
OUT VendorDescriptor* Output
)
{
CONST VendorDescriptorGeneric* Desc;
EFI_STATUS Status;
Desc = NULL;
Status = ValidateHeader (Data, Length, &Desc);
if (EFI_ERROR (Status)) {
return Status;
}
// Default capabilities
Output->Capabilities1 = 0;
CONST UINTN CapsHeaderLength = sizeof (Desc->CapabilityVersion) + sizeof (Desc->CapabilityLength);
ASSERT (CapsHeaderLength < MAX_UINT8);
UINTN DataRemaining;
UINTN Offset;
DataRemaining = Desc->CapabilityLength - CapsHeaderLength;
Offset = 0;
while (DataRemaining >= sizeof (DescriptorKLV)) {
CONST DescriptorKLV* KeyHeader = (CONST DescriptorKLV*)(Desc->Klv + Offset);
CONST UINTN KeyValueSize = sizeof (DescriptorKLV) + KeyHeader->Length;
if (KeyValueSize > DataRemaining) {
DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid value Length (%d)\n", Desc->CapabilityLength));
return EFI_INVALID_PARAMETER;
}
switch (KeyHeader->Key) {
case CAPABILITIES1_KEY: {
if (KeyHeader->Length != CAPABILITIES1_LENGTH) {
DEBUG ((DEBUG_ERROR, "Capability descriptor: invalid length (%d) for Capabilities 1\n", KeyHeader->Length));
return EFI_INVALID_PARAMETER;
}
Output->Capabilities1 = *(UINT32*)KeyHeader->Value;
break;
default:
// Ignore unknown types
break;
}
}
DataRemaining -= KeyValueSize;
Offset += KeyValueSize;
}
return EFI_SUCCESS;
}
/**
* Check that the DisplayLink device supports the basic level of functionality to display GOP pixels.
* @param Descriptor The USB descriptor received from the DisplayLink device
* @return True we can bind, False we can't
*/
BOOLEAN
UsbDisplayLinkCapabilitiesSufficientToBind (
CONST IN VendorDescriptor* Descriptor
)
{
BOOLEAN Sufficient;
Sufficient = (BOOLEAN)(Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL);
if (Sufficient == FALSE) {
DEBUG ((DEBUG_ERROR, "DisplayLink device does not report support for base capabilites - reports x%x, required x%x\n", Descriptor->Capabilities1 & CAPABILITIES1_BASE_PROTOCOL));
}
return Sufficient;
}