summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c')
-rw-r--r--MdeModulePkg/Bus/Usb/UsbNetwork/UsbCdcEcm/UsbCdcEcm.c502
1 files changed, 502 insertions, 0 deletions
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.<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
+ );
+}