/** @file | |
This file contains code for UNDI command based on UEFI specification. | |
Copyright (c) 2023, American Megatrends International LLC. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "DriverBinding.h" | |
// API table, defined in UEFI specification | |
API_FUNC gUndiApiTable[] = { | |
UndiGetState, | |
UndiStart, | |
UndiStop, | |
UndiGetInitInfo, | |
UndiGetConfigInfo, | |
UndiInitialize, | |
UndiReset, | |
UndiShutdown, | |
UndiInterruptEnable, | |
UndiReceiveFilter, | |
UndiStationAddress, | |
UndiStatistics, | |
UndiMcastIp2Mac, | |
UndiNvData, | |
UndiGetStatus, | |
UndiFillHeader, | |
UndiTransmit, | |
UndiReceive | |
}; | |
/** | |
Callback function for enable Rate Limiter. | |
@param[in] Event Event whose notification function is being invoked | |
@param[in] Context Pointer to the notification function's context | |
**/ | |
VOID | |
EFIAPI | |
UndiRateLimiterCallback ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
NIC_DATA *Nic; | |
Nic = Context; | |
if (Nic->RateLimitingCreditCount < Nic->RateLimitingCredit) { | |
Nic->RateLimitingCreditCount++; | |
} | |
} | |
/** | |
This command is used to determine the operational state of the UNDI. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiGetState ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_GET_STATE) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) || | |
(Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) || | |
(Cdb->DBsize != PXE_DBSIZE_NOT_USED) || | |
(Cdb->DBaddr != PXE_DBADDR_NOT_USED) || | |
(Cdb->OpFlags != PXE_OPFLAGS_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
Cdb->StatFlags = Cdb->StatFlags | Nic->State; | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetState (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
This command is used to change the UNDI operational state from stopped to started. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiStart ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
PXE_CPB_START_31 *Cpb; | |
EFI_STATUS Status; | |
BOOLEAN EventError; | |
if ((Cdb->OpCode != PXE_OPCODE_START) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != sizeof (PXE_CPB_START_31)) || | |
(Cdb->DBsize != PXE_DBSIZE_NOT_USED) || | |
(Cdb->DBaddr != PXE_DBADDR_NOT_USED) || | |
(Cdb->OpFlags != PXE_OPFLAGS_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_STOPPED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_ALREADY_STARTED; | |
return; | |
} | |
Cpb = (PXE_CPB_START_31 *)(UINTN)Cdb->CPBaddr; | |
Nic->PxeStart.Delay = Cpb->Delay; | |
Nic->PxeStart.Virt2Phys = Cpb->Virt2Phys; | |
Nic->PxeStart.Block = Cpb->Block; | |
Nic->PxeStart.Map_Mem = 0; | |
Nic->PxeStart.UnMap_Mem = 0; | |
Nic->PxeStart.Sync_Mem = Cpb->Sync_Mem; | |
Nic->PxeStart.Unique_ID = Cpb->Unique_ID; | |
EventError = FALSE; | |
Status = EFI_SUCCESS; | |
if (Nic->RateLimitingEnable == TRUE) { | |
Status = gBS->CreateEvent ( | |
EVT_TIMER | EVT_NOTIFY_SIGNAL, | |
TPL_NOTIFY, | |
UndiRateLimiterCallback, | |
Nic, | |
&Nic->RateLimiter | |
); | |
if (!EFI_ERROR (Status)) { | |
Status = gBS->SetTimer ( | |
Nic->RateLimiter, | |
TimerPeriodic, | |
Nic->RateLimitingPollTimer * 10000 | |
); | |
if (EFI_ERROR (Status)) { | |
EventError = TRUE; | |
} | |
} | |
} | |
if ((Nic->UsbEth->UsbEthUndi.UsbEthUndiStart != NULL) && (EventError == FALSE)) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStart (Cdb, Nic); | |
} | |
if (!EFI_ERROR (Status)) { | |
// Initial the state for UNDI start. | |
Nic->State = PXE_STATFLAGS_GET_STATE_STARTED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} else { | |
if (Nic->RateLimitingEnable == TRUE) { | |
if (!EventError) { | |
gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0); | |
} | |
if (Nic->RateLimiter) { | |
gBS->CloseEvent (&Nic->RateLimiter); | |
Nic->RateLimiter = 0; | |
} | |
} | |
// Initial the state when UNDI start is fail | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_DEVICE_FAILURE; | |
} | |
} | |
/** | |
This command is used to change the UNDI operational state from started to stopped. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiStop ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_STOP) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) || | |
(Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) || | |
(Cdb->DBsize != PXE_DBSIZE_NOT_USED) || | |
(Cdb->DBaddr != PXE_DBADDR_NOT_USED) || | |
(Cdb->OpFlags != PXE_OPFLAGS_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_NOT_STARTED; | |
return; | |
} | |
if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_NOT_SHUTDOWN; | |
return; | |
} | |
Nic->PxeStart.Delay = 0; | |
Nic->PxeStart.Virt2Phys = 0; | |
Nic->PxeStart.Block = 0; | |
Nic->PxeStart.Map_Mem = 0; | |
Nic->PxeStart.UnMap_Mem = 0; | |
Nic->PxeStart.Sync_Mem = 0; | |
Nic->State = PXE_STATFLAGS_GET_STATE_STOPPED; | |
if (Nic->RateLimitingEnable == TRUE) { | |
gBS->SetTimer (&Nic->RateLimiter, TimerCancel, 0); | |
gBS->CloseEvent (&Nic->RateLimiter); | |
} | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStop != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStop (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
This command is used to retrieve initialization information that is | |
needed by drivers and applications to initialized UNDI. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiGetInitInfo ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
PXE_DB_GET_INIT_INFO *Db; | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_GET_INIT_INFO) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) || | |
(Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) || | |
(Cdb->DBsize != sizeof (PXE_DB_GET_INIT_INFO)) || | |
(Cdb->OpFlags != PXE_OPFLAGS_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_NOT_STARTED; | |
return; | |
} | |
Db = (PXE_DB_GET_INIT_INFO *)(UINTN)Cdb->DBaddr; | |
Db->MemoryRequired = MEMORY_REQUIRE; | |
Db->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER; | |
Db->LinkSpeeds[0] = 10; | |
Db->LinkSpeeds[1] = 100; | |
Db->LinkSpeeds[2] = 1000; | |
Db->LinkSpeeds[3] = 0; | |
Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER; | |
Db->HWaddrLen = PXE_HWADDR_LEN_ETHER; | |
Db->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT; | |
Db->TxBufCnt = Nic->PxeInit.TxBufCnt; | |
Db->TxBufSize = Nic->PxeInit.TxBufSize; | |
Db->RxBufCnt = Nic->PxeInit.RxBufCnt; | |
Db->RxBufSize = Nic->PxeInit.RxBufSize; | |
Db->IFtype = PXE_IFTYPE_ETHERNET; | |
Db->SupportedDuplexModes = PXE_DUPLEX_DEFAULT; | |
Db->SupportedLoopBackModes = LOOPBACK_NORMAL; | |
Cdb->StatFlags |= (PXE_STATFLAGS_CABLE_DETECT_SUPPORTED | | |
PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED); | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetInitInfo (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
This command is used to retrieve configuration information about | |
the NIC being controlled by the UNDI. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiGetConfigInfo ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
PXE_DB_GET_CONFIG_INFO *Db; | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_GET_CONFIG_INFO) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) || | |
(Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) || | |
(Cdb->DBsize != sizeof (PXE_DB_GET_CONFIG_INFO)) || | |
(Cdb->OpFlags != PXE_OPFLAGS_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_NOT_STARTED; | |
return; | |
} | |
Db = (PXE_DB_GET_CONFIG_INFO *)(UINTN)Cdb->DBaddr; | |
Db->pci.BusType = PXE_BUSTYPE_USB; | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetConfigInfo (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
This command resets the network adapter and initializes UNDI using | |
the parameters supplied in the CPB. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in, out] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiInitialize ( | |
IN PXE_CDB *Cdb, | |
IN OUT NIC_DATA *Nic | |
) | |
{ | |
PXE_CPB_INITIALIZE *Cpb; | |
PXE_DB_INITIALIZE *Db; | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_INITIALIZE) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != sizeof (PXE_CPB_INITIALIZE))) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
} | |
if (Nic->State == PXE_STATFLAGS_GET_STATE_STOPPED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_NOT_STARTED; | |
return; | |
} | |
if ((Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) && | |
(Cdb->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} | |
if (Nic->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_ALREADY_INITIALIZED; | |
return; | |
} | |
Cpb = (PXE_CPB_INITIALIZE *)(UINTN)Cdb->CPBaddr; | |
Db = (PXE_DB_INITIALIZE *)(UINTN)Cdb->DBaddr; | |
Nic->PxeInit.LinkSpeed = Cpb->LinkSpeed; | |
Nic->PxeInit.DuplexMode = Cpb->DuplexMode; | |
Nic->PxeInit.LoopBackMode = Cpb->LoopBackMode; | |
Nic->PxeInit.MemoryAddr = Cpb->MemoryAddr; | |
Nic->PxeInit.MemoryLength = Cpb->MemoryLength; | |
Nic->PxeInit.TxBufCnt = TX_BUFFER_COUNT; | |
Nic->PxeInit.TxBufSize = Nic->MaxSegmentSize; | |
Nic->PxeInit.RxBufCnt = RX_BUFFER_COUNT; | |
Nic->PxeInit.RxBufSize = Nic->MaxSegmentSize; | |
Cdb->StatCode = Initialize (Cdb, Nic); | |
Db->MemoryUsed = MEMORY_REQUIRE; | |
Db->TxBufCnt = Nic->PxeInit.TxBufCnt; | |
Db->TxBufSize = Nic->PxeInit.TxBufSize; | |
Db->RxBufCnt = Nic->PxeInit.RxBufCnt; | |
Db->RxBufSize = Nic->PxeInit.RxBufSize; | |
Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST; | |
Nic->CanTransmit = FALSE; | |
if (Cdb->OpFlags == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) { | |
if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) { | |
Nic->CableDetect = 0; | |
} else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) { | |
Nic->CableDetect = 1; | |
} | |
if (Nic->CableDetect == 0) { | |
Cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA; | |
} | |
} | |
if (Cdb->StatCode != PXE_STATCODE_SUCCESS) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} else { | |
Nic->State = PXE_STATFLAGS_GET_STATE_INITIALIZED; | |
} | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInitialize (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
Initialize Network interface controller data. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in, out] Nic A pointer to the Network interface controller data. | |
@retval Status A value of Pxe statcode. | |
**/ | |
UINT16 | |
Initialize ( | |
IN PXE_CDB *Cdb, | |
IN OUT NIC_DATA *Nic | |
) | |
{ | |
UINTN Status; | |
UINT32 Index; | |
EFI_STATUS EfiStatus; | |
Status = MapIt ( | |
Nic, | |
Nic->PxeInit.MemoryAddr, | |
Nic->PxeInit.MemoryLength, | |
TO_AND_FROM_DEVICE, | |
(UINT64)(UINTN)&Nic->MappedAddr | |
); | |
if (Status != 0) { | |
return (UINT16)Status; | |
} | |
for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { | |
Nic->PermNodeAddress[Index] = Nic->MacAddr.Addr[Index]; | |
} | |
for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { | |
Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index]; | |
} | |
for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { | |
Nic->BroadcastNodeAddress[Index] = 0xFF; | |
} | |
for (Index = PXE_HWADDR_LEN_ETHER; Index < PXE_MAC_LENGTH; Index++) { | |
Nic->CurrentNodeAddress[Index] = 0; | |
Nic->PermNodeAddress[Index] = 0; | |
Nic->BroadcastNodeAddress[Index] = 0; | |
} | |
if (Nic->UsbEth->UsbEthInitialize != NULL) { | |
EfiStatus = Nic->UsbEth->UsbEthInitialize (Cdb, Nic); | |
if (EFI_ERROR (EfiStatus)) { | |
return PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
return (UINT16)Status; | |
} | |
/** | |
This command resets the network adapter and reinitializes the UNDI | |
with the same parameters provided in the Initialize command. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiReset ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_RESET) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) || | |
(Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) || | |
(Cdb->DBsize != PXE_DBSIZE_NOT_USED) || | |
(Cdb->DBaddr != PXE_DBADDR_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
return; | |
} | |
if ((Cdb->OpFlags != PXE_OPFLAGS_NOT_USED) && | |
(Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) && | |
(Cdb->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} | |
if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_FILTERS) == 0) { | |
Nic->RxFilter = PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST; | |
} | |
if ((Cdb->OpFlags & PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS) != 0) { | |
Nic->InterrupOpFlag = 0; | |
} | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReset != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReset (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
The Shutdown command resets the network adapter and leaves it in a | |
safe state for another driver to initialize. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in, out] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiShutdown ( | |
IN PXE_CDB *Cdb, | |
IN OUT NIC_DATA *Nic | |
) | |
{ | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_SHUTDOWN) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) || | |
(Cdb->CPBaddr != PXE_CPBADDR_NOT_USED) || | |
(Cdb->DBsize != PXE_DBSIZE_NOT_USED) || | |
(Cdb->DBaddr != PXE_DBADDR_NOT_USED) || | |
(Cdb->OpFlags != PXE_OPFLAGS_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
return; | |
} | |
Nic->CanTransmit = FALSE; | |
Nic->State = PXE_STATFLAGS_GET_STATE_STARTED; | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiShutdown (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
The Interrupt Enables command can be used to read and/or change | |
the current external interrupt enable settings. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiInterruptEnable ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
EFI_STATUS Status; | |
Cdb->StatCode = PXE_STATCODE_UNSUPPORTED; | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiInterruptEnable (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
} | |
} | |
/** | |
This command is used to read and change receive filters and, | |
if supported, read and change the multicast MAC address filter list. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiReceiveFilter ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
UINT16 NewFilter; | |
PXE_DB_RECEIVE_FILTERS *Db; | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_RECEIVE_FILTERS) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8))) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
return; | |
} | |
NewFilter = (UINT16)(Cdb->OpFlags & 0x1F); | |
switch (Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) { | |
case PXE_OPFLAGS_RECEIVE_FILTER_READ: | |
if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
} | |
if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) { | |
if ((Cdb->DBsize != 0)) { | |
Db = (PXE_DB_RECEIVE_FILTERS *)(UINTN)Cdb->DBaddr; | |
CopyMem (Db, &Nic->McastList, Nic->McastCount); | |
} | |
} | |
break; | |
case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE: | |
if (NewFilter == 0) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
if (Cdb->CPBsize != 0) { | |
if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) || | |
((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) || | |
((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) || | |
((Cdb->CPBsize % sizeof (PXE_MAC_ADDR)) != 0)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
if ((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) { | |
if (((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) || | |
((Cdb->OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
if ((Cdb->CPBsize == 0)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
Cdb->StatCode = SetFilter (Nic, NewFilter, Cdb->CPBaddr, Cdb->CPBsize); | |
break; | |
case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE: | |
if (Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
} | |
break; | |
default: | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
} | |
Cdb->StatFlags = (PXE_STATFLAGS)(Cdb->StatFlags | Nic->RxFilter); | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceiveFilter (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
Set PXE receive filter. | |
@param[in] Nic A pointer to the Network interface controller data. | |
@param[in] SetFilter PXE receive filter | |
@param[in] CpbAddr Command Parameter Block Address | |
@param[in] CpbSize Command Parameter Block Size | |
**/ | |
UINT16 | |
SetFilter ( | |
IN NIC_DATA *Nic, | |
IN UINT16 SetFilter, | |
IN UINT64 CpbAddr, | |
IN UINT32 CpbSize | |
) | |
{ | |
EFI_STATUS Status; | |
UINT8 *McastList; | |
UINT8 Count; | |
UINT8 Index1; | |
UINT8 Index2; | |
PXE_CPB_RECEIVE_FILTERS *Cpb; | |
USB_ETHERNET_FUN_DESCRIPTOR UsbEthFunDescriptor; | |
Count = 0; | |
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); | |
} | |
Nic->UsbEth->UsbEthFunDescriptor (Nic->UsbEth, &UsbEthFunDescriptor); | |
if ((UsbEthFunDescriptor.NumberMcFilters & MAC_FILTERS_MASK) == 0) { | |
Nic->RxFilter |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST; | |
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 PXE_STATCODE_SUCCESS; | |
} | |
/** | |
This command is used to get current station and broadcast MAC addresses | |
and, if supported, to change the current station MAC address. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiStationAddress ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
PXE_CPB_STATION_ADDRESS *Cpb; | |
PXE_DB_STATION_ADDRESS *Db; | |
UINT16 Index; | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_STATION_ADDRESS) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->DBsize != sizeof (PXE_DB_STATION_ADDRESS))) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
return; | |
} | |
if (Cdb->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) { | |
if (CompareMem (&Nic->CurrentNodeAddress[0], &Nic->PermNodeAddress[0], PXE_MAC_LENGTH) != 0) { | |
for (Index = 0; Index < PXE_MAC_LENGTH; Index++) { | |
Nic->CurrentNodeAddress[Index] = Nic->PermNodeAddress[Index]; | |
} | |
} | |
} | |
if (Cdb->CPBaddr != 0) { | |
Cpb = (PXE_CPB_STATION_ADDRESS *)(UINTN)Cdb->CPBaddr; | |
for (Index = 0; Index < PXE_MAC_LENGTH; Index++) { | |
Nic->CurrentNodeAddress[Index] = Cpb->StationAddr[Index]; | |
} | |
} | |
if (Cdb->DBaddr != 0) { | |
Db = (PXE_DB_STATION_ADDRESS *)(UINTN)Cdb->DBaddr; | |
for (Index = 0; Index < PXE_MAC_LENGTH; Index++) { | |
Db->StationAddr[Index] = Nic->CurrentNodeAddress[Index]; | |
Db->BroadcastAddr[Index] = Nic->BroadcastNodeAddress[Index]; | |
Db->PermanentAddr[Index] = Nic->PermNodeAddress[Index]; | |
} | |
} | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStationAddress (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
This command is used to read and clear the NIC traffic statistics. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiStatistics ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_STATISTICS) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) || | |
(Cdb->CPBaddr != PXE_CPBADDR_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
return; | |
} | |
if ((Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_RESET) && | |
(Cdb->OpFlags != PXE_OPFLAGS_STATISTICS_READ)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} | |
Cdb->StatCode = Statistics (Nic, Cdb->DBaddr, Cdb->DBsize); | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiStatistics (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
Return data for DB data. | |
@param[in] Nic A pointer to the Network interface controller data. | |
@param[in] DbAddr Data Block Address. | |
@param[in] DbSize Data Block Size. | |
**/ | |
UINT16 | |
Statistics ( | |
IN NIC_DATA *Nic, | |
IN UINT64 DbAddr, | |
IN UINT16 DbSize | |
) | |
{ | |
PXE_DB_STATISTICS *DbStatistic; | |
EFI_STATUS Status; | |
DbStatistic = (PXE_DB_STATISTICS *)(UINTN)DbAddr; | |
if (DbSize == 0) { | |
return PXE_STATCODE_SUCCESS; | |
} | |
DbStatistic->Supported = 0x802; | |
DbStatistic->Data[0x01] = Nic->RxFrame; | |
DbStatistic->Data[0x0B] = Nic->TxFrame; | |
if (Nic->UsbEth->UsbEthStatistics != NULL) { | |
Status = Nic->UsbEth->UsbEthStatistics (Nic, DbAddr, DbSize); | |
if (EFI_ERROR (Status)) { | |
return PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
return PXE_STATCODE_SUCCESS; | |
} | |
/** | |
Translate a multicast IPv4 or IPv6 address to a multicast MAC address. | |
@param[in, out] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiMcastIp2Mac ( | |
IN OUT PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
PXE_CPB_MCAST_IP_TO_MAC *Cpb; | |
PXE_DB_MCAST_IP_TO_MAC *Db; | |
UINT8 *Tmp; | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_MCAST_IP_TO_MAC) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != sizeof (PXE_CPB_MCAST_IP_TO_MAC)) || | |
(Cdb->DBsize != sizeof (PXE_DB_MCAST_IP_TO_MAC))) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
return; | |
} | |
Cpb = (PXE_CPB_MCAST_IP_TO_MAC *)(UINTN)Cdb->CPBaddr; | |
Db = (PXE_DB_MCAST_IP_TO_MAC *)(UINTN)Cdb->DBaddr; | |
if ((Cdb->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_UNSUPPORTED; | |
return; | |
} | |
Tmp = (UINT8 *)(&Cpb->IP.IPv4); | |
if ((Tmp[0] & 0xF0) != 0xE0) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CPB; | |
} | |
Db->MAC[0] = 0x01; | |
Db->MAC[1] = 0x00; | |
Db->MAC[2] = 0x5E; | |
Db->MAC[3] = Tmp[1] & 0x7F; | |
Db->MAC[4] = Tmp[2]; | |
Db->MAC[5] = Tmp[3]; | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiMcastIp2Mac (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
This command is used to read and write (if supported by NIC H/W) | |
nonvolatile storage on the NIC. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiNvData ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
EFI_STATUS Status; | |
Cdb->StatCode = PXE_STATCODE_UNSUPPORTED; | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiNvData (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
} | |
} | |
/** | |
This command returns the current interrupt status and/or the | |
transmitted buffer addresses and the current media status. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiGetStatus ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
PXE_DB_GET_STATUS *Db; | |
PXE_DB_GET_STATUS TmpGetStatus; | |
UINT16 NumEntries; | |
UINTN Index; | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_GET_STATUS) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != PXE_CPBSIZE_NOT_USED) || | |
(Cdb->CPBaddr != PXE_CPBADDR_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
return; | |
} | |
TmpGetStatus.RxFrameLen = 0; | |
TmpGetStatus.reserved = 0; | |
Db = (PXE_DB_GET_STATUS *)(UINTN)Cdb->DBaddr; | |
if ((Cdb->DBsize > 0) && (Cdb->DBsize < sizeof (UINT32) * 2)) { | |
CopyMem (Db, &TmpGetStatus, Cdb->DBsize); | |
} else { | |
CopyMem (Db, &TmpGetStatus, sizeof (UINT32) * 2); | |
} | |
if ((Cdb->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) { | |
if (Cdb->DBsize == 0) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} | |
NumEntries = Cdb->DBsize - sizeof (UINT64); | |
Cdb->DBsize = sizeof (UINT32) * 2; | |
for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) { | |
if (Nic->TxBufferCount > 0) { | |
Nic->TxBufferCount--; | |
Db->TxBuffer[Index] = Nic->MediaHeader[Nic->TxBufferCount]; | |
} | |
} | |
} | |
if ((Cdb->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) { | |
if (Nic->ReceiveStatus != 0) { | |
Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE; | |
} | |
} | |
if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_DISCONNECT)) { | |
Nic->CableDetect = 0; | |
} else if ((Nic->Request.Request == USB_CDC_NETWORK_CONNECTION) && (Nic->Request.Value == NETWORK_CONNECTED)) { | |
Nic->CableDetect = 1; | |
} | |
if ((Cdb->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) { | |
if (Nic->CableDetect == 0) { | |
Cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA; | |
} | |
} | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiGetStatus (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
This command is used to fill the media header(s) in transmit packet(s). | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiFillHeader ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
PXE_CPB_FILL_HEADER *CpbFillHeader; | |
PXE_CPB_FILL_HEADER_FRAGMENTED *CpbFill; | |
ETHERNET_HEADER *MacHeader; | |
UINTN Index; | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_FILL_HEADER) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED)) || | |
(Cdb->DBsize != PXE_DBSIZE_NOT_USED) || | |
(Cdb->DBaddr != PXE_DBADDR_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
return; | |
} | |
if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} | |
if ((Cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) { | |
CpbFill = (PXE_CPB_FILL_HEADER_FRAGMENTED *)(UINTN)Cdb->CPBaddr; | |
if ((CpbFill->FragCnt == 0) || (CpbFill->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} | |
MacHeader = (ETHERNET_HEADER *)(UINTN)CpbFill->FragDesc[0].FragAddr; | |
MacHeader->Protocol = CpbFill->Protocol; | |
for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { | |
MacHeader->DestAddr[Index] = CpbFill->DestAddr[Index]; | |
MacHeader->SrcAddr[Index] = CpbFill->SrcAddr[Index]; | |
} | |
} else { | |
CpbFillHeader = (PXE_CPB_FILL_HEADER *)(UINTN)Cdb->CPBaddr; | |
MacHeader = (ETHERNET_HEADER *)(UINTN)CpbFillHeader->MediaHeader; | |
MacHeader->Protocol = CpbFillHeader->Protocol; | |
for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { | |
MacHeader->DestAddr[Index] = CpbFillHeader->DestAddr[Index]; | |
MacHeader->SrcAddr[Index] = CpbFillHeader->SrcAddr[Index]; | |
} | |
} | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiFillHeader (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
} | |
/** | |
The Transmit command is used to place a packet into the transmit queue. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiTransmit ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_TRANSMIT) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != sizeof (PXE_CPB_TRANSMIT)) || | |
(Cdb->DBsize != PXE_DBSIZE_NOT_USED) || | |
(Cdb->DBaddr != PXE_DBADDR_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
return; | |
} | |
if (Cdb->CPBsize == PXE_CPBSIZE_NOT_USED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiTransmit (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
return; | |
} | |
Cdb->StatCode = Transmit (Cdb, Nic, Cdb->CPBaddr, Cdb->OpFlags); | |
if (Cdb->StatCode != PXE_STATCODE_SUCCESS) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
/** | |
Use USB Ethernet Protocol Bulk out command to transmit data. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in, out] Nic A pointer to the Network interface controller data. | |
@param[in] CpbAddr Command Parameter Block Address. | |
@param[in] OpFlags Operation Flags. | |
**/ | |
UINT16 | |
Transmit ( | |
IN PXE_CDB *Cdb, | |
IN OUT NIC_DATA *Nic, | |
IN UINT64 CpbAddr, | |
IN UINT16 OpFlags | |
) | |
{ | |
EFI_STATUS Status; | |
PXE_CPB_TRANSMIT *Cpb; | |
UINT64 BulkOutData; | |
UINTN DataLength; | |
UINTN TransmitLength; | |
UINTN Map; | |
UINT32 Counter; | |
UINT16 StatCode; | |
BulkOutData = 0; | |
Counter = 0; | |
Cpb = (PXE_CPB_TRANSMIT *)(UINTN)CpbAddr; | |
if (Nic->CanTransmit) { | |
return PXE_STATCODE_BUSY; | |
} | |
Nic->CanTransmit = TRUE; | |
if ((OpFlags & PXE_OPFLAGS_TRANSMIT_FRAGMENTED) != 0) { | |
return PXE_STATCODE_INVALID_PARAMETER; | |
} | |
Map = MapIt ( | |
Nic, | |
Cpb->FrameAddr, | |
Cpb->DataLen + (UINT32)Cpb->MediaheaderLen, | |
TO_DEVICE, | |
(UINT64)(UINTN)&BulkOutData | |
); | |
if (Map != 0) { | |
Nic->CanTransmit = FALSE; | |
return PXE_STATCODE_INVALID_PARAMETER; | |
} | |
if (Nic->TxBufferCount < MAX_XMIT_BUFFERS) { | |
Nic->MediaHeader[Nic->TxBufferCount] = Cpb->FrameAddr; | |
Nic->TxBufferCount++; | |
} | |
DataLength = (UINTN)(Cpb->DataLen + (UINT32)Cpb->MediaheaderLen); | |
while (1) { | |
if (Counter >= 3) { | |
StatCode = PXE_STATCODE_BUSY; | |
break; | |
} | |
TransmitLength = DataLength; | |
Status = Nic->UsbEth->UsbEthTransmit (Cdb, Nic->UsbEth, (VOID *)(UINTN)BulkOutData, &TransmitLength); | |
if (EFI_ERROR (Status)) { | |
StatCode = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
if (Status == EFI_INVALID_PARAMETER) { | |
StatCode = PXE_STATCODE_INVALID_PARAMETER; | |
break; | |
} | |
if (Status == EFI_DEVICE_ERROR) { | |
StatCode = PXE_STATCODE_DEVICE_FAILURE; | |
break; | |
} | |
if (!EFI_ERROR (Status)) { | |
Nic->TxFrame++; | |
StatCode = PXE_STATCODE_SUCCESS; | |
break; | |
} | |
Counter++; | |
} | |
UnMapIt ( | |
Nic, | |
Cpb->FrameAddr, | |
Cpb->DataLen + (UINT32)Cpb->MediaheaderLen, | |
TO_DEVICE, | |
BulkOutData | |
); | |
Nic->CanTransmit = FALSE; | |
return StatCode; | |
} | |
/** | |
When the network adapter has received a frame, this command is used | |
to copy the frame into driver/application storage. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in] Nic A pointer to the Network interface controller data. | |
**/ | |
VOID | |
UndiReceive ( | |
IN PXE_CDB *Cdb, | |
IN NIC_DATA *Nic | |
) | |
{ | |
EFI_STATUS Status; | |
if ((Cdb->OpCode != PXE_OPCODE_RECEIVE) || | |
(Cdb->StatCode != PXE_STATCODE_INITIALIZE) || | |
(Cdb->StatFlags != PXE_STATFLAGS_INITIALIZE) || | |
(Cdb->IFnum >= (gPxe->IFcnt | gPxe->IFcntExt << 8)) || | |
(Cdb->CPBsize != sizeof (PXE_CPB_RECEIVE)) || | |
(Cdb->DBsize != sizeof (PXE_DB_RECEIVE)) || | |
(Cdb->OpFlags != PXE_OPFLAGS_NOT_USED)) | |
{ | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_INVALID_CDB; | |
return; | |
} else { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE; | |
Cdb->StatCode = PXE_STATCODE_SUCCESS; | |
} | |
if (Nic->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
Cdb->StatCode = PXE_STATCODE_NOT_INITIALIZED; | |
return; | |
} | |
if (Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive != NULL) { | |
Status = Nic->UsbEth->UsbEthUndi.UsbEthUndiReceive (Cdb, Nic); | |
if (EFI_ERROR (Status)) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
return; | |
} | |
Cdb->StatCode = Receive (Cdb, Nic, Cdb->CPBaddr, Cdb->DBaddr); | |
if (Cdb->StatCode != PXE_STATCODE_SUCCESS) { | |
Cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; | |
} | |
} | |
/** | |
Use USB Ethernet Protocol Bulk in command to receive data. | |
@param[in] Cdb A pointer to the command descriptor block. | |
@param[in, out] Nic A pointer to the Network interface controller data. | |
@param[in] CpbAddr Command Parameter Block Address. | |
@param[in, out] DbAddr Data Block Address. | |
**/ | |
UINT16 | |
Receive ( | |
IN PXE_CDB *Cdb, | |
IN OUT NIC_DATA *Nic, | |
IN UINT64 CpbAddr, | |
IN OUT UINT64 DbAddr | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Index; | |
PXE_FRAME_TYPE FrameType; | |
PXE_CPB_RECEIVE *Cpb; | |
PXE_DB_RECEIVE *Db; | |
NIC_DEVICE *NicDevice; | |
UINT8 *BulkInData; | |
UINTN DataLength; | |
ETHERNET_HEADER *Header; | |
EFI_TPL OriginalTpl; | |
FrameType = PXE_FRAME_TYPE_NONE; | |
NicDevice = UNDI_DEV_FROM_NIC (Nic); | |
BulkInData = NicDevice->ReceiveBuffer; | |
DataLength = (UINTN)Nic->MaxSegmentSize; | |
Cpb = (PXE_CPB_RECEIVE *)(UINTN)CpbAddr; | |
Db = (PXE_DB_RECEIVE *)(UINTN)DbAddr; | |
if (!BulkInData) { | |
return PXE_STATCODE_INVALID_PARAMETER; | |
} | |
if ((Nic->RateLimitingCreditCount == 0) && (Nic->RateLimitingEnable == TRUE)) { | |
return PXE_STATCODE_NO_DATA; | |
} | |
Status = Nic->UsbEth->UsbEthReceive (Cdb, Nic->UsbEth, (VOID *)BulkInData, &DataLength); | |
if (EFI_ERROR (Status)) { | |
Nic->ReceiveStatus = 0; | |
if (Nic->RateLimitingEnable == TRUE) { | |
OriginalTpl = gBS->RaiseTPL (TPL_NOTIFY); | |
if (Nic->RateLimitingCreditCount != 0) { | |
Nic->RateLimitingCreditCount--; | |
} | |
gBS->RestoreTPL (OriginalTpl); | |
} | |
return PXE_STATCODE_NO_DATA; | |
} | |
Nic->RxFrame++; | |
if (DataLength != 0) { | |
if (DataLength > Cpb->BufferLen) { | |
DataLength = (UINTN)Cpb->BufferLen; | |
} | |
CopyMem ((UINT8 *)(UINTN)Cpb->BufferAddr, (UINT8 *)BulkInData, DataLength); | |
Header = (ETHERNET_HEADER *)BulkInData; | |
Db->FrameLen = (UINT32)DataLength; | |
Db->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER; | |
for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { | |
if (Header->DestAddr[Index] != Nic->CurrentNodeAddress[Index]) { | |
break; | |
} | |
} | |
if (Index >= PXE_HWADDR_LEN_ETHER) { | |
FrameType = PXE_FRAME_TYPE_UNICAST; | |
} else { | |
for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { | |
if (Header->DestAddr[Index] != Nic->BroadcastNodeAddress[Index]) { | |
break; | |
} | |
} | |
if (Index >= PXE_HWADDR_LEN_ETHER) { | |
FrameType = PXE_FRAME_TYPE_BROADCAST; | |
} else { | |
if ((Header->DestAddr[0] & 1) == 1) { | |
FrameType = PXE_FRAME_TYPE_FILTERED_MULTICAST; | |
} else { | |
FrameType = PXE_FRAME_TYPE_PROMISCUOUS; | |
} | |
} | |
} | |
Db->Type = FrameType; | |
Db->Protocol = Header->Protocol; | |
for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) { | |
Db->SrcAddr[Index] = Header->SrcAddr[Index]; | |
Db->DestAddr[Index] = Header->DestAddr[Index]; | |
} | |
} | |
if (FrameType == PXE_FRAME_TYPE_NONE) { | |
Nic->ReceiveStatus = 0; | |
} else { | |
Nic->ReceiveStatus = 1; | |
} | |
return PXE_STATCODE_SUCCESS; | |
} | |
/** | |
Fill out PXE SW UNDI structure. | |
@param[out] PxeSw A pointer to the PXE SW UNDI structure. | |
**/ | |
VOID | |
PxeStructInit ( | |
OUT PXE_SW_UNDI *PxeSw | |
) | |
{ | |
PxeSw->Signature = PXE_ROMID_SIGNATURE; | |
PxeSw->Len = (UINT8)sizeof (PXE_SW_UNDI); | |
PxeSw->Fudge = 0; | |
PxeSw->IFcnt = 0; | |
PxeSw->IFcntExt = 0; | |
PxeSw->Rev = PXE_ROMID_REV; | |
PxeSw->MajorVer = PXE_ROMID_MAJORVER; | |
PxeSw->MinorVer = PXE_ROMID_MINORVER; | |
PxeSw->reserved1 = 0; | |
PxeSw->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR | | |
PXE_ROMID_IMP_FRAG_SUPPORTED | | |
PXE_ROMID_IMP_CMD_LINK_SUPPORTED | | |
PXE_ROMID_IMP_STATION_ADDR_SETTABLE | | |
PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED | | |
PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED | | |
PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED | | |
PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED; | |
PxeSw->EntryPoint = (UINT64)(UINTN)UndiApiEntry; | |
PxeSw->reserved2[0] = 0; | |
PxeSw->reserved2[1] = 0; | |
PxeSw->reserved2[2] = 0; | |
PxeSw->BusCnt = 1; | |
PxeSw->BusType[0] = PXE_BUSTYPE_USB; | |
PxeSw->Fudge = PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len); | |
} | |
/** | |
Update NIC number. | |
@param[in] Nic A pointer to the Network interface controller data. | |
@param[in, out] PxeSw A pointer to the PXE SW UNDI structure. | |
**/ | |
VOID | |
UpdateNicNum ( | |
IN NIC_DATA *Nic, | |
IN OUT PXE_SW_UNDI *PxeSw | |
) | |
{ | |
UINT16 NicNum; | |
NicNum = (PxeSw->IFcnt | PxeSw->IFcntExt << 8); | |
if (Nic == NULL) { | |
if (NicNum > 0) { | |
NicNum--; | |
} | |
PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte | |
PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte | |
PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len)); | |
return; | |
} | |
NicNum++; | |
PxeSw->IFcnt = (UINT8)(NicNum & 0xFF); // Get lower byte | |
PxeSw->IFcntExt = (UINT8)((NicNum & 0xFF00) >> 8); // Get upper byte | |
PxeSw->Fudge = (UINT8)(PxeSw->Fudge - CalculateSum8 ((VOID *)PxeSw, PxeSw->Len)); | |
} | |
/** | |
UNDI API table entry. | |
@param[in] Cdb A pointer to the command descriptor block. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
UndiApiEntry ( | |
IN UINT64 Cdb | |
) | |
{ | |
PXE_CDB *CdbPtr; | |
NIC_DATA *Nic; | |
if (Cdb == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
CdbPtr = (PXE_CDB *)(UINTN)Cdb; | |
Nic = &(gLanDeviceList[CdbPtr->IFnum]->NicInfo); | |
gUndiApiTable[CdbPtr->OpCode](CdbPtr, Nic); | |
return EFI_SUCCESS; | |
} | |
/** | |
Map virtual memory address for DMA. This field can be set to | |
zero if there is no mapping service. | |
@param[in] Nic A pointer to the Network interface controller data. | |
@param[in] MemAddr Virtual address to be mapped. | |
@param[in] Size Size of memory to be mapped. | |
@param[in] Direction Direction of data flow for this memory's usage: | |
cpu->device, device->cpu or both ways. | |
@param[out] MappedAddr Pointer to return the mapped device address. | |
**/ | |
UINTN | |
MapIt ( | |
IN NIC_DATA *Nic, | |
IN UINT64 MemAddr, | |
IN UINT32 Size, | |
IN UINT32 Direction, | |
OUT UINT64 MappedAddr | |
) | |
{ | |
UINT64 *PhyAddr; | |
PhyAddr = (UINT64 *)(UINTN)MappedAddr; | |
if (Nic->PxeStart.Map_Mem == 0) { | |
*PhyAddr = MemAddr; | |
} else { | |
((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.Map_Mem)( | |
Nic->PxeStart.Unique_ID, | |
MemAddr, | |
Size, | |
Direction, | |
MappedAddr | |
); | |
} | |
return PXE_STATCODE_SUCCESS; | |
} | |
/** | |
Un-map previously mapped virtual memory address. This field can be set | |
to zero only if the Map_Mem() service is also set to zero. | |
@param[in] Nic A pointer to the Network interface controller data. | |
@param[in] MemAddr Virtual address to be mapped. | |
@param[in] Size Size of memory to be mapped. | |
@param[in] Direction Direction of data flow for this memory's usage: | |
cpu->device, device->cpu or both ways. | |
@param[in] MappedAddr Pointer to return the mapped device address. | |
**/ | |
VOID | |
UnMapIt ( | |
IN NIC_DATA *Nic, | |
IN UINT64 MemAddr, | |
IN UINT32 Size, | |
IN UINT32 Direction, | |
IN UINT64 MappedAddr | |
) | |
{ | |
if (Nic->PxeStart.UnMap_Mem != 0) { | |
((void (*)(UINT64, UINT64, UINT32, UINT32, UINT64))(UINTN) Nic->PxeStart.UnMap_Mem)( | |
Nic->PxeStart.Unique_ID, | |
MemAddr, | |
Size, | |
Direction, | |
MappedAddr | |
); | |
} | |
return; | |
} |