From: "olegi via groups.io" <olegi=ami.com@groups.io>
To: "gaoliming" <gaoliming@byosoft.com.cn>, devel@edk2.groups.io
Subject: Re: [edk2-devel] 回复: [edk2-devel] 回复: [edk2-devel] [staging/usb_iad] MdeModulePkg UsbBusDxe: Add support for USB Interface Association
Date: Mon, 06 Jan 2025 13:53:36 -0800 [thread overview]
Message-ID: <25918.1736200416648086778@groups.io> (raw)
In-Reply-To: <02ed01db5e87$e72db590$b58920b0$@byosoft.com.cn>
[-- Attachment #1.1: Type: text/plain, Size: 1035 bytes --]
Attaching the USB Association IO consumer code sample. This is the prototype of the USB video class code driver prototype, it illustrates the usage of USB Association IO protocol.
Usb bus driver in MdeModulePkg implements this protocol (implementation is also in the patch). The definition is in MdePkg so that it can be implemented by non-edk2 USB bus.
Usb association is a part of USB specification, USB Association IO protocol should be eventually added to UEFI specification.
There are additional comments by Michael Kinney (@mdkinney) in https://github.com/tianocore/edk2/pull/10558
Please take a look and let me know how to proceed.
Thanks,
Oleg
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#120965): https://edk2.groups.io/g/devel/message/120965
Mute This Topic: https://groups.io/mt/110420476/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
[-- Attachment #1.2: Type: text/html, Size: 1673 bytes --]
[-- Attachment #2: diff.patch --]
[-- Type: application/octet-stream, Size: 67109 bytes --]
diff --git a/MdeModulePkg/Application/UsbVideoDxe/ComponentName.c b/MdeModulePkg/Application/UsbVideoDxe/ComponentName.c
new file mode 100644
index 0000000000..48b26e7ab7
--- /dev/null
+++ b/MdeModulePkg/Application/UsbVideoDxe/ComponentName.c
@@ -0,0 +1,298 @@
+/** @file
+
+ UEFI Component Name(2) protocol implementation for Usb Video driver.
+
+Copyright (c) 2024, American Megatrends LLC.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiLib.h>
+#include <PiDxe.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form 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 name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language 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
+UsbVideoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified 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 specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus 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 name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle 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 readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @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 currently
+ 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
+UsbVideoComponentNameGetControllerName (
+ 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 gUsbVideoComponentName = {
+ UsbVideoComponentNameGetDriverName,
+ UsbVideoComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUsbVideoComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbVideoComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbVideoComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE gUsbVideoDriverNameTable[] = {
+ { "eng;en", L"Usb Video Driver" },
+ { NULL, NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form 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 name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language 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
+UsbVideoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ gUsbVideoDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUsbVideoComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified 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 specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus 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 name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle 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 readable 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_HANDLE.
+
+ @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 currently
+ 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
+UsbVideoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Application/UsbVideoDxe/UsbVideoDxe.c b/MdeModulePkg/Application/UsbVideoDxe/UsbVideoDxe.c
new file mode 100644
index 0000000000..57d53153e6
--- /dev/null
+++ b/MdeModulePkg/Application/UsbVideoDxe/UsbVideoDxe.c
@@ -0,0 +1,222 @@
+/** @file
+
+ Usb Video driver provides services for Usb video device
+
+ (C) Copyright 2011-2024, American Megatrends International LLC<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Protocol/UsbAssociationIo.h>
+#include "UsbVideoDxe.h"
+
+//
+// USB Keyboard Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gUsbVideoDriverBinding = {
+ UsbVideoDriverBindingSupported,
+ UsbVideoDriverBindingStart,
+ UsbVideoDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Check whether USB video driver supports this device.
+
+ @param This The USB video driver binding protocol.
+ @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
+UsbVideoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL *UsbIaIo;
+ EFI_USB_INTERFACE_ASSOCIATION_DESCRIPTOR Desc;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ (VOID **)&UsbIaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UsbIaIo->UsbIaGetAssociationDescriptor (UsbIaIo, &Desc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if ((Desc.FunctionClass == USB_VIDEO_CLASS) && (Desc.FunctionSubclass == USB_VIDEO_INTERFACE_COLLECTION_SUBCLASS)) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Starts the USB video device with this driver.
+
+ @param This The USB video driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the usb video driver.
+ @retval EFI_UNSUPPORTED No interrupt endpoint can be found.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbVideoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL *UsbIaIo;
+ EFI_USB_INTERFACE_ASSOCIATION_DESCRIPTOR AssocDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR IntrfDesc;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINT8 IfNum;
+ UINTN SettingCount;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ (VOID **)&UsbIaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UsbIaIo->UsbIaGetAssociationDescriptor (UsbIaIo, &AssocDesc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (IfNum = AssocDesc.FirstInterface; IfNum < (AssocDesc.FirstInterface + AssocDesc.InterfaceCount); IfNum++) {
+ Status = UsbIaIo->UsbIaGetAssociateSettings (UsbIaIo, IfNum, &UsbIo, &SettingCount);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IntrfDesc);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (IntrfDesc.InterfaceClass == USB_VIDEO_CLASS) {
+ if (IntrfDesc.InterfaceSubClass == USB_VIDEOCONTROL_SUBCLASS) {
+ // found video control UsbIo, store it in the device for future use
+ // TBD
+ //
+ }
+ if (IntrfDesc.InterfaceSubClass == USB_VIDEOSTREAMING_SUBCLASS) {
+ // found video streaming UsbIo, store it in the device for future use
+ // TBD
+ //
+ }
+ }
+ }
+ if (IfNum == (AssocDesc.FirstInterface + AssocDesc.InterfaceCount)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Stops the USB video device handled by this driver.
+
+ @param This The USB video driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol
+ is not installed on Controller.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbVideoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The USB video driver entry pointer.
+
+ @param ImageHandle The driver image handle.
+ @param SystemTable The system table.
+
+ @return EFI_SUCCESS The component name protocol is installed.
+ @return Others Failed to init the usb driver.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbVideoDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUsbVideoDriverBinding,
+ ImageHandle,
+ &gUsbVideoComponentName,
+ &gUsbVideoComponentName2
+ );
+}
diff --git a/MdeModulePkg/Application/UsbVideoDxe/UsbVideoDxe.h b/MdeModulePkg/Application/UsbVideoDxe/UsbVideoDxe.h
new file mode 100644
index 0000000000..e3779e691b
--- /dev/null
+++ b/MdeModulePkg/Application/UsbVideoDxe/UsbVideoDxe.h
@@ -0,0 +1,102 @@
+/** @file
+ Header file for USB Video Driver's Data Structures.
+
+Copyright (c) 2025, American Megatrends LLC.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_USB_VIDEO_H_
+#define _EFI_USB_VIDEO_H_
+
+#include <Uefi.h>
+#include <Protocol/DriverBinding.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <PiDxe.h>
+
+#define USB_VIDEO_CLASS 0xE
+#define USB_VIDEO_INTERFACE_COLLECTION_SUBCLASS 0x3
+#define USB_VIDEOCONTROL_SUBCLASS 0x1
+#define USB_VIDEOSTREAMING_SUBCLASS 0x2
+
+
+typedef struct _USB_VIDEO_DEVICE {
+ EFI_USB_IO_PROTOCOL *VideoCtlIo;
+} USB_VIDEO_DEVICE;
+
+extern EFI_COMPONENT_NAME_PROTOCOL gUsbVideoComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUsbVideoComponentName2;
+
+//
+// Functions of Driver Binding Protocol
+//
+
+/**
+ Check whether USB video driver supports this device.
+
+ @param This The USB video driver binding protocol.
+ @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
+UsbVideoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the USB video device with this driver.
+
+ @param This The USB video driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the usb video driver.
+ @retval EFI_UNSUPPORTED No interrupt endpoint can be found.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbVideoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops the USB video device handled by this driver.
+
+ @param This The USB video driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_UNSUPPORTED Simple Text In Protocol or Simple Text In Ex Protocol
+ is not installed on Controller.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbVideoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+
+#endif
diff --git a/MdeModulePkg/Application/UsbVideoDxe/UsbVideoDxe.inf b/MdeModulePkg/Application/UsbVideoDxe/UsbVideoDxe.inf
new file mode 100644
index 0000000000..cfa7fac901
--- /dev/null
+++ b/MdeModulePkg/Application/UsbVideoDxe/UsbVideoDxe.inf
@@ -0,0 +1,44 @@
+## @file
+# Usb Video driver provides services for Usb video device
+#
+# Copyright (c) 2025, American Megatrends LLC. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbVideoDxe
+ FILE_GUID = 4134A1FD-D9DB-405E-9876-7E58DB3B7908
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UsbVideoDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ UsbVideoDxe.c
+ UsbVideoDxe.h
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DevicePathLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ ReportStatusCodeLib
+
+[Protocols]
+ gEfiUsbIoProtocolGuid
+ gEfiUsbInterfaceAssociationProtocolGuid
+
\ No newline at end of file
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
index 21a24218fc..f734442737 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
@@ -3,6 +3,7 @@
Usb Bus Driver Binding and Bus IO Protocol.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2025, American Megatrends International, LLC. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -15,6 +16,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Protocol/Usb2HostController.h>
#include <Protocol/UsbHostController.h>
#include <Protocol/UsbIo.h>
+#include <Protocol/UsbAssociationIo.h>
#include <Protocol/DevicePath.h>
#include <Library/BaseLib.h>
@@ -29,10 +31,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <IndustryStandard/Usb.h>
-typedef struct _USB_DEVICE USB_DEVICE;
-typedef struct _USB_INTERFACE USB_INTERFACE;
-typedef struct _USB_BUS USB_BUS;
-typedef struct _USB_HUB_API USB_HUB_API;
+typedef struct _USB_DEVICE USB_DEVICE;
+typedef struct _USB_INTERFACE USB_INTERFACE;
+typedef struct _USB_BUS USB_BUS;
+typedef struct _USB_HUB_API USB_HUB_API;
+typedef struct _USB_ASSOCIATION USB_ASSOCIATION;
#include "UsbUtility.h"
#include "UsbDesc.h"
@@ -132,8 +135,9 @@ typedef struct _USB_HUB_API USB_HUB_API;
//
#define USB_BUS_TPL TPL_NOTIFY
-#define USB_INTERFACE_SIGNATURE SIGNATURE_32 ('U', 'S', 'B', 'I')
-#define USB_BUS_SIGNATURE SIGNATURE_32 ('U', 'S', 'B', 'B')
+#define USB_INTERFACE_SIGNATURE SIGNATURE_32 ('U', 'S', 'B', 'I')
+#define USB_BUS_SIGNATURE SIGNATURE_32 ('U', 'S', 'B', 'B')
+#define USB_ASSOCIATION_SIGNATURE SIGNATURE_32 ('U', 'S', 'B', 'A')
#define USB_BIT(a) ((UINTN)(1 << (a)))
#define USB_BIT_IS_SET(Data, Bit) ((BOOLEAN)(((Data) & (Bit)) == (Bit)))
@@ -141,6 +145,9 @@ typedef struct _USB_HUB_API USB_HUB_API;
#define USB_INTERFACE_FROM_USBIO(a) \
CR(a, USB_INTERFACE, UsbIo, USB_INTERFACE_SIGNATURE)
+#define USB_ASSOCIATION_FROM_USBIA(a) \
+ CR(a, USB_ASSOCIATION, UsbIaProtocol, USB_ASSOCIATION_SIGNATURE)
+
#define USB_BUS_FROM_THIS(a) \
CR(a, USB_BUS, BusId, USB_BUS_SIGNATURE)
@@ -176,6 +183,9 @@ struct _USB_DEVICE {
UINT16 LangId[USB_MAX_LANG_ID];
UINT16 TotalLangId;
+ UINT8 NumOfAssociation;
+ USB_ASSOCIATION *Associations[USB_MAX_ASSOCIATION];
+
UINT8 NumOfInterface;
USB_INTERFACE *Interfaces[USB_MAX_INTERFACE];
@@ -230,6 +240,23 @@ struct _USB_INTERFACE {
UINT8 MaxSpeed;
};
+//
+// Stands for a function implemented using interface association
+//
+struct _USB_ASSOCIATION {
+ UINTN Signature;
+ USB_DEVICE *Device;
+ USB_INTERFACE_ASSOCIATION_DESC *IaDesc;
+
+ //
+ // Handles and protocols
+ //
+ EFI_HANDLE Handle;
+ EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL UsbIaProtocol;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN IsManaged;
+};
+
//
// Stands for the current USB Bus
//
@@ -751,9 +778,10 @@ UsbBusControllerDriverStop (
IN EFI_HANDLE *ChildHandleBuffer
);
-extern EFI_USB_IO_PROTOCOL mUsbIoProtocol;
-extern EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding;
-extern EFI_COMPONENT_NAME_PROTOCOL mUsbBusComponentName;
-extern EFI_COMPONENT_NAME2_PROTOCOL mUsbBusComponentName2;
+extern EFI_USB_IO_PROTOCOL mUsbIoProtocol;
+extern EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL mUsbIaProtocol;
+extern EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL mUsbBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL mUsbBusComponentName2;
#endif
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
index dd85894346..fdb40f9110 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
@@ -2,6 +2,7 @@
# The Usb Bus Dxe driver is used to enumerate and manage all attached usb devices.
#
# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2025, American Megatrends International, LLC. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -40,6 +41,7 @@
UsbUtility.c
UsbDesc.h
UsbBus.h
+ UsbIntfAssoc.c
[Packages]
MdePkg/MdePkg.dec
@@ -58,6 +60,7 @@
[Protocols]
gEfiUsbIoProtocolGuid ## BY_START
+ gEfiUsbInterfaceAssociationProtocolGuid
## TO_START
## BY_START
gEfiDevicePathProtocolGuid
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
index 8b078e7e49..f96df11e99 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
@@ -3,6 +3,7 @@
Manage Usb Descriptor List
Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2025, American Megatrends International, LLC. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -46,6 +47,24 @@ UsbFreeInterfaceDesc (
FreePool (Setting);
}
+/**
+ Free the interface association descriptor
+
+ @param Iad The interface association descriptor to free.
+
+**/
+VOID
+UsbFreeInterfaceAssociationDesc (
+ IN USB_INTERFACE_ASSOCIATION_DESC *Iad
+ )
+{
+ if (Iad->Interfaces != NULL) {
+ FreePool (Iad->Interfaces);
+ }
+
+ FreePool (Iad);
+}
+
/**
Free a configuration descriptor with its interface
descriptors. It may be initialized partially.
@@ -167,6 +186,11 @@ UsbCreateDesc (
CtrlLen = sizeof (USB_ENDPOINT_DESC);
break;
+ case USB_DESC_TYPE_INTERFACE_ASSOCIATION:
+ DescLen = sizeof (EFI_USB_INTERFACE_ASSOCIATION_DESCRIPTOR);
+ CtrlLen = sizeof (USB_INTERFACE_ASSOCIATION_DESC);
+ break;
+
default:
ASSERT (FALSE);
return NULL;
@@ -231,6 +255,7 @@ UsbCreateDesc (
return NULL;
}
+ ASSERT (CtrlLen >= DescLen);
CopyMem (Desc, Head, (UINTN)DescLen);
*Consumed = Offset;
@@ -319,6 +344,85 @@ ON_ERROR:
return NULL;
}
+/**
+ Parse an interface association and its interfaces.
+
+ @param DescBuf The buffer of raw interface association descriptor.
+ @param Len The length of the raw descriptor buffer.
+ @param Config The device configuration buffer.
+ @param Consumed The number of raw descriptor consumed.
+
+ @return The created interface association descriptor or NULL if failed.
+
+**/
+USB_INTERFACE_ASSOCIATION_DESC *
+UsbParseInterfaceAssociationDesc (
+ IN UINT8 *DescBuf,
+ IN UINTN Len,
+ IN USB_CONFIG_DESC *Config,
+ OUT UINTN *Consumed
+ )
+{
+ USB_INTERFACE_ASSOCIATION_DESC *Iad;
+ UINT8 Index;
+ UINT8 IfIndex;
+ UINT8 i;
+ UINTN NumIf;
+ UINTN Used;
+
+ *Consumed = 0;
+ Iad = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_INTERFACE_ASSOCIATION, &Used);
+
+ if (Iad == NULL) {
+ return NULL;
+ }
+
+ //
+ // Create an array to hold the association's interfaces
+ //
+ NumIf = Iad->Desc.InterfaceCount;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "UsbParseInterfaceAssociationDesc: interface association has %d interfaces\n",
+ (UINT32)NumIf
+ ));
+
+ ASSERT (NumIf > 0);
+ if (NumIf == 0) {
+ DEBUG ((DEBUG_ERROR, "UsbParseInterfaceAssociationDesc: no interfaces are reported for this association.\n"));
+ goto ON_ERROR;
+ }
+
+ Iad->Interfaces = AllocateZeroPool (sizeof (USB_INTERFACE_DESC *) * NumIf);
+
+ //
+ // Populate interfaces for this association
+ //
+ IfIndex = 0;
+ for (Index = Iad->Desc.FirstInterface; Index < (Iad->Desc.FirstInterface + Iad->Desc.InterfaceCount); Index++) {
+ for (i = 0; i < Config->Desc.NumInterfaces; i++) {
+ if (Index == Config->Interfaces[i]->Settings[0]->Desc.InterfaceNumber) {
+ break;
+ }
+ }
+
+ if (i == Config->Desc.NumInterfaces) {
+ DEBUG ((DEBUG_ERROR, "UsbParseInterfaceAssociationDesc: interface %d not found.\n", Index));
+ goto ON_ERROR;
+ }
+
+ Iad->Interfaces[IfIndex++] = Config->Interfaces[i];
+ }
+
+ *Consumed = Used;
+ return Iad;
+
+ON_ERROR:
+ UsbFreeInterfaceAssociationDesc (Iad);
+ return NULL;
+}
+
/**
Parse the configuration descriptor and its interfaces.
@@ -334,16 +438,22 @@ UsbParseConfigDesc (
IN UINTN Len
)
{
- USB_CONFIG_DESC *Config;
- USB_INTERFACE_SETTING *Setting;
- USB_INTERFACE_DESC *Interface;
- UINTN Index;
- UINTN NumIf;
- UINTN Consumed;
+ USB_CONFIG_DESC *Config;
+ USB_INTERFACE_SETTING *Setting;
+ USB_INTERFACE_DESC *Interface;
+ UINTN Index;
+ UINTN NumIf;
+ UINTN Consumed;
+ UINT8 *Buffer;
+ UINTN Length;
+ USB_INTERFACE_ASSOCIATION_DESC *Iad;
ASSERT (DescBuf != NULL);
- Config = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_CONFIG, &Consumed);
+ Buffer = DescBuf;
+ Length = Len;
+
+ Config = UsbCreateDesc (Buffer, Length, USB_DESC_TYPE_CONFIG, &Consumed);
if (Config == NULL) {
return NULL;
@@ -384,15 +494,15 @@ UsbParseConfigDesc (
// setting 1|interface 1, setting 0|interface 2, setting 0|. Check
// USB2.0 spec, page 267.
//
- DescBuf += Consumed;
- Len -= Consumed;
+ Buffer += Consumed;
+ Length -= Consumed;
//
// Make allowances for devices that return extra data at the
// end of their config descriptors
//
- while (Len >= sizeof (EFI_USB_INTERFACE_DESCRIPTOR)) {
- Setting = UsbParseInterfaceDesc (DescBuf, Len, &Consumed);
+ while (Length >= sizeof (EFI_USB_INTERFACE_DESCRIPTOR)) {
+ Setting = UsbParseInterfaceDesc (Buffer, Length, &Consumed);
if (Setting == NULL) {
DEBUG ((DEBUG_ERROR, "UsbParseConfigDesc: warning: failed to get interface setting, stop parsing now.\n"));
@@ -416,8 +526,36 @@ UsbParseConfigDesc (
Interface->Settings[Interface->NumOfSetting] = Setting;
Interface->NumOfSetting++;
- DescBuf += Consumed;
- Len -= Consumed;
+ Buffer += Consumed;
+ Length -= Consumed;
+ }
+
+ //
+ // Process interface association descriptors.
+ //
+ Buffer = DescBuf;
+ Length = Len;
+
+ while (Length >= sizeof (EFI_USB_INTERFACE_ASSOCIATION_DESCRIPTOR)) {
+ Iad = UsbParseInterfaceAssociationDesc (Buffer, Length, Config, &Consumed);
+
+ if (Iad == NULL) {
+ break;
+ }
+
+ //
+ // Insert the association descriptor to the corresponding set.
+ //
+ if (Config->NumOfIads >= USB_MAX_ASSOCIATION) {
+ DEBUG ((DEBUG_ERROR, "UsbParseConfigDesc: too many interface association descriptors in this configuration.\n"));
+ goto ON_ERROR;
+ }
+
+ Config->Iads[Config->NumOfIads] = Iad;
+ Config->NumOfIads++;
+
+ Buffer += Consumed;
+ Length -= Consumed;
}
return Config;
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h
index ce205e706d..03f38c7afa 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h
@@ -3,6 +3,7 @@
Manage Usb Descriptor List
Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2025, American Megatrends International, LLC. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -11,6 +12,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#define _USB_DESCRIPTOR_H_
#define USB_MAX_INTERFACE_SETTING 256
+#define USB_MAX_ASSOCIATION 16
//
// The RequestType in EFI_USB_DEVICE_REQUEST is composed of
@@ -62,8 +64,15 @@ typedef struct {
} USB_INTERFACE_DESC;
typedef struct {
- EFI_USB_CONFIG_DESCRIPTOR Desc;
- USB_INTERFACE_DESC **Interfaces;
+ EFI_USB_INTERFACE_ASSOCIATION_DESCRIPTOR Desc;
+ USB_INTERFACE_DESC **Interfaces;
+} USB_INTERFACE_ASSOCIATION_DESC;
+
+typedef struct {
+ EFI_USB_CONFIG_DESCRIPTOR Desc;
+ USB_INTERFACE_ASSOCIATION_DESC *Iads[USB_MAX_ASSOCIATION];
+ UINT8 NumOfIads;
+ USB_INTERFACE_DESC **Interfaces;
} USB_CONFIG_DESC;
typedef struct {
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
index b3a40639f2..64786603c3 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
@@ -3,6 +3,7 @@
Usb bus enumeration support.
Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2025, American Megatrends International, LLC. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -41,6 +42,41 @@ UsbGetEndpointDesc (
return NULL;
}
+/**
+ Check if given Usb interface is a part of Usb association.
+
+ @param[in] Device The device may have the interface association descriptor.
+ @param[in] IfDesc The interface descriptor to check for.
+ @param[out] IfAssoc The USB association device pointer.
+
+ @retval EFI_SUCCESS IfDesc is found within associations, IfAssoc has valid pointer.
+ @retval EFI_NOT_FOUND IfDesc does no belong to any association.
+
+**/
+EFI_STATUS
+GetInterfaceAssociation (
+ IN USB_DEVICE *Device,
+ IN USB_INTERFACE_DESC *IfDesc,
+ OUT USB_ASSOCIATION **IfAssoc
+ )
+{
+ UINTN Index;
+ UINTN i;
+ USB_ASSOCIATION *Ia;
+
+ for (Index = 0; Index < Device->NumOfAssociation; Index++) {
+ Ia = Device->Associations[Index];
+ for (i = 0; i < Ia->IaDesc->Desc.InterfaceCount; i++) {
+ if (IfDesc->Settings[0]->Desc.InterfaceNumber == Ia->IaDesc->Interfaces[i]->Settings[0]->Desc.InterfaceNumber) {
+ *IfAssoc = Ia;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
/**
Free the resource used by USB interface.
@@ -54,9 +90,25 @@ UsbFreeInterface (
IN USB_INTERFACE *UsbIf
)
{
- EFI_STATUS Status;
+ EFI_STATUS Status;
+ USB_ASSOCIATION *UsbIa;
- UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
+ Status = GetInterfaceAssociation (UsbIf->Device, UsbIf->IfDesc, &UsbIa);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Close USB Interface Association Protocol by Child
+ //
+ Status = gBS->CloseProtocol (
+ UsbIa->Handle,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ mUsbBusDriverBinding.DriverBindingHandle,
+ UsbIf->Handle
+ );
+ DEBUG ((DEBUG_INFO, "UsbFreeInterface: close IAD protocol by child, %r\n", Status));
+ } else {
+ UsbCloseHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
+ }
Status = gBS->UninstallMultipleProtocolInterfaces (
UsbIf->Handle,
@@ -73,7 +125,66 @@ UsbFreeInterface (
FreePool (UsbIf);
} else {
- UsbOpenHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
+ Status = GetInterfaceAssociation (UsbIf->Device, UsbIf->IfDesc, &UsbIa);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Reopen USB Interface Assiciation Protocol by Child
+ //
+ Status = gBS->OpenProtocol (
+ UsbIa->Handle,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ (VOID **)&UsbIa,
+ mUsbBusDriverBinding.DriverBindingHandle,
+ UsbIf->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ DEBUG ((DEBUG_INFO, "UsbFreeInterface: reopen IAD for child, Status = %r\n", Status));
+ } else {
+ //
+ // Reopen USB Host Controller Protocol by Child
+ //
+ Status = UsbOpenHostProtoByChild (UsbIf->Device->Bus, UsbIf->Handle);
+ DEBUG ((DEBUG_INFO, "UsbFreeInterface: reopen host controller for child, Status = %r\n", Status));
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Free the resource used by USB association.
+
+ @param UsbIa The USB association to free.
+
+ @retval EFI_ACCESS_DENIED The Usb association resource is still occupied.
+ @retval EFI_SUCCESS The Usb association resource is freed.
+
+**/
+EFI_STATUS
+UsbFreeAssociation (
+ IN USB_ASSOCIATION *UsbIa
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ UsbIa->Handle,
+ &gEfiDevicePathProtocolGuid,
+ UsbIa->DevicePath,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ &UsbIa->UsbIaProtocol,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ if (UsbIa->DevicePath != NULL) {
+ FreePool (UsbIa->DevicePath);
+ }
+
+ FreePool (UsbIa);
+ } else {
+ UsbOpenHostProtoByChild (UsbIa->Device->Bus, UsbIa->Handle);
}
return Status;
@@ -82,6 +193,7 @@ UsbFreeInterface (
/**
Create an interface for the descriptor IfDesc. Each
device's configuration can have several interfaces.
+ Interface may belong to interface association.
@param Device The device has the interface descriptor.
@param IfDesc The interface descriptor.
@@ -95,10 +207,12 @@ UsbCreateInterface (
IN USB_INTERFACE_DESC *IfDesc
)
{
- USB_DEVICE_PATH UsbNode;
- USB_INTERFACE *UsbIf;
- USB_INTERFACE *HubIf;
- EFI_STATUS Status;
+ USB_DEVICE_PATH UsbNode;
+ USB_INTERFACE *UsbIf;
+ USB_INTERFACE *HubIf;
+ USB_ASSOCIATION *UsbIa;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol;
+ EFI_STATUS Status;
UsbIf = AllocateZeroPool (sizeof (USB_INTERFACE));
@@ -128,10 +242,17 @@ UsbCreateInterface (
SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));
- HubIf = Device->ParentIf;
- ASSERT (HubIf != NULL);
+ Status = GetInterfaceAssociation (Device, IfDesc, &UsbIa);
+
+ if (!EFI_ERROR (Status)) {
+ DevicePathProtocol = UsbIa->DevicePath;
+ } else {
+ HubIf = Device->ParentIf;
+ ASSERT (HubIf != NULL);
+ DevicePathProtocol = HubIf->DevicePath;
+ }
- UsbIf->DevicePath = AppendDevicePathNode (HubIf->DevicePath, &UsbNode.Header);
+ UsbIf->DevicePath = AppendDevicePathNode (DevicePathProtocol, &UsbNode.Header);
if (UsbIf->DevicePath == NULL) {
DEBUG ((DEBUG_ERROR, "UsbCreateInterface: failed to create device path\n"));
@@ -154,10 +275,28 @@ UsbCreateInterface (
goto ON_ERROR;
}
- //
- // Open USB Host Controller Protocol by Child
- //
- Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);
+ Status = GetInterfaceAssociation (Device, IfDesc, &UsbIa);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Open USB Interface Assiciation Protocol by Child
+ //
+ Status = gBS->OpenProtocol (
+ UsbIa->Handle,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ (VOID **)&UsbIa,
+ mUsbBusDriverBinding.DriverBindingHandle,
+ UsbIf->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ DEBUG ((DEBUG_INFO, "UsbCreateInterface: open IAD for child, Status = %r\n", Status));
+ } else {
+ //
+ // Open USB Host Controller Protocol by Child
+ //
+ Status = UsbOpenHostProtoByChild (Device->Bus, UsbIf->Handle);
+ DEBUG ((DEBUG_INFO, "UsbCreateInterface: open host controller for child, Status = %r\n", Status));
+ }
if (EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
@@ -184,6 +323,112 @@ ON_ERROR:
return NULL;
}
+/**
+ Create an interface association instance and install protocols to manage it.
+
+ @param Device The Usb device that has the interface association.
+ @param Index The interface association index within Device.
+ @param IfAssocDesc The interface association descriptor.
+
+ @return The created USB interface association, or NULL.
+
+**/
+USB_ASSOCIATION *
+UsbCreateAssociation (
+ IN USB_DEVICE *Device,
+ IN UINT8 Index,
+ IN USB_INTERFACE_ASSOCIATION_DESC *IfAssocDesc
+ )
+{
+ USB_DEVICE_PATH UsbNode;
+ USB_ASSOCIATION *UsbAssoc;
+ EFI_STATUS Status;
+
+ UsbAssoc = AllocateZeroPool (sizeof (USB_ASSOCIATION));
+
+ if (UsbAssoc == NULL) {
+ return NULL;
+ }
+
+ UsbAssoc->Signature = USB_ASSOCIATION_SIGNATURE;
+ UsbAssoc->Device = Device;
+ UsbAssoc->IaDesc = IfAssocDesc;
+
+ CopyMem (
+ &(UsbAssoc->UsbIaProtocol),
+ &mUsbIaProtocol,
+ sizeof (EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL)
+ );
+
+ //
+ // Install USB association protocols
+ //
+ // Device path protocol for the association has the USB node similar to the
+ // one installed for USB interface.
+ //
+
+ UsbNode.Header.Type = MESSAGING_DEVICE_PATH;
+ UsbNode.Header.SubType = MSG_USB_DP;
+ UsbNode.ParentPortNumber = Device->ParentPort;
+ UsbNode.InterfaceNumber = Index;
+
+ SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));
+
+ ASSERT (Device->ParentIf != NULL);
+
+ UsbAssoc->DevicePath = AppendDevicePathNode (Device->ParentIf->DevicePath, &UsbNode.Header);
+
+ if (UsbAssoc->DevicePath == NULL) {
+ DEBUG ((DEBUG_ERROR, "UsbCreateAssociation: failed to create device path\n"));
+
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &UsbAssoc->Handle,
+ &gEfiDevicePathProtocolGuid,
+ UsbAssoc->DevicePath,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ &UsbAssoc->UsbIaProtocol,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "UsbCreateAssociation: failed to install UsbIad - %r\n", Status));
+ goto ON_ERROR;
+ }
+
+ //
+ // Open USB Host Controller Protocol by Child
+ //
+ Status = UsbOpenHostProtoByChild (Device->Bus, UsbAssoc->Handle);
+
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ UsbAssoc->Handle,
+ &gEfiDevicePathProtocolGuid,
+ UsbAssoc->DevicePath,
+ &gEfiUsbInterfaceAssociationProtocolGuid,
+ &UsbAssoc->UsbIaProtocol,
+ NULL
+ );
+
+ DEBUG ((DEBUG_ERROR, "UsbCreateAssociation: failed to open host for child - %r\n", Status));
+ goto ON_ERROR;
+ }
+
+ return UsbAssoc;
+
+ON_ERROR:
+ if (UsbAssoc->DevicePath != NULL) {
+ FreePool (UsbAssoc->DevicePath);
+ }
+
+ FreePool (UsbAssoc);
+ return NULL;
+}
+
/**
Free the resource used by this USB device.
@@ -236,6 +481,41 @@ UsbCreateDevice (
return Device;
}
+/**
+ Connect USB controller at TPL_CALLBACK
+
+ This function is called in both UsbIoControlTransfer and
+ the timer callback in hub enumeration. So, at least it is
+ called at TPL_CALLBACK. Some driver sitting on USB has
+ twisted TPL used. It should be no problem for us to connect
+ or disconnect at CALLBACK.
+
+ @param Handle Controller handle to be connected
+
+**/
+EFI_STATUS
+UsbConnectController (
+ EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = UsbGetCurrentTpl ();
+ DEBUG ((DEBUG_INFO, "UsbConnectDriver: TPL before connect is %d, %p\n", (UINT32)OldTpl, Handle));
+
+ gBS->RestoreTPL (TPL_CALLBACK);
+
+ Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
+
+ DEBUG ((DEBUG_INFO, "UsbConnectDriver: TPL after connect is %d\n", (UINT32)UsbGetCurrentTpl ()));
+ ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
+
+ gBS->RaiseTPL (OldTpl);
+
+ return Status;
+}
+
/**
Connect the USB interface with its driver. EFI USB bus will
create a USB interface for each separate interface descriptor.
@@ -252,7 +532,6 @@ UsbConnectDriver (
)
{
EFI_STATUS Status;
- EFI_TPL OldTpl;
Status = EFI_SUCCESS;
@@ -264,30 +543,12 @@ UsbConnectDriver (
DEBUG ((DEBUG_INFO, "UsbConnectDriver: found a hub device\n"));
Status = mUsbHubApi.Init (UsbIf);
} else {
- //
- // This function is called in both UsbIoControlTransfer and
- // the timer callback in hub enumeration. So, at least it is
- // called at TPL_CALLBACK. Some driver sitting on USB has
- // twisted TPL used. It should be no problem for us to connect
- // or disconnect at CALLBACK.
- //
-
//
// Only recursively wanted usb child device
//
if (UsbBusIsWantedUsbIO (UsbIf->Device->Bus, UsbIf)) {
- OldTpl = UsbGetCurrentTpl ();
- DEBUG ((DEBUG_INFO, "UsbConnectDriver: TPL before connect is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));
-
- gBS->RestoreTPL (TPL_CALLBACK);
-
- Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE);
+ Status = UsbConnectController (UsbIf->Handle);
UsbIf->IsManaged = (BOOLEAN) !EFI_ERROR (Status);
-
- DEBUG ((DEBUG_INFO, "UsbConnectDriver: TPL after connect is %d\n", (UINT32)UsbGetCurrentTpl ()));
- ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
-
- gBS->RaiseTPL (OldTpl);
}
}
@@ -378,6 +639,7 @@ UsbSelectConfig (
USB_INTERFACE *UsbIf;
EFI_STATUS Status;
UINT8 Index;
+ USB_ASSOCIATION *UsbIa;
//
// Locate the active config, then set the device's pointer
@@ -393,7 +655,7 @@ UsbSelectConfig (
}
}
- if (Index == DevDesc->Desc.NumConfigurations) {
+ if ((ConfigDesc == NULL) || (Index == DevDesc->Desc.NumConfigurations)) {
return EFI_NOT_FOUND;
}
@@ -406,6 +668,19 @@ UsbSelectConfig (
Device->Address
));
+ //
+ // Create interfaces for each USB interface association descriptor.
+ //
+ Device->NumOfAssociation = ConfigDesc->NumOfIads;
+
+ for (Index = 0; Index < ConfigDesc->NumOfIads; Index++) {
+ DEBUG ((DEBUG_INFO, "UsbSelectConfig: process IAD %d\n", Index));
+
+ UsbIa = UsbCreateAssociation (Device, Index, ConfigDesc->Iads[Index]);
+ ASSERT (Index < USB_MAX_ASSOCIATION);
+ Device->Associations[Index] = UsbIa;
+ }
+
//
// Create interfaces for each USB interface descriptor.
//
@@ -448,9 +723,55 @@ UsbSelectConfig (
Device->NumOfInterface = Index;
+ //
+ // Connect association device drivers. Connection may fail if if device driver has been already
+ // started for any UsbIo that belongs to the association.
+ //
+ for (Index = 0; Index < Device->NumOfAssociation; Index++) {
+ Status = gBS->ConnectController (Device->Associations[Index]->Handle, NULL, NULL, TRUE);
+ Device->Associations[Index]->IsManaged = (BOOLEAN) !EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "UsbSelectConfig: association driver connect: %r\n", Status));
+ }
+
return EFI_SUCCESS;
}
+/**
+ Disconnect USB controller at TPL_CALLBACK
+
+ This function is called in both UsbIoControlTransfer and
+ the timer callback in hub enumeration. So, at least it is
+ called at TPL_CALLBACK. Some driver sitting on USB has
+ twisted TPL used. It should be no problem for us to connect
+ or disconnect at CALLBACK.
+
+ @param Handle Controller handle to be disconnected
+
+**/
+EFI_STATUS
+UsbDisconnectController (
+ EFI_HANDLE Handle
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ OldTpl = UsbGetCurrentTpl ();
+ DEBUG ((DEBUG_INFO, "UsbDisconnectDriver: old TPL is %d, %p\n", (UINT32)OldTpl, Handle));
+
+ gBS->RestoreTPL (TPL_CALLBACK);
+
+ Status = gBS->DisconnectController (Handle, NULL, NULL);
+
+ DEBUG ((DEBUG_INFO, "UsbDisconnectDriver: TPL after disconnect is %d, %d\n", (UINT32)UsbGetCurrentTpl (), Status));
+ ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
+
+ gBS->RaiseTPL (OldTpl);
+
+ return Status;
+}
+
/**
Disconnect the USB interface with its driver.
@@ -462,7 +783,6 @@ UsbDisconnectDriver (
IN USB_INTERFACE *UsbIf
)
{
- EFI_TPL OldTpl;
EFI_STATUS Status;
//
@@ -473,27 +793,11 @@ UsbDisconnectDriver (
if (UsbIf->IsHub) {
Status = UsbIf->HubApi->Release (UsbIf);
} else if (UsbIf->IsManaged) {
- //
- // This function is called in both UsbIoControlTransfer and
- // the timer callback in hub enumeration. So, at least it is
- // called at TPL_CALLBACK. Some driver sitting on USB has
- // twisted TPL used. It should be no problem for us to connect
- // or disconnect at CALLBACK.
- //
- OldTpl = UsbGetCurrentTpl ();
- DEBUG ((DEBUG_INFO, "UsbDisconnectDriver: old TPL is %d, %p\n", (UINT32)OldTpl, UsbIf->Handle));
+ Status = UsbDisconnectController (UsbIf->Handle);
- gBS->RestoreTPL (TPL_CALLBACK);
-
- Status = gBS->DisconnectController (UsbIf->Handle, NULL, NULL);
if (!EFI_ERROR (Status)) {
UsbIf->IsManaged = FALSE;
}
-
- DEBUG ((DEBUG_INFO, "UsbDisconnectDriver: TPL after disconnect is %d, %d\n", (UINT32)UsbGetCurrentTpl (), Status));
- ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
-
- gBS->RaiseTPL (OldTpl);
}
return Status;
@@ -510,10 +814,11 @@ UsbRemoveConfig (
IN USB_DEVICE *Device
)
{
- USB_INTERFACE *UsbIf;
- UINTN Index;
- EFI_STATUS Status;
- EFI_STATUS ReturnStatus;
+ USB_INTERFACE *UsbIf;
+ USB_ASSOCIATION *UsbIa;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
//
// Remove each interface of the device
@@ -543,6 +848,35 @@ UsbRemoveConfig (
}
Device->ActiveConfig = NULL;
+
+ if (EFI_ERROR (ReturnStatus)) {
+ return ReturnStatus;
+ }
+
+ // ReturnStatus is EFI_SUCCESS
+
+ //
+ // Remove each interface association
+ //
+ for (Index = 0; Index < Device->NumOfAssociation; Index++) {
+ UsbIa = Device->Associations[Index];
+
+ Status = UsbDisconnectController (UsbIa->Handle);
+ if (!EFI_ERROR (Status)) {
+ Status = UsbFreeAssociation (UsbIa);
+ DEBUG ((DEBUG_INFO, "UsbRemoveConfig: free association: %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ UsbConnectController (UsbIa->Handle);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Device->Associations[Index] = NULL;
+ } else {
+ ReturnStatus = Status;
+ }
+ }
+
return ReturnStatus;
}
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbIntfAssoc.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbIntfAssoc.c
new file mode 100644
index 0000000000..87218705b8
--- /dev/null
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbIntfAssoc.c
@@ -0,0 +1,153 @@
+/** @file
+
+ Usb Interface Association Protocol implementation.
+
+Copyright (c) 2025, American Megatrends International, LLC. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UsbBus.h"
+
+/**
+ Get the interface from interface association.
+
+ @param[in] UsbIa A pointer to the interface association data.
+ @param[in] InterfaceNumber Interface to look for inside the association.
+
+ @retval A pointer to the interface data
+ @retval NULL Interface is not found in the association.
+
+**/
+USB_INTERFACE_DESC *
+UsbAssocFindInterface (
+ IN USB_ASSOCIATION *UsbIa,
+ IN UINT8 InterfaceNumber
+ )
+{
+ UINT8 Index;
+ UINT8 Intrf;
+
+ Intrf = UsbIa->IaDesc->Desc.FirstInterface;
+ for (Index = 0; Index < UsbIa->IaDesc->Desc.InterfaceCount; Index++) {
+ if (InterfaceNumber == Intrf) {
+ return UsbIa->IaDesc->Interfaces[Index];
+ }
+
+ Intrf++;
+ }
+
+ DEBUG ((DEBUG_ERROR, "UsbAssocFindInterface: interface 0x%x does not belong to this association\n", InterfaceNumber));
+ return NULL;
+}
+
+/**
+ Get the USB Interface Association Descriptor from the current USB configuration.
+
+ @param[in] This A pointer to the EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL instance.
+ @param[out] Descriptor A pointer to the caller allocated USB Interface Association Descriptor.
+
+ @retval EFI_SUCCESS The descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIaGetAssociationDescriptor (
+ IN EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL *This,
+ OUT EFI_USB_INTERFACE_ASSOCIATION_DESCRIPTOR *Descriptor
+ )
+{
+ USB_ASSOCIATION *UsbIa;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ Status = EFI_SUCCESS;
+
+ ASSERT (Descriptor != NULL);
+ if (Descriptor == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ UsbIa = USB_ASSOCIATION_FROM_USBIA (This);
+ CopyMem (Descriptor, &(UsbIa->IaDesc->Desc), sizeof (EFI_USB_INTERFACE_ASSOCIATION_DESCRIPTOR));
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Retrieve the details of the requested interface that belongs to USB association.
+
+ @param[in] This A pointer to the EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL instance.
+ @param[in] InterfaceNumber Interface number.
+ @param[out] UsbIo A pointer to the caller allocated UsbIo protocol.
+ @param[out] SettingsCount A pointer to the caller allocated number of settings for this interface.
+
+ @retval EFI_SUCCESS Output parameters were updated successfully.
+ @retval EFI_INVALID_PARAMETER UsbIo or SettuntsCount is NULL.
+ @retval EFI_NOT_FOUND Interface does not belong to this interface association.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbIaGetAssociateSettings (
+ IN EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL *This,
+ IN UINT8 InterfaceNumber,
+ OUT EFI_USB_IO_PROTOCOL **UsbIo,
+ OUT UINTN *SettingsCount
+ )
+{
+ USB_ASSOCIATION *UsbIa;
+ EFI_TPL OldTpl;
+ UINT8 Index;
+ EFI_STATUS Status;
+ USB_DEVICE *Device;
+ USB_INTERFACE_DESC *IfDesc;
+
+ OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
+
+ ASSERT ((UsbIo != NULL) && (SettingsCount != NULL));
+ if ((UsbIo == NULL) || (SettingsCount == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ UsbIa = USB_ASSOCIATION_FROM_USBIA (This);
+
+ IfDesc = UsbAssocFindInterface (UsbIa, InterfaceNumber);
+ if (IfDesc == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto ON_EXIT;
+ }
+
+ *SettingsCount = IfDesc->NumOfSetting - 1;
+
+ //
+ // Find UsbIo protocol for this interface
+ //
+ Device = UsbIa->Device;
+ Status = EFI_NOT_FOUND;
+
+ for (Index = 0; Index < Device->NumOfInterface; Index++) {
+ if (Device->Interfaces[Index]->IfSetting->Desc.InterfaceNumber == InterfaceNumber) {
+ *UsbIo = &Device->Interfaces[Index]->UsbIo;
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ON_EXIT:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL mUsbIaProtocol = {
+ UsbIaGetAssociationDescriptor,
+ UsbIaGetAssociateSettings
+};
diff --git a/MdePkg/Include/Protocol/UsbAssociationIo.h b/MdePkg/Include/Protocol/UsbAssociationIo.h
new file mode 100644
index 0000000000..8ce66207c9
--- /dev/null
+++ b/MdePkg/Include/Protocol/UsbAssociationIo.h
@@ -0,0 +1,81 @@
+/** @file
+ EFI Usb Interface Association protocol.
+
+ This protocol is used by USB drivers, running in the EFI boot services
+ environment to access USB devices that implement their configurations
+ using interface association: USB cameras, USB audio devices, USB modems, etc.
+
+ Copyright (c) 2025, American Megatrends International LLC. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __USB_ASSOCIATION_IO_H__
+#define __USB_ASSOCIATION_IO_H__
+
+#include <IndustryStandard/Usb.h>
+#include <Protocol/UsbIo.h>
+
+typedef USB_INTERFACE_ASSOCIATION_DESCRIPTOR EFI_USB_INTERFACE_ASSOCIATION_DESCRIPTOR;
+
+//
+// Global ID for the USB IAD Protocol
+//
+#define EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL_GUID \
+ { \
+ 0xf4279fb1, 0xef1e, 0x4346, { 0xab, 0x32, 0x3f, 0xe3, 0x86, 0xee, 0xb4, 0x52 } \
+ }
+
+typedef struct _EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL;
+
+/**
+ Get the USB Interface Association Descriptor from the current USB configuration.
+
+ @param[in] This A pointer to the EFI_USB_IA_PROTOCOL instance.
+ @param[out] Descriptor A pointer to the caller allocated USB Interface Association Descriptor.
+
+ @retval EFI_SUCCESS The descriptor was retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Descriptor is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_USB_IA_GET_ASSOCIATION_DESCRIPTOR)(
+ IN EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL *This,
+ OUT EFI_USB_INTERFACE_ASSOCIATION_DESCRIPTOR *Descriptor
+ );
+
+/**
+ Retrieve the details of the requested interface that belongs to USB association.
+
+ @param[in] This A pointer to the EFI_USB_IA_PROTOCOL instance.
+ @param[in] InterfaceNumber Interface number.
+ @param[out] UsbIo A pointer to the caller allocated UsbIo protocol.
+ @param[out] SettingsCount A pointer to the caller allocated number of settings for this interface.
+
+ @retval EFI_SUCCESS Output parameters were updated successfully.
+ @retval EFI_INVALID_PARAMETER UsbIo or SettuntsCount is NULL.
+ @retval EFI_NOT_FOUND Interface does not belong to this interface association.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_USB_IA_GET_ASSOCIATE_SETTINGS)(
+ IN EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL *This,
+ IN UINT8 InterfaceNumber,
+ OUT EFI_USB_IO_PROTOCOL **UsbIo,
+ OUT UINTN *SettingsCount
+ );
+
+/**
+ USB interface association protocol functions.
+
+**/
+struct _EFI_USB_INTERFACE_ASSOCIATION_PROTOCOL {
+ EFI_USB_IA_GET_ASSOCIATION_DESCRIPTOR UsbIaGetAssociationDescriptor;
+ EFI_USB_IA_GET_ASSOCIATE_SETTINGS UsbIaGetAssociateSettings;
+};
+
+extern EFI_GUID gEfiUsbInterfaceAssociationProtocolGuid;
+
+#endif
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index f4a60e5cc7..3fc30c23b9 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -1991,6 +1991,9 @@
## Include/Protocol/ShellDynamicCommand.h
gEfiShellDynamicCommandProtocolGuid = { 0x3c7200e9, 0x005f, 0x4ea4, {0x87, 0xde, 0xa3, 0xdf, 0xac, 0x8a, 0x27, 0xc3 }}
+ ## Include/Protocol/UsbAssociationIo.h
+ gEfiUsbInterfaceAssociationProtocolGuid = { 0xf4279fb1, 0xef1e, 0x4346, { 0xab, 0x32, 0x3f, 0xe3, 0x86, 0xee, 0xb4, 0x52 }}
+
#
# [Error.gEfiMdePkgTokenSpaceGuid]
# 0x80000001 | Invalid value provided.
prev parent reply other threads:[~2025-01-06 21:53 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-03 21:39 [edk2-devel] [staging/usb_iad] MdeModulePkg UsbBusDxe: Add support for USB Interface Association olegi via groups.io
2025-01-04 2:10 ` 回复: " gaoliming via groups.io
2025-01-04 2:46 ` [edk2-devel] " olegi via groups.io
2025-01-04 9:06 ` 回复: " gaoliming via groups.io
2025-01-06 21:53 ` olegi via groups.io [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=25918.1736200416648086778@groups.io \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox