From: "olegi via groups.io" <olegi=ami.com@groups.io>
To: devel@edk2.groups.io
Subject: [edk2-devel] [staging/usb_iad] MdeModulePkg UsbBusDxe: Add support for USB Interface Association
Date: Fri, 03 Jan 2025 13:39:12 -0800 [thread overview]
Message-ID: <6rTt.1735940352524703631.nU95@groups.io> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 1173 bytes --]
USB Interface Association is a group of UsbIo that implement a USB function. UEFI device driver manages multiple UsbIo instances. Examples of such devices are: USB camera, USB serial, USB network, etc.
Current approach for supporting these devices is to respond on UsbIo installation and analyze if the current UsbIo belongs to the USB association. This algorithm is based on assumptions that may not be correct for different device configurations. Having USB association protocol that reports its associates (UsbIo) simplifies the USB device driver.
For the USB configurations that implement USB association the UsbDxeBus driver will:
* create USB association device
* install device path
* install USB association IO protocol
Request to create edk2-staging/usb_iad branch, patch is attached.
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#120949): https://edk2.groups.io/g/devel/message/120949
Mute This Topic: https://groups.io/mt/110414302/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: 1691 bytes --]
[-- Attachment #2: diff.patch --]
[-- Type: application/octet-stream, Size: 40885 bytes --]
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
index 21a24218fc..af1fed1bc4 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;
+ EDKII_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 EDKII_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..2b866fc204 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,10 +41,11 @@
UsbUtility.c
UsbDesc.h
UsbBus.h
+ UsbIntfAssoc.c
[Packages]
MdePkg/MdePkg.dec
-
+ MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
MemoryAllocationLib
@@ -58,6 +60,7 @@
[Protocols]
gEfiUsbIoProtocolGuid ## BY_START
+ gEdkiiUsbInterfaceAssociationProtocolGuid
## TO_START
## BY_START
gEfiDevicePathProtocolGuid
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
index 8b078e7e49..c57038ec56 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 < (UINT8)(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..f6e5418931 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,
+ &gEdkiiUsbInterfaceAssociationProtocolGuid,
+ 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,
+ &gEdkiiUsbInterfaceAssociationProtocolGuid,
+ (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,
+ &gEdkiiUsbInterfaceAssociationProtocolGuid,
+ &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,
+ &gEdkiiUsbInterfaceAssociationProtocolGuid,
+ (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 (EDKII_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,
+ &gEdkiiUsbInterfaceAssociationProtocolGuid,
+ &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,
+ &gEdkiiUsbInterfaceAssociationProtocolGuid,
+ &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..15ea41dce9
--- /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 EDKII_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 EDKII_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 EDKII_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 EDKII_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;
+}
+
+EDKII_USB_INTERFACE_ASSOCIATION_PROTOCOL mUsbIaProtocol = {
+ UsbIaGetAssociationDescriptor,
+ UsbIaGetAssociateSettings
+};
diff --git a/MdeModulePkg/Include/Protocol/UsbAssociationIo.h b/MdeModulePkg/Include/Protocol/UsbAssociationIo.h
new file mode 100644
index 0000000000..2835dab5c0
--- /dev/null
+++ b/MdeModulePkg/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 EDKII_USB_INTERFACE_ASSOCIATION_PROTOCOL_GUID \
+ { \
+ 0xf4279fb1, 0xef1e, 0x4346, { 0xab, 0x32, 0x3f, 0xe3, 0x86, 0xee, 0xb4, 0x52 } \
+ }
+
+typedef struct _EDKII_USB_INTERFACE_ASSOCIATION_PROTOCOL EDKII_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 *EDKII_USB_IA_GET_ASSOCIATION_DESCRIPTOR)(
+ IN EDKII_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 *EDKII_USB_IA_GET_ASSOCIATE_SETTINGS)(
+ IN EDKII_USB_INTERFACE_ASSOCIATION_PROTOCOL *This,
+ IN UINT8 InterfaceNumber,
+ OUT EFI_USB_IO_PROTOCOL **UsbIo,
+ OUT UINTN *SettingsCount
+ );
+
+/**
+ USB interface association protocol functions.
+
+**/
+struct _EDKII_USB_INTERFACE_ASSOCIATION_PROTOCOL {
+ EDKII_USB_IA_GET_ASSOCIATION_DESCRIPTOR UsbIaGetAssociationDescriptor;
+ EDKII_USB_IA_GET_ASSOCIATE_SETTINGS UsbIaGetAssociateSettings;
+};
+
+extern EFI_GUID gEdkiiUsbInterfaceAssociationProtocolGuid;
+
+#endif
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index b9bc7041f2..8bf118161c 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -10,6 +10,7 @@
# Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
# Copyright (c) Microsoft Corporation.<BR>
# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (C) 2025 American Megatrends International, LLC. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
@@ -735,6 +736,9 @@
## Include/Protocol/PlatformBootManager.h
gEdkiiPlatformBootManagerProtocolGuid = { 0xaa17add4, 0x756c, 0x460d, { 0x94, 0xb8, 0x43, 0x88, 0xd7, 0xfb, 0x3e, 0x59 } }
+ ## Include/Protocol/UsbAssociationIo.h
+ gEdkiiUsbInterfaceAssociationProtocolGuid = { 0xf4279fb1, 0xef1e, 0x4346, { 0xab, 0x32, 0x3f, 0xe3, 0x86, 0xee, 0xb4, 0x52 }}
+
#
# [Error.gEfiMdeModulePkgTokenSpaceGuid]
# 0x80000001 | Invalid value provided.
next reply other threads:[~2025-01-03 21:39 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-03 21:39 olegi via groups.io [this message]
2025-01-04 2:10 ` 回复: [edk2-devel] [staging/usb_iad] MdeModulePkg UsbBusDxe: Add support for USB Interface Association 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 ` [edk2-devel] " olegi via groups.io
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=6rTt.1735940352524703631.nU95@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