public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "RichardHo [何明忠]" <richardho@ami.com>
To: "devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Andrew Fish" <afish@apple.com>,
	"Leif Lindholm" <quic_llindhol@quicinc.com>,
	"Michael D Kinney" <michael.d.kinney@intel.com>,
	"Michael Kubacki" <mikuback@linux.microsoft.com>,
	"Zhiguang Liu" <zhiguang.liu@intel.com>,
	"Liming Gao" <gaoliming@byosoft.com.cn>,
	"Rebecca Cran" <rebecca@bsdio.com>,
	"Tinh Nguyen" <tinhnguyen@os.amperecomputing.com>,
	"Tony Lo (羅金松)" <TonyLo@ami.com>
Subject: [PATCH v6 3/3] UsbNetworkPkg/UsbCdcNcm: Add USB Cdc NCM devices support
Date: Thu, 9 Mar 2023 07:51:50 +0000	[thread overview]
Message-ID: <20230309075134.864-3-richardho@ami.com> (raw)
In-Reply-To: <20230309075134.864-1-richardho@ami.com>

This driver provides UEFI driver for USB CDC NCM device

Signed-off-by: Richard Ho <richardho@ami.com>
Cc: Andrew Fish <afish@apple.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Michael Kubacki <mikuback@linux.microsoft.com>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Rebecca Cran <rebecca@bsdio.com>
Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
Reviewed-by: Tony Lo <tonylo@ami.com>
---
 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf    |  42 +
 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h      | 245 ++++++
 UsbNetworkPkg/UsbCdcNcm/ComponentName.c  | 170 ++++
 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c      | 506 ++++++++++++
 UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c | 966 +++++++++++++++++++++++
 5 files changed, 1929 insertions(+)
 create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
 create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
 create mode 100644 UsbNetworkPkg/UsbCdcNcm/ComponentName.c
 create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c
 create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c

diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
new file mode 100644
index 000000000000..bd085bdd0037
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
@@ -0,0 +1,42 @@
+## @file
+#   This is Usb Cdc Ncm driver for DXE phase.
+#
+# Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = UsbCdcNcm
+  FILE_GUID                      = 52230d31-6c11-4442-b262-bec6bfe84efa
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = UsbNcmEntry
+
+[Sources]
+  UsbCdcNcm.c
+  UsbCdcNcm.h
+  UsbNcmFunction.c
+  ComponentName.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UsbNetworkPkg/UsbNetworkPkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  UefiLib
+  DebugLib
+  UefiUsbLib
+  MemoryAllocationLib
+  BaseMemoryLib
+
+[Protocols]
+  gEfiUsbIoProtocolGuid
+  gEfiDevicePathProtocolGuid
+  gEfiDriverBindingProtocolGuid
+  gEdkIIUsbEthProtocolGuid
+
+[Depex]
+  TRUE
diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
new file mode 100644
index 000000000000..f8c21302f170
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
@@ -0,0 +1,245 @@
+/** @file
+  Header file for USB Network Control Model driver
+
+  Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _USB_CDC_NCM_H_
+#define _USB_CDC_NCM_H_
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiUsbLib.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/EdkIIUsbEthernetProtocol.h>
+
+typedef struct {
+  UINTN                          Signature;
+  EDKII_USB_ETHERNET_PROTOCOL    UsbEth;
+  EFI_HANDLE                     UsbCdcDataHandle;
+  EFI_USB_IO_PROTOCOL            *UsbIo;
+  EFI_USB_CONFIG_DESCRIPTOR      *Config;
+  UINT8                          NumOfInterface;
+  UINT8                          BulkInEndpoint;
+  UINT8                          BulkOutEndpoint;
+  UINT8                          InterruptEndpoint;
+  EFI_MAC_ADDRESS                MacAddress;
+  UINT16                         BulkOutSequence;
+  UINT8                          *BulkBuffer;
+  UINT8                          TotalDatagram;
+  UINT8                          NowDatagram;
+} USB_ETHERNET_DRIVER;
+
+#define USB_NCM_DRIVER_VERSION         1
+#define USB_ETHERNET_BULK_TIMEOUT      1
+#define USB_ETHERNET_TRANSFER_TIMEOUT  200
+#define USB_NCM_MAX_NTB_SIZE           0xFFFF
+#define USB_ETHERNET_FRAME_SIZE        0x5F2  // MAX ethernet frame size
+
+// Defined in USB NCM 1.0 spec., section 3.2 and 3.3
+#define USB_NCM_NTH_SIGN_16      0x484D434E
+#define USB_NCM_NDP_SIGN_16      0x304D434E
+#define USB_NCM_NDP_SIGN_16_CRC  0x314D434E
+#define USB_NCM_NTH_LENGTH       0x000C
+#define USB_NCM_NDP_LENGTH       0x0010// at least 16
+
+// USB NCM Transfer header structure - UINT16
+typedef struct {
+  UINT32    Signature;
+  UINT16    HeaderLength;
+  UINT16    Sequence;
+  UINT16    BlockLength;
+  UINT16    NdpIndex;
+} USB_NCM_TRANSFER_HEADER_16;
+
+// USB NCM Datagram pointer structure - UINT16
+typedef struct {
+  UINT32    Signature;
+  UINT16    Length;
+  UINT16    NextNdpIndex;
+} USB_NCM_DATAGRAM_POINTER_16;
+
+// USB NCM Datagram structure
+typedef struct {
+  UINT16    DatagramIndex;
+  UINT16    DatagramLength;
+} USB_NCM_DATA_GRAM;
+
+#define USB_ETHERNET_SIGNATURE  SIGNATURE_32('u', 'e', 't', 'h')
+#define USB_ETHERNET_DEV_FROM_THIS(a)  CR (a, USB_ETHERNET_DRIVER, UsbEth, USB_ETHERNET_SIGNATURE)
+
+typedef struct {
+  UINT16    Src;
+  UINT16    Dst;
+} BIT_MAP;
+
+extern EFI_COMPONENT_NAME2_PROTOCOL  gUsbNcmComponentName2;
+
+EFI_STATUS
+EFIAPI
+UsbNcmDriverSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+EFI_STATUS
+EFIAPI
+UsbNcmDriverStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+EFI_STATUS
+EFIAPI
+UsbNcmDriverStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   ControllerHandle,
+  IN  UINTN                        NumberOfChildren,
+  IN  EFI_HANDLE                   *ChildHandleBuffer
+  );
+
+EFI_STATUS
+LoadAllDescriptor (
+  IN  EFI_USB_IO_PROTOCOL        *UsbIo,
+  OUT EFI_USB_CONFIG_DESCRIPTOR  **ConfigDesc
+  );
+
+BOOLEAN
+NextDescriptor (
+  IN EFI_USB_CONFIG_DESCRIPTOR  *Desc,
+  IN OUT UINTN                  *Offset
+  );
+
+EFI_STATUS
+GetFunctionalDescriptor (
+  IN  EFI_USB_CONFIG_DESCRIPTOR  *Config,
+  IN  UINT8                      FunDescriptorType,
+  OUT VOID                       *DataBuffer
+  );
+
+VOID
+GetEndpoint (
+  IN      EFI_USB_IO_PROTOCOL  *UsbIo,
+  IN OUT  USB_ETHERNET_DRIVER  *UsbEthDriver
+  );
+
+EFI_STATUS
+EFIAPI
+UsbEthNcmReceive (
+  IN     PXE_CDB                      *Cdb,
+  IN     EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN OUT VOID                         *Packet,
+  IN OUT UINTN                        *PacketLength
+  );
+
+EFI_STATUS
+EFIAPI
+UsbEthNcmTransmit (
+  IN      PXE_CDB                      *Cdb,
+  IN      EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN      VOID                         *Packet,
+  IN OUT  UINTN                        *PacketLength
+  );
+
+EFI_STATUS
+EFIAPI
+UsbEthNcmInterrupt (
+  IN EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN BOOLEAN                      IsNewTransfer,
+  IN UINTN                        PollingInterval,
+  IN EFI_USB_DEVICE_REQUEST       *Request
+  );
+
+EFI_STATUS
+EFIAPI
+InterruptCallback (
+  IN  VOID    *Data,
+  IN  UINTN   DataLength,
+  IN  VOID    *Context,
+  IN  UINT32  Status
+  );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthMacAddress (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT EFI_MAC_ADDRESS              *MacAddress
+  );
+
+EFI_STATUS
+EFIAPI
+UsbEthNcmBulkSize (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT UINTN                        *BulkSize
+  );
+
+EFI_STATUS
+EFIAPI
+GetUsbHeaderFunDescriptor (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT USB_HEADER_FUN_DESCRIPTOR    *UsbHeaderFunDescriptor
+  );
+
+EFI_STATUS
+EFIAPI
+GetUsbUnionFunDescriptor (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT USB_UNION_FUN_DESCRIPTOR     *UsbUnionFunDescriptor
+  );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthFunDescriptor (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT USB_ETHERNET_FUN_DESCRIPTOR  *UsbEthFunDescriptor
+  );
+
+EFI_STATUS
+EFIAPI
+SetUsbEthMcastFilter (
+  IN EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN UINT16                       Value,
+  IN VOID                         *McastAddr
+  );
+
+EFI_STATUS
+EFIAPI
+SetUsbEthPowerFilter (
+  IN EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN UINT16                       Value,
+  IN UINT16                       Length,
+  IN VOID                         *PatternFilter
+  );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthPowerFilter (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN  UINT16                       Value,
+  OUT BOOLEAN                      *PatternActive
+  );
+
+EFI_STATUS
+EFIAPI
+SetUsbEthPacketFilter (
+  IN EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN UINT16                       Value
+  );
+
+EFI_STATUS
+EFIAPI
+GetUsbEthStatistic (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN  UINT16                       FeatureSelector,
+  OUT VOID                         *Statistic
+  );
+
+#endif
diff --git a/UsbNetworkPkg/UsbCdcNcm/ComponentName.c b/UsbNetworkPkg/UsbCdcNcm/ComponentName.c
new file mode 100644
index 000000000000..3cf3dc222df9
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/ComponentName.c
@@ -0,0 +1,170 @@
+/** @file
+  This file contains code for USB Ncm Driver Component Name definitions
+
+  Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "UsbCdcNcm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE  gUsbNcmDriverNameTable[] = {
+  {
+    "eng;en",
+    L"USB NCM Driver"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+
+EFI_STATUS
+EFIAPI
+UsbNcmComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+EFI_STATUS
+EFIAPI
+UsbNcmComponentNameGetControllerName (
+  IN EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_HANDLE                   ChildHandle        OPTIONAL,
+  IN CHAR8                        *Language,
+  OUT CHAR16                      **ControllerName
+  );
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gUsbNcmComponentName = {
+  UsbNcmComponentNameGetDriverName,
+  UsbNcmComponentNameGetControllerName,
+  "eng"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL  gUsbNcmComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbNcmComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbNcmComponentNameGetControllerName,
+  "en"
+};
+
+/**
+  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[in]  This              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  Language          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[out] DriverName        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
+UsbNcmComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           gUsbNcmDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gUsbNcmComponentName)
+           );
+}
+
+/**
+  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[in]  This              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  Controller        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[in]  ChildHandle       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[in]  Language          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[out] ControllerName    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
+UsbNcmComponentNameGetControllerName (
+  IN EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_HANDLE                   ChildHandle        OPTIONAL,
+  IN CHAR8                        *Language,
+  OUT CHAR16                      **ControllerName
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c
new file mode 100644
index 000000000000..f67e6aab695f
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c
@@ -0,0 +1,506 @@
+/** @file
+  This file contains code for USB Network Control Model
+  binding driver
+
+  Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "UsbCdcNcm.h"
+
+EFI_DRIVER_BINDING_PROTOCOL  gUsbNcmDriverBinding = {
+  UsbNcmDriverSupported,
+  UsbNcmDriverStart,
+  UsbNcmDriverStop,
+  USB_NCM_DRIVER_VERSION,
+  NULL,
+  NULL
+};
+
+/**
+  Check if this interface is USB NCM SubType
+
+  @param[in]  UsbIo   A pointer to the EFI_USB_IO_PROTOCOL instance.
+
+  @retval TRUE        USB NCM SubType.
+  @retval FALSE       Not USB NCM SubType.
+
+**/
+BOOLEAN
+IsSupportedDevice (
+  IN EFI_USB_IO_PROTOCOL  *UsbIo
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
+
+  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDescriptor);
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  if ((InterfaceDescriptor.InterfaceClass == USB_CDC_CLASS) &&
+      (InterfaceDescriptor.InterfaceSubClass == USB_CDC_NCM_SUBCLASS) &&
+      (InterfaceDescriptor.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
+  {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  USB NCM Driver Binding Support.
+
+  @param[in]  This                  Protocol instance pointer.
+  @param[in]  ControllerHandle      Handle of device to test.
+  @param[in]  RemainingDevicePath   Optional parameter use to pick a specific child
+                                    device to start.
+
+  @retval EFI_SUCCESS               This driver supports this device.
+  @retval EFI_ALREADY_STARTED       This driver is already running on this device.
+  @retval other                     This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbNcmDriverSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS           Status;
+  EFI_USB_IO_PROTOCOL  *UsbIo;
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiUsbIoProtocolGuid,
+                  (VOID **)&UsbIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = IsSupportedDevice (UsbIo) ? EFI_SUCCESS : EFI_UNSUPPORTED;
+
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiUsbIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+  return Status;
+}
+
+/**
+  Check if the USB NCM and USB CDC Data interfaces are from the same device.
+
+  @param[in]  UsbEthPath                  A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
+  @param[in]  UsbCdcDataPath              A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS                     Is the same device.
+  @retval EFI_NOT_FOUND                   Is not the same device.
+
+**/
+EFI_STATUS
+IsSameDevice (
+  IN  EFI_DEVICE_PATH_PROTOCOL  *UsbEthPath,
+  IN  EFI_DEVICE_PATH_PROTOCOL  *UsbCdcDataPath
+  )
+{
+  while (1) {
+    if ((UsbEthPath->Type == ACPI_DEVICE_PATH) && (UsbEthPath->SubType == ACPI_DP)) {
+      if (CompareMem ((ACPI_HID_DEVICE_PATH *)UsbCdcDataPath, (ACPI_HID_DEVICE_PATH *)UsbEthPath, sizeof (ACPI_HID_DEVICE_PATH))) {
+        return EFI_NOT_FOUND;
+      }
+    }
+
+    if ((UsbEthPath->Type == HARDWARE_DEVICE_PATH) && (UsbEthPath->SubType == HW_PCI_DP)) {
+      if (CompareMem ((PCI_DEVICE_PATH *)UsbCdcDataPath, (PCI_DEVICE_PATH *)UsbEthPath, sizeof (PCI_DEVICE_PATH))) {
+        return EFI_NOT_FOUND;
+      }
+    }
+
+    if ((UsbEthPath->Type == MESSAGING_DEVICE_PATH) && (UsbEthPath->SubType == MSG_USB_DP)) {
+      if (IsDevicePathEnd (NextDevicePathNode (UsbEthPath))) {
+        if (((USB_DEVICE_PATH *)UsbEthPath)->ParentPortNumber ==
+            ((USB_DEVICE_PATH *)UsbCdcDataPath)->ParentPortNumber)
+        {
+          return EFI_SUCCESS;
+        } else {
+          return EFI_NOT_FOUND;
+        }
+      } else {
+        if (CompareMem ((USB_DEVICE_PATH *)UsbCdcDataPath, (USB_DEVICE_PATH *)UsbEthPath, sizeof (USB_DEVICE_PATH))) {
+          return EFI_NOT_FOUND;
+        }
+      }
+    }
+
+    UsbEthPath     = NextDevicePathNode (UsbEthPath);
+    UsbCdcDataPath = NextDevicePathNode (UsbCdcDataPath);
+  }
+}
+
+/**
+  Check if the USB CDC Data(UsbIo) installed and return USB CDC Data Handle.
+
+  @param[in]      UsbEthPath          A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
+  @param[in, out] UsbCdcDataHandle    A pointer to the EFI_HANDLE for USB CDC Data.
+
+  @retval TRUE                USB CDC Data(UsbIo) installed.
+  @retval FALSE               USB CDC Data(UsbIo) did not installed.
+
+**/
+BOOLEAN
+IsUsbCdcData (
+  IN      EFI_DEVICE_PATH_PROTOCOL  *UsbEthPath,
+  IN OUT  EFI_HANDLE                *UsbCdcDataHandle
+  )
+{
+  EFI_STATUS                    Status;
+  UINTN                         Index;
+  UINTN                         HandleCount;
+  EFI_HANDLE                    *HandleBuffer;
+  EFI_USB_IO_PROTOCOL           *UsbIo;
+  EFI_USB_INTERFACE_DESCRIPTOR  Interface;
+  EFI_DEVICE_PATH_PROTOCOL      *UsbCdcDataPath;
+
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiUsbIoProtocolGuid,
+                  NULL,
+                  &HandleCount,
+                  &HandleBuffer
+                  );
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  for (Index = 0; Index < HandleCount; Index++) {
+    Status = gBS->HandleProtocol (
+                    HandleBuffer[Index],
+                    &gEfiUsbIoProtocolGuid,
+                    (VOID **)&UsbIo
+                    );
+    ASSERT_EFI_ERROR (Status);
+
+    Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+    ASSERT_EFI_ERROR (Status);
+
+    if ((Interface.InterfaceClass == USB_CDC_DATA_CLASS) &&
+        (Interface.InterfaceSubClass == USB_CDC_DATA_SUBCLASS) &&
+        (Interface.InterfaceProtocol == USB_NCM_NTB_PROTOCOL))
+    {
+      Status = gBS->HandleProtocol (
+                      HandleBuffer[Index],
+                      &gEfiDevicePathProtocolGuid,
+                      (VOID **)&UsbCdcDataPath
+                      );
+      if (EFI_ERROR (Status)) {
+        continue;
+      }
+
+      Status = IsSameDevice (UsbEthPath, UsbCdcDataPath);
+      if (!EFI_ERROR (Status)) {
+        CopyMem (UsbCdcDataHandle, &HandleBuffer[Index], sizeof (EFI_HANDLE));
+        FreePool (HandleBuffer);
+        return TRUE;
+      }
+    }
+  }
+
+  FreePool (HandleBuffer);
+  return FALSE;
+}
+
+/**
+  Call Back Function.
+
+  @param[in]  Event       Event whose notification function is being invoked.
+  @param[in]  Context     The pointer to the notification function's context,
+                          which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+CallbackFunction (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  EFI_STATUS                    Status;
+  UINTN                         Index;
+  UINTN                         HandleCount;
+  EFI_HANDLE                    *HandleBuffer;
+  EFI_USB_IO_PROTOCOL           *UsbIo;
+  EFI_USB_INTERFACE_DESCRIPTOR  Interface;
+
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiUsbIoProtocolGuid,
+                  NULL,
+                  &HandleCount,
+                  &HandleBuffer
+                  );
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  for (Index = 0; Index < HandleCount; Index++) {
+    Status = gBS->HandleProtocol (
+                    HandleBuffer[Index],
+                    &gEfiUsbIoProtocolGuid,
+                    (VOID **)&UsbIo
+                    );
+    ASSERT_EFI_ERROR (Status);
+
+    Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+    ASSERT_EFI_ERROR (Status);
+
+    if ((Interface.InterfaceClass == USB_CDC_CLASS) &&
+        (Interface.InterfaceSubClass == USB_CDC_NCM_SUBCLASS) &&
+        (Interface.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
+    {
+      gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+    }
+  }
+
+  FreePool (HandleBuffer);
+  gBS->CloseEvent (Event);
+}
+
+/**
+  USB NCM Driver Binding Start.
+
+  @param[in]  This                    Protocol instance pointer.
+  @param[in]  ControllerHandle        Handle of device to bind driver to.
+  @param[in]  RemainingDevicePath     Optional parameter use to pick a specific child
+                                      device to start.
+
+  @retval EFI_SUCCESS                 This driver is added to ControllerHandle
+  @retval EFI_DEVICE_ERROR            This driver could not be started due to a device error
+  @retval EFI_OUT_OF_RESOURCES        The driver could not install successfully due to a lack of resources.
+  @retval other                       This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+UsbNcmDriverStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS                    Status;
+  VOID                          *Reg;
+  EFI_EVENT                     Event;
+  USB_ETHERNET_DRIVER           *UsbEthDriver;
+  EFI_DEVICE_PATH_PROTOCOL      *UsbEthPath;
+  EFI_HANDLE                    UsbCdcDataHandle;
+  EFI_USB_IO_PROTOCOL           *UsbIo;
+  EFI_USB_INTERFACE_DESCRIPTOR  Interface;
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiUsbIoProtocolGuid,
+                  (VOID **)&UsbIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID **)&UsbEthPath,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    gBS->CloseProtocol (
+           ControllerHandle,
+           &gEfiUsbIoProtocolGuid,
+           This->DriverBindingHandle,
+           ControllerHandle
+           );
+    return Status;
+  }
+
+  Status = IsUsbCdcData (UsbEthPath, &UsbCdcDataHandle) ? EFI_SUCCESS : EFI_UNSUPPORTED;
+  if (EFI_ERROR (Status)) {
+    gBS->CloseProtocol (
+           ControllerHandle,
+           &gEfiUsbIoProtocolGuid,
+           This->DriverBindingHandle,
+           ControllerHandle
+           );
+
+    Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CallbackFunction, NULL, &Event);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Status = gBS->RegisterProtocolNotify (&gEfiUsbIoProtocolGuid, Event, &Reg);
+    return Status;
+  }
+
+  UsbEthDriver = AllocateZeroPool (sizeof (USB_ETHERNET_DRIVER));
+  if (!UsbEthDriver) {
+    gBS->CloseProtocol (
+           ControllerHandle,
+           &gEfiUsbIoProtocolGuid,
+           This->DriverBindingHandle,
+           ControllerHandle
+           );
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = LoadAllDescriptor (UsbIo, &UsbEthDriver->Config);
+  ASSERT_EFI_ERROR (Status);
+
+  GetEndpoint (UsbIo, UsbEthDriver);
+
+  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+  ASSERT_EFI_ERROR (Status);
+
+  UsbEthDriver->Signature                          = USB_ETHERNET_SIGNATURE;
+  UsbEthDriver->NumOfInterface                     = Interface.InterfaceNumber;
+  UsbEthDriver->UsbCdcDataHandle                   = UsbCdcDataHandle;
+  UsbEthDriver->UsbIo                              = UsbIo;
+  UsbEthDriver->UsbEth.UsbEthReceive               = UsbEthNcmReceive;
+  UsbEthDriver->UsbEth.UsbEthTransmit              = UsbEthNcmTransmit;
+  UsbEthDriver->UsbEth.UsbEthInterrupt             = UsbEthNcmInterrupt;
+  UsbEthDriver->UsbEth.UsbEthMacAddress            = GetUsbEthMacAddress;
+  UsbEthDriver->UsbEth.UsbEthMaxBulkSize           = UsbEthNcmBulkSize;
+  UsbEthDriver->UsbEth.UsbHeaderFunDescriptor      = GetUsbHeaderFunDescriptor;
+  UsbEthDriver->UsbEth.UsbUnionFunDescriptor       = GetUsbUnionFunDescriptor;
+  UsbEthDriver->UsbEth.UsbEthFunDescriptor         = GetUsbEthFunDescriptor;
+  UsbEthDriver->UsbEth.SetUsbEthMcastFilter        = SetUsbEthMcastFilter;
+  UsbEthDriver->UsbEth.SetUsbEthPowerPatternFilter = SetUsbEthPowerFilter;
+  UsbEthDriver->UsbEth.GetUsbEthPowerPatternFilter = GetUsbEthPowerFilter;
+  UsbEthDriver->UsbEth.SetUsbEthPacketFilter       = SetUsbEthPacketFilter;
+  UsbEthDriver->UsbEth.GetUsbEthStatistic          = GetUsbEthStatistic;
+
+  UsbEthDriver->BulkBuffer = AllocateZeroPool (USB_NCM_MAX_NTB_SIZE);
+
+  Status = gBS->InstallProtocolInterface (
+                  &ControllerHandle,
+                  &gEdkIIUsbEthProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &(UsbEthDriver->UsbEth)
+                  );
+  if (EFI_ERROR (Status)) {
+    gBS->CloseProtocol (
+           ControllerHandle,
+           &gEfiUsbIoProtocolGuid,
+           This->DriverBindingHandle,
+           ControllerHandle
+           );
+    FreePool (UsbEthDriver);
+    return Status;
+  }
+
+  return Status;
+}
+
+/**
+  USB NCM Driver Binding Stop.
+
+  @param[in]  This                  Protocol instance pointer.
+  @param[in]  ControllerHandle      Handle of device to stop driver on
+  @param[in]  NumberOfChildren      Number of Handles in ChildHandleBuffer. If number of
+                                    children is zero stop the entire bus driver.
+  @param[in]  ChildHandleBuffer     List of Child Handles to Stop.
+
+  @retval EFI_SUCCESS               This driver is removed ControllerHandle
+  @retval other                     This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+UsbNcmDriverStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   ControllerHandle,
+  IN  UINTN                        NumberOfChildren,
+  IN  EFI_HANDLE                   *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                   Status;
+  EDKII_USB_ETHERNET_PROTOCOL  *UsbEthProtocol;
+  USB_ETHERNET_DRIVER          *UsbEthDriver;
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEdkIIUsbEthProtocolGuid,
+                  (VOID **)&UsbEthProtocol,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (UsbEthProtocol);
+
+  Status = gBS->UninstallProtocolInterface (
+                  ControllerHandle,
+                  &gEdkIIUsbEthProtocolGuid,
+                  UsbEthProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->CloseProtocol (
+                  ControllerHandle,
+                  &gEfiUsbIoProtocolGuid,
+                  This->DriverBindingHandle,
+                  ControllerHandle
+                  );
+  FreePool (UsbEthDriver->Config);
+  FreePool (UsbEthDriver->BulkBuffer);
+  FreePool (UsbEthDriver);
+  return Status;
+}
+
+/**
+  Entrypoint of NCM Driver.
+
+  This function is the entrypoint of NCM Driver. It installs Driver Binding
+  Protocols together with Component Name Protocols.
+
+  @param[in]  ImageHandle       The firmware allocated handle for the EFI image.
+  @param[in]  SystemTable       A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS           The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbNcmEntry (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  gUsbNcmDriverBinding.DriverBindingHandle = ImageHandle;
+  gUsbNcmDriverBinding.ImageHandle         = ImageHandle;
+
+  return gBS->InstallMultipleProtocolInterfaces (
+                &gUsbNcmDriverBinding.DriverBindingHandle,
+                &gEfiDriverBindingProtocolGuid,
+                &gUsbNcmDriverBinding,
+                &gEfiComponentName2ProtocolGuid,
+                &gUsbNcmComponentName2,
+                NULL
+                );
+}
diff --git a/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c b/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
new file mode 100644
index 000000000000..24ced413d60b
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
@@ -0,0 +1,966 @@
+/** @file
+  This file contains code for USB Ethernet descriptor
+  and specific requests implement.
+
+  Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "UsbCdcNcm.h"
+
+/**
+  Load All of device descriptor.
+
+  @param[in]  UsbIo                 A pointer to the EFI_USB_IO_PROTOCOL instance.
+  @param[out] ConfigDesc            A pointer to the configuration descriptor.
+
+  @retval EFI_SUCCESS           The request executed successfully.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed because the
+                                buffer specified by DescriptorLength and Descriptor
+                                is not large enough to hold the result of the request.
+  @retval EFI_TIMEOUT           A timeout occurred executing the request.
+  @retval EFI_DEVICE_ERROR      The request failed due to a device error. The transfer
+                                status is returned in Status.
+
+**/
+EFI_STATUS
+LoadAllDescriptor (
+  IN  EFI_USB_IO_PROTOCOL        *UsbIo,
+  OUT EFI_USB_CONFIG_DESCRIPTOR  **ConfigDesc
+  )
+{
+  EFI_STATUS                 Status;
+  UINT32                     TransStatus;
+  EFI_USB_CONFIG_DESCRIPTOR  Tmp;
+
+  Status = UsbIo->UsbGetConfigDescriptor (UsbIo, &Tmp);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->AllocatePool (EfiBootServicesData, Tmp.TotalLength, (VOID **)ConfigDesc);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = UsbGetDescriptor (
+             UsbIo,
+             USB_DESC_TYPE_CONFIG << 8 | (Tmp.ConfigurationValue - 1),                   // zero based
+             0,
+             Tmp.TotalLength,
+             *ConfigDesc,
+             &TransStatus
+             );
+  return Status;
+}
+
+/**
+  Returns pointer to the next descriptor for the pack of USB descriptors
+  located in continues memory segment
+
+  @param[in]      Desc   A pointer to the CONFIG_DESCRIPTOR instance.
+  @param[in, out] Offset A pointer to the sum of descriptor length.
+
+  @retval TRUE   The request executed successfully.
+  @retval FALSE  No next descriptor.
+
+**/
+BOOLEAN
+NextDescriptor (
+  IN EFI_USB_CONFIG_DESCRIPTOR  *Desc,
+  IN OUT UINTN                  *Offset
+  )
+{
+  if ((Desc == NULL) || (*Offset >= Desc->TotalLength)) {
+    return FALSE;
+  }
+
+  if (((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length == 0) {
+    return FALSE;
+  }
+
+  *Offset += ((EFI_USB_CONFIG_DESCRIPTOR *)((char *)Desc+*Offset))->Length;
+  if ( *Offset >= Desc->TotalLength ) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+  Read Function descriptor
+
+  @param[in]  Config             A pointer to all of configuration.
+  @param[in]  FunDescriptorType  USB CDC class descriptor SubType.
+  @param[out] DataBuffer         A pointer to the Data of corresponding to device capability.
+
+  @retval EFI_SUCCESS        The device capability descriptor was retrieved
+                             successfully.
+  @retval EFI_UNSUPPORTED    No supported.
+  @retval EFI_NOT_FOUND      The device capability descriptor was not found.
+
+**/
+EFI_STATUS
+GetFunctionalDescriptor (
+  IN  EFI_USB_CONFIG_DESCRIPTOR  *Config,
+  IN  UINT8                      FunDescriptorType,
+  OUT VOID                       *DataBuffer
+  )
+{
+  EFI_STATUS                    Status;
+  UINTN                         Offset;
+  EFI_USB_INTERFACE_DESCRIPTOR  *Interface;
+
+  Status = EFI_NOT_FOUND;
+
+  for (Offset = 0; NextDescriptor (Config, &Offset);) {
+    Interface = (EFI_USB_INTERFACE_DESCRIPTOR *)((UINT8 *)Config + Offset);
+    if (Interface->DescriptorType == CS_INTERFACE) {
+      if (((USB_HEADER_FUN_DESCRIPTOR *)Interface)->DescriptorSubtype == FunDescriptorType) {
+        switch (FunDescriptorType) {
+          case HEADER_FUN_DESCRIPTOR:
+            CopyMem (
+              DataBuffer,
+              (USB_HEADER_FUN_DESCRIPTOR *)Interface,
+              sizeof (USB_HEADER_FUN_DESCRIPTOR)
+              );
+            return EFI_SUCCESS;
+          case UNION_FUN_DESCRIPTOR:
+            CopyMem (
+              DataBuffer,
+              (USB_UNION_FUN_DESCRIPTOR *)Interface,
+              ((USB_UNION_FUN_DESCRIPTOR *)Interface)->FunctionLength
+              );
+            return EFI_SUCCESS;
+          case ETHERNET_FUN_DESCRIPTOR:
+            CopyMem (
+              DataBuffer,
+              (USB_ETHERNET_FUN_DESCRIPTOR *)Interface,
+              sizeof (USB_ETHERNET_FUN_DESCRIPTOR)
+              );
+            return EFI_SUCCESS;
+          default:
+            Status = EFI_UNSUPPORTED;
+            break;
+        }
+      }
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Get USB Ethernet IO endpoint and USB CDC data IO endpoint.
+
+  @param[in]      UsbIo         A pointer to the EFI_USB_IO_PROTOCOL instance.
+  @param[in, out] UsbEthDriver  A pointer to the USB_ETHERNET_DRIVER instance.
+
+**/
+VOID
+GetEndpoint (
+  IN      EFI_USB_IO_PROTOCOL  *UsbIo,
+  IN OUT  USB_ETHERNET_DRIVER  *UsbEthDriver
+  )
+{
+  EFI_STATUS                    Status;
+  UINT8                         Index;
+  UINT32                        Result;
+  EFI_USB_INTERFACE_DESCRIPTOR  Interface;
+  EFI_USB_ENDPOINT_DESCRIPTOR   Endpoint;
+
+  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+  ASSERT_EFI_ERROR (Status);
+
+  if (Interface.NumEndpoints == 0) {
+    Status = UsbSetInterface (UsbIo, Interface.InterfaceNumber, 1, &Result);
+    ASSERT_EFI_ERROR (Status);
+
+    Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  for (Index = 0; Index < Interface.NumEndpoints; Index++) {
+    Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
+    ASSERT_EFI_ERROR (Status);
+
+    switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
+      case USB_ENDPOINT_BULK:
+        if (Endpoint.EndpointAddress & BIT7) {
+          UsbEthDriver->BulkInEndpoint = Endpoint.EndpointAddress;
+        } else {
+          UsbEthDriver->BulkOutEndpoint = Endpoint.EndpointAddress;
+        }
+
+        break;
+      case USB_ENDPOINT_INTERRUPT:
+        UsbEthDriver->InterruptEndpoint = Endpoint.EndpointAddress;
+        break;
+    }
+  }
+}
+
+/**
+  This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk in.
+
+  @param[in]      Cdb           A pointer to the command descriptor block.
+  @param[in]      This          A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[in, out] Packet        A pointer to the buffer of data that will be transmitted to USB
+                                device or received from USB device.
+  @param[in, out] PacketLength  A pointer to the PacketLength.
+
+  @retval EFI_SUCCESS           The bulk transfer has been successfully executed.
+  @retval EFI_DEVICE_ERROR      The transfer failed. The transfer status is returned in status.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be submitted due to a lack of resources.
+  @retval EFI_TIMEOUT           The control transfer fails due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthNcmReceive (
+  IN     PXE_CDB                      *Cdb,
+  IN     EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN OUT VOID                         *Packet,
+  IN OUT UINTN                        *PacketLength
+  )
+{
+  EFI_STATUS                   Status;
+  USB_ETHERNET_DRIVER          *UsbEthDriver;
+  EFI_USB_IO_PROTOCOL          *UsbIo;
+  UINT32                       TransStatus;
+  UINT8                        Index;
+  UINTN                        BulkDataLength;
+  UINTN                        TotalLength;
+  USB_NCM_TRANSFER_HEADER_16   *Nth;
+  USB_NCM_DATAGRAM_POINTER_16  *Ndp;
+  USB_NCM_DATA_GRAM            *Datagram;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+  TotalLength  = 0;
+
+  if (UsbEthDriver->TotalDatagram == UsbEthDriver->NowDatagram) {
+    Status = gBS->HandleProtocol (
+                    UsbEthDriver->UsbCdcDataHandle,
+                    &gEfiUsbIoProtocolGuid,
+                    (VOID **)&UsbIo
+                    );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    if (UsbEthDriver->BulkInEndpoint == 0) {
+      GetEndpoint (UsbIo, UsbEthDriver);
+    }
+
+    BulkDataLength = USB_NCM_MAX_NTB_SIZE;
+    SetMem (UsbEthDriver->BulkBuffer, BulkDataLength, 0);
+    UsbEthDriver->NowDatagram   = 0;
+    UsbEthDriver->TotalDatagram = 0;
+
+    Status = UsbIo->UsbBulkTransfer (
+                      UsbIo,
+                      UsbEthDriver->BulkInEndpoint,
+                      UsbEthDriver->BulkBuffer,
+                      &BulkDataLength,
+                      USB_ETHERNET_BULK_TIMEOUT,
+                      &TransStatus
+                      );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Nth                         = (USB_NCM_TRANSFER_HEADER_16 *)UsbEthDriver->BulkBuffer;
+    Ndp                         = (USB_NCM_DATAGRAM_POINTER_16 *)((UINT8 *)UsbEthDriver->BulkBuffer + Nth->NdpIndex);
+    Datagram                    = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+    UsbEthDriver->TotalDatagram = (UINT8)((Ndp->Length - 8) / 4 - 1);
+
+    for (Index = 0; Index < UsbEthDriver->TotalDatagram; Index++) {
+      TotalLength += Datagram->DatagramLength;
+      Datagram     = (USB_NCM_DATA_GRAM *)((UINT8 *)Datagram + sizeof (USB_NCM_DATA_GRAM));
+    }
+
+    if (TotalLength < USB_ETHERNET_FRAME_SIZE) {
+      Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+
+      TotalLength = 0;
+      for (Index = 0; Index < UsbEthDriver->TotalDatagram; Index++) {
+        CopyMem ((UINT8 *)Packet + TotalLength, (UINT8 *)UsbEthDriver->BulkBuffer + Datagram->DatagramIndex, Datagram->DatagramLength);
+        TotalLength += Datagram->DatagramLength;
+        Datagram     = (USB_NCM_DATA_GRAM *)((UINT8 *)Datagram + sizeof (USB_NCM_DATA_GRAM));
+      }
+
+      *PacketLength             = TotalLength;
+      UsbEthDriver->NowDatagram = UsbEthDriver->TotalDatagram;
+    } else {
+      UsbEthDriver->NowDatagram++;
+
+      Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+      CopyMem (Packet, (UINT8 *)UsbEthDriver->BulkBuffer + Datagram->DatagramIndex, Datagram->DatagramLength);
+      *PacketLength = Datagram->DatagramLength;
+    }
+
+    return Status;
+  } else {
+    UsbEthDriver->NowDatagram++;
+
+    Nth      = (USB_NCM_TRANSFER_HEADER_16 *)UsbEthDriver->BulkBuffer;
+    Ndp      = (USB_NCM_DATAGRAM_POINTER_16 *)((UINT8 *)UsbEthDriver->BulkBuffer + Nth->NdpIndex);
+    Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+    Datagram = (USB_NCM_DATA_GRAM *)((UINT8 *)Datagram + sizeof (USB_NCM_DATA_GRAM) * (UsbEthDriver->NowDatagram - 1));
+
+    CopyMem (Packet, (UINT8 *)UsbEthDriver->BulkBuffer + Datagram->DatagramIndex, Datagram->DatagramLength);
+    *PacketLength = Datagram->DatagramLength;
+
+    return EFI_SUCCESS;
+  }
+}
+
+/**
+  This function is used to manage a USB device with the bulk transfer pipe. The endpoint is Bulk out.
+
+  @param[in]      Cdb           A pointer to the command descriptor block.
+  @param[in]      This          A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[in]      Packet        A pointer to the buffer of data that will be transmitted to USB
+                                device or received from USB device.
+  @param[in, out] PacketLength  A pointer to the PacketLength.
+
+  @retval EFI_SUCCESS           The bulk transfer has been successfully executed.
+  @retval EFI_DEVICE_ERROR      The transfer failed. The transfer status is returned in status.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be submitted due to a lack of resources.
+  @retval EFI_TIMEOUT           The control transfer fails due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthNcmTransmit (
+  IN      PXE_CDB                      *Cdb,
+  IN      EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN      VOID                         *Packet,
+  IN OUT  UINTN                        *PacketLength
+  )
+{
+  EFI_STATUS                   Status;
+  USB_ETHERNET_DRIVER          *UsbEthDriver;
+  EFI_USB_IO_PROTOCOL          *UsbIo;
+  UINT32                       TransStatus;
+  USB_NCM_TRANSFER_HEADER_16   *Nth;
+  USB_NCM_DATAGRAM_POINTER_16  *Ndp;
+  USB_NCM_DATA_GRAM            *Datagram;
+  UINT8                        *TotalPacket;
+  UINTN                        TotalLength;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+  Status = gBS->HandleProtocol (
+                  UsbEthDriver->UsbCdcDataHandle,
+                  &gEfiUsbIoProtocolGuid,
+                  (VOID **)&UsbIo
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (UsbEthDriver->BulkOutEndpoint == 0) {
+    GetEndpoint (UsbIo, UsbEthDriver);
+  }
+
+  TotalLength = (UINTN)(USB_NCM_NTH_LENGTH + USB_NCM_NDP_LENGTH + (*PacketLength));
+
+  Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&TotalPacket);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SetMem (TotalPacket, TotalLength, 0);
+
+  Nth               = (USB_NCM_TRANSFER_HEADER_16 *)TotalPacket;
+  Nth->Signature    = USB_NCM_NTH_SIGN_16;
+  Nth->HeaderLength = USB_NCM_NTH_LENGTH;
+  Nth->Sequence     = UsbEthDriver->BulkOutSequence++;
+  Nth->BlockLength  = (UINT16)TotalLength;
+  Nth->NdpIndex     = Nth->HeaderLength;
+
+  Ndp               = (USB_NCM_DATAGRAM_POINTER_16 *)((UINT8 *)TotalPacket + Nth->NdpIndex);
+  Ndp->Signature    = USB_NCM_NDP_SIGN_16;
+  Ndp->Length       = USB_NCM_NDP_LENGTH;
+  Ndp->NextNdpIndex = 0x00;
+
+  Datagram                 = (USB_NCM_DATA_GRAM *)((UINT8 *)Ndp + sizeof (USB_NCM_DATAGRAM_POINTER_16));
+  Datagram->DatagramIndex  = Nth->HeaderLength + Ndp->Length;
+  Datagram->DatagramLength = (UINT16)*PacketLength;
+
+  CopyMem (TotalPacket + Datagram->DatagramIndex, Packet, *PacketLength);
+
+  *PacketLength = TotalLength;
+
+  Status = UsbIo->UsbBulkTransfer (
+                    UsbIo,
+                    UsbEthDriver->BulkOutEndpoint,
+                    TotalPacket,
+                    PacketLength,
+                    USB_ETHERNET_BULK_TIMEOUT,
+                    &TransStatus
+                    );
+  FreePool (TotalPacket);
+  return Status;
+}
+
+/**
+  Async USB transfer callback routine.
+
+  @param[in]  Data            Data received or sent via the USB Asynchronous Transfer, if the
+                              transfer completed successfully.
+  @param[in]  DataLength      The length of Data received or sent via the Asynchronous
+                              Transfer, if transfer successfully completes.
+  @param[in]  Context         Data passed from UsbAsyncInterruptTransfer() request.
+  @param[in]  Status          Indicates the result of the asynchronous transfer.
+
+  @retval EFI_SUCCESS           The asynchronous USB transfer request has been successfully executed.
+  @retval EFI_DEVICE_ERROR      The asynchronous USB transfer request failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InterruptCallback (
+  IN  VOID    *Data,
+  IN  UINTN   DataLength,
+  IN  VOID    *Context,
+  IN  UINT32  Status
+  )
+{
+  if ((Data == NULL) || (Context == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (((EFI_USB_DEVICE_REQUEST *)Data)->Request == USB_CDC_NETWORK_CONNECTION) {
+    CopyMem (
+      (EFI_USB_DEVICE_REQUEST *)Context,
+      (EFI_USB_DEVICE_REQUEST *)Data,
+      sizeof (EFI_USB_DEVICE_REQUEST)
+      );
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function is used to manage a USB device with an interrupt transfer pipe.
+
+  @param[in]  This              A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[in]  IsNewTransfer     If TRUE, a new transfer will be submitted to USB controller. If
+                                FALSE, the interrupt transfer is deleted from the device's interrupt
+                                transfer queue.
+  @param[in]  PollingInterval   Indicates the periodic rate, in milliseconds, that the transfer is to be
+                                executed.This parameter is required when IsNewTransfer is TRUE. The
+                                value must be between 1 to 255, otherwise EFI_INVALID_PARAMETER is returned.
+                                The units are in milliseconds.
+  @param[in]  Request           A pointer to the EFI_USB_DEVICE_REQUEST data.
+
+  @retval EFI_SUCCESS           The asynchronous USB transfer request transfer has been successfully executed.
+  @retval EFI_DEVICE_ERROR      The asynchronous USB transfer request failed.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthNcmInterrupt (
+  IN EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN BOOLEAN                      IsNewTransfer,
+  IN UINTN                        PollingInterval,
+  IN EFI_USB_DEVICE_REQUEST       *Request
+  )
+{
+  EFI_STATUS           Status;
+  USB_ETHERNET_DRIVER  *UsbEthDriver;
+  UINTN                DataLength;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+  DataLength   = 0;
+
+  if (IsNewTransfer == TRUE) {
+    DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
+    Status     = UsbEthDriver->UsbIo->UsbAsyncInterruptTransfer (
+                                        UsbEthDriver->UsbIo,
+                                        UsbEthDriver->InterruptEndpoint,
+                                        IsNewTransfer,
+                                        PollingInterval,
+                                        DataLength,
+                                        (EFI_ASYNC_USB_TRANSFER_CALLBACK)InterruptCallback,
+                                        Request
+                                        );
+  } else {
+    Status = UsbEthDriver->UsbIo->UsbAsyncInterruptTransfer (
+                                    UsbEthDriver->UsbIo,
+                                    UsbEthDriver->InterruptEndpoint,
+                                    IsNewTransfer,
+                                    0,
+                                    0,
+                                    NULL,
+                                    NULL
+                                    );
+  }
+
+  return Status;
+}
+
+/**
+  Retrieves the USB Ethernet Mac Address.
+
+  @param[in]  This          A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[out] MacAddress    A pointer to the caller allocated USB Ethernet Mac Address.
+
+  @retval EFI_SUCCESS           The USB Header Functional descriptor was retrieved successfully.
+  @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
+  @retval EFI_NOT_FOUND         The USB Header Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthMacAddress (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT EFI_MAC_ADDRESS              *MacAddress
+  )
+{
+  EFI_STATUS                   Status;
+  USB_ETHERNET_DRIVER          *UsbEthDriver;
+  USB_ETHERNET_FUN_DESCRIPTOR  UsbEthDescriptor;
+  CHAR16                       *Data;
+  CHAR16                       *DataPtr;
+  CHAR16                       TmpStr[1];
+  UINT8                        Index;
+  UINT8                        Hi;
+  UINT8                        Low;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+  Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  Status = UsbEthDriver->UsbIo->UsbGetStringDescriptor (
+                                  UsbEthDriver->UsbIo,
+                                  0x409,                        // English-US Language ID
+                                  UsbEthDescriptor.MacAddress,
+                                  &Data
+                                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a:UsbGetStringDescriptor status = %r\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  DataPtr = Data;
+  for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
+    CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
+    DataPtr++;
+    Hi = (UINT8)StrHexToUintn (TmpStr);
+    CopyMem (TmpStr, DataPtr, sizeof (CHAR16));
+    DataPtr++;
+    Low                     = (UINT8)StrHexToUintn (TmpStr);
+    MacAddress->Addr[Index] = (Hi << 4) | Low;
+  }
+
+  return Status;
+}
+
+/**
+  Get the USB NCM max NTB size.
+
+  @param[in]  This          A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[out] BulkSize      A pointer to the Bulk transfer data size.
+
+  @retval EFI_SUCCESS           Get the USB NCM max NTB size successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthNcmBulkSize (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT UINTN                        *BulkSize
+  )
+{
+  *BulkSize = USB_NCM_MAX_NTB_SIZE;
+  return EFI_SUCCESS;
+}
+
+/**
+  Retrieves the USB Header functional Descriptor.
+
+  @param[in]  This                   A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[out] UsbHeaderFunDescriptor A pointer to the caller allocated USB Header Functional Descriptor.
+
+  @retval EFI_SUCCESS           The USB Header Functional descriptor was retrieved successfully.
+  @retval EFI_INVALID_PARAMETER UsbHeaderFunDescriptor is NULL.
+  @retval EFI_NOT_FOUND         The USB Header Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbHeaderFunDescriptor (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT USB_HEADER_FUN_DESCRIPTOR    *UsbHeaderFunDescriptor
+  )
+{
+  EFI_STATUS           Status;
+  USB_ETHERNET_DRIVER  *UsbEthDriver;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+  if (UsbHeaderFunDescriptor == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GetFunctionalDescriptor (UsbEthDriver->Config, HEADER_FUN_DESCRIPTOR, UsbHeaderFunDescriptor);
+  return Status;
+}
+
+/**
+  Retrieves the USB Union functional Descriptor.
+
+  @param[in]  This                   A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[out] UsbUnionFunDescriptor  A pointer to the caller allocated USB Union Functional Descriptor.
+
+  @retval EFI_SUCCESS           The USB Union Functional descriptor was retrieved successfully.
+  @retval EFI_INVALID_PARAMETER UsbUnionFunDescriptor is NULL.
+  @retval EFI_NOT_FOUND         The USB Union Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbUnionFunDescriptor (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT USB_UNION_FUN_DESCRIPTOR     *UsbUnionFunDescriptor
+  )
+{
+  EFI_STATUS           Status;
+  USB_ETHERNET_DRIVER  *UsbEthDriver;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+  if (UsbUnionFunDescriptor == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GetFunctionalDescriptor (UsbEthDriver->Config, UNION_FUN_DESCRIPTOR, UsbUnionFunDescriptor);
+  return Status;
+}
+
+/**
+  Retrieves the USB Ethernet functional Descriptor.
+
+  This function get the Mac Address, Ethernet statistics, maximum segment size,
+  number of multicast filters, and number of pattern filters from Ethernet
+  functional Descriptor.
+
+  @param[in]  This                   A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[out] UsbEthFunDescriptor    A pointer to the caller allocated USB Ethernet Functional Descriptor.
+
+  @retval EFI_SUCCESS           The USB Ethernet Functional descriptor was retrieved successfully.
+  @retval EFI_INVALID_PARAMETER UsbEthFunDescriptor is NULL.
+  @retval EFI_NOT_FOUND         The USB Ethernet Functional descriptor was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthFunDescriptor (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  OUT USB_ETHERNET_FUN_DESCRIPTOR  *UsbEthFunDescriptor
+  )
+{
+  EFI_STATUS           Status;
+  USB_ETHERNET_DRIVER  *UsbEthDriver;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+  if (UsbEthFunDescriptor == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = GetFunctionalDescriptor (UsbEthDriver->Config, ETHERNET_FUN_DESCRIPTOR, UsbEthFunDescriptor);
+  return Status;
+}
+
+/**
+  This request sets the Ethernet device multicast filters as specified in the
+  sequential list of 48 bit Ethernet multicast addresses.
+
+  @param[in]  This                   A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[in]  Value                  Number of filters.
+  @param[in]  McastAddr              A pointer to the value of the multicast addresses.
+
+  @retval EFI_SUCCESS           The request executed successfully.
+  @retval EFI_TIMEOUT           A timeout occurred executing the request.
+  @retval EFI_DEVICE_ERROR      The request failed due to a device error.
+  @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+  @retval EFI_UNSUPPORTED       Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetUsbEthMcastFilter (
+  IN EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN UINT16                       Value,
+  IN VOID                         *McastAddr
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_USB_DEVICE_REQUEST       Request;
+  UINT32                       TransStatus;
+  USB_ETHERNET_FUN_DESCRIPTOR  UsbEthFunDescriptor;
+  USB_ETHERNET_DRIVER          *UsbEthDriver;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+  Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
+  Request.Request     = SET_ETH_MULTICAST_FILTERS_REQ;
+  Request.Value       = Value;
+  Request.Index       = UsbEthDriver->NumOfInterface;
+  Request.Length      = Value * 6;
+
+  return UsbEthDriver->UsbIo->UsbControlTransfer (
+                                UsbEthDriver->UsbIo,
+                                &Request,
+                                EfiUsbDataOut,
+                                USB_ETHERNET_TRANSFER_TIMEOUT,
+                                McastAddr,
+                                Request.Length,
+                                &TransStatus
+                                );
+}
+
+/**
+  This request sets up the specified Ethernet power management pattern filter as
+  described in the data structure.
+
+  @param[in]  This                  A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[in]  Value                 Number of filters.
+  @param[in]  Length                Size of the power management pattern filter data.
+  @param[in]  PatternFilter         A pointer to the power management pattern filter structure.
+
+  @retval EFI_SUCCESS           The request executed successfully.
+  @retval EFI_TIMEOUT           A timeout occurred executing the request.
+  @retval EFI_DEVICE_ERROR      The request failed due to a device error.
+  @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+  @retval EFI_UNSUPPORTED       Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetUsbEthPowerFilter (
+  IN EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN UINT16                       Value,
+  IN UINT16                       Length,
+  IN VOID                         *PatternFilter
+  )
+{
+  EFI_USB_DEVICE_REQUEST  Request;
+  UINT32                  TransStatus;
+  USB_ETHERNET_DRIVER     *UsbEthDriver;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+  Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
+  Request.Request     = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
+  Request.Value       = Value;
+  Request.Index       = UsbEthDriver->NumOfInterface;
+  Request.Length      = Length;
+
+  return UsbEthDriver->UsbIo->UsbControlTransfer (
+                                UsbEthDriver->UsbIo,
+                                &Request,
+                                EfiUsbDataOut,
+                                USB_ETHERNET_TRANSFER_TIMEOUT,
+                                PatternFilter,
+                                Length,
+                                &TransStatus
+                                );
+}
+
+/**
+  This request retrieves the status of the specified Ethernet power management
+  pattern filter from the device.
+
+  @param[in]  This                   A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[in]  Value                  The filter number.
+  @param[out] PatternActive          A pointer to the pattern active boolean.
+
+  @retval EFI_SUCCESS           The request executed successfully.
+  @retval EFI_TIMEOUT           A timeout occurred executing the request.
+  @retval EFI_DEVICE_ERROR      The request failed due to a device error.
+  @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+  @retval EFI_UNSUPPORTED       Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthPowerFilter (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN  UINT16                       Value,
+  OUT BOOLEAN                      *PatternActive
+  )
+{
+  EFI_USB_DEVICE_REQUEST  Request;
+  UINT32                  TransStatus;
+  USB_ETHERNET_DRIVER     *UsbEthDriver;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+  Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
+  Request.Request     = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
+  Request.Value       = Value;
+  Request.Index       = UsbEthDriver->NumOfInterface;
+  Request.Length      = USB_ETH_POWER_FILTER_LENGTH;
+
+  return UsbEthDriver->UsbIo->UsbControlTransfer (
+                                UsbEthDriver->UsbIo,
+                                &Request,
+                                EfiUsbDataIn,
+                                USB_ETHERNET_TRANSFER_TIMEOUT,
+                                PatternActive,
+                                USB_ETH_POWER_FILTER_LENGTH,
+                                &TransStatus
+                                );
+}
+
+BIT_MAP  gTable[] = {
+  { PXE_OPFLAGS_RECEIVE_FILTER_UNICAST,            USB_ETH_PACKET_TYPE_DIRECTED      },
+  { PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST,          USB_ETH_PACKET_TYPE_BROADCAST     },
+  { PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, USB_ETH_PACKET_TYPE_MULTICAST     },
+  { PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS,        USB_ETH_PACKET_TYPE_PROMISCUOUS   },
+  { PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST,      USB_ETH_PACKET_TYPE_ALL_MULTICAST },
+};
+
+/**
+  Convert value between PXE receive filter and USB ETH packet filter.
+
+  @param[in]  Value      PXE filter data.
+  @param[out] CdcFilter  A pointer to the Ethernet Packet Filter Bitmap value converted by PXE_OPFLAGS.
+
+**/
+VOID
+ConvertFilter (
+  IN  UINT16  Value,
+  OUT UINT16  *CdcFilter
+  )
+{
+  UINT32  Index;
+  UINT32  Count;
+
+  Count = sizeof (gTable)/sizeof (gTable[0]);
+
+  for (Index = 0; (gTable[Index].Src != 0) && (Index < Count); Index++) {
+    if (gTable[Index].Src & Value) {
+      *CdcFilter |= gTable[Index].Dst;
+    }
+  }
+}
+
+/**
+  This request is used to configure device Ethernet packet filter settings.
+
+  @param[in]  This              A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[in]  Value             Packet Filter Bitmap.
+
+  @retval EFI_SUCCESS           The request executed successfully.
+  @retval EFI_TIMEOUT           A timeout occurred executing the request.
+  @retval EFI_DEVICE_ERROR      The request failed due to a device error.
+  @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+  @retval EFI_UNSUPPORTED       Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SetUsbEthPacketFilter (
+  IN EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN UINT16                       Value
+  )
+{
+  EFI_USB_DEVICE_REQUEST  Request;
+  UINT32                  TransStatus;
+  USB_ETHERNET_DRIVER     *UsbEthDriver;
+  UINT16                  CommandFilter;
+
+  UsbEthDriver  = USB_ETHERNET_DEV_FROM_THIS (This);
+  CommandFilter = 0;
+
+  ConvertFilter (Value, &CommandFilter);
+
+  Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
+  Request.Request     = SET_ETH_PACKET_FILTER_REQ;
+  Request.Value       = CommandFilter;
+  Request.Index       = UsbEthDriver->NumOfInterface;
+  Request.Length      = USB_ETH_PACKET_FILTER_LENGTH;
+
+  return UsbEthDriver->UsbIo->UsbControlTransfer (
+                                UsbEthDriver->UsbIo,
+                                &Request,
+                                EfiUsbNoData,
+                                USB_ETHERNET_TRANSFER_TIMEOUT,
+                                NULL,
+                                USB_ETH_PACKET_FILTER_LENGTH,
+                                &TransStatus
+                                );
+}
+
+/**
+  This request is used to retrieve a statistic based on the feature selector.
+
+  @param[in]  This                  A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
+  @param[in]  FeatureSelector       Value of the feature selector.
+  @param[out] Statistic             A pointer to the 32 bit unsigned integer.
+
+  @retval EFI_SUCCESS           The request executed successfully.
+  @retval EFI_TIMEOUT           A timeout occurred executing the request.
+  @retval EFI_DEVICE_ERROR      The request failed due to a device error.
+  @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+  @retval EFI_UNSUPPORTED       Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+GetUsbEthStatistic (
+  IN  EDKII_USB_ETHERNET_PROTOCOL  *This,
+  IN  UINT16                       FeatureSelector,
+  OUT VOID                         *Statistic
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_USB_DEVICE_REQUEST       Request;
+  UINT32                       TransStatus;
+  USB_ETHERNET_FUN_DESCRIPTOR  UsbEthFunDescriptor;
+  USB_ETHERNET_DRIVER          *UsbEthDriver;
+
+  UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+  Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (UsbEthFunDescriptor.EthernetStatistics == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
+  Request.Request     = GET_ETH_STATISTIC_REQ;
+  Request.Value       = FeatureSelector;
+  Request.Index       = UsbEthDriver->NumOfInterface;
+  Request.Length      = USB_ETH_STATISTIC;
+
+  return UsbEthDriver->UsbIo->UsbControlTransfer (
+                                UsbEthDriver->UsbIo,
+                                &Request,
+                                EfiUsbDataIn,
+                                USB_ETHERNET_TRANSFER_TIMEOUT,
+                                Statistic,
+                                USB_ETH_STATISTIC,
+                                &TransStatus
+                                );
+}
--
2.35.1.windows.2
-The information contained in this message may be confidential and proprietary to American Megatrends (AMI). This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission.

  parent reply	other threads:[~2023-03-09  7:51 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-09  7:51 [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS devices support RichardHo [何明忠]
2023-03-09  7:51 ` [PATCH v6 2/3] UsbNetworkPkg/UsbCdcEcm: Add USB Cdc ECM " RichardHo [何明忠]
2023-03-09  7:51 ` RichardHo [何明忠] [this message]
2023-03-27 14:59 ` [PATCH v6 1/3] UsbNetworkPkg/UsbRndis: Add USB RNDIS " Tinh Nguyen
2023-03-27 15:13   ` [edk2-devel] " Rebecca Cran
2023-03-28 11:40 ` Rebecca Cran
2023-03-29  2:11   ` RichardHo [何明忠]
2023-04-07  1:57 ` Rebecca Cran
2023-04-07  2:49   ` RichardHo [何明忠]
2023-04-07  2:52     ` [edk2-devel] " Rebecca Cran
2023-04-07 11:47     ` Rebecca Cran

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=20230309075134.864-3-richardho@ami.com \
    --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