This driver provides UEFI driver for USB CDC ECM device
Signed-off-by: Richard Ho<richar...@ami.com>
Cc: Andrew Fish<af...@apple.com>
Cc: Leif Lindholm<quic_llind...@quicinc.com>
Cc: Michael D Kinney<michael.d.kin...@intel.com>
Cc: Michael Kubacki<mikub...@linux.microsoft.com>
Cc: Zhiguang Liu<zhiguang....@intel.com>
Cc: Liming Gao<gaolim...@byosoft.com.cn>
Cc: Rebecca Cran<rebe...@bsdio.com>
Reviewed-by: Tony Lo<ton...@ami.com>
---
UsbNetworkPkg/UsbCdcEcm/ComponentName.c | 170 +++++
UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c | 502 +++++++++++++
UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h | 211 ++++++
UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf | 42 ++
UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c | 880 +++++++++++++++++++++++
5 files changed, 1805 insertions(+)
create mode 100644 UsbNetworkPkg/UsbCdcEcm/ComponentName.c
create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c
create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h
create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
create mode 100644 UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
diff --git a/UsbNetworkPkg/UsbCdcEcm/ComponentName.c
b/UsbNetworkPkg/UsbCdcEcm/ComponentName.c
new file mode 100644
index 0000000000..e37eecf229
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/ComponentName.c
@@ -0,0 +1,170 @@
+/** @file
+ This file contains code for USB Ecm Driver Component Name definitions
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights
reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "UsbCdcEcm.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE
gUsbEcmDriverNameTable[] = {
+ {
+ "eng;en",
+ L"USB ECM Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+EFI_STATUS
+EFIAPI
+UsbEcmComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEcmComponentNameGetControllerName (
+ 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
gUsbEcmComponentName = {
+ UsbEcmComponentNameGetDriverName,
+ UsbEcmComponentNameGetControllerName,
+ "eng"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL
gUsbEcmComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)UsbEcmComponentNameGetDriverName,
+
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)UsbEcmComponentNameGetControllerName,
+ "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
+UsbEcmComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ gUsbEcmDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUsbEcmComponentName)
+ );
+}
+
+/**
+ 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
+UsbEcmComponentNameGetControllerName (
+ 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/UsbCdcEcm/UsbCdcEcm.c
b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c
new file mode 100644
index 0000000000..eb52d2af7a
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.c
@@ -0,0 +1,502 @@
+/** @file
+ This file contains code for USB Ethernet Control Model
+ Driver
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights
reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "UsbCdcEcm.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gUsbEcmDriverBinding = {
+ UsbEcmDriverSupported,
+ UsbEcmDriverStart,
+ UsbEcmDriverStop,
+ USB_ECM_DRIVER_VERSION,
+ NULL,
+ NULL
+};
+
+/**
+ Check if this interface is USB ECM SubType
+
+ @param[in] UsbIo A pointer to the EFI_USB_IO_PROTOCOL instance.
+
+ @retval TRUE USB ECM SubType.
+ @retval FALSE Not USB ECM 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_ECM_SUBCLASS) &&
+ (InterfaceDescriptor.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ USB ECM 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
+UsbEcmDriverSupported (
+ 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 ECM 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_NO_CLASS_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_ECM_SUBCLASS) &&
+ (Interface.InterfaceProtocol == USB_NO_CLASS_PROTOCOL))
+ {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+ }
+
+ FreePool (HandleBuffer);
+ gBS->CloseEvent (Event);
+}
+
+/**
+ USB ECM 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
+UsbEcmDriverStart (
+ 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 = UsbEthEcmReceive;
+ UsbEthDriver->UsbEth.UsbEthTransmit = UsbEthEcmTransmit;
+ UsbEthDriver->UsbEth.UsbEthInterrupt = UsbEthEcmInterrupt;
+ UsbEthDriver->UsbEth.UsbEthMacAddress = GetUsbEthMacAddress;
+ UsbEthDriver->UsbEth.UsbEthMaxBulkSize = UsbEthEcmBulkSize;
+ 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;
+
+ 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 ECM 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
+UsbEcmDriverStop (
+ 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);
+ return Status;
+}
+
+/**
+ Entrypoint of ECM Driver.
+
+ This function is the entrypoint of ECM 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
+UsbEcmEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ gUsbEcmDriverBinding.DriverBindingHandle = ImageHandle;
+ gUsbEcmDriverBinding.ImageHandle = ImageHandle;
+
+ return gBS->InstallMultipleProtocolInterfaces (
+ &gUsbEcmDriverBinding.DriverBindingHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &gUsbEcmDriverBinding,
+ &gEfiComponentName2ProtocolGuid,
+ &gUsbEcmComponentName2,
+ NULL
+ );
+}
diff --git a/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h
b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h
new file mode 100644
index 0000000000..598b7af14f
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.h
@@ -0,0 +1,211 @@
+/** @file
+ Header file contains code for USB Ethernet Control Model
+ driver definitions
+
+ Copyright (c) 2023, American Megatrends International LLC. All rights
reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _USB_CDC_ECM_H_
+#define _USB_CDC_ECM_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;
+} USB_ETHERNET_DRIVER;
+
+#define USB_ECM_DRIVER_VERSION 1
+#define USB_ETHERNET_BULK_TIMEOUT 1
+#define USB_ETHERNET_TRANSFER_TIMEOUT 200
+
+#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 gUsbEcmComponentName2;
+
+EFI_STATUS
+EFIAPI
+UsbEcmDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEcmDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEcmDriverStop (
+ 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
+UsbEthEcmReceive (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN OUT VOID *Packet,
+ IN OUT UINTN *PacketLength
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthEcmTransmit (
+ IN PXE_CDB *Cdb,
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ IN VOID *Packet,
+ IN OUT UINTN *PacketLength
+ );
+
+EFI_STATUS
+EFIAPI
+UsbEthEcmInterrupt (
+ 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
+UsbEthEcmBulkSize (
+ 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/UsbCdcEcm/UsbCdcEcm.inf
b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
new file mode 100644
index 0000000000..8e19982c1f
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/UsbCdcEcm.inf
@@ -0,0 +1,42 @@
+## @file
+# This is Usb Cdc Ecm 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 = UsbCdcEcm
+ FILE_GUID = 07a84945-685d-48ec-a6a1-1b397579fa76
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UsbEcmEntry
+
+[Sources]
+ UsbCdcEcm.c
+ UsbCdcEcm.h
+ UsbEcmFunction.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/UsbCdcEcm/UsbEcmFunction.c
b/UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
new file mode 100644
index 0000000000..1017278a5d
--- /dev/null
+++ b/UsbNetworkPkg/UsbCdcEcm/UsbEcmFunction.c
@@ -0,0 +1,880 @@
+/** @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 "UsbCdcEcm.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
+UsbEthEcmReceive (
+ 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;
+
+ UsbEthDriver = USB_ETHERNET_DEV_FROM_THIS (This);
+
+ Status = gBS->HandleProtocol (
+ UsbEthDriver->UsbCdcDataHandle,
+ &gEfiUsbIoProtocolGuid,
+ (VOID **)&UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (UsbEthDriver->BulkInEndpoint == 0) {
+ GetEndpoint (UsbIo, UsbEthDriver);
+ }
+
+ Status = UsbIo->UsbBulkTransfer (
+ UsbIo,
+ UsbEthDriver->BulkInEndpoint,
+ Packet,
+ PacketLength,
+ USB_ETHERNET_BULK_TIMEOUT,
+ &TransStatus
+ );
+ return Status;
+}
+
+/**
+ 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
+UsbEthEcmTransmit (
+ 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;
+
+ 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);
+ }
+
+ Status = UsbIo->UsbBulkTransfer (
+ UsbIo,
+ UsbEthDriver->BulkOutEndpoint,
+ Packet,
+ PacketLength,
+ USB_ETHERNET_BULK_TIMEOUT,
+ &TransStatus
+ );
+ 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
+UsbEthEcmInterrupt (
+ 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;
+}
+
+/**
+ Retrieves the USB Ethernet Bulk transfer data 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 The bulk transfer data size was retrieved
successfully.
+ @retval other Failed to retrieve the bulk transfer data size.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbEthEcmBulkSize (
+ IN EDKII_USB_ETHERNET_PROTOCOL *This,
+ OUT UINTN *BulkSize
+ )
+{
+ EFI_STATUS Status;
+ USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
+
+ Status = This->UsbEthFunDescriptor (This, &UsbEthFunDescriptor);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *BulkSize = (UINTN)UsbEthFunDescriptor.MaxSegmentSize;
+ return Status;
+}
+
+/**
+ 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.