From 1a440d96387bbbf04c24ef024e0bc19e99cd849f Mon Sep 17 00:00:00 2001 From: Oleg Ilyasov Date: Mon, 9 Dec 2024 15:57:25 -0500 Subject: [PATCH] Retrieve the USB class specific data from the configuration descriptor If USB device reports class specific descriptors, it is currently the job of device driver to parse the configuration to find the class specific data. The new library functions parse the configuration descriptor and return class specific interface and class specific endpoint descriptors. Also, these new functions allow to retrieve the data from non-default alternate settings without performing a switch to this setting. Switching to the alternate setting currently implies the execution of UsbSetInterface function that performs USB control trnasfer. In some cases this switch is not desirable so the new functions UsbGetInterfaceDescriptorSetting and UsbGetEndpointDescriptorSetting come in handy. Signed-off-by: Oleg Ilyasov --- MdePkg/Include/Library/UefiUsbLib.h | 131 +++++ MdePkg/Library/UefiUsbLib/UefiUsbLib.inf | 3 + .../Library/UefiUsbLib/UefiUsbLibInternal.h | 2 + MdePkg/Library/UefiUsbLib/UsbDxeLib.c | 533 ++++++++++++++++++ 4 files changed, 669 insertions(+) diff --git a/MdePkg/Include/Library/UefiUsbLib.h b/MdePkg/Include/Library/UefiUsbLib.h index a8ab47aeff..fd85be0670 100644 --- a/MdePkg/Include/Library/UefiUsbLib.h +++ b/MdePkg/Include/Library/UefiUsbLib.h @@ -3,6 +3,7 @@ and the standard requests defined in USB 1.1 spec. Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+Copyright (c) 2024, American Megatrends Intenational LLC. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -552,4 +553,134 @@ UsbClearEndpointHalt ( OUT UINT32 *Status ); +/** + Retrieve the interface descriptor details from the interface setting. + + This is an extended version of UsbIo->GetInterfaceDescriptor. It returns the interface + descriptor for an alternate setting of the interface without executing SET_INTERFACE + transfer. It also returns the number of class specific interfaces. + AlternateSetting parameter is the zero-based interface descriptor index that is used in USB + interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting. + + @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance. + @param[in] AlternateSetting Interface alternate setting. + @param[out] Descriptor The caller allocated buffer to return the contents of the Interface descriptor. + @param[out] CsInterfaceNumber Number of class specific interfaces for this interface setting. + + @retval EFI_SUCCESS Output parameters were updated successfully. + @retval EFI_INVALID_PARAMETER Descriptor or CsInterfaceNumber is NULL. + @retval EFI_UNSUPPORTED Setting is greater than the number of alternate settings in this interface. + @retval EFI_DEVICE_ERROR Error reading device data. + +**/ +EFI_STATUS +EFIAPI +UsbGetInterfaceDescriptorSetting ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 AlternateSetting, + OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor, + OUT UINTN *CsInterfacesNumber + ); + +/** + Retrieve the endpoint descriptor from the interface setting. + + This is an extended version of UsbIo->GetEndpointDescriptor. It returns the endpoint + descriptor for an alternate setting of a given interface. + AlternateSetting parameter is the zero-based interface descriptor index that is used in USB + interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting. + + Note: The total number of endpoints can be retrieved from the interface descriptor + returned by EDKII_USBIO_EXT_GET_INTERFACE_DESCRIPTOR function. + + @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance. + @param[in] AlternateSetting Interface alternate setting. + @param[in] Index Index of the endpoint to retrieve. The valid range is 0..15. + @param[out] Descriptor A pointer to the caller allocated USB Interface Descriptor. + + @retval EFI_SUCCESS Output parameters were updated successfully. + @retval EFI_INVALID_PARAMETER Descriptor is NULL. + @retval EFI_UNSUPPORTED Setting is greater than the number of alternate settings in this interface. + @retval EFI_NOT_FOUND Index is greater than the number of endpoints in this interface. + @retval EFI_DEVICE_ERROR Error reading device data. + +**/ +EFI_STATUS +EFIAPI +UsbGetEndpointDescriptorSetting ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 AlternateSetting, + IN UINTN Index, + OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor + ); + +/** + Retrieve class specific interface descriptor. + + AlternateSetting parameter is the zero-based interface descriptor index that is used in USB + interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting. + + @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance. + @param[in] AlternateSetting Interface alternate setting. + @param[in] Index Zero-based index of the class specific interface. + @param[in][out] BufferSize On input, the size in bytes of the return Descriptor buffer. + On output the size of data returned in Descriptor. + @param[out] Descriptor The buffer to return the contents of the class specific interface descriptor. May + be NULL with a zero BufferSize in order to determine the size buffer needed. + + @retval EFI_SUCCESS Output parameters were updated successfully. + @retval EFI_INVALID_PARAMETER BufferSize is NULL. + Buffer is NULL and *BufferSize is not zero. + @retval EFI_UNSUPPORTED Setting is greater than the number of alternate settings in this interface. + @retval EFI_NOT_FOUND Index is greater than the number of class specific interfaces. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been updated with the size + needed to complete the request. + @retval EFI_DEVICE_ERROR Error reading device data. + +**/ +EFI_STATUS +EFIAPI +UsbGetCsInterfaceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 AlternateSetting, + IN UINTN Index, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +/** + Retrieve class specific endpoint descriptor. + + AlternateSetting parameter is the zero-based interface descriptor index that is used in USB + interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting. + + @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance. + @param[in] AlternateSetting Interface alternate setting. + @param[in] Index Zero-based index of the non-zero endpoint. + @param[in][out] BufferSize On input, the size in bytes of the return Descriptor buffer. + On output the size of data returned in Descriptor. + @param[out] Descriptor The buffer to return the contents of the class specific endpoint descriptor. May + be NULL with a zero BufferSize in order to determine the size buffer needed. + + @retval EFI_SUCCESS Output parameters were updated successfully. + @retval EFI_INVALID_PARAMETER BufferSize is NULL. + Buffer is NULL and *BufferSize is not zero. + @retval EFI_UNSUPPORTED Setting is greater than the number of alternate settings in this interface. + @retval EFI_NOT_FOUND Index is greater than the number of endpoints in this interface. + Endpoint does not have class specific endpoint descriptor. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been updated with the size + needed to complete the request. + @retval EFI_DEVICE_ERROR Error reading device data. + +**/ +EFI_STATUS +EFIAPI +UsbGetCsEndpointDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 AlternateSetting, + IN UINTN Index, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + #endif diff --git a/MdePkg/Library/UefiUsbLib/UefiUsbLib.inf b/MdePkg/Library/UefiUsbLib/UefiUsbLib.inf index bb483b922f..ae6d598f23 100644 --- a/MdePkg/Library/UefiUsbLib/UefiUsbLib.inf +++ b/MdePkg/Library/UefiUsbLib/UefiUsbLib.inf @@ -5,6 +5,7 @@ # Usb Hid 1.1 spec and the standard requests defined in Usb 1.1 spec. # # Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2024, American Megatrends International LLC. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -19,6 +20,7 @@ MODULE_TYPE = UEFI_DRIVER VERSION_STRING = 1.0 LIBRARY_CLASS = UefiUsbLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + DESTRUCTOR = UefiUsbLibDestructor # @@ -37,6 +39,7 @@ DebugLib BaseMemoryLib PcdLib + UefiBootServicesTableLib [Pcd] gEfiMdePkgTokenSpaceGuid.PcdUsbTransferTimeoutValue ## CONSUMES diff --git a/MdePkg/Library/UefiUsbLib/UefiUsbLibInternal.h b/MdePkg/Library/UefiUsbLib/UefiUsbLibInternal.h index 185fc6d86e..9112983452 100644 --- a/MdePkg/Library/UefiUsbLib/UefiUsbLibInternal.h +++ b/MdePkg/Library/UefiUsbLib/UefiUsbLibInternal.h @@ -5,6 +5,7 @@ This file includes package header files, library classes and protocol, PPI & GUID definitions. Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2024, American Megatrends International LLC. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -17,6 +18,7 @@ #include #include #include +#include #include diff --git a/MdePkg/Library/UefiUsbLib/UsbDxeLib.c b/MdePkg/Library/UefiUsbLib/UsbDxeLib.c index 53b90984f7..b783a31620 100644 --- a/MdePkg/Library/UefiUsbLib/UsbDxeLib.c +++ b/MdePkg/Library/UefiUsbLib/UsbDxeLib.c @@ -4,12 +4,16 @@ in Usb specification 9.4 section. Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2024, American Megatrends International LLC. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "UefiUsbLibInternal.h" +static UINT8 *mConfigData = NULL; +static EFI_USB_DEVICE_DESCRIPTOR mDeviceDescriptor; + /** Get the descriptor of the specified USB device. @@ -650,3 +654,532 @@ UsbClearEndpointHalt ( return Result; } + +/** + Global library data initialization. + + Library public functions' input is the instance of UsbIo protocol. Check if the global + data relevant to the UsbIo. If not, read the device and update the global data. + + @param UsbIo The instance of EFI_USB_IO_PROTOCOL. + + @retval EFI_SUCCESS The global data is updated. + @retval EFI_NOT_FOUND The UsbIo configuration was not found. + +**/ +static +EFI_STATUS +InitUsbConfigDescriptorData ( + EFI_USB_IO_PROTOCOL *UsbIo + ) +{ + EFI_STATUS Status; + EFI_USB_DEVICE_DESCRIPTOR DevDesc; + EFI_USB_CONFIG_DESCRIPTOR CnfDesc; + UINT8 ConfigNum; + UINT8 ConfigValue; + UINT32 UsbStatus; + + // + // Get UsbIo device and configuration descriptors. + // + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); + ASSERT_EFI_ERROR (Status); + + Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &CnfDesc); + ASSERT_EFI_ERROR (Status); + + if (mConfigData != NULL) { + if ( (CompareMem (&DevDesc, &mDeviceDescriptor, sizeof (EFI_USB_DEVICE_DESCRIPTOR)) == 0) + && (CompareMem (&CnfDesc, mConfigData, sizeof (EFI_USB_CONFIG_DESCRIPTOR)) == 0)) + { + return EFI_SUCCESS; + } + + gBS->FreePool (mConfigData); + mConfigData = NULL; + } + + CopyMem (&mDeviceDescriptor, &DevDesc, sizeof (EFI_USB_DEVICE_DESCRIPTOR)); + + // + // Examine device with multiple configurations: find configuration index of UsbIo config descriptor. + // + // Use EFI_USB_DEVICE_DESCRIPTOR.NumConfigurations to loop through configuration descriptors, match + // EFI_USB_CONFIG_DESCRIPTOR.ConfigurationValue to the configuration value reported by UsbIo->UsbGetConfigDescriptor. + // The index of the matched configuration is used in wValue of the following GET_DESCRIPTOR request. + // + ConfigValue = CnfDesc.ConfigurationValue; + for (ConfigNum = 0; ConfigNum < DevDesc.NumConfigurations; ConfigNum++) { + Status = UsbGetDescriptor ( + UsbIo, + (USB_DESC_TYPE_CONFIG << 8) | ConfigNum, + 0, + sizeof (EFI_USB_CONFIG_DESCRIPTOR), + &CnfDesc, + &UsbStatus + ); + ASSERT_EFI_ERROR (Status); + + if (CnfDesc.ConfigurationValue == ConfigValue) { + break; + } + } + + ASSERT (ConfigNum < DevDesc.NumConfigurations); + if (ConfigNum == DevDesc.NumConfigurations) { + return EFI_NOT_FOUND; + } + + // + // ConfigNum has zero based index of the configuration that UsbIo belongs to. Use this index to retrieve + // full configuration descriptor data. + // + Status = gBS->AllocatePool (EfiBootServicesData, CnfDesc.TotalLength, (VOID **)&mConfigData); + ASSERT_EFI_ERROR (Status); + + Status = UsbGetDescriptor ( + UsbIo, + (USB_DESC_TYPE_CONFIG << 8) | ConfigNum, + 0, + CnfDesc.TotalLength, + mConfigData, + &UsbStatus + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Find descriptor of a given type within data area pointed by mConfigData. + + The following are the assumptions of the configuration descriptor layout: + - mConfigData is populated with the configuration data that contains USB interface referenced by UsbIo. + - Endpoint may have only one class specific descriptor that immediately follows the endpoint descriptor. + + @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance. + @param[in] DescType Type of descriptor to look for. + @param[in] Setting Interface alternate setting. + @param[in] Index Index of the descriptor. This descriptor index is used to find a specific + descriptor (only for endpoint descriptors and class specific interface descriptors) + when several descriptors of the same type are implemented in a device. For other + descriptor types, a descriptor index of zero must be used. + @param[out] Data A pointer to the caller allocated Descriptor. + + @retval EFI_SUCCESS Output parameters were updated successfully. + @retval EFI_UNSUPPORTED Setting is greater than the number of alternate settings in this interface. + @retval EFI_NOT_FOUND Index is greater than the number of descriptors of the requested type in this + interface. +**/ +static +EFI_STATUS +FindUsbDescriptor ( + EFI_USB_IO_PROTOCOL *UsbIo, + UINT8 DescType, + UINT16 Setting, + UINTN Index, + VOID **Data + ) +{ + EFI_USB_INTERFACE_DESCRIPTOR IntfDesc; + EFI_STATUS Status; + UINT8 *BufferPtr; + UINT8 *BufferEnd; + UINT8 *ConfigEnd; + UINTN Idx; + + // + // Find the interface descriptor referenced by UsbIo in the current configuration + // + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IntfDesc); + ASSERT_EFI_ERROR (Status); + + ConfigEnd = mConfigData + ((EFI_USB_CONFIG_DESCRIPTOR *)mConfigData)->TotalLength; + + for (BufferPtr = mConfigData; BufferPtr < ConfigEnd; BufferPtr += BufferPtr[0]) { + if (BufferPtr[1] == USB_DESC_TYPE_INTERFACE) { + if ((BufferPtr[2] == IntfDesc.InterfaceNumber) && (BufferPtr[3] == (UINT8)Setting)) { + break; + } + } + } + + if (BufferPtr >= ConfigEnd) { + return EFI_UNSUPPORTED; + } + + // + // Found the beginning of the interface, find the ending + // + for (BufferEnd = BufferPtr + BufferPtr[0]; BufferEnd < ConfigEnd; BufferEnd += BufferEnd[0]) { + if (BufferEnd[1] == USB_DESC_TYPE_INTERFACE) { + break; + } + } + + Idx = 0; + + if (DescType == USB_DESC_TYPE_INTERFACE) { + *Data = BufferPtr; + return EFI_SUCCESS; + } + + if ((DescType == USB_DESC_TYPE_ENDPOINT) || (DescType == USB_DESC_TYPE_CS_ENDPOINT)) { + while (BufferPtr < BufferEnd) { + BufferPtr += BufferPtr[0]; + if (BufferPtr[1] == USB_DESC_TYPE_ENDPOINT) { + if (Idx == Index) { + if (DescType == USB_DESC_TYPE_CS_ENDPOINT) { + BufferPtr += BufferPtr[0]; + if (BufferPtr[1] != USB_DESC_TYPE_CS_ENDPOINT) { + break; + } + } + + *Data = BufferPtr; + return EFI_SUCCESS; + } + + Idx++; + } + } + } + + if (DescType == USB_DESC_TYPE_CS_INTERFACE) { + while (BufferPtr < BufferEnd) { + BufferPtr += BufferPtr[0]; + if (BufferPtr[1] == USB_DESC_TYPE_CS_INTERFACE) { + if (Idx == Index) { + *Data = BufferPtr; + return EFI_SUCCESS; + } + + Idx++; + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Retrieve the number of class specific interface descriptors. + + @param[in] Data A pointer to the USB interface descriptor that may contain class code descriptors. + + @retval UINT8 Number of the class code interface descriptors. + +**/ +static +UINT8 +FindNumberOfCsInterfaces ( + VOID *Data + ) +{ + UINT8 *Buffer; + UINT8 *ConfigEnd; + UINT8 Index; + + Buffer = Data; + ConfigEnd = mConfigData + ((EFI_USB_CONFIG_DESCRIPTOR *)mConfigData)->TotalLength; + + Index = 0; + + for (Buffer += Buffer[0]; Buffer < ConfigEnd; Buffer += Buffer[0]) { + if (Buffer[1] == USB_DESC_TYPE_INTERFACE) { + break; + } + + if (Buffer[1] == USB_DESC_TYPE_CS_INTERFACE) { + Index++; + } + } + + return Index; +} + +/** + Retrieve the interface descriptor details from the interface setting. + + This is an extended version of UsbIo->GetInterfaceDescriptor. It returns the interface + descriptor for an alternate setting of the interface without executing SET_INTERFACE + transfer. It also returns the number of class specific interfaces. + AlternateSetting parameter is the zero-based interface descriptor index that is used in USB + interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting. + + + @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance. + @param[in] AlternateSetting Interface alternate setting. + @param[out] Descriptor The caller allocated buffer to return the contents of the Interface descriptor. + @param[out] CsInterfaceNumber Number of class specific interfaces for this interface setting. + + @retval EFI_SUCCESS Output parameters were updated successfully. + @retval EFI_INVALID_PARAMETER Descriptor or CsInterfaceNumber is NULL. + @retval EFI_UNSUPPORTED AlternateSetting is greater than the number of alternate settings in this interface. + @retval EFI_DEVICE_ERROR Error reading device data. + +**/ +EFI_STATUS +EFIAPI +UsbGetInterfaceDescriptorSetting ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 AlternateSetting, + OUT EFI_USB_INTERFACE_DESCRIPTOR *Descriptor, + OUT UINTN *CsInterfacesNumber + ) +{ + EFI_STATUS Status; + VOID *Data; + EFI_TPL OldTpl; + + if ((Descriptor == NULL) || (CsInterfacesNumber == NULL)) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + Status = InitUsbConfigDescriptorData (This); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + Status = FindUsbDescriptor (This, USB_DESC_TYPE_INTERFACE, AlternateSetting, 0, &Data); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + *CsInterfacesNumber = FindNumberOfCsInterfaces (Data); + CopyMem (Descriptor, Data, sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Retrieve the endpoint descriptor from the interface setting. + + This is an extended version of UsbIo->GetEndpointDescriptor. It returns the endpoint + descriptor for an alternate setting of a given interface. + AlternateSetting parameter is the zero-based interface descriptor index that is used in USB + interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting. + + Note: The total number of endpoints can be retrieved from the interface descriptor + returned by EDKII_USBIO_EXT_GET_INTERFACE_DESCRIPTOR function. + + @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance. + @param[in] AlternateSetting Interface alternate setting. + @param[in] Index Index of the endpoint to retrieve. The valid range is 0..15. + @param[out] Descriptor A pointer to the caller allocated USB Interface Descriptor. + + @retval EFI_SUCCESS Output parameters were updated successfully. + @retval EFI_INVALID_PARAMETER Descriptor is NULL. + @retval EFI_UNSUPPORTED AlternateSetting is greater than the number of alternate settings in this interface. + @retval EFI_NOT_FOUND Index is greater than the number of endpoints in this interface. + @retval EFI_DEVICE_ERROR Error reading device data. + +**/ +EFI_STATUS +EFIAPI +UsbGetEndpointDescriptorSetting ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 AlternateSetting, + IN UINTN Index, + OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor + ) +{ + EFI_STATUS Status; + VOID *Data; + EFI_TPL OldTpl; + + if (Descriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + Status = InitUsbConfigDescriptorData (This); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + Status = FindUsbDescriptor (This, USB_DESC_TYPE_ENDPOINT, AlternateSetting, Index, &Data); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + CopyMem (Descriptor, Data, sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)); + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Retrieve class specific interface descriptor. + + AlternateSetting parameter is the zero-based interface descriptor index that is used in USB + interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting. + + @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance. + @param[in] AlternateSetting Interface alternate setting. + @param[in] Index Zero-based index of the class specific interface. + @param[in][out] BufferSize On input, the size in bytes of the return Descriptor buffer. + On output the size of data returned in Descriptor. + @param[out] Descriptor The buffer to return the contents of the class specific interface descriptor. May + be NULL with a zero BufferSize in order to determine the size buffer needed. + + @retval EFI_SUCCESS Output parameters were updated successfully. + @retval EFI_INVALID_PARAMETER BufferSize is NULL. + Buffer is NULL and *BufferSize is not zero. + @retval EFI_UNSUPPORTED AlternateSetting is greater than the number of alternate settings in this interface. + @retval EFI_NOT_FOUND Index is greater than the number of class specific interfaces. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been updated with the size + needed to complete the request. + @retval EFI_DEVICE_ERROR Error reading device data. + +**/ +EFI_STATUS +EFIAPI +UsbGetCsInterfaceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 AlternateSetting, + IN UINTN Index, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + VOID *Data; + UINT8 DescLength; + EFI_TPL OldTpl; + + if ((BufferSize == NULL) || ((Buffer == NULL) && (*BufferSize != 0))) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + Status = InitUsbConfigDescriptorData (This); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + Status = FindUsbDescriptor (This, USB_DESC_TYPE_CS_INTERFACE, AlternateSetting, Index, &Data); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + DescLength = ((UINT8 *)Data)[0]; + + if ((Buffer == NULL) || (DescLength > *BufferSize)) { + *BufferSize = DescLength; + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + + CopyMem (Buffer, Data, DescLength); + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Retrieve class specific endpoint descriptor. + + AlternateSetting parameter is the zero-based interface descriptor index that is used in USB + interface descriptor as USB_INTERFACE_DESCRIPTOR.AlternateSetting. + + @param[in] This A pointer to the EFI_USB_IO_PROTOCOL instance. + @param[in] AlternateSetting Interface alternate setting. + @param[in] Index Zero-based index of the non-zero endpoint. + @param[in][out] BufferSize On input, the size in bytes of the return Descriptor buffer. + On output the size of data returned in Descriptor. + @param[out] Descriptor The buffer to return the contents of the class specific endpoint descriptor. May + be NULL with a zero BufferSize in order to determine the size buffer needed. + + @retval EFI_SUCCESS Output parameters were updated successfully. + @retval EFI_INVALID_PARAMETER BufferSize is NULL. + Buffer is NULL and *BufferSize is not zero. + @retval EFI_UNSUPPORTED AlternateSetting is greater than the number of alternate settings in this interface. + @retval EFI_NOT_FOUND Index is greater than the number of endpoints in this interface. + Endpoint does not have class specific endpoint descriptor. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been updated with the size + needed to complete the request. + @retval EFI_DEVICE_ERROR Error reading device data. + +**/ +EFI_STATUS +EFIAPI +UsbGetCsEndpointDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 AlternateSetting, + IN UINTN Index, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + VOID *Data; + UINT8 DescLength; + EFI_TPL OldTpl; + + if ((BufferSize == NULL) || ((Buffer == NULL) && (*BufferSize != 0))) { + return EFI_INVALID_PARAMETER; + } + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + Status = InitUsbConfigDescriptorData (This); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + Status = FindUsbDescriptor (This, USB_DESC_TYPE_CS_ENDPOINT, AlternateSetting, Index, &Data); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + DescLength = ((UINT8 *)Data)[0]; + + if ((Buffer == NULL) || (DescLength > *BufferSize)) { + *BufferSize = DescLength; + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + + CopyMem (Buffer, Data, DescLength); + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Destructor frees memory which was allocated by the library functions. + + @param ImageHandle Handle that identifies the image to be unloaded. + @param SystemTable The system table. + + @retval EFI_SUCCESS The image has been unloaded. + +**/ +EFI_STATUS +EFIAPI +UefiUsbLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (mConfigData != NULL) { + gBS->FreePool (mConfigData); + } + + return EFI_SUCCESS; +}