/** * @file UsbDescriptors.c * @brief Functions to read USB Interface and Capabilities descriptors * * Copyright (c) 2018-2019, DisplayLink (UK) Ltd. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include "UsbDisplayLink.h" #include "UsbDescriptors.h" /** * * @param UsbIo * @param descriptorType * @param index * @param Buffer * @param Length * @param UsbStatus * @return */ STATIC EFI_STATUS ReadDescriptor ( IN EFI_USB_IO_PROTOCOL *UsbIo, UINT8 DescriptorType, UINT8 Index, VOID* Buffer, UINT16 Length, UINT32* UsbStatus) { EFI_STATUS Status; UINT8 Header[2]; ZeroMem (Header, sizeof (Header)); EFI_USB_DEVICE_REQUEST Request; ZeroMem (&Request, sizeof (Request)); Request.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_STANDARD | USB_TARGET_DEVICE; Request.Request = USB_REQ_GET_DESCRIPTOR; Request.Index = 0; Request.Value = DescriptorType << 8 | Index; Request.Length = sizeof (Header); // Read the descriptor header to see how many bytes it contains Status = UsbIo->UsbControlTransfer ( UsbIo, &Request, EfiUsbDataIn, DISPLAYLINK_USB_CTRL_TIMEOUT, Header, sizeof (Header), UsbStatus); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to read length of descriptor type x%x, index %u (code %r, USB status x%x)\n", DescriptorType, Index, Status, *UsbStatus)); return Status; } CONST UINT16 TotalLength = Header[0]; // Now we know the size of it, we can read the entire descriptor Request.Length = TotalLength; Status = UsbIo->UsbControlTransfer ( UsbIo, &Request, EfiUsbDataIn, DISPLAYLINK_USB_CTRL_TIMEOUT, Buffer, TotalLength, UsbStatus); return Status; } /** Perform a USB control transfer to read the DisplayLink vendor descriptor. @param UsbIo Pointer to the instance of the USBIO protocol @param Buffer Pointer to the buffer where descriptor should be written @param Length Length of buffer (and the maximum amount of descriptor data that shall be read) @retval EFI_SUCCESS The descriptor has been copied into Buffer @retval Other The descriptor could not be read **/ EFI_STATUS ReadCapabilitiesDescriptor ( IN EFI_USB_IO_PROTOCOL *UsbIo, OUT VOID* Buffer, IN UINT16 Length) { UINT32 UsbStatus; EFI_STATUS Status; Status = ReadDescriptor ( UsbIo, DESCRIPTOR_TYPE_DIRECTFB_CAPABILITY, 0, Buffer, Length, &UsbStatus); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Could not read capabilities descriptor from DL device (code %r, USB status x%x). Unrecognised firmware version?\n", Status, UsbStatus)); } return Status; } /** An alternative to the UBSIO protocol function EFI_USB_IO_GET_INTERFACE_DESCRIPTOR. This version allows you to specify an index. * @param UsbIo Pointer to the instance of the USBIO protocol * @param interfaceDescriptor Where the descriptor should be written * @param index The index of the descriptor required (the standard USBIO function doesn't let you do this) * @return */ EFI_STATUS UsbDisplayLinkGetInterfaceDescriptor ( IN EFI_USB_IO_PROTOCOL *UsbIo, OUT EFI_USB_INTERFACE_DESCRIPTOR* InterfaceDescriptor, UINT8 Index ) { UINT32 UsbStatus; EFI_STATUS Status; Status = ReadDescriptor ( UsbIo, USB_DESC_TYPE_INTERFACE, Index, InterfaceDescriptor, sizeof (EFI_USB_INTERFACE_DESCRIPTOR), &UsbStatus); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "USB control transfer failed while reading interface descriptor (code %r, USB status x%x)\n", Status, UsbStatus)); } return Status; }