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>
1722 lines
56 KiB
C
1722 lines
56 KiB
C
/** @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 "UsbRndis.h"
|
|
|
|
UINT16 gStopBulkInCnt = 0;
|
|
UINT16 gBlockBulkInCnt = 0;
|
|
|
|
/**
|
|
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);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:UsbGetConfigDescriptor status = %r\n", __func__, Status));
|
|
return Status;
|
|
}
|
|
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
Tmp.TotalLength,
|
|
(VOID **)ConfigDesc
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: AllocatePool status = %r\n", __func__, Status));
|
|
return 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] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
|
|
|
|
**/
|
|
VOID
|
|
GetEndpoint (
|
|
IN EFI_USB_IO_PROTOCOL *UsbIo,
|
|
IN OUT USB_RNDIS_DEVICE *UsbRndisDevice
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Index;
|
|
UINT32 Result;
|
|
EFI_USB_INTERFACE_DESCRIPTOR Interface;
|
|
EFI_USB_ENDPOINT_DESCRIPTOR Endpoint;
|
|
|
|
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __func__, Status));
|
|
return;
|
|
}
|
|
|
|
if (Interface.NumEndpoints == 0 ) {
|
|
Status = UsbSetInterface (UsbIo, 1, 0, &Result);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:UsbSetInterface status = %r\n", __func__, Status));
|
|
return;
|
|
}
|
|
|
|
Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:UsbGetInterfaceDescriptor status = %r\n", __func__, Status));
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (Index = 0; Index < Interface.NumEndpoints; Index++) {
|
|
Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &Endpoint);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:UsbGetEndpointDescriptor status = %r\n", __func__, Status));
|
|
return;
|
|
}
|
|
|
|
switch ((Endpoint.Attributes & (BIT0 | BIT1))) {
|
|
case USB_ENDPOINT_BULK:
|
|
if (Endpoint.EndpointAddress & BIT7) {
|
|
UsbRndisDevice->BulkInEndpoint = Endpoint.EndpointAddress;
|
|
} else {
|
|
UsbRndisDevice->BulkOutEndpoint = Endpoint.EndpointAddress;
|
|
}
|
|
|
|
break;
|
|
case USB_ENDPOINT_INTERRUPT:
|
|
UsbRndisDevice->InterrupEndpoint = Endpoint.EndpointAddress;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
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 == 0) {
|
|
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] Requst 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
|
|
UsbRndisInterrupt (
|
|
IN EDKII_USB_ETHERNET_PROTOCOL *This,
|
|
IN BOOLEAN IsNewTransfer,
|
|
IN UINTN PollingInterval,
|
|
IN EFI_USB_DEVICE_REQUEST *Requst
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
UINTN DataLength;
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
DataLength = 0;
|
|
|
|
if (IsNewTransfer) {
|
|
DataLength = sizeof (EFI_USB_DEVICE_REQUEST) + sizeof (USB_CONNECT_SPEED_CHANGE);
|
|
Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
|
|
UsbRndisDevice->UsbIo,
|
|
UsbRndisDevice->InterrupEndpoint,
|
|
IsNewTransfer,
|
|
PollingInterval,
|
|
DataLength,
|
|
InterruptCallback,
|
|
Requst
|
|
);
|
|
|
|
if (Status == EFI_INVALID_PARAMETER) {
|
|
// Because of Stacked AsyncInterrupt request are not supported
|
|
Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
|
|
UsbRndisDevice->UsbIo,
|
|
UsbRndisDevice->InterrupEndpoint,
|
|
0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
} else {
|
|
Status = UsbRndisDevice->UsbIo->UsbAsyncInterruptTransfer (
|
|
UsbRndisDevice->UsbIo,
|
|
UsbRndisDevice->InterrupEndpoint,
|
|
IsNewTransfer,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function is used to read USB interrupt transfer before the response RNDIS message.
|
|
|
|
@param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
|
|
|
|
@retval EFI_SUCCESS The USB interrupt transfer has been successfully executed.
|
|
@retval EFI_DEVICE_ERROR The USB interrupt transfer failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ReadRndisResponseInterrupt (
|
|
IN USB_RNDIS_DEVICE *UsbRndisDevice
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 Data[2];
|
|
UINT32 UsbStatus;
|
|
UINTN DataLength;
|
|
|
|
DataLength = 8;
|
|
|
|
ZeroMem (Data, sizeof (Data));
|
|
|
|
Status = UsbRndisDevice->UsbIo->UsbSyncInterruptTransfer (
|
|
UsbRndisDevice->UsbIo,
|
|
UsbRndisDevice->InterrupEndpoint,
|
|
&Data,
|
|
&DataLength,
|
|
0x20,
|
|
&UsbStatus
|
|
);
|
|
|
|
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_RNDIS_DEVICE *UsbRndisDevice;
|
|
USB_ETHERNET_FUN_DESCRIPTOR UsbEthDescriptor;
|
|
CHAR16 *Data;
|
|
CHAR16 *DataPtr;
|
|
CHAR16 TmpStr[1];
|
|
UINT8 Index;
|
|
UINT8 Hi;
|
|
UINT8 Low;
|
|
|
|
REMOTE_NDIS_QUERY_MAC_MSG RndisQueryMsg;
|
|
REMOTE_NDIS_QUERY_MAC_CMPLT RndisQueryMsgCmplt;
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
|
|
ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAC_MSG));
|
|
ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT));
|
|
|
|
RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
|
|
RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_MSG);
|
|
RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
|
|
RndisQueryMsg.QueryMsg.Oid = OID_802_3_CURRENT_ADDRESS;
|
|
|
|
RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
|
|
RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAC_CMPLT);
|
|
|
|
Status = RndisControlMsg (
|
|
UsbRndisDevice,
|
|
(REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
|
|
(REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Success to get Mac address from RNDIS message.\n"));
|
|
for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {
|
|
MacAddress->Addr[Index] = RndisQueryMsgCmplt.Addr[Index];
|
|
}
|
|
|
|
UsbRndisDevice->RequestId++;
|
|
return Status;
|
|
}
|
|
|
|
// If it is not support the OID_802_3_CURRENT_ADDRESS.
|
|
// To check USB Ethernet functional Descriptor
|
|
Status = This->UsbEthFunDescriptor (This, &UsbEthDescriptor);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a:UsbEthFunDescriptor status = %r\n", __func__, Status));
|
|
return Status;
|
|
}
|
|
|
|
Status = UsbRndisDevice->UsbIo->UsbGetStringDescriptor (
|
|
UsbRndisDevice->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
|
|
UsbEthBulkSize (
|
|
IN EDKII_USB_ETHERNET_PROTOCOL *This,
|
|
OUT UINTN *BulkSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
|
|
REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG RndisQueryMsg;
|
|
REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT RndisQueryMsgCmplt;
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
|
|
ZeroMem (&RndisQueryMsg, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG));
|
|
ZeroMem (&RndisQueryMsgCmplt, sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT));
|
|
|
|
RndisQueryMsg.QueryMsg.MessageType = RNDIS_QUERY_MSG;
|
|
RndisQueryMsg.QueryMsg.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_MSG);
|
|
RndisQueryMsg.QueryMsg.RequestID = UsbRndisDevice->RequestId;
|
|
RndisQueryMsg.QueryMsg.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
|
|
|
|
RndisQueryMsgCmplt.QueryCmplt.MessageType = RNDIS_QUERY_CMPLT;
|
|
RndisQueryMsgCmplt.QueryCmplt.MessageLength = sizeof (REMOTE_NDIS_QUERY_MAX_TOTAL_SIZE_CMPLT);
|
|
|
|
Status = RndisControlMsg (
|
|
UsbRndisDevice,
|
|
(REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsg,
|
|
(REMOTE_NDIS_MSG_HEADER *)&RndisQueryMsgCmplt
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Success to get Max Total size : %X \n", RndisQueryMsgCmplt.MaxTotalSize));
|
|
*BulkSize = RndisQueryMsgCmplt.MaxTotalSize;
|
|
UsbRndisDevice->RequestId++;
|
|
return Status;
|
|
}
|
|
|
|
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_RNDIS_DEVICE *UsbRndisDevice;
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
|
|
if (UsbHeaderFunDescriptor == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = GetFunctionalDescriptor (
|
|
UsbRndisDevice->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_RNDIS_DEVICE *UsbRndisDevice;
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
|
|
if (UsbUnionFunDescriptor == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = GetFunctionalDescriptor (
|
|
UsbRndisDevice->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
|
|
GetUsbRndisFunDescriptor (
|
|
IN EDKII_USB_ETHERNET_PROTOCOL *This,
|
|
OUT USB_ETHERNET_FUN_DESCRIPTOR *UsbEthFunDescriptor
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
|
|
if (UsbEthFunDescriptor == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = GetFunctionalDescriptor (
|
|
UsbRndisDevice->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
|
|
SetUsbRndisMcastFilter (
|
|
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_RNDIS_DEVICE *UsbRndisDevice;
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_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 = UsbRndisDevice->NumOfInterface;
|
|
Request.Length = Value * 6;
|
|
|
|
return UsbRndisDevice->UsbIo->UsbControlTransfer (
|
|
UsbRndisDevice->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
|
|
SetUsbRndisPowerFilter (
|
|
IN EDKII_USB_ETHERNET_PROTOCOL *This,
|
|
IN UINT16 Value,
|
|
IN UINT16 Length,
|
|
IN VOID *PatternFilter
|
|
)
|
|
{
|
|
EFI_USB_DEVICE_REQUEST Request;
|
|
UINT32 TransStatus;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
|
|
Request.RequestType = USB_ETHERNET_SET_REQ_TYPE;
|
|
Request.Request = SET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
|
|
Request.Value = Value;
|
|
Request.Index = UsbRndisDevice->NumOfInterface;
|
|
Request.Length = Length;
|
|
|
|
return UsbRndisDevice->UsbIo->UsbControlTransfer (
|
|
UsbRndisDevice->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
|
|
GetUsbRndisPowerFilter (
|
|
IN EDKII_USB_ETHERNET_PROTOCOL *This,
|
|
IN UINT16 Value,
|
|
OUT BOOLEAN *PatternActive
|
|
)
|
|
{
|
|
EFI_USB_DEVICE_REQUEST Request;
|
|
UINT32 TransStatus;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
|
|
Request.RequestType = USB_ETHERNET_GET_REQ_TYPE;
|
|
Request.Request = GET_ETH_POWER_MANAGEMENT_PATTERN_FILTER_REQ;
|
|
Request.Value = Value;
|
|
Request.Index = UsbRndisDevice->NumOfInterface;
|
|
Request.Length = USB_ETH_POWER_FILTER_LENGTH;
|
|
|
|
return UsbRndisDevice->UsbIo->UsbControlTransfer (
|
|
UsbRndisDevice->UsbIo,
|
|
&Request,
|
|
EfiUsbDataIn,
|
|
USB_ETHERNET_TRANSFER_TIMEOUT,
|
|
PatternActive,
|
|
USB_ETH_POWER_FILTER_LENGTH,
|
|
&TransStatus
|
|
);
|
|
}
|
|
|
|
BIT_MAP gTable[] = {
|
|
{ PXE_OPFLAGS_RECEIVE_FILTER_UNICAST, NDIS_PACKET_TYPE_DIRECTED },
|
|
{ PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST, NDIS_PACKET_TYPE_BROADCAST },
|
|
{ PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST, NDIS_PACKET_TYPE_MULTICAST },
|
|
{ PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS, NDIS_PACKET_TYPE_PROMISCUOUS },
|
|
{ PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST, NDIS_PACKET_TYPE_ALL_MULTICAST },
|
|
};
|
|
|
|
/**
|
|
|
|
Converts PXE filter settings to RNDIS values
|
|
|
|
@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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
Updates Filter settings on the device.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_STATUS
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiReceiveFilter (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *McastList;
|
|
UINT8 Count;
|
|
UINT8 Index1;
|
|
UINT8 Index2;
|
|
UINT64 CpbAddr;
|
|
UINT32 CpbSize;
|
|
UINT16 SetFilter;
|
|
PXE_CPB_RECEIVE_FILTERS *Cpb;
|
|
USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor;
|
|
|
|
Count = 0;
|
|
CpbAddr = Cdb->CPBaddr;
|
|
CpbSize = Cdb->CPBsize;
|
|
SetFilter = (UINT16)(Cdb->OpFlags & 0x1F);
|
|
Cpb = (PXE_CPB_RECEIVE_FILTERS *)(UINTN)CpbAddr;
|
|
|
|
// The Cpb could be NULL.(ref:PXE_CPBADDR_NOT_USED)
|
|
Nic->RxFilter = (UINT8)SetFilter;
|
|
|
|
if (((SetFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) || (Cpb != NULL)) {
|
|
if (Cpb != NULL) {
|
|
Nic->McastCount = (UINT8)(CpbSize / PXE_MAC_LENGTH);
|
|
CopyMem (&Nic->McastList, Cpb, Nic->McastCount);
|
|
} else {
|
|
Nic->McastCount = 0;
|
|
}
|
|
|
|
Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor);
|
|
if ((UsbEthFunDescriptor.NumberMcFilters << 1) == 0) {
|
|
Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
|
|
DEBUG ((DEBUG_INFO, "SetUsbEthPacketFilter Nic %lx Nic->UsbEth %lx ", Nic, Nic->UsbEth));
|
|
Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
|
|
} else {
|
|
Status = gBS->AllocatePool (EfiBootServicesData, Nic->McastCount * 6, (VOID **)&McastList);
|
|
if (EFI_ERROR (Status)) {
|
|
return PXE_STATCODE_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Cpb != NULL) {
|
|
for (Index1 = 0; Index1 < Nic->McastCount; Index1++) {
|
|
for (Index2 = 0; Index2 < 6; Index2++) {
|
|
McastList[Count++] = Cpb->MCastList[Index1][Index2];
|
|
}
|
|
}
|
|
}
|
|
|
|
Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
|
|
if (Cpb != NULL) {
|
|
Nic->UsbEth->SetUsbEthMcastFilter (Nic->UsbEth, Nic->McastCount, McastList);
|
|
}
|
|
|
|
Nic->UsbEth->SetUsbEthPacketFilter (Nic->UsbEth, Nic->RxFilter);
|
|
FreePool (McastList);
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
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
|
|
SetUsbRndisPacketFilter (
|
|
IN EDKII_USB_ETHERNET_PROTOCOL *This,
|
|
IN UINT16 Value
|
|
)
|
|
{
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
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
|
|
GetRndisStatistic (
|
|
IN EDKII_USB_ETHERNET_PROTOCOL *This,
|
|
IN UINT16 FeatureSelector,
|
|
OUT VOID *Statistic
|
|
)
|
|
{
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is called when UndiStart is invoked.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiStart (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_INFO, "RndisUndiStart Nic %lx Cdb %lx Nic State %x\n", Nic, Cdb, Nic->State));
|
|
|
|
// Issue Rndis Reset and bring the device to RNDIS_BUS_INITIALIZED state
|
|
Status = RndisUndiReset (Cdb, Nic);
|
|
if (EFI_ERROR (Status)) {
|
|
RndisUndiReset (Cdb, Nic);
|
|
}
|
|
|
|
Status = RndisUndiInitialize (Cdb, Nic);
|
|
if (EFI_ERROR (Status)) {
|
|
RndisUndiInitialize (Cdb, Nic);
|
|
}
|
|
|
|
RndisUndiShutdown (Cdb, Nic);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is called when Undistop is invoked.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiStop (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "RndisUndiStop State %x\n", Nic->State));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is called when UndiGetInitInfo is invoked.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiGetInitInfo (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
EDKII_USB_ETHERNET_PROTOCOL *UsbEthDevice;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
PXE_DB_GET_INIT_INFO *Db;
|
|
|
|
DEBUG ((DEBUG_INFO, "RndisUndiGetInitInfo\n"));
|
|
|
|
UsbEthDevice = Nic->UsbEth;
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDevice);
|
|
|
|
Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr;
|
|
|
|
Db->FrameDataLen = UsbRndisDevice->MaxTransferSize - sizeof (REMOTE_NDIS_PACKET_MSG) - PXE_MAC_HEADER_LEN_ETHER;
|
|
// Limit Max MTU size to 1500 bytes as RNDIS spec.
|
|
if (Db->FrameDataLen > PXE_MAX_TXRX_UNIT_ETHER) {
|
|
Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Db->FrameDataLen %x\n", Db->FrameDataLen));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is called when RndisUndiGetConfigInfo is invoked.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiGetConfigInfo (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "RndisUndiGetConfigInfo\n"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is called when UndiInitialize is invoked.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
@retval EFI_UNSUPPORTED Not supported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiInitialize (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
REMOTE_NDIS_INITIALIZE_MSG RndisInitMsg;
|
|
REMOTE_NDIS_INITIALIZE_CMPLT RndisInitMsgCmplt;
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_INFO, "RndisUndiInitialize\n"));
|
|
|
|
UsbEthDriver = Nic->UsbEth;
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
|
|
|
|
ZeroMem (&RndisInitMsg, sizeof (REMOTE_NDIS_INITIALIZE_MSG));
|
|
ZeroMem (&RndisInitMsgCmplt, sizeof (REMOTE_NDIS_INITIALIZE_CMPLT));
|
|
|
|
RndisInitMsg.MessageType = RNDIS_INITIALIZE_MSG;
|
|
RndisInitMsg.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
|
|
RndisInitMsg.RequestID = UsbRndisDevice->RequestId;
|
|
RndisInitMsg.MajorVersion = RNDIS_MAJOR_VERSION;
|
|
RndisInitMsg.MinorVersion = RNDIS_MINOR_VERSION;
|
|
RndisInitMsg.MaxTransferSize = RNDIS_MAX_TRANSFER_SIZE;
|
|
|
|
RndisInitMsgCmplt.MessageType = RNDIS_INITIALIZE_CMPLT;
|
|
RndisInitMsgCmplt.MessageLength = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
|
|
|
|
Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisInitMsgCmplt);
|
|
|
|
UsbRndisDevice->RequestId++;
|
|
|
|
if (EFI_ERROR (Status) || (RndisInitMsgCmplt.Status & 0x80000000)) {
|
|
return Status;
|
|
}
|
|
|
|
// Only Wired Medium is supported
|
|
if (RndisInitMsgCmplt.Medium) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
UsbRndisDevice->Medium = RndisInitMsgCmplt.Medium;
|
|
UsbRndisDevice->MaxPacketsPerTransfer = RndisInitMsgCmplt.MaxPacketsPerTransfer;
|
|
UsbRndisDevice->MaxTransferSize = RndisInitMsgCmplt.MaxTransferSize;
|
|
UsbRndisDevice->PacketAlignmentFactor = RndisInitMsgCmplt.PacketAlignmentFactor;
|
|
|
|
DEBUG ((DEBUG_INFO, "Medium : %x \n", RndisInitMsgCmplt.Medium));
|
|
DEBUG ((DEBUG_INFO, "MaxPacketsPerTransfer : %x \n", RndisInitMsgCmplt.MaxPacketsPerTransfer));
|
|
DEBUG ((DEBUG_INFO, "MaxTransferSize : %x\n", RndisInitMsgCmplt.MaxTransferSize));
|
|
DEBUG ((DEBUG_INFO, "PacketAlignmentFactor : %x\n", RndisInitMsgCmplt.PacketAlignmentFactor));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function is called when UndiReset is invoked.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
@retval EFI_DEVICE_ERROR The request failed due to a device error.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiReset (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
REMOTE_NDIS_RESET_MSG RndisResetMsg;
|
|
REMOTE_NDIS_RESET_CMPLT RndisResetCmplt;
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_INFO, "RndisUndiReset\n"));
|
|
|
|
UsbEthDriver = Nic->UsbEth;
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
|
|
|
|
ZeroMem (&RndisResetMsg, sizeof (REMOTE_NDIS_RESET_MSG));
|
|
ZeroMem (&RndisResetCmplt, sizeof (REMOTE_NDIS_RESET_CMPLT));
|
|
|
|
RndisResetMsg.MessageType = RNDIS_RESET_MSG;
|
|
RndisResetMsg.MessageLength = sizeof (REMOTE_NDIS_RESET_MSG);
|
|
|
|
RndisResetCmplt.MessageType = RNDIS_RESET_CMPLT;
|
|
RndisResetCmplt.MessageLength = sizeof (REMOTE_NDIS_RESET_CMPLT);
|
|
|
|
Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisResetMsg, (REMOTE_NDIS_MSG_HEADER *)&RndisResetCmplt);
|
|
|
|
UsbRndisDevice->RequestId = 1; // Let's start with 1
|
|
|
|
if (EFI_ERROR (Status) || (RndisResetCmplt.Status & 0x80000000)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is called when UndiShutdown is invoked.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiShutdown (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
EDKII_USB_ETHERNET_PROTOCOL *UsbEthDriver;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
REMOTE_NDIS_HALT_MSG RndisHltMsg;
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_INFO, "RndisUndiShutdown\n"));
|
|
|
|
UsbEthDriver = Nic->UsbEth;
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (UsbEthDriver);
|
|
|
|
ZeroMem (&RndisHltMsg, sizeof (REMOTE_NDIS_HALT_MSG));
|
|
|
|
RndisHltMsg.MessageType = RNDIS_HLT_MSG;
|
|
RndisHltMsg.MessageLength = sizeof (REMOTE_NDIS_HALT_MSG);
|
|
|
|
Status = RndisControlMsg (UsbRndisDevice, (REMOTE_NDIS_MSG_HEADER *)&RndisHltMsg, NULL);
|
|
|
|
if (Status == EFI_DEVICE_ERROR) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
UsbRndisDevice->RequestId = 1;
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Update the Media connection.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiGetStatus (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
Cdb->StatFlags &= ~(PXE_STATFLAGS_GET_STATUS_NO_MEDIA);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Transmit the data after appending RNDIS header.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] This A pointer to the EDKII_USB_ETHERNET_PROTOCOL instance.
|
|
@param[in] BulkOutData A pointer to the buffer of data that will be transmitted to USB
|
|
device or received from USB device.
|
|
@param[in, out] DataLength A pointer to the PacketLength.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiTransmit (
|
|
IN PXE_CDB *Cdb,
|
|
IN EDKII_USB_ETHERNET_PROTOCOL *This,
|
|
IN VOID *BulkOutData,
|
|
IN OUT UINTN *DataLength
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
|
|
UINTN TransferLength;
|
|
|
|
DEBUG ((DEBUG_INFO, "RndisUndiTransmit DataLength : %x\n", *DataLength));
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
|
|
RndisPacketMsg = AllocateZeroPool (sizeof (REMOTE_NDIS_PACKET_MSG) + *DataLength);
|
|
if (RndisPacketMsg == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
RndisPacketMsg->MessageType = RNDIS_PACKET_MSG;
|
|
RndisPacketMsg->MessageLength = sizeof (REMOTE_NDIS_PACKET_MSG) + (UINT32)*DataLength;
|
|
RndisPacketMsg->DataOffset = sizeof (REMOTE_NDIS_PACKET_MSG) - 8;
|
|
RndisPacketMsg->DataLength = (UINT32)*DataLength;
|
|
|
|
CopyMem (
|
|
((UINT8 *)RndisPacketMsg) + sizeof (REMOTE_NDIS_PACKET_MSG),
|
|
BulkOutData,
|
|
*DataLength
|
|
);
|
|
|
|
TransferLength = RndisPacketMsg->MessageLength;
|
|
|
|
Status = RndisTransmitDataMsg (
|
|
UsbRndisDevice,
|
|
(REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
|
|
&TransferLength
|
|
);
|
|
|
|
DEBUG ((DEBUG_INFO, "\nRndisUndiTransmit TransferLength %lx\n", TransferLength));
|
|
|
|
FreePool (RndisPacketMsg);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Receives and removes RNDIS header and returns the raw data.
|
|
|
|
@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] BulkInData A pointer to the buffer of data that will be transmitted to USB
|
|
device or received from USB device.
|
|
@param[in, out] DataLength A pointer to the PacketLength.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
@retval EFI_BUFFER_TOO_SMALL The user provided buffer is too small
|
|
@retval EFI_NOT_FOUND No buffer was found in the list.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisUndiReceive (
|
|
IN PXE_CDB *Cdb,
|
|
IN EDKII_USB_ETHERNET_PROTOCOL *This,
|
|
IN OUT VOID *BulkInData,
|
|
IN OUT UINTN *DataLength
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_RNDIS_DEVICE *UsbRndisDevice;
|
|
REMOTE_NDIS_PACKET_MSG *RndisPacketMsg;
|
|
UINTN TransferLength;
|
|
VOID *Buffer;
|
|
PACKET_LIST *HeadPacket;
|
|
PACKET_LIST *PacketList;
|
|
|
|
// Check if there is any outstanding packet to receive
|
|
// The buffer allocated has a linked List followed by the packet.
|
|
|
|
UsbRndisDevice = USB_RNDIS_DEVICE_FROM_THIS (This);
|
|
Buffer = NULL;
|
|
HeadPacket = NULL;
|
|
|
|
while (1) {
|
|
Buffer = AllocateZeroPool (sizeof (PACKET_LIST) + sizeof (REMOTE_NDIS_PACKET_MSG) + UsbRndisDevice->MaxTransferSize);
|
|
if (Buffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(sizeof (PACKET_LIST) + (UINT8 *)Buffer);
|
|
PacketList = (PACKET_LIST *)Buffer;
|
|
PacketList->PacketStartBuffer = (UINT8 *)Buffer + sizeof (PACKET_LIST);
|
|
// Save the original address for freeing it up
|
|
PacketList->OrgBuffer = (UINT8 *)Buffer;
|
|
TransferLength = UsbRndisDevice->MaxTransferSize;
|
|
|
|
Status = RndisReceiveDataMsg (
|
|
UsbRndisDevice,
|
|
(REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg,
|
|
&TransferLength
|
|
);
|
|
|
|
if (EFI_ERROR (Status) || (TransferLength == 0)) {
|
|
FreePool (Buffer);
|
|
break;
|
|
}
|
|
|
|
// Collect all the RNDIS packet in Linked list.
|
|
if ((RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
|
|
(RndisPacketMsg->DataOffset == sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH) &&
|
|
(TransferLength >= RndisPacketMsg->MessageLength))
|
|
{
|
|
// Insert Packet
|
|
PacketList->RemainingLength = TransferLength;
|
|
InsertTailList (&UsbRndisDevice->ReceivePacketList, Buffer);
|
|
} else {
|
|
FreePool (Buffer);
|
|
}
|
|
}
|
|
|
|
while (!IsListEmpty (&UsbRndisDevice->ReceivePacketList)) {
|
|
HeadPacket = (PACKET_LIST *)GetFirstNode (&UsbRndisDevice->ReceivePacketList);
|
|
|
|
RndisPacketMsg = (REMOTE_NDIS_PACKET_MSG *)(UINT8 *)HeadPacket->PacketStartBuffer;
|
|
|
|
PrintRndisMsg ((REMOTE_NDIS_MSG_HEADER *)RndisPacketMsg);
|
|
|
|
// Check whether the packet is valid RNDIS packet.
|
|
if ((HeadPacket->RemainingLength > sizeof (REMOTE_NDIS_PACKET_MSG)) && (RndisPacketMsg->MessageType == RNDIS_PACKET_MSG) &&
|
|
(RndisPacketMsg->DataOffset == (sizeof (REMOTE_NDIS_PACKET_MSG) - RNDIS_RESERVED_BYTE_LENGTH)) &&
|
|
(HeadPacket->RemainingLength >= RndisPacketMsg->MessageLength))
|
|
{
|
|
if (*DataLength >= RndisPacketMsg->DataLength) {
|
|
CopyMem (
|
|
BulkInData,
|
|
(UINT8 *)RndisPacketMsg + (RndisPacketMsg->DataOffset + RNDIS_RESERVED_BYTE_LENGTH),
|
|
RndisPacketMsg->DataLength
|
|
);
|
|
|
|
*DataLength = RndisPacketMsg->DataLength;
|
|
|
|
HeadPacket->RemainingLength = HeadPacket->RemainingLength - RndisPacketMsg->MessageLength;
|
|
HeadPacket->PacketStartBuffer = (UINT8 *)RndisPacketMsg + RndisPacketMsg->MessageLength;
|
|
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
*DataLength = RndisPacketMsg->DataLength;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
}
|
|
|
|
RemoveEntryList (&HeadPacket->PacketList);
|
|
FreePool ((PACKET_LIST *)HeadPacket->OrgBuffer);
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This is a dummy function which just returns. Unimplemented EDKII_USB_ETHERNET_PROTOCOL functions
|
|
point to this function.
|
|
|
|
@param[in] Cdb A pointer to the command descriptor block.
|
|
@param[in] Nic A pointer to the Network interface controller data.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RndisDummyReturn (
|
|
IN PXE_CDB *Cdb,
|
|
IN NIC_DATA *Nic
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "RndisDummyReturn called\n"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function send the RNDIS command through the device's control endpoint
|
|
|
|
@param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
|
|
@param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
|
|
@param[out] RndisMsgResponse A pointer to the REMOTE_NDIS_MSG_HEADER data for getting responses.
|
|
|
|
@retval EFI_SUCCESS The bulk transfer has been successfully executed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RndisControlMsg (
|
|
IN USB_RNDIS_DEVICE *UsbRndisDevice,
|
|
IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
|
|
OUT REMOTE_NDIS_MSG_HEADER *RndisMsgResponse
|
|
)
|
|
{
|
|
EFI_USB_IO_PROTOCOL *UsbIo;
|
|
EFI_USB_DEVICE_REQUEST DevReq;
|
|
UINT32 UsbStatus;
|
|
EFI_STATUS Status;
|
|
UINT32 SaveResponseType;
|
|
UINT32 SaveResponseLength;
|
|
UINT32 Index;
|
|
REMOTE_NDIS_INITIALIZE_CMPLT *RndisInitCmplt;
|
|
|
|
UsbIo = UsbRndisDevice->UsbIo;
|
|
SaveResponseType = 0;
|
|
SaveResponseLength = 0;
|
|
RndisInitCmplt = (REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsgResponse;
|
|
|
|
if (RndisMsgResponse != NULL) {
|
|
SaveResponseType = RndisMsgResponse->MessageType;
|
|
SaveResponseLength = RndisMsgResponse->MessageLength;
|
|
}
|
|
|
|
ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
|
|
|
|
DevReq.RequestType = USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
|
|
DevReq.Request = SEND_ENCAPSULATED_COMMAND;
|
|
DevReq.Value = 0;
|
|
DevReq.Index = 0;
|
|
DevReq.Length = (UINT16)RndisMsg->MessageLength;
|
|
|
|
PrintRndisMsg (RndisMsg);
|
|
|
|
Status = UsbIo->UsbControlTransfer (
|
|
UsbIo,
|
|
&DevReq,
|
|
EfiUsbDataOut,
|
|
USB_ETHERNET_TRANSFER_TIMEOUT,
|
|
RndisMsg,
|
|
RndisMsg->MessageLength,
|
|
&UsbStatus
|
|
);
|
|
|
|
DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r RndisMsgResponse : %lx\n", UsbStatus, Status, RndisMsgResponse));
|
|
|
|
// Error or no response expected
|
|
if ((EFI_ERROR (Status)) || (RndisMsgResponse == NULL)) {
|
|
DEBUG ((DEBUG_INFO, "RndisControlMsg: UsbStatus : %x Status : %r\n", UsbStatus, Status));
|
|
return Status;
|
|
}
|
|
|
|
for (Index = 0; Index < (RNDIS_CONTROL_TIMEOUT/100); Index++) {
|
|
ReadRndisResponseInterrupt (UsbRndisDevice);
|
|
ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
|
|
|
|
DevReq.RequestType = USB_ENDPOINT_DIR_IN | USB_REQ_TYPE_CLASS | USB_TARGET_INTERFACE;
|
|
DevReq.Request = GET_ENCAPSULATED_RESPONSE;
|
|
DevReq.Value = 0;
|
|
DevReq.Index = 0;
|
|
DevReq.Length = (UINT16)RndisMsgResponse->MessageLength;
|
|
|
|
Status = UsbIo->UsbControlTransfer (
|
|
UsbIo,
|
|
&DevReq,
|
|
EfiUsbDataIn,
|
|
USB_ETHERNET_TRANSFER_TIMEOUT,
|
|
RndisMsgResponse,
|
|
RndisMsgResponse->MessageLength,
|
|
&UsbStatus
|
|
);
|
|
|
|
DEBUG ((DEBUG_INFO, "RndisControlMsg Response: UsbStatus : %x Status : %r \n", UsbStatus, Status));
|
|
|
|
PrintRndisMsg (RndisMsgResponse);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if ((RndisInitCmplt->RequestID != ((REMOTE_NDIS_INITIALIZE_CMPLT *)RndisMsg)->RequestID) || (RndisInitCmplt->MessageType != SaveResponseType)) {
|
|
DEBUG ((DEBUG_INFO, "Retry the response\n"));
|
|
|
|
RndisMsgResponse->MessageType = SaveResponseType;
|
|
RndisMsgResponse->MessageLength = SaveResponseLength;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "RndisControlMsg: TimeOut\n"));
|
|
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
/**
|
|
This function send the RNDIS command through the device's Data endpoint
|
|
|
|
@param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
|
|
@param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
|
|
@param[in, out] TransferLength The length of the RndisMsg data to transfer.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RndisTransmitDataMsg (
|
|
IN USB_RNDIS_DEVICE *UsbRndisDevice,
|
|
IN REMOTE_NDIS_MSG_HEADER *RndisMsg,
|
|
IN OUT UINTN *TransferLength
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbStatus;
|
|
|
|
if (UsbRndisDevice->BulkInEndpoint == 0) {
|
|
GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
|
|
}
|
|
|
|
PrintRndisMsg (RndisMsg);
|
|
|
|
Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
|
|
UsbRndisDevice->UsbIoCdcData,
|
|
UsbRndisDevice->BulkOutEndpoint,
|
|
RndisMsg,
|
|
TransferLength,
|
|
USB_TX_ETHERNET_BULK_TIMEOUT,
|
|
&UsbStatus
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
gStopBulkInCnt = MAXIMUM_STOPBULKIN_CNT; // After sending cmd ,we will polling receive package for MAXIMUM_STOPBULKIN_CNT times
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function send the RNDIS command through the device's Data endpoint
|
|
|
|
@param[in] UsbRndisDevice A pointer to the USB_RNDIS_DEVICE instance.
|
|
@param[in, out] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER to send out.
|
|
@param[in, out] TransferLength The length of the RndisMsg data to transfer.
|
|
|
|
@retval EFI_SUCCESS The request executed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RndisReceiveDataMsg (
|
|
IN USB_RNDIS_DEVICE *UsbRndisDevice,
|
|
IN OUT REMOTE_NDIS_MSG_HEADER *RndisMsg,
|
|
IN OUT UINTN *TransferLength
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 UsbStatus;
|
|
|
|
UsbStatus = 0;
|
|
|
|
if (UsbRndisDevice->BulkInEndpoint == 0) {
|
|
GetEndpoint (UsbRndisDevice->UsbIoCdcData, UsbRndisDevice);
|
|
}
|
|
|
|
// Use gStopBulkInCnt to stop BulkIn command
|
|
if ((gStopBulkInCnt != 0) || LAN_BULKIN_CMD_CONTROL) {
|
|
Status = UsbRndisDevice->UsbIoCdcData->UsbBulkTransfer (
|
|
UsbRndisDevice->UsbIoCdcData,
|
|
UsbRndisDevice->BulkInEndpoint,
|
|
RndisMsg,
|
|
TransferLength,
|
|
USB_RX_ETHERNET_BULK_TIMEOUT,
|
|
&UsbStatus
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
|
|
} else {
|
|
gStopBulkInCnt--;
|
|
}
|
|
} else {
|
|
Status = EFI_TIMEOUT;
|
|
*TransferLength = 0;
|
|
gBlockBulkInCnt++;
|
|
}
|
|
|
|
if (gBlockBulkInCnt > BULKIN_CMD_POLLING_CNT) {
|
|
gStopBulkInCnt = MINIMUM_STOPBULKIN_CNT;
|
|
gBlockBulkInCnt = 0;
|
|
}
|
|
|
|
PrintRndisMsg (RndisMsg);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Prints RNDIS Header and Data
|
|
|
|
@param[in] RndisMsg A pointer to the REMOTE_NDIS_MSG_HEADER data.
|
|
|
|
**/
|
|
VOID
|
|
PrintRndisMsg (
|
|
IN REMOTE_NDIS_MSG_HEADER *RndisMsg
|
|
)
|
|
{
|
|
UINTN Length;
|
|
REMOTE_NDIS_QUERY_CMPLT *RndisQueryCmplt;
|
|
|
|
Length = 0;
|
|
|
|
switch (RndisMsg->MessageType) {
|
|
case RNDIS_PACKET_MSG:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_PACKET_MSG:\n"));
|
|
Length = sizeof (REMOTE_NDIS_PACKET_MSG) + 0x14;
|
|
break;
|
|
case RNDIS_INITIALIZE_MSG:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_MSG:\n"));
|
|
Length = sizeof (REMOTE_NDIS_INITIALIZE_MSG);
|
|
break;
|
|
case RNDIS_INITIALIZE_CMPLT:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_INITIALIZE_CMPLT:\n"));
|
|
Length = sizeof (REMOTE_NDIS_INITIALIZE_CMPLT);
|
|
break;
|
|
case RNDIS_HLT_MSG:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_HLT_MSG:\n"));
|
|
Length = sizeof (REMOTE_NDIS_HALT_MSG);
|
|
break;
|
|
case RNDIS_QUERY_MSG:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_QUERY_MSG:\n"));
|
|
Length = sizeof (REMOTE_NDIS_QUERY_MSG);
|
|
break;
|
|
case RNDIS_QUERY_CMPLT:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_QUERY_CMPLT:\n"));
|
|
RndisQueryCmplt = (REMOTE_NDIS_QUERY_CMPLT *)RndisMsg;
|
|
Length = sizeof (REMOTE_NDIS_QUERY_CMPLT) + RndisQueryCmplt->InformationBufferLength;
|
|
break;
|
|
case RNDIS_SET_MSG:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_SET_MSG:\n"));
|
|
Length = sizeof (REMOTE_NDIS_SET_MSG);
|
|
break;
|
|
case RNDIS_SET_CMPLT:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_SET_CMPLT:\n"));
|
|
Length = sizeof (REMOTE_NDIS_SET_CMPLT);
|
|
break;
|
|
case RNDIS_RESET_MSG:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_RESET_MSG:\n"));
|
|
Length = sizeof (REMOTE_NDIS_RESET_MSG);
|
|
break;
|
|
case RNDIS_RESET_CMPLT:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_RESET_CMPLT:\n"));
|
|
Length = sizeof (REMOTE_NDIS_RESET_CMPLT);
|
|
break;
|
|
case RNDIS_INDICATE_STATUS_MSG:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_INDICATE_STATUS_MSG:\n"));
|
|
Length = sizeof (REMOTE_NDIS_INDICATE_STATUS_MSG);
|
|
break;
|
|
case RNDIS_KEEPALIVE_MSG:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_MSG:\n"));
|
|
Length = sizeof (REMOTE_NDIS_KEEPALIVE_MSG);
|
|
break;
|
|
case RNDIS_KEEPALIVE_CMPLT:
|
|
DEBUG ((DEBUG_INFO, "RNDIS_KEEPALIVE_CMPLT:\n"));
|
|
Length = sizeof (REMOTE_NDIS_KEEPALIVE_CMPLT);
|
|
}
|
|
|
|
if (Length) {
|
|
UINTN Index;
|
|
Index = 0;
|
|
for ( ; Length; Length -= 4, Index++) {
|
|
DEBUG ((DEBUG_INFO, "%8X\t", *((UINT32 *)RndisMsg + Index)));
|
|
if (((Index % 4) == 3) && (Index != 0)) {
|
|
DEBUG ((DEBUG_INFO, "\n"));
|
|
}
|
|
|
|
if ((Length < 8) && (Length > 4)) {
|
|
UINT32 Data32;
|
|
Index++;
|
|
Data32 = *((UINT32 *)RndisMsg + Index);
|
|
DEBUG ((DEBUG_INFO, "%8X\t", Data32));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((Index % 4) != 0) {
|
|
DEBUG ((DEBUG_INFO, "\n"));
|
|
}
|
|
}
|
|
}
|