Files
system76-edk2/MdeModulePkg/Bus/Usb/UsbNetwork/NetworkCommon/DriverBinding.c
Richard Ho fc0d5922f1 MdeModulePkg/Bus/Usb/UsbNetwork/UsbRndis: Add USB RNDIS devices support
This driver provides UEFI driver for USB RNDIS device

Signed-off-by: Richard Ho <richardho@ami.com>
Cc: Andrew Fish <afish@apple.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Michael Kubacki <mikuback@linux.microsoft.com>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Tested-by: Tinh Nguyen <tinhnguyen@os.amperecomputing.com>
Acked-by: Hao A Wu <hao.a.wu@intel.com>
Reviewed-by: Rebecca Cran <rebecca@bsdio.com>
Reviewed-by: Tony Lo <tonylo@ami.com>
2023-07-13 17:18:40 +00:00

596 lines
19 KiB
C

/** @file
This file contains code for USB network binding driver
Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "DriverBinding.h"
PXE_SW_UNDI *gPxe = NULL;
NIC_DEVICE *gLanDeviceList[MAX_LAN_INTERFACE];
UINT32 gRateLimitingCredit;
UINT32 gRateLimitingPollTimer;
BOOLEAN gRateLimitingEnable;
EFI_DRIVER_BINDING_PROTOCOL gNetworkCommonDriverBinding = {
NetworkCommonSupported,
NetworkCommonDriverStart,
NetworkCommonDriverStop,
NETWORK_COMMON_DRIVER_VERSION,
NULL,
NULL
};
/**
Create MAC Device Path
@param[in, out] Dev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
@param[in] BaseDev A pointer to the EFI_DEVICE_PATH_PROTOCOL instance.
@param[in] Nic A pointer to the Network interface controller data.
@retval EFI_OUT_OF_RESOURCES The device path could not be created successfully due to a lack of resources.
@retval EFI_SUCCESS MAC device path created successfully.
**/
EFI_STATUS
CreateMacDevicePath (
IN OUT EFI_DEVICE_PATH_PROTOCOL **Dev,
IN EFI_DEVICE_PATH_PROTOCOL *BaseDev,
IN NIC_DATA *Nic
)
{
EFI_STATUS Status;
MAC_ADDR_DEVICE_PATH MacAddrNode;
EFI_DEVICE_PATH_PROTOCOL *EndNode;
UINT8 *DevicePath;
UINT16 TotalLength;
UINT16 BaseLength;
ZeroMem (&MacAddrNode, sizeof (MAC_ADDR_DEVICE_PATH));
CopyMem (&MacAddrNode.MacAddress, &Nic->MacAddr, sizeof (EFI_MAC_ADDRESS));
MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
MacAddrNode.Header.Length[0] = (UINT8)sizeof (MacAddrNode);
MacAddrNode.Header.Length[1] = 0;
EndNode = BaseDev;
while (!IsDevicePathEnd (EndNode)) {
EndNode = NextDevicePathNode (EndNode);
}
BaseLength = (UINT16)((UINTN)(EndNode) - (UINTN)(BaseDev));
TotalLength = (UINT16)(BaseLength + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
Status = gBS->AllocatePool (EfiBootServicesData, TotalLength, (VOID **)&DevicePath);
if (EFI_ERROR (Status)) {
return Status;
}
*Dev = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
CopyMem (DevicePath, (CHAR8 *)BaseDev, BaseLength);
DevicePath += BaseLength;
CopyMem (DevicePath, (CHAR8 *)&MacAddrNode, sizeof (MacAddrNode));
DevicePath += sizeof (MacAddrNode);
CopyMem (DevicePath, (CHAR8 *)EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
return EFI_SUCCESS;
}
/**
Network Common 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
NetworkCommonSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
Status = gBS->OpenProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
(VOID **)&UsbEth,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return Status;
}
/**
Network Common 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
NetworkCommonDriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *UsbEthPath;
EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
EFI_MAC_ADDRESS MacAddress;
UINTN BulkDataSize;
NIC_DEVICE *NicDevice;
UINT8 *TmpPxePointer;
Status = gBS->OpenProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
(VOID **)&UsbEth,
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_BY_DRIVER
);
if (EFI_ERROR (Status)) {
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return Status;
}
ZeroMem (&MacAddress, sizeof (EFI_MAC_ADDRESS));
Status = UsbEth->UsbEthMacAddress (UsbEth, &MacAddress);
ASSERT_EFI_ERROR (Status);
Status = UsbEth->UsbEthMaxBulkSize (UsbEth, &BulkDataSize);
if (EFI_ERROR (Status)) {
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return Status;
}
NicDevice = AllocateZeroPool (sizeof (NIC_DEVICE) + BulkDataSize + 4096);
if (!NicDevice) {
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_OUT_OF_RESOURCES;
}
// for alignment adjustment
if (gPxe == NULL) {
TmpPxePointer = NULL;
TmpPxePointer = AllocateZeroPool (sizeof (PXE_SW_UNDI) + 16);
if (!TmpPxePointer) {
if (NicDevice != NULL) {
FreePool (NicDevice);
}
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_OUT_OF_RESOURCES;
} else {
// check for paragraph alignment here
if (((UINTN)TmpPxePointer & 0x0F) != 0) {
gPxe = (PXE_SW_UNDI *)(TmpPxePointer + 8);
} else {
gPxe = (PXE_SW_UNDI *)TmpPxePointer;
}
if (gPxe == NULL) {
if (NicDevice != NULL) {
FreePool (NicDevice);
}
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_OUT_OF_RESOURCES;
}
PxeStructInit (gPxe);
}
}
NicDevice->NiiProtocol.Id = (UINT64)(UINTN)(gPxe);
NicDevice->NiiProtocol.IfNum = gPxe->IFcnt | gPxe->IFcntExt << 8;
UpdateNicNum (&NicDevice->NicInfo, gPxe);
NicDevice->NicInfo.Signature = NIC_DATA_SIGNATURE;
NicDevice->NicInfo.UsbEth = UsbEth;
NicDevice->NicInfo.MaxSegmentSize = (UINT16)BulkDataSize;
NicDevice->NicInfo.CableDetect = 0;
NicDevice->ReceiveBuffer = ALIGN_POINTER ((VOID *)NicDevice, 4096);
CopyMem ((CHAR8 *)&(NicDevice->NicInfo.MacAddr), (CHAR8 *)&MacAddress, sizeof (MacAddress));
NicDevice->NicInfo.TxBufferCount = 0;
if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NicDevice;
} else {
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
if (TmpPxePointer != NULL) {
FreePool (TmpPxePointer);
}
if (NicDevice != NULL) {
FreePool (NicDevice);
}
return EFI_DEVICE_ERROR;
}
Status = CreateMacDevicePath (
&NicDevice->DevPath,
UsbEthPath,
&NicDevice->NicInfo
);
if (EFI_ERROR (Status)) {
UpdateNicNum (NULL, gPxe);
if (TmpPxePointer != NULL) {
FreePool (TmpPxePointer);
}
}
NicDevice->Signature = UNDI_DEV_SIGNATURE;
NicDevice->NiiProtocol.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
NicDevice->NiiProtocol.Type = EfiNetworkInterfaceUndi;
NicDevice->NiiProtocol.MajorVer = PXE_ROMID_MAJORVER;
NicDevice->NiiProtocol.MinorVer = PXE_ROMID_MINORVER;
NicDevice->NiiProtocol.ImageSize = 0;
NicDevice->NiiProtocol.ImageAddr = 0;
NicDevice->NiiProtocol.Ipv6Supported = TRUE;
NicDevice->NiiProtocol.StringId[0] = 'U';
NicDevice->NiiProtocol.StringId[1] = 'N';
NicDevice->NiiProtocol.StringId[2] = 'D';
NicDevice->NiiProtocol.StringId[3] = 'I';
NicDevice->DeviceHandle = NULL;
NicDevice->NicInfo.RateLimitingEnable = gRateLimitingEnable;
NicDevice->NicInfo.RateLimitingCreditCount = 0;
NicDevice->NicInfo.RateLimitingCredit = gRateLimitingCredit;
NicDevice->NicInfo.RateLimitingPollTimer = gRateLimitingPollTimer;
NicDevice->NicInfo.RateLimiter = NULL;
ZeroMem (&NicDevice->NicInfo.Request, sizeof (EFI_USB_DEVICE_REQUEST));
Status = UsbEth->UsbEthInterrupt (UsbEth, TRUE, NETWORK_COMMON_POLLING_INTERVAL, &NicDevice->NicInfo.Request);
ASSERT_EFI_ERROR (Status);
Status = gBS->InstallMultipleProtocolInterfaces (
&NicDevice->DeviceHandle,
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
&NicDevice->NiiProtocol,
&gEfiDevicePathProtocolGuid,
NicDevice->DevPath,
NULL
);
if (EFI_ERROR (Status)) {
if (NicDevice->NiiProtocol.IfNum < MAX_LAN_INTERFACE) {
gLanDeviceList[NicDevice->NiiProtocol.IfNum] = NULL;
}
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
if (TmpPxePointer != NULL) {
FreePool (TmpPxePointer);
}
if (NicDevice->DevPath != NULL) {
FreePool (NicDevice->DevPath);
}
if (NicDevice != NULL) {
FreePool (NicDevice);
}
return EFI_DEVICE_ERROR;
}
Status = gBS->OpenProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
(VOID **)&UsbEth,
This->DriverBindingHandle,
NicDevice->DeviceHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
return Status;
}
/**
Network Common 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
NetworkCommonDriverStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
BOOLEAN AllChildrenStopped;
UINTN Index;
EDKII_USB_ETHERNET_PROTOCOL *UsbEth;
NIC_DEVICE *NicDevice;
EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
if (NumberOfChildren == 0) {
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
(VOID **)&NiiProtocol,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_SUCCESS;
}
NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
Status = gBS->UninstallMultipleProtocolInterfaces (
ControllerHandle,
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
&NicDevice->NiiProtocol,
&gEfiDevicePathProtocolGuid,
NicDevice->DevPath,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
FreePool (NicDevice->DevPath);
FreePool (NicDevice);
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_SUCCESS;
}
AllChildrenStopped = TRUE;
for (Index = 0; Index < NumberOfChildren; Index++) {
Status = gBS->OpenProtocol (
ChildHandleBuffer[Index],
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
(VOID **)&NiiProtocol,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
AllChildrenStopped = FALSE;
continue;
}
NicDevice = UNDI_DEV_FROM_THIS (NiiProtocol);
gBS->CloseProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
This->DriverBindingHandle,
ChildHandleBuffer[Index]
);
Status = gBS->UninstallMultipleProtocolInterfaces (
ChildHandleBuffer[Index],
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
&NicDevice->NiiProtocol,
&gEfiDevicePathProtocolGuid,
NicDevice->DevPath,
NULL
);
if (EFI_ERROR (Status)) {
Status = gBS->OpenProtocol (
ControllerHandle,
&gEdkIIUsbEthProtocolGuid,
(VOID **)&UsbEth,
This->DriverBindingHandle,
ChildHandleBuffer[Index],
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
} else {
FreePool (NicDevice->DevPath);
FreePool (NicDevice);
}
}
if (!AllChildrenStopped) {
return EFI_DEVICE_ERROR;
}
return Status;
}
/**
Entrypoint of Network Common Driver.
This function is the entrypoint of Network Common 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
NetworkCommonEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
gNetworkCommonDriverBinding.DriverBindingHandle = ImageHandle;
gNetworkCommonDriverBinding.ImageHandle = ImageHandle;
gRateLimitingEnable = PcdGetBool (PcdEnableUsbNetworkRateLimiting);
gRateLimitingCredit = PcdGet32 (PcdUsbNetworkRateLimitingCredit);
gRateLimitingPollTimer = PcdGet32 (PcdUsbNetworkRateLimitingFactor);
Status = gBS->InstallMultipleProtocolInterfaces (
&gNetworkCommonDriverBinding.DriverBindingHandle,
&gEfiDriverBindingProtocolGuid,
&gNetworkCommonDriverBinding,
&gEfiComponentName2ProtocolGuid,
&gNetworkCommonComponentName2,
NULL
);
return Status;
}