[PATCH 3/3] UsbNetworkPkg/UsbCdcNcm: Add USB Cdc NCM devices support


RichardHo [何明忠]
 

This driver provides UEFI driver for USB CDC NCM device

Signed-off-by: Richard Ho <richardho@...>
Cc: Andrew Fish <afish@...>
Cc: Leif Lindholm <quic_llindhol@...>
Cc: Michael D Kinney <michael.d.kinney@...>
Cc: Michael Kubacki <michael.kubacki@...>
Cc: Zhiguang Liu <zhiguang.liu@...>
Cc: Liming Gao <gaoliming@...>
Reviewed-by: Tony Lo <tonylo@...>
---
UsbNetworkPkg/UsbCdcNcm/ComponentName.c | 170 ++++
UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c | 506 ++++++++++++
UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h | 245 ++++++
UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf | 42 +
UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c | 950 +++++++++++++++++++++++
5 files changed, 1913 insertions(+)
create mode 100644 UsbNetworkPkg/UsbCdcNcm/ComponentName.c
create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.c
create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
create mode 100644 UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c

diff --git a/UsbNetworkPkg/UsbCdcNcm/ComponentName.c b/UsbNetworkPkg/UsbCdcNcm/ComponentName.c
new file mode 100644
index 0000000000..3db1dc6933
--- /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) 2022, 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 0000000000..7328d56228
--- /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) 2022, 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 = NULL;
+
+ 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));
+ gBS->FreePool (HandleBuffer);
+ return TRUE;
+ }
+ }
+ }
+
+ gBS->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);
+ }
+ }
+
+ gBS->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 = UsbEthReceive;
+ UsbEthDriver->UsbEth.UsbEthTransmit = UsbEthTransmit;
+ UsbEthDriver->UsbEth.UsbEthInterrupt = UsbEthInterrupt;
+ UsbEthDriver->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
+ UsbEthDriver->UsbEth.UsbEthMaxBulkSize = UsbEthBulkSize;
+ UsbEthDriver->UsbEth.UsbHeaderFunDescriptor = GetUsbHeaderFunDescriptor;
+ UsbEthDriver->UsbEth.UsbUnionFunDescriptor = GetUsbUnionFunDescriptor;
+ UsbEthDriver->UsbEth.UsbEthFunDescriptor = GetUsbEthFunDescriptor;
+ UsbEthDriver->UsbEth.SetUsbEthMcastFilter = SetUsbEthMcastFilter;
+ UsbEthDriver->UsbEth.SetUsbEthPowerPatternFilter = SetUsbEthPowerFilter;
+ UsbEthDriver->UsbEth.GetUsbEthPoewrPatternFilter = 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
+ );
+ gBS->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
+ );
+ gBS->FreePool (UsbEthDriver->Config);
+ gBS->FreePool (UsbEthDriver->BulkBuffer);
+ gBS->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/UsbCdcNcm.h b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
new file mode 100644
index 0000000000..e90be6dc7a
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.h
@@ -0,0 +1,245 @@
+/** @file
+ Header file for USB Network Control Model driver
+
+ Copyright (c) 2022, 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_ETH_FRAME_SIZE 0x5F2 // frome network stack snp
+
+// 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
+UsbEthReceive (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN OUT VOID *Packet,
+ IN OUT UINTN *PacketLength
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthTransmit (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN VOID *Packet,
+ IN OUT UINTN *PacketLength
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthInterrupt (
+ 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
+UsbEthBulkSize (
+ 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/UsbCdcNcm.inf b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
new file mode 100644
index 0000000000..0a3441bd24
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbCdcNcm.inf
@@ -0,0 +1,42 @@
+## @file
+# This is Usb Cdc Ncm driver for DXE phase.
+#
+# Copyright (c) 2022, 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/UsbNcmFunction.c b/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
new file mode 100644
index 0000000000..4244f9ec7d
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcNcm/UsbNcmFunction.c
@@ -0,0 +1,950 @@
+/** @file
+ This file contains code for USB Ethernet descriptor
+ and specific requests implement.
+
+ Copyright (c) 2022, 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 = EFI_NOT_FOUND;
+ UINTN Offset;
+ EFI_USB_INTERFACE_DESCRIPTOR *Interface;
+
+ 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_PARAMETE 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
+UsbEthReceive (
+ 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 BulkDataLenght;
+ UINTN TotalLength = 0;
+ USB_NCM_TRANSFER_HEADER_16 *Nth;
+ USB_NCM_DATAGRAM_POINTER_16 *Ndp;
+ USB_NCM_DATA_GRAM *Datagram;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ 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);
+ }
+
+ BulkDataLenght = USB_NCM_MAX_NTB_SIZE;
+ SetMem (UsbEthDriver->BulkBuffer, BulkDataLenght, 0);
+ UsbEthDriver->NowDatagram = 0;
+ UsbEthDriver->TotalDatagram = 0;
+
+ Status = UsbIo->UsbBulkTransfer (
+ UsbIo,
+ UsbEthDriver->BulkInEndpoint,
+ UsbEthDriver->BulkBuffer,
+ &BulkDataLenght,
+ 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_ETH_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_PARAMETE 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
+UsbEthTransmit (
+ 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
+ );
+ gBS->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 (((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
+UsbEthInterrupt (
+ 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 = 0;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+ 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);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UsbEthDriver->UsbIo->UsbGetStringDescriptor (
+ UsbEthDriver->UsbIo,
+ 0x409, // English-US Language ID
+ UsbEthDescriptor.MacAddress,
+ &Data
+ );
+ ASSERT_EFI_ERROR (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
+UsbEthBulkSize (
+ 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_ETHRTNET_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_ETHRTNET_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 = 0;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ ConvertFilter (Value, &CommandFilter);
+
+ Request.RequestType = USB_ETHRTNET_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.