From 5e400d22a0d19452eba56cd553ac692318d9dd80 Mon Sep 17 00:00:00 2001 From: Richard Ho Date: Thu, 13 Jul 2023 14:18:44 +0800 Subject: MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm: Add USB Cdc ECM devices support This driver provides UEFI driver for USB CDC ECM device Signed-off-by: Richard Ho Cc: Andrew Fish Cc: Leif Lindholm Cc: Michael D Kinney Cc: Michael Kubacki Cc: Zhiguang Liu Cc: Liming Gao Cc: Hao A Wu Cc: Ray Ni Tested-by: Tinh Nguyen Acked-by: Hao A Wu Reviewed-by: Rebecca Cran Reviewed-by: Tony Lo --- .../Bus/Usb/UsbNetwork/UsbCdcEcm/ComponentName.c | 170 ++++ .../Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c | 502 ++++++++++++ .../Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.h | 211 +++++ .../Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.inf | 42 + .../Bus/Usb/UsbNetwork/UsbCdcEcm/UsbEcmFunction.c | 880 +++++++++++++++++++++ 5 files changed, 1805 insertions(+) create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/ComponentName.c create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.h create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.inf create mode 100644 MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbEcmFunction.c diff --git a/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/ComponentName.c b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/ComponentName.c new file mode 100644 index 0000000000..e37eecf229 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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.
+ 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/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c new file mode 100644 index 0000000000..eb52d2af7a --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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.
+ 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/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.h b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.h new file mode 100644 index 0000000000..1fd723e6fc --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef USB_CDC_ECM_H_ +#define USB_CDC_ECM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.inf b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.inf new file mode 100644 index 0000000000..02c56f8378 --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UsbCdcEcm + FILE_GUID = 07a84945-685d-48ec-a6a1-1b397579fa76 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = UsbEcmEntry + +[Sources] + UsbCdcEcm.c + UsbCdcEcm.h + UsbEcmFunction.c + ComponentName.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiLib + DebugLib + UefiUsbLib + MemoryAllocationLib + BaseMemoryLib + +[Protocols] + gEfiUsbIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiDriverBindingProtocolGuid + gEdkIIUsbEthProtocolGuid + +[Depex] + TRUE diff --git a/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbEcmFunction.c b/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbEcmFunction.c new file mode 100644 index 0000000000..63003e07ff --- /dev/null +++ b/MdeModulePkg/Bus/Usb/UsbNetwork/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.
+ 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) { + 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", __func__, 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", __func__, 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 + ); +} -- cgit v1.2.3