/** @file
Copyright (c) 1999 - 2012, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
of the BSD License which accompanies this distribution. The
full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "BiosSnp16.h"
///
/// EFI Driver Binding Protocol Instance
///
EFI_DRIVER_BINDING_PROTOCOL gBiosSnp16DriverBinding = {
BiosSnp16DriverBindingSupported,
BiosSnp16DriverBindingStart,
BiosSnp16DriverBindingStop,
0x3,
NULL,
NULL
};
///
/// This boolean is used to determine if we should release the cached vector during an error condition.
///
BOOLEAN mCachedInt1A = FALSE;
//
// Private worker functions;
//
/**
Start the UNDI interface.
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@param Ax PCI address of Undi device.
@retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM.
@retval Others Status of start 16 bit UNDI ROM.
**/
EFI_STATUS
Undi16SimpleNetworkStartUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
UINT16 Ax
);
/**
Start the UNDI interface
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM.
@retval Others Status of start 16 bit UNDI ROM.
**/
EFI_STATUS
Undi16SimpleNetworkStopUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
);
/**
Stop the UNDI interface
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@retval EFI_DEVICE_ERROR Fail to stop 16 bit UNDI ROM.
@retval Others Status of stop 16 bit UNDI ROM.
**/
EFI_STATUS
Undi16SimpleNetworkCleanupUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
);
/**
Get runtime information for Undi network interface
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_SUCCESS Sucess operation.
@retval Others Fail to get runtime information for Undi network interface.
**/
EFI_STATUS
Undi16SimpleNetworkGetInformation (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
);
/**
Get NIC type
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_SUCCESS Sucess operation.
@retval Others Fail to get NIC type.
**/
EFI_STATUS
Undi16SimpleNetworkGetNicType (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
);
/**
Get NDIS information
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_SUCCESS Sucess operation.
@retval Others Fail to get NDIS information.
**/
EFI_STATUS
Undi16SimpleNetworkGetNdisInfo (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
);
/**
Signal handlers for ExitBootServices event.
Clean up any Real-mode UNDI residue from the system
@param Event ExitBootServices event
@param Context
**/
VOID
EFIAPI
Undi16SimpleNetworkEvent (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
Loads the undi driver.
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@retval EFI_SUCCESS - Successfully loads undi driver.
@retval EFI_NOT_FOUND - Doesn't find undi driver or undi driver load failure.
**/
EFI_STATUS
Undi16SimpleNetworkLoadUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
);
/**
Unload 16 bit UNDI Option ROM from memory
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@return EFI_STATUS
**/
EFI_STATUS
Undi16SimpleNetworkUnloadUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
);
/**
Entry point for EFI drivers.
@param ImageHandle Handle that identifies the loaded image.
@param SystemTable System Table for this image.
@return EFI_STATUS Return status from EfiLibInstallAllDriverProtocols.
**/
EFI_STATUS
EFIAPI
BiosSnp16DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gBiosSnp16DriverBinding,
ImageHandle,
&gBiosSnp16ComponentName,
&gBiosSnp16ComponentName2
);
}
//
// EFI Driver Binding Protocol Functions
//
/**
Tests to see if this driver supports a given controller.
@param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param Controller The handle of the controller to test.
@param RemainingDevicePath A pointer to the remaining portion of a device path.
@retval EFI_SUCCESS The driver supports given controller.
@retval EFI_UNSUPPORT The driver doesn't support given controller.
@retval Other Other errors prevent driver finishing to test
if the driver supports given controller.
**/
EFI_STATUS
EFIAPI
BiosSnp16DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_PCI_IO_PROTOCOL *PciIo;
PCI_TYPE00 Pci;
//
// See if the Legacy BIOS Protocol is available
//
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open the IO Abstraction(s) needed to perform the supported test
//
Status = gBS->OpenProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **) &DevicePath,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
Controller
);
//
// Open the IO Abstraction(s) needed to perform the supported test
//
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// See if this is a PCI Network Controller by looking at the Command register and
// Class Code Register
//
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);
if (EFI_ERROR (Status)) {
Status = EFI_UNSUPPORTED;
goto Done;
}
Status = EFI_UNSUPPORTED;
if (Pci.Hdr.ClassCode[2] == PCI_CLASS_NETWORK) {
Status = EFI_SUCCESS;
}
Done:
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
/**
Starts the Snp device controller
@param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param Controller The handle of the controller to test.
@param RemainingDevicePath A pointer to the remaining portion of a device path.
@retval EFI_SUCCESS - The device was started.
@retval EFI_DEVICE_ERROR - The device could not be started due to a device error.
@retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
**/
EFI_STATUS
EFIAPI
BiosSnp16DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_PCI_IO_PROTOCOL *PciIo;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
EFI_DEV_PATH Node;
UINTN Index;
UINTN Index2;
UINTN Segment;
UINTN Bus;
UINTN Device;
UINTN Function;
UINTN Flags;
UINT64 Supports;
SimpleNetworkDevice = NULL;
PciIo = NULL;
//
// See if the Legacy BIOS Protocol is available
//
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open the IO Abstraction(s) needed
//
Status = gBS->OpenProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **) &DevicePath,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationSupported,
0,
&Supports
);
if (!EFI_ERROR (Status)) {
Supports &= EFI_PCI_DEVICE_ENABLE;
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationEnable,
Supports,
NULL
);
}
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Check to see if there is a legacy option ROM image associated with this PCI device
//
Status = LegacyBios->CheckPciRom (
LegacyBios,
Controller,
NULL,
NULL,
&Flags
);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Post the legacy option ROM if it is available.
//
Status = LegacyBios->InstallPciRom (
LegacyBios,
Controller,
NULL,
&Flags,
NULL,
NULL,
NULL,
NULL
);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Allocate memory for this SimpleNetwork device instance
//
Status = gBS->AllocatePool (
EfiBootServicesData,
sizeof (EFI_SIMPLE_NETWORK_DEV),
(VOID **) &SimpleNetworkDevice
);
if (EFI_ERROR (Status)) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
ZeroMem (SimpleNetworkDevice, sizeof (EFI_SIMPLE_NETWORK_DEV));
//
// Initialize the SimpleNetwork device instance
//
SimpleNetworkDevice->Signature = EFI_SIMPLE_NETWORK_DEV_SIGNATURE;
SimpleNetworkDevice->LegacyBios = LegacyBios;
SimpleNetworkDevice->BaseDevicePath = DevicePath;
SimpleNetworkDevice->PciIo = PciIo;
//
// Initialize the Nii Protocol
//
SimpleNetworkDevice->Nii.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
SimpleNetworkDevice->Nii.Type = EfiNetworkInterfaceUndi;
CopyMem (&SimpleNetworkDevice->Nii.StringId, "UNDI", 4);
//
// Load 16 bit UNDI Option ROM into Memory
//
Status = Undi16SimpleNetworkLoadUndi (SimpleNetworkDevice);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_NET, "ERROR : Could not load UNDI. Status = %r\n", Status));
goto Done;
}
SimpleNetworkDevice->UndiLoaded = TRUE;
//
// Call PXENV_START_UNDI - Initilizes the UNID interface for use.
//
PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
Status = Undi16SimpleNetworkStartUndi (
SimpleNetworkDevice,
(UINT16) ((Bus << 0x8) | (Device << 0x3) | (Function))
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_NET, "ERROR : Could not StartUndi. Status = %r\n", Status));
goto Done;
}
//
// Initialize the Simple Network Protocol
//
DEBUG ((DEBUG_NET, "Initialize SimpleNetworkDevice instance\n"));
SimpleNetworkDevice->SimpleNetwork.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
SimpleNetworkDevice->SimpleNetwork.Start = Undi16SimpleNetworkStart;
SimpleNetworkDevice->SimpleNetwork.Stop = Undi16SimpleNetworkStop;
SimpleNetworkDevice->SimpleNetwork.Initialize = Undi16SimpleNetworkInitialize;
SimpleNetworkDevice->SimpleNetwork.Reset = Undi16SimpleNetworkReset;
SimpleNetworkDevice->SimpleNetwork.Shutdown = Undi16SimpleNetworkShutdown;
SimpleNetworkDevice->SimpleNetwork.ReceiveFilters = Undi16SimpleNetworkReceiveFilters;
SimpleNetworkDevice->SimpleNetwork.StationAddress = Undi16SimpleNetworkStationAddress;
SimpleNetworkDevice->SimpleNetwork.Statistics = Undi16SimpleNetworkStatistics;
SimpleNetworkDevice->SimpleNetwork.MCastIpToMac = Undi16SimpleNetworkMCastIpToMac;
SimpleNetworkDevice->SimpleNetwork.NvData = Undi16SimpleNetworkNvData;
SimpleNetworkDevice->SimpleNetwork.GetStatus = Undi16SimpleNetworkGetStatus;
SimpleNetworkDevice->SimpleNetwork.Transmit = Undi16SimpleNetworkTransmit;
SimpleNetworkDevice->SimpleNetwork.Receive = Undi16SimpleNetworkReceive;
SimpleNetworkDevice->SimpleNetwork.Mode = &(SimpleNetworkDevice->SimpleNetworkMode);
Status = gBS->CreateEvent (
EVT_NOTIFY_WAIT,
TPL_NOTIFY,
Undi16SimpleNetworkWaitForPacket,
&SimpleNetworkDevice->SimpleNetwork,
&SimpleNetworkDevice->SimpleNetwork.WaitForPacket
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "ERROR : Could not create event. Status = %r\n", Status));
goto Done;
}
//
// Create an event to be signalled when ExitBootServices occurs in order
// to clean up nicely
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
Undi16SimpleNetworkEvent,
NULL,
&gEfiEventExitBootServicesGuid,
&SimpleNetworkDevice->EfiBootEvent
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "ERROR : Could not create event. Status = %r\n", Status));
goto Done;
}
//
// Create an event to be signalled when Legacy Boot occurs to clean up the IVT
//
Status = EfiCreateEventLegacyBootEx(
TPL_NOTIFY,
Undi16SimpleNetworkEvent,
NULL,
&SimpleNetworkDevice->LegacyBootEvent
);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_ERROR,"ERROR : Could not create event. Status = %r\n",Status));
goto Done;
}
//
// Initialize the SimpleNetwork Mode Information
//
DEBUG ((DEBUG_NET, "Initialize Mode Information\n"));
SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStopped;
SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize = 14;
SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable = TRUE;
SimpleNetworkDevice->SimpleNetworkMode.MultipleTxSupported = TRUE;
SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |
EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
SimpleNetworkDevice->SimpleNetworkMode.MaxMCastFilterCount = MAXNUM_MCADDR;
//
// Initialize the SimpleNetwork Private Information
//
DEBUG ((DEBUG_NET, "Initialize Private Information\n"));
Status = BiosSnp16AllocatePagesBelowOneMb (
sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1,
(VOID **) &SimpleNetworkDevice->Xmit
);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = BiosSnp16AllocatePagesBelowOneMb (
1,
&SimpleNetworkDevice->TxRealModeMediaHeader
);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = BiosSnp16AllocatePagesBelowOneMb (
1,
&SimpleNetworkDevice->TxRealModeDataBuffer
);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = BiosSnp16AllocatePagesBelowOneMb (
1,
&SimpleNetworkDevice->TxDestAddr
);
if (EFI_ERROR (Status)) {
goto Done;
}
SimpleNetworkDevice->Xmit->XmitOffset = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeMediaHeader) & 0x000f);
SimpleNetworkDevice->Xmit->XmitSegment = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeMediaHeader) >> 4);
SimpleNetworkDevice->Xmit->DataBlkCount = 1;
SimpleNetworkDevice->Xmit->DataBlock[0].TDPtrType = 1;
SimpleNetworkDevice->Xmit->DataBlock[0].TDRsvdByte = 0;
SimpleNetworkDevice->Xmit->DataBlock[0].TDDataPtrOffset = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeDataBuffer) & 0x000f);
SimpleNetworkDevice->Xmit->DataBlock[0].TDDataPtrSegment = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeDataBuffer) >> 4);
SimpleNetworkDevice->TxBufferFifo.First = 0;
SimpleNetworkDevice->TxBufferFifo.Last = 0;
//
// Start() the SimpleNetwork device
//
DEBUG ((DEBUG_NET, "Start()\n"));
Status = Undi16SimpleNetworkStart (&SimpleNetworkDevice->SimpleNetwork);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// GetInformation() the SimpleNetwork device
//
DEBUG ((DEBUG_NET, "GetInformation()\n"));
Status = Undi16SimpleNetworkGetInformation (&SimpleNetworkDevice->SimpleNetwork);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Build the device path for the child device
//
ZeroMem (&Node, sizeof (Node));
Node.DevPath.Type = MESSAGING_DEVICE_PATH;
Node.DevPath.SubType = MSG_MAC_ADDR_DP;
SetDevicePathNodeLength (&Node.DevPath, sizeof (MAC_ADDR_DEVICE_PATH));
CopyMem (
&Node.MacAddr.MacAddress,
&SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
sizeof (EFI_MAC_ADDRESS)
);
SimpleNetworkDevice->DevicePath = AppendDevicePathNode (
SimpleNetworkDevice->BaseDevicePath,
&Node.DevPath
);
//
// GetNicType() the SimpleNetwork device
//
DEBUG ((DEBUG_NET, "GetNicType()\n"));
Status = Undi16SimpleNetworkGetNicType (&SimpleNetworkDevice->SimpleNetwork);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// GetNdisInfo() the SimpleNetwork device
//
DEBUG ((DEBUG_NET, "GetNdisInfo()\n"));
Status = Undi16SimpleNetworkGetNdisInfo (&SimpleNetworkDevice->SimpleNetwork);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Stop() the SimpleNetwork device
//
DEBUG ((DEBUG_NET, "Stop()\n"));
Status = SimpleNetworkDevice->SimpleNetwork.Stop (&SimpleNetworkDevice->SimpleNetwork);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Print Mode information
//
DEBUG ((DEBUG_NET, "Mode->State = %d\n", SimpleNetworkDevice->SimpleNetworkMode.State));
DEBUG ((DEBUG_NET, "Mode->HwAddressSize = %d\n", SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize));
DEBUG ((DEBUG_NET, "Mode->MacAddressChangeable = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable));
DEBUG ((DEBUG_NET, "Mode->MultiplTxSupported = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MultipleTxSupported));
DEBUG ((DEBUG_NET, "Mode->NvRamSize = %d\n", SimpleNetworkDevice->SimpleNetworkMode.NvRamSize));
DEBUG ((DEBUG_NET, "Mode->NvRamAccessSize = %d\n", SimpleNetworkDevice->SimpleNetworkMode.NvRamAccessSize));
DEBUG ((DEBUG_NET, "Mode->ReceiveFilterSetting = %d\n", SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting));
DEBUG ((DEBUG_NET, "Mode->IfType = %d\n", SimpleNetworkDevice->SimpleNetworkMode.IfType));
DEBUG ((DEBUG_NET, "Mode->MCastFilterCount = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount));
for (Index = 0; Index < SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount; Index++) {
DEBUG ((DEBUG_NET, " Filter[%02d] = ", Index));
for (Index2 = 0; Index2 < 16; Index2++) {
DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index].Addr[Index2]));
}
DEBUG ((DEBUG_NET, "\n"));
}
DEBUG ((DEBUG_NET, "CurrentAddress = "));
for (Index2 = 0; Index2 < 16; Index2++) {
DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress.Addr[Index2]));
}
DEBUG ((DEBUG_NET, "\n"));
DEBUG ((DEBUG_NET, "BroadcastAddress = "));
for (Index2 = 0; Index2 < 16; Index2++) {
DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress.Addr[Index2]));
}
DEBUG ((DEBUG_NET, "\n"));
DEBUG ((DEBUG_NET, "PermanentAddress = "));
for (Index2 = 0; Index2 < 16; Index2++) {
DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress.Addr[Index2]));
}
DEBUG ((DEBUG_NET, "\n"));
//
// The network device was started, information collected, and stopped.
// Install protocol interfaces for the SimpleNetwork device.
//
DEBUG ((DEBUG_NET, "Install Protocol Interfaces on network interface\n"));
Status = gBS->InstallMultipleProtocolInterfaces (
&SimpleNetworkDevice->Handle,
&gEfiSimpleNetworkProtocolGuid,
&SimpleNetworkDevice->SimpleNetwork,
&gEfiNetworkInterfaceIdentifierProtocolGuid,
&SimpleNetworkDevice->Nii,
&gEfiDevicePathProtocolGuid,
SimpleNetworkDevice->DevicePath,
NULL
);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Open PCI I/O from the newly created child handle
//
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
SimpleNetworkDevice->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
DEBUG ((DEBUG_INIT, "UNDI16 Driver : EFI_SUCCESS\n"));
Done:
if (EFI_ERROR (Status)) {
if (SimpleNetworkDevice != NULL) {
Undi16SimpleNetworkShutdown (&SimpleNetworkDevice->SimpleNetwork);
//
// CLOSE + SHUTDOWN
//
Undi16SimpleNetworkCleanupUndi (SimpleNetworkDevice);
//
// CLEANUP
//
Undi16SimpleNetworkStopUndi (SimpleNetworkDevice);
//
// STOP
//
if (SimpleNetworkDevice->UndiLoaded) {
Undi16SimpleNetworkUnloadUndi (SimpleNetworkDevice);
}
if (SimpleNetworkDevice->SimpleNetwork.WaitForPacket != NULL) {
gBS->CloseEvent (SimpleNetworkDevice->SimpleNetwork.WaitForPacket);
}
if (SimpleNetworkDevice->LegacyBootEvent != NULL) {
gBS->CloseEvent (SimpleNetworkDevice->LegacyBootEvent);
}
if (SimpleNetworkDevice->EfiBootEvent != NULL) {
gBS->CloseEvent (SimpleNetworkDevice->EfiBootEvent);
}
if (SimpleNetworkDevice->Xmit != NULL) {
gBS->FreePages (
(EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->Xmit,
sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1
);
}
if (SimpleNetworkDevice->TxRealModeMediaHeader != NULL) {
gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeMediaHeader, 1);
}
if (SimpleNetworkDevice->TxRealModeDataBuffer != NULL) {
gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeDataBuffer, 1);
}
if (SimpleNetworkDevice->TxDestAddr != NULL) {
gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxDestAddr, 1);
}
gBS->FreePool (SimpleNetworkDevice);
//
// Only restore the vector if it was cached.
//
if (mCachedInt1A) {
RestoreCachedVectorAddress (0x1A);
mCachedInt1A = FALSE;
}
}
if (PciIo != NULL) {
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationSupported,
0,
&Supports
);
if (!EFI_ERROR (Status)) {
Supports &= EFI_PCI_DEVICE_ENABLE;
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationDisable,
Supports,
NULL
);
}
}
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
Controller
);
if (Status != EFI_OUT_OF_RESOURCES) {
Status = EFI_DEVICE_ERROR;
}
}
return Status;
}
/**
Stops the device by given device controller.
@param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
@param Controller The handle of the controller to test.
@param NumberOfChildren The number of child device handles in ChildHandleBuffer.
@param ChildHandleBuffer An array of child handles to be freed. May be NULL if
NumberOfChildren is 0.
@retval EFI_SUCCESS - The device was stopped.
@retval EFI_DEVICE_ERROR - The device could not be stopped due to a device error.
**/
EFI_STATUS
EFIAPI
BiosSnp16DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
UINTN Index;
BOOLEAN AllChildrenStopped;
EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT64 Supports;
//
// Complete all outstanding transactions to Controller.
// Don't allow any new transaction to Controller to be started.
//
if (NumberOfChildren == 0) {
//
// Close the bus driver
//
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationSupported,
0,
&Supports
);
if (!EFI_ERROR (Status)) {
Supports &= EFI_PCI_DEVICE_ENABLE;
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationDisable,
Supports,
NULL
);
}
}
Status = gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
Status = gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
Controller
);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
}
return Status;
}
AllChildrenStopped = TRUE;
for (Index = 0; Index < NumberOfChildren; Index++) {
Status = gBS->OpenProtocol (
ChildHandleBuffer[Index],
&gEfiSimpleNetworkProtocolGuid,
(VOID **) &SimpleNetwork,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SimpleNetwork);
Status = gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
ChildHandleBuffer[Index]
);
Status = gBS->UninstallMultipleProtocolInterfaces (
SimpleNetworkDevice->Handle,
&gEfiSimpleNetworkProtocolGuid,
&SimpleNetworkDevice->SimpleNetwork,
&gEfiNetworkInterfaceIdentifierProtocolGuid,
&SimpleNetworkDevice->Nii,
&gEfiDevicePathProtocolGuid,
SimpleNetworkDevice->DevicePath,
NULL
);
if (EFI_ERROR (Status)) {
gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
ChildHandleBuffer[Index],
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
} else {
Undi16SimpleNetworkShutdown (&SimpleNetworkDevice->SimpleNetwork);
//
// CLOSE + SHUTDOWN
//
Undi16SimpleNetworkCleanupUndi (SimpleNetworkDevice);
//
// CLEANUP
//
Undi16SimpleNetworkStopUndi (SimpleNetworkDevice);
//
// STOP
//
if (SimpleNetworkDevice->UndiLoaded) {
Undi16SimpleNetworkUnloadUndi (SimpleNetworkDevice);
}
if (SimpleNetworkDevice->SimpleNetwork.WaitForPacket != NULL) {
gBS->CloseEvent (SimpleNetworkDevice->SimpleNetwork.WaitForPacket);
}
if (SimpleNetworkDevice->LegacyBootEvent != NULL) {
gBS->CloseEvent (SimpleNetworkDevice->LegacyBootEvent);
}
if (SimpleNetworkDevice->EfiBootEvent != NULL) {
gBS->CloseEvent (SimpleNetworkDevice->EfiBootEvent);
}
if (SimpleNetworkDevice->Xmit != NULL) {
gBS->FreePages (
(EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->Xmit,
sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1
);
}
if (SimpleNetworkDevice->TxRealModeMediaHeader != NULL) {
gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeMediaHeader, 1);
}
if (SimpleNetworkDevice->TxRealModeDataBuffer != NULL) {
gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeDataBuffer, 1);
}
if (SimpleNetworkDevice->TxDestAddr != NULL) {
gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxDestAddr, 1);
}
gBS->FreePool (SimpleNetworkDevice);
}
}
if (EFI_ERROR (Status)) {
AllChildrenStopped = FALSE;
}
}
if (!AllChildrenStopped) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
//
// FIFO Support Functions
//
/**
Judge whether transmit FIFO is full.
@param Fifo Point to trasmit FIFO structure.
@return BOOLEAN whether transmit FIFO is full.
**/
BOOLEAN
SimpleNetworkTransmitFifoFull (
EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo
)
{
if (((Fifo->Last + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE) == Fifo->First) {
return TRUE;
}
return FALSE;
}
/**
Judge whether transmit FIFO is empty.
@param Fifo Point to trasmit FIFO structure.
@return BOOLEAN whether transmit FIFO is empty.
**/
BOOLEAN
SimpleNetworkTransmitFifoEmpty (
EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo
)
{
if (Fifo->Last == Fifo->First) {
return TRUE;
}
return FALSE;
}
/**
Add data into transmit buffer.
@param Fifo Point to trasmit FIFO structure.
@param Data The data point want to be added.
@retval EFI_OUT_OF_RESOURCES FIFO is full
@retval EFI_SUCCESS Success operation.
**/
EFI_STATUS
SimpleNetworkTransmitFifoAdd (
EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo,
VOID *Data
)
{
if (SimpleNetworkTransmitFifoFull (Fifo)) {
return EFI_OUT_OF_RESOURCES;
}
Fifo->Data[Fifo->Last] = Data;
Fifo->Last = (Fifo->Last + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE;
return EFI_SUCCESS;
}
/**
Get a data and remove it from network transmit FIFO.
@param Fifo Point to trasmit FIFO structure.
@param Data On return, point to the data point want to be got and removed.
@retval EFI_OUT_OF_RESOURCES network transmit buffer is empty.
@retval EFI_SUCCESS Success operation.
**/
EFI_STATUS
SimpleNetworkTransmitFifoRemove (
EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo,
VOID **Data
)
{
if (SimpleNetworkTransmitFifoEmpty (Fifo)) {
return EFI_OUT_OF_RESOURCES;
}
*Data = Fifo->Data[Fifo->First];
Fifo->First = (Fifo->First + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE;
return EFI_SUCCESS;
}
/**
Get recive filter setting according to EFI mask value.
@param ReceiveFilterSetting filter setting EFI mask value.
@return UINT16 Undi filter setting value.
**/
UINT16
Undi16GetPacketFilterSetting (
UINTN ReceiveFilterSetting
)
{
UINT16 PktFilter;
PktFilter = 0;
if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
PktFilter |= FLTR_DIRECTED;
}
if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
PktFilter |= FLTR_DIRECTED;
}
if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
PktFilter |= FLTR_BRDCST;
}
if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
PktFilter |= FLTR_PRMSCS;
}
if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
PktFilter |= FLTR_PRMSCS;
//
// @bug : Do not know if this is right????
//
}
//
// @bug : What is FLTR_SRC_RTG?
//
return PktFilter;
}
/**
Get filter setting from multi cast buffer .
@param Mode Point to mode structure.
@param McastBuffer The multi cast buffer
@param HwAddressSize Size of filter value.
**/
VOID
Undi16GetMCastFilters (
IN EFI_SIMPLE_NETWORK_MODE *Mode,
IN OUT PXENV_UNDI_MCAST_ADDR_T *McastBuffer,
IN UINTN HwAddressSize
)
{
UINTN Index;
//
// @bug : What if Mode->MCastFilterCount > MAXNUM_MCADDR?
//
McastBuffer->MCastAddrCount = (UINT16) Mode->MCastFilterCount;
for (Index = 0; Index < MAXNUM_MCADDR; Index++) {
if (Index < McastBuffer->MCastAddrCount) {
CopyMem (&McastBuffer->MCastAddr[Index], &Mode->MCastFilter[Index], HwAddressSize);
} else {
ZeroMem (&McastBuffer->MCastAddr[Index], HwAddressSize);
}
}
}
//
// Load 16 bit UNDI Option ROM into memory
//
/**
Loads the undi driver.
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@retval EFI_SUCCESS - Successfully loads undi driver.
@retval EFI_NOT_FOUND - Doesn't find undi driver or undi driver load failure.
**/
EFI_STATUS
Undi16SimpleNetworkLoadUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINTN RomAddress;
PCI_EXPANSION_ROM_HEADER *PciExpansionRomHeader;
PCI_DATA_STRUCTURE *PciDataStructure;
PCI_TYPE00 Pci;
if (!mCachedInt1A) {
Status = CacheVectorAddress (0x1A);
if (!EFI_ERROR (Status)) {
mCachedInt1A = TRUE;
}
}
PciIo = SimpleNetworkDevice->PciIo;
PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint32,
0,
sizeof (Pci) / sizeof (UINT32),
&Pci
);
for (RomAddress = 0xc0000; RomAddress < 0xfffff; RomAddress += 0x800) {
PciExpansionRomHeader = (PCI_EXPANSION_ROM_HEADER *) RomAddress;
if (PciExpansionRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
continue;
}
DEBUG ((DEBUG_INIT, "Option ROM found at %X\n", RomAddress));
//
// If the pointer to the PCI Data Structure is invalid, no further images can be located.
// The PCI Data Structure must be DWORD aligned.
//
if (PciExpansionRomHeader->PcirOffset == 0 ||
(PciExpansionRomHeader->PcirOffset & 3) != 0 ||
RomAddress + PciExpansionRomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > 0x100000) {
break;
}
PciDataStructure = (PCI_DATA_STRUCTURE *) (RomAddress + PciExpansionRomHeader->PcirOffset);
if (PciDataStructure->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
continue;
}
DEBUG ((DEBUG_INIT, "PCI Data Structure found at %X\n", PciDataStructure));
if (PciDataStructure->VendorId != Pci.Hdr.VendorId || PciDataStructure->DeviceId != Pci.Hdr.DeviceId) {
continue;
}
DEBUG (
(DEBUG_INIT,
"PCI device with matchinng VendorId and DeviceId (%d,%d)\n",
(UINTN) PciDataStructure->VendorId,
(UINTN) PciDataStructure->DeviceId)
);
Status = LaunchBaseCode (SimpleNetworkDevice, RomAddress);
if (!EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Unload 16 bit UNDI Option ROM from memory
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@return EFI_STATUS
**/
EFI_STATUS
Undi16SimpleNetworkUnloadUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
)
{
if (SimpleNetworkDevice->UndiLoaderTable != NULL) {
ZeroMem (SimpleNetworkDevice->UndiLoaderTable, SimpleNetworkDevice->UndiLoaderTablePages << EFI_PAGE_SHIFT);
gBS->FreePages (
(EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->UndiLoaderTable,
SimpleNetworkDevice->UndiLoaderTablePages
);
}
if (SimpleNetworkDevice->DestinationDataSegment != NULL) {
ZeroMem (
SimpleNetworkDevice->DestinationDataSegment,
SimpleNetworkDevice->DestinationDataSegmentPages << EFI_PAGE_SHIFT
);
gBS->FreePages (
(EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationDataSegment,
SimpleNetworkDevice->DestinationDataSegmentPages
);
}
if (SimpleNetworkDevice->DestinationStackSegment != NULL) {
ZeroMem (
SimpleNetworkDevice->DestinationStackSegment,
SimpleNetworkDevice->DestinationStackSegmentPages << EFI_PAGE_SHIFT
);
gBS->FreePages (
(EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationStackSegment,
SimpleNetworkDevice->DestinationStackSegmentPages
);
}
if (SimpleNetworkDevice->DestinationCodeSegment != NULL) {
ZeroMem (
SimpleNetworkDevice->DestinationCodeSegment,
SimpleNetworkDevice->DestinationCodeSegmentPages << EFI_PAGE_SHIFT
);
gBS->FreePages (
(EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationCodeSegment,
SimpleNetworkDevice->DestinationCodeSegmentPages
);
}
return EFI_SUCCESS;
}
/**
Start the UNDI interface.
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@param Ax PCI address of Undi device.
@retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM.
@retval Others Status of start 16 bit UNDI ROM.
**/
EFI_STATUS
Undi16SimpleNetworkStartUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
UINT16 Ax
)
{
EFI_STATUS Status;
PXENV_START_UNDI_T Start;
//
// Call 16 bit UNDI ROM to start the network interface
//
//
// @bug : What is this state supposed to be???
//
Start.Status = INIT_PXE_STATUS;
Start.Ax = Ax;
Start.Bx = 0x0000;
Start.Dx = 0x0000;
Start.Di = 0x0000;
Start.Es = 0x0000;
Status = PxeStartUndi (SimpleNetworkDevice, &Start);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Start.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
return Status;
}
/**
Stop the UNDI interface
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@retval EFI_DEVICE_ERROR Fail to stop 16 bit UNDI ROM.
@retval Others Status of stop 16 bit UNDI ROM.
**/
EFI_STATUS
Undi16SimpleNetworkStopUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
)
{
EFI_STATUS Status;
PXENV_STOP_UNDI_T Stop;
//
// Call 16 bit UNDI ROM to start the network interface
//
Stop.Status = INIT_PXE_STATUS;
Status = PxeUndiStop (SimpleNetworkDevice, &Stop);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Stop.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
return Status;
}
/**
Cleanup Unid network interface
@param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
@retval EFI_DEVICE_ERROR Fail to cleanup 16 bit UNDI ROM.
@retval Others Status of cleanup 16 bit UNDI ROM.
**/
EFI_STATUS
Undi16SimpleNetworkCleanupUndi (
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
)
{
EFI_STATUS Status;
PXENV_UNDI_CLEANUP_T Cleanup;
//
// Call 16 bit UNDI ROM to cleanup the network interface
//
Cleanup.Status = INIT_PXE_STATUS;
Status = PxeUndiCleanup (SimpleNetworkDevice, &Cleanup);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Cleanup.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
return Status;
}
/**
Get runtime information for Undi network interface
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_SUCCESS Sucess operation.
@retval Others Fail to get runtime information for Undi network interface.
**/
EFI_STATUS
Undi16SimpleNetworkGetInformation (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
UINTN Index;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkStarted:
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
default:
return EFI_DEVICE_ERROR;
}
//
// Call 16 bit UNDI ROM to start the network interface
//
ZeroMem (&SimpleNetworkDevice->GetInformation, sizeof (PXENV_UNDI_GET_INFORMATION_T));
SimpleNetworkDevice->GetInformation.Status = INIT_PXE_STATUS;
Status = PxeUndiGetInformation (SimpleNetworkDevice, &SimpleNetworkDevice->GetInformation);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((DEBUG_NET, " GetInformation.Status = %d\n", SimpleNetworkDevice->GetInformation.Status));
DEBUG ((DEBUG_NET, " GetInformation.BaseIo = %d\n", SimpleNetworkDevice->GetInformation.BaseIo));
DEBUG ((DEBUG_NET, " GetInformation.IntNumber = %d\n", SimpleNetworkDevice->GetInformation.IntNumber));
DEBUG ((DEBUG_NET, " GetInformation.MaxTranUnit = %d\n", SimpleNetworkDevice->GetInformation.MaxTranUnit));
DEBUG ((DEBUG_NET, " GetInformation.HwType = %d\n", SimpleNetworkDevice->GetInformation.HwType));
DEBUG ((DEBUG_NET, " GetInformation.HwAddrLen = %d\n", SimpleNetworkDevice->GetInformation.HwAddrLen));
DEBUG ((DEBUG_NET, " GetInformation.ROMAddress = %d\n", SimpleNetworkDevice->GetInformation.ROMAddress));
DEBUG ((DEBUG_NET, " GetInformation.RxBufCt = %d\n", SimpleNetworkDevice->GetInformation.RxBufCt));
DEBUG ((DEBUG_NET, " GetInformation.TxBufCt = %d\n", SimpleNetworkDevice->GetInformation.TxBufCt));
DEBUG ((DEBUG_NET, " GetInformation.CurNodeAddr ="));
for (Index = 0; Index < 16; Index++) {
DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->GetInformation.CurrentNodeAddress[Index]));
}
DEBUG ((DEBUG_NET, "\n"));
DEBUG ((DEBUG_NET, " GetInformation.PermNodeAddr ="));
for (Index = 0; Index < 16; Index++) {
DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->GetInformation.PermNodeAddress[Index]));
}
DEBUG ((DEBUG_NET, "\n"));
//
// Check the status code from the 16 bit UNDI ROM
//
if (SimpleNetworkDevice->GetInformation.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// The information has been retrieved. Fill in Mode data.
//
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize = SimpleNetworkDevice->GetInformation.HwAddrLen;
SimpleNetworkDevice->SimpleNetworkMode.MaxPacketSize = SimpleNetworkDevice->GetInformation.MaxTranUnit;
SimpleNetworkDevice->SimpleNetworkMode.IfType = (UINT8) SimpleNetworkDevice->GetInformation.HwType;
ZeroMem (
&SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
sizeof SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress
);
CopyMem (
&SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
&SimpleNetworkDevice->GetInformation.CurrentNodeAddress,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
ZeroMem (
&SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
sizeof SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress
);
CopyMem (
&SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
&SimpleNetworkDevice->GetInformation.PermNodeAddress,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
//
// hard code broadcast address - not avail in PXE2.1
//
ZeroMem (
&SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress,
sizeof SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress
);
SetMem (
&SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize,
0xff
);
return Status;
}
/**
Get NIC type
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_SUCCESS Sucess operation.
@retval Others Fail to get NIC type.
**/
EFI_STATUS
Undi16SimpleNetworkGetNicType (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
ZeroMem (&SimpleNetworkDevice->GetNicType, sizeof (PXENV_UNDI_GET_NIC_TYPE_T));
SimpleNetworkDevice->GetNicType.Status = INIT_PXE_STATUS;
Status = PxeUndiGetNicType (SimpleNetworkDevice, &SimpleNetworkDevice->GetNicType);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((DEBUG_NET, " GetNicType.Status = %d\n", SimpleNetworkDevice->GetNicType.Status));
DEBUG ((DEBUG_NET, " GetNicType.NicType = %d\n", SimpleNetworkDevice->GetNicType.NicType));
//
// Check the status code from the 16 bit UNDI ROM
//
if (SimpleNetworkDevice->GetNicType.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// The information has been retrieved. Fill in Mode data.
//
return Status;
}
/**
Get NDIS information
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_SUCCESS Sucess operation.
@retval Others Fail to get NDIS information.
**/
EFI_STATUS
Undi16SimpleNetworkGetNdisInfo (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
ZeroMem (&SimpleNetworkDevice->GetNdisInfo, sizeof (PXENV_UNDI_GET_NDIS_INFO_T));
SimpleNetworkDevice->GetNdisInfo.Status = INIT_PXE_STATUS;
Status = PxeUndiGetNdisInfo (SimpleNetworkDevice, &SimpleNetworkDevice->GetNdisInfo);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((DEBUG_NET, " GetNdisInfo.Status = %d\n", SimpleNetworkDevice->GetNdisInfo.Status));
DEBUG ((DEBUG_NET, " GetNdisInfo.IfaceType = %a\n", SimpleNetworkDevice->GetNdisInfo.IfaceType));
DEBUG ((DEBUG_NET, " GetNdisInfo.LinkSpeed = %d\n", SimpleNetworkDevice->GetNdisInfo.LinkSpeed));
DEBUG ((DEBUG_NET, " GetNdisInfo.ServiceFlags = %08x\n", SimpleNetworkDevice->GetNdisInfo.ServiceFlags));
//
// Check the status code from the 16 bit UNDI ROM
//
if (SimpleNetworkDevice->GetNdisInfo.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// The information has been retrieved. Fill in Mode data.
//
return Status;
}
/**
Call Undi ROM 16bit ISR() to check interrupt cause.
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@param FrameLength The length of frame buffer.
@param FrameHeaderLength The length of frame buffer's header if has.
@param Frame The frame buffer to process network interrupt.
@param ProtType The type network transmit protocol
@param PktType The type of package.
@retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM's ISR, or status is invalid.
@retval EFI_SUCCESS Success operation.
**/
EFI_STATUS
Undi16SimpleNetworkIsr (
IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
IN UINTN *FrameLength,
IN UINTN *FrameHeaderLength, OPTIONAL
IN UINT8 *Frame, OPTIONAL
IN UINT8 *ProtType, OPTIONAL
IN UINT8 *PktType OPTIONAL
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
BOOLEAN FrameReceived;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
FrameReceived = FALSE;
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
DEBUG ((DEBUG_NET, "Isr() IsrValid = %d\n", SimpleNetworkDevice->IsrValid));
if (!SimpleNetworkDevice->IsrValid) {
//
// Call 16 bit UNDI ROM to open the network interface
//
ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));
SimpleNetworkDevice->Isr.Status = INIT_PXE_STATUS;
SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
DEBUG ((DEBUG_NET, "Isr() START\n"));
Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// There have been no events on this UNDI interface, so return EFI_NOT_READY
//
if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_NOT_OURS) {
return EFI_SUCCESS;
}
//
// There is data to process, so call until all events processed.
//
ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));
SimpleNetworkDevice->Isr.Status = INIT_PXE_STATUS;
SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
DEBUG ((DEBUG_NET, "Isr() PROCESS\n"));
Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);
if (EFI_ERROR (Status)) {
return Status;
}
SimpleNetworkDevice->IsrValid = TRUE;
}
//
// Call UNDI GET_NEXT until DONE
//
while (SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_DONE) {
//
// Check the status code from the 16 bit UNDI ROM
//
if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// UNDI is busy. Caller will have to call again.
// This should never happen with a polled mode driver.
//
if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_BUSY) {
DEBUG ((DEBUG_NET, " BUSY\n"));
return EFI_SUCCESS;
}
//
// Check for invalud UNDI FuncFlag
//
if (SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE &&
SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_TRANSMIT
) {
DEBUG ((DEBUG_NET, " Invalid SimpleNetworkDevice->Isr.FuncFlag value %d\n", SimpleNetworkDevice->Isr.FuncFlag));
return EFI_DEVICE_ERROR;
}
//
// Check for Transmit Event
//
if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) {
DEBUG ((DEBUG_NET, " TRANSMIT\n"));
SimpleNetworkDevice->InterruptStatus |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
}
//
// Check for Receive Event
//
else if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE) {
//
// note - this code will hang on a receive interrupt in a GetStatus loop
//
DEBUG ((DEBUG_NET, " RECEIVE\n"));
SimpleNetworkDevice->InterruptStatus |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.BufferLength = %d\n", SimpleNetworkDevice->Isr.BufferLength));
DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.FrameLength = %d\n", SimpleNetworkDevice->Isr.FrameLength));
DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.FrameHeaderLength = %d\n", SimpleNetworkDevice->Isr.FrameHeaderLength));
DEBUG (
(
DEBUG_NET, "SimpleNetworkDevice->Isr.Frame = %04x:%04x\n", SimpleNetworkDevice->Isr.FrameSegSel,
SimpleNetworkDevice->Isr.FrameOffset
)
);
DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.ProtType = 0x%02x\n", SimpleNetworkDevice->Isr.BufferLength));
DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.PktType = 0x%02x\n", SimpleNetworkDevice->Isr.BufferLength));
if (FrameReceived) {
return EFI_SUCCESS;
}
if ((Frame == NULL) || (SimpleNetworkDevice->Isr.FrameLength > *FrameLength)) {
DEBUG ((DEBUG_NET, "return EFI_BUFFER_TOO_SMALL *FrameLength = %08x\n", *FrameLength));
*FrameLength = SimpleNetworkDevice->Isr.FrameLength;
return EFI_BUFFER_TOO_SMALL;
}
*FrameLength = SimpleNetworkDevice->Isr.FrameLength;
if (FrameHeaderLength != NULL) {
*FrameHeaderLength = SimpleNetworkDevice->Isr.FrameHeaderLength;
}
if (ProtType != NULL) {
*ProtType = SimpleNetworkDevice->Isr.ProtType;
}
if (PktType != NULL) {
*PktType = SimpleNetworkDevice->Isr.PktType;
}
CopyMem (
Frame,
(VOID *)(UINTN) ((SimpleNetworkDevice->Isr.FrameSegSel << 4) + SimpleNetworkDevice->Isr.FrameOffset),
SimpleNetworkDevice->Isr.BufferLength
);
Frame = Frame + SimpleNetworkDevice->Isr.BufferLength;
if (SimpleNetworkDevice->Isr.BufferLength == SimpleNetworkDevice->Isr.FrameLength) {
FrameReceived = TRUE;
}
}
//
// There is data to process, so call until all events processed.
//
ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));
SimpleNetworkDevice->Isr.Status = INIT_PXE_STATUS;
SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
DEBUG ((DEBUG_NET, "Isr() GET NEXT\n"));
Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
// if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {
// return EFI_DEVICE_ERROR;
// }
//
}
SimpleNetworkDevice->IsrValid = FALSE;
return EFI_SUCCESS;
}
//
// ///////////////////////////////////////////////////////////////////////////////////////
// Simple Network Protocol Interface Functions using 16 bit UNDI Option ROMs
/////////////////////////////////////////////////////////////////////////////////////////
//
// Start()
//
/**
Call 16 bit UNDI ROM to start the network interface
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_DEVICE_ERROR Network interface has not be initialized.
@retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
@retval EFI_SUCESS Success operation.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkStart (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
PXENV_UNDI_STARTUP_T Startup;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkStopped:
break;
case EfiSimpleNetworkStarted:
case EfiSimpleNetworkInitialized:
return EFI_ALREADY_STARTED;
default:
return EFI_DEVICE_ERROR;
}
//
// Call 16 bit UNDI ROM to start the network interface
//
Startup.Status = INIT_PXE_STATUS;
Status = PxeUndiStartup (SimpleNetworkDevice, &Startup);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Startup.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// The UNDI interface has been started, so update the State.
//
SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStarted;
//
//
//
SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting = 0;
SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount = 0;
return Status;
}
//
// Stop()
//
/**
Call 16 bit UNDI ROM to stop the network interface
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_DEVICE_ERROR Network interface has not be initialized.
@retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
@retval EFI_SUCESS Success operation.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkStop (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkStarted:
break;
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkInitialized:
default:
return EFI_DEVICE_ERROR;
}
SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStopped;
return Status;
}
//
// Initialize()
//
/**
Initialize network interface
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@param ExtraRxBufferSize The size of extra request receive buffer.
@param ExtraTxBufferSize The size of extra request transmit buffer.
@retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
@retval EFI_SUCESS Success operation.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkInitialize (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN UINTN ExtraRxBufferSize OPTIONAL,
IN UINTN ExtraTxBufferSize OPTIONAL
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
PXENV_UNDI_INITIALIZE_T Initialize;
PXENV_UNDI_OPEN_T Open;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkStarted:
break;
case EfiSimpleNetworkInitialized:
default:
return EFI_DEVICE_ERROR;
}
//
// Call 16 bit UNDI ROM to start the network interface
//
Initialize.Status = INIT_PXE_STATUS;
Initialize.ProtocolIni = 0;
Status = PxeUndiInitialize (SimpleNetworkDevice, &Initialize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiInitialize() - Status = %r\n", Status));
DEBUG ((DEBUG_ERROR, "Initialize.Status == %xh\n", Initialize.Status));
if (Initialize.Status == PXENV_STATUS_UNDI_MEDIATEST_FAILED) {
Status = EFI_NO_MEDIA;
}
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Initialize.Status != PXENV_STATUS_SUCCESS) {
DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiInitialize() - Initialize.Status = %04x\n", Initialize.Status));
return EFI_DEVICE_ERROR;
}
//
// Call 16 bit UNDI ROM to open the network interface
//
Open.Status = INIT_PXE_STATUS;
Open.OpenFlag = 0;
Open.PktFilter = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);
Undi16GetMCastFilters (
&SimpleNetworkDevice->SimpleNetworkMode,
&Open.McastBuffer,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
Status = PxeUndiOpen (SimpleNetworkDevice, &Open);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiOpen() - Status = %r\n", Status));
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Open.Status != PXENV_STATUS_SUCCESS) {
DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiOpen() - Open.Status = %04x\n", Open.Status));
return EFI_DEVICE_ERROR;
}
//
// The UNDI interface has been initialized, so update the State.
//
SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkInitialized;
//
// If initialize succeeds, then assume that media is present.
//
SimpleNetworkDevice->SimpleNetworkMode.MediaPresent = TRUE;
//
// Reset the recycled transmit buffer FIFO
//
SimpleNetworkDevice->TxBufferFifo.First = 0;
SimpleNetworkDevice->TxBufferFifo.Last = 0;
SimpleNetworkDevice->IsrValid = FALSE;
return Status;
}
//
// Reset()
//
/**
Reset network interface.
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@param ExtendedVerification Need extended verfication.
@retval EFI_INVALID_PARAMETER Invalid This paramter.
@retval EFI_DEVICE_ERROR Network device has not been initialized.
@retval EFI_NOT_STARTED Network device has been stopped.
@retval EFI_DEVICE_ERROR Invalid status for network device
@retval EFI_SUCCESS Success operation.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkReset (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
PXENV_UNDI_RESET_T Reset;
UINT16 Rx_filter;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
Reset.Status = INIT_PXE_STATUS;
Rx_filter = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);
Undi16GetMCastFilters (
&SimpleNetworkDevice->SimpleNetworkMode,
&Reset.R_Mcast_Buf,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
Status = PxeUndiResetNic (SimpleNetworkDevice, &Reset, Rx_filter);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Reset.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// Reset the recycled transmit buffer FIFO
//
SimpleNetworkDevice->TxBufferFifo.First = 0;
SimpleNetworkDevice->TxBufferFifo.Last = 0;
SimpleNetworkDevice->IsrValid = FALSE;
return Status;
}
//
// Shutdown()
//
/**
Shutdown network interface.
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_INVALID_PARAMETER Invalid This paramter.
@retval EFI_DEVICE_ERROR Network device has not been initialized.
@retval EFI_NOT_STARTED Network device has been stopped.
@retval EFI_DEVICE_ERROR Invalid status for network device
@retval EFI_SUCCESS Success operation.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkShutdown (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
PXENV_UNDI_CLOSE_T Close;
PXENV_UNDI_SHUTDOWN_T Shutdown;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
SimpleNetworkDevice->IsrValid = FALSE;
//
// Call 16 bit UNDI ROM to start the network interface
//
Close.Status = INIT_PXE_STATUS;
Status = PxeUndiClose (SimpleNetworkDevice, &Close);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Close.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// Call 16 bit UNDI ROM to open the network interface
//
Shutdown.Status = INIT_PXE_STATUS;
Status = PxeUndiShutdown (SimpleNetworkDevice, &Shutdown);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Shutdown.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// The UNDI interface has been initialized, so update the State.
//
SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStarted;
//
// If shutdown succeeds, then assume that media is not present.
//
SimpleNetworkDevice->SimpleNetworkMode.MediaPresent = FALSE;
//
// Reset the recycled transmit buffer FIFO
//
SimpleNetworkDevice->TxBufferFifo.First = 0;
SimpleNetworkDevice->TxBufferFifo.Last = 0;
//
// A short delay. Without this an initialize immediately following
// a shutdown will cause some versions of UNDI-16 to stop operating.
//
gBS->Stall (250000);
return Status;
}
//
// ReceiveFilters()
//
/**
Reset network interface.
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@param Enable Enable mask value
@param Disable Disable mask value
@param ResetMCastFilter Whether reset multi cast filter or not
@param MCastFilterCnt Count of mutli cast filter for different MAC address
@param MCastFilter Buffer for mustli cast filter for different MAC address.
@retval EFI_INVALID_PARAMETER Invalid This paramter.
@retval EFI_DEVICE_ERROR Network device has not been initialized.
@retval EFI_NOT_STARTED Network device has been stopped.
@retval EFI_DEVICE_ERROR Invalid status for network device
@retval EFI_SUCCESS Success operation.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkReceiveFilters (
IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
IN UINT32 Enable,
IN UINT32 Disable,
IN BOOLEAN ResetMCastFilter,
IN UINTN MCastFilterCnt OPTIONAL,
IN EFI_MAC_ADDRESS * MCastFilter OPTIONAL
)
{
EFI_STATUS Status;
UINTN Index;
UINT32 NewFilter;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
PXENV_UNDI_CLOSE_T Close;
PXENV_UNDI_OPEN_T Open;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
//
// First deal with possible filter setting changes
//
if ((Enable == 0) && (Disable == 0) && !ResetMCastFilter) {
return EFI_SUCCESS;
}
NewFilter = (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting | Enable) &~Disable;
if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
if ((MCastFilterCnt == 0) || (MCastFilter == 0) || MCastFilterCnt > SimpleNetworkDevice->SimpleNetworkMode.MaxMCastFilterCount) {
return EFI_INVALID_PARAMETER;
}
}
//
// Call 16 bit UNDI ROM to close the network interface
//
Close.Status = INIT_PXE_STATUS;
Status = PxeUndiClose (SimpleNetworkDevice, &Close);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Close.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// Call 16 bit UNDI ROM to open the network interface
//
//
// Reset the recycled transmit buffer FIFO
//
SimpleNetworkDevice->TxBufferFifo.First = 0;
SimpleNetworkDevice->TxBufferFifo.Last = 0;
//
// Call 16 bit UNDI ROM to open the network interface
//
ZeroMem (&Open, sizeof Open);
Open.Status = INIT_PXE_STATUS;
Open.PktFilter = Undi16GetPacketFilterSetting (NewFilter);
if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
//
// Copy the MAC addresses into the UNDI open parameter structure
//
Open.McastBuffer.MCastAddrCount = (UINT16) MCastFilterCnt;
for (Index = 0; Index < MCastFilterCnt; ++Index) {
CopyMem (
Open.McastBuffer.MCastAddr[Index],
&MCastFilter[Index],
sizeof Open.McastBuffer.MCastAddr[Index]
);
}
} else if (!ResetMCastFilter) {
for (Index = 0; Index < SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount; ++Index) {
CopyMem (
Open.McastBuffer.MCastAddr[Index],
&SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index],
sizeof Open.McastBuffer.MCastAddr[Index]
);
}
}
Status = PxeUndiOpen (SimpleNetworkDevice, &Open);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (Open.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
SimpleNetworkDevice->IsrValid = FALSE;
SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting = NewFilter;
if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount = (UINT32) MCastFilterCnt;
for (Index = 0; Index < MCastFilterCnt; ++Index) {
CopyMem (
&SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index],
&MCastFilter[Index],
sizeof (EFI_MAC_ADDRESS)
);
}
}
//
// Read back multicast addresses.
//
return EFI_SUCCESS;
}
//
// StationAddress()
//
/**
Set new MAC address.
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@param Reset Whether reset station MAC address to permenent address
@param New A pointer to New address
@retval EFI_INVALID_PARAMETER Invalid This paramter.
@retval EFI_DEVICE_ERROR Network device has not been initialized.
@retval EFI_NOT_STARTED Network device has been stopped.
@retval EFI_DEVICE_ERROR Invalid status for network device
@retval EFI_SUCCESS Success operation.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkStationAddress (
IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
IN BOOLEAN Reset,
IN EFI_MAC_ADDRESS * New OPTIONAL
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
PXENV_UNDI_SET_STATION_ADDR_T SetStationAddr;
//
// EFI_DEVICE_PATH_PROTOCOL *OldDevicePath;
//
PXENV_UNDI_CLOSE_T Close;
PXENV_UNDI_OPEN_T Open;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
//
// Call 16 bit UNDI ROM to open the network interface
//
SetStationAddr.Status = INIT_PXE_STATUS;
if (Reset) {
//
// If we are reseting the Station Address to the permanent address, and the
// Station Address is not programmable, then just return EFI_SUCCESS.
//
if (!SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable) {
return EFI_SUCCESS;
}
//
// If the address is already the permanent address, then just return success.
//
if (CompareMem (
&SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
&SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
) == 0) {
return EFI_SUCCESS;
}
//
// Copy the adapters permanent address to the new station address
//
CopyMem (
&SetStationAddr.StationAddress,
&SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
} else {
//
// If we are setting the Station Address, and the
// Station Address is not programmable, return invalid parameter.
//
if (!SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable) {
return EFI_INVALID_PARAMETER;
}
//
// If the address is already the new address, then just return success.
//
if (CompareMem (
&SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
New,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
) == 0) {
return EFI_SUCCESS;
}
//
// Copy New to the new station address
//
CopyMem (
&SetStationAddr.StationAddress,
New,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
}
//
// Call 16 bit UNDI ROM to stop the network interface
//
Close.Status = INIT_PXE_STATUS;
PxeUndiClose (SimpleNetworkDevice, &Close);
//
// Call 16-bit UNDI ROM to set the station address
//
SetStationAddr.Status = PXENV_STATUS_SUCCESS;
Status = PxeUndiSetStationAddr (SimpleNetworkDevice, &SetStationAddr);
//
// Call 16-bit UNDI ROM to start the network interface
//
Open.Status = PXENV_STATUS_SUCCESS;
Open.OpenFlag = 0;
Open.PktFilter = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);
Undi16GetMCastFilters (
&SimpleNetworkDevice->SimpleNetworkMode,
&Open.McastBuffer,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
PxeUndiOpen (SimpleNetworkDevice, &Open);
//
// Check status from station address change
//
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (SetStationAddr.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
CopyMem (
&SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
&SetStationAddr.StationAddress,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
#if 0 /* The device path is based on the permanent address not the current address. */
//
// The station address was changed, so update the device path with the new MAC address.
//
OldDevicePath = SimpleNetworkDevice->DevicePath;
SimpleNetworkDevice->DevicePath = DuplicateDevicePath (SimpleNetworkDevice->BaseDevicePath);
SimpleNetworkAppendMacAddressDevicePath (
&SimpleNetworkDevice->DevicePath,
&SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress
);
Status = LibReinstallProtocolInterfaces (
SimpleNetworkDevice->Handle,
&DevicePathProtocol,
OldDevicePath,
SimpleNetworkDevice->DevicePath,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Failed to reinstall the DevicePath protocol for the Simple Network Device\n"));
DEBUG ((DEBUG_ERROR, " Status = %r\n", Status));
}
FreePool (OldDevicePath);
#endif /* 0 */
return Status;
}
//
// Statistics()
//
/**
Resets or collects the statistics on a network interface.
@param This Protocol instance pointer.
@param Reset Set to TRUE to reset the statistics for the network interface.
@param StatisticsSize On input the size, in bytes, of StatisticsTable. On
output the size, in bytes, of the resulting table of
statistics.
@param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
contains the statistics.
@retval EFI_SUCCESS The statistics were collected from the network interface.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
size needed to hold the statistics is returned in
StatisticsSize.
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED This function is not supported by the network interface.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkStatistics (
IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
IN BOOLEAN Reset,
IN OUT UINTN *StatisticsSize OPTIONAL,
OUT EFI_NETWORK_STATISTICS * StatisticsTable OPTIONAL
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
PXENV_UNDI_CLEAR_STATISTICS_T ClearStatistics;
PXENV_UNDI_GET_STATISTICS_T GetStatistics;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
if ((StatisticsSize != NULL) && (*StatisticsSize != 0) && (StatisticsTable == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// If Reset is TRUE, then clear all the statistics.
//
if (Reset) {
DEBUG ((DEBUG_NET, " RESET Statistics\n"));
//
// Call 16 bit UNDI ROM to open the network interface
//
ClearStatistics.Status = INIT_PXE_STATUS;
Status = PxeUndiClearStatistics (SimpleNetworkDevice, &ClearStatistics);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (ClearStatistics.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
DEBUG ((DEBUG_NET, " RESET Statistics Complete"));
}
if (StatisticsSize != NULL) {
EFI_NETWORK_STATISTICS LocalStatisticsTable;
DEBUG ((DEBUG_NET, " GET Statistics\n"));
//
// If the size if valid, then see if the table is valid
//
if (StatisticsTable == NULL) {
DEBUG ((DEBUG_NET, " StatisticsTable is NULL\n"));
return EFI_INVALID_PARAMETER;
}
//
// Call 16 bit UNDI ROM to open the network interface
//
GetStatistics.Status = INIT_PXE_STATUS;
GetStatistics.XmtGoodFrames = 0;
GetStatistics.RcvGoodFrames = 0;
GetStatistics.RcvCRCErrors = 0;
GetStatistics.RcvResourceErrors = 0;
Status = PxeUndiGetStatistics (SimpleNetworkDevice, &GetStatistics);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (GetStatistics.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// Fill in the Statistics Table with the collected values.
//
SetMem (&LocalStatisticsTable, sizeof LocalStatisticsTable, 0xff);
LocalStatisticsTable.TxGoodFrames = GetStatistics.XmtGoodFrames;
LocalStatisticsTable.RxGoodFrames = GetStatistics.RcvGoodFrames;
LocalStatisticsTable.RxCrcErrorFrames = GetStatistics.RcvCRCErrors;
LocalStatisticsTable.RxDroppedFrames = GetStatistics.RcvResourceErrors;
CopyMem (StatisticsTable, &LocalStatisticsTable, *StatisticsSize);
DEBUG (
(DEBUG_NET,
" Statistics Collected : Size=%d Buf=%08x\n",
*StatisticsSize,
StatisticsTable)
);
DEBUG ((DEBUG_NET, " GET Statistics Complete"));
if (*StatisticsSize < sizeof LocalStatisticsTable) {
DEBUG ((DEBUG_NET, " BUFFER TOO SMALL\n"));
Status = EFI_BUFFER_TOO_SMALL;
}
*StatisticsSize = sizeof LocalStatisticsTable;
return Status;
}
return EFI_SUCCESS;
}
//
// MCastIpToMac()
//
/**
Translate IP address to MAC address.
@param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
@param IPv6 IPv6 or IPv4
@param IP A pointer to given Ip address.
@param MAC On return, translated MAC address.
@retval EFI_INVALID_PARAMETER Invalid This paramter.
@retval EFI_INVALID_PARAMETER Invalid IP address.
@retval EFI_INVALID_PARAMETER Invalid return buffer for holding MAC address.
@retval EFI_UNSUPPORTED Do not support IPv6
@retval EFI_DEVICE_ERROR Network device has not been initialized.
@retval EFI_NOT_STARTED Network device has been stopped.
@retval EFI_DEVICE_ERROR Invalid status for network device
@retval EFI_SUCCESS Success operation.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkMCastIpToMac (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN IPv6,
IN EFI_IP_ADDRESS *IP,
OUT EFI_MAC_ADDRESS *MAC
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
PXENV_UNDI_GET_MCAST_ADDR_T GetMcastAddr;
if (This == NULL || IP == NULL || MAC == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
//
// 16 bit UNDI Option ROMS do not support IPv6. Check for IPv6 usage.
//
if (IPv6) {
return EFI_UNSUPPORTED;
}
//
// Call 16 bit UNDI ROM to open the network interface
//
GetMcastAddr.Status = INIT_PXE_STATUS;
CopyMem (&GetMcastAddr.InetAddr, IP, 4);
Status = PxeUndiGetMcastAddr (SimpleNetworkDevice, &GetMcastAddr);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
if (GetMcastAddr.Status != PXENV_STATUS_SUCCESS) {
return EFI_DEVICE_ERROR;
}
//
// Copy the MAC address from the returned data structure.
//
CopyMem (
MAC,
&GetMcastAddr.MediaAddr,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
return Status;
}
//
// NvData()
//
/**
Performs read and write operations on the NVRAM device attached to a
network interface.
@param This The protocol instance pointer.
@param ReadWrite TRUE for read operations, FALSE for write operations.
@param Offset Byte offset in the NVRAM device at which to start the read or
write operation. This must be a multiple of NvRamAccessSize and
less than NvRamSize.
@param BufferSize The number of bytes to read or write from the NVRAM device.
This must also be a multiple of NvramAccessSize.
@param Buffer A pointer to the data buffer.
@retval EFI_SUCCESS The NVRAM access was performed.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED This function is not supported by the network interface.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkNvData (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN ReadWrite,
IN UINTN Offset,
IN UINTN BufferSize,
IN OUT VOID *Buffer
)
{
return EFI_UNSUPPORTED;
}
//
// GetStatus()
//
/**
Reads the current interrupt status and recycled transmit buffer status from
a network interface.
@param This The protocol instance pointer.
@param InterruptStatus A pointer to the bit mask of the currently active interrupts
If this is NULL, the interrupt status will not be read from
the device. If this is not NULL, the interrupt status will
be read from the device. When the interrupt status is read,
it will also be cleared. Clearing the transmit interrupt
does not empty the recycled transmit buffer array.
@param TxBuf Recycled transmit buffer address. The network interface will
not transmit if its internal recycled transmit buffer array
is full. Reading the transmit buffer does not clear the
transmit interrupt. If this is NULL, then the transmit buffer
status will not be read. If there are no transmit buffers to
recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
@retval EFI_SUCCESS The status of the network interface was retrieved.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED This function is not supported by the network interface.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkGetStatus (
IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
OUT UINT32 *InterruptStatus OPTIONAL,
OUT VOID **TxBuf OPTIONAL
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
UINTN FrameLength;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
if (InterruptStatus == NULL && TxBuf == NULL) {
return EFI_INVALID_PARAMETER;
}
FrameLength = 0;
Status = Undi16SimpleNetworkIsr (This, &FrameLength, NULL, NULL, NULL, NULL);
if (Status != EFI_BUFFER_TOO_SMALL) {
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// See if the caller wants interrupt info.
//
if (InterruptStatus != NULL) {
*InterruptStatus = SimpleNetworkDevice->InterruptStatus;
SimpleNetworkDevice->InterruptStatus = 0;
}
//
// See if the caller wants transmit buffer status info.
//
if (TxBuf != NULL) {
*TxBuf = 0;
SimpleNetworkTransmitFifoRemove (&(SimpleNetworkDevice->TxBufferFifo), TxBuf);
}
return EFI_SUCCESS;
}
/**
Places a packet in the transmit queue of a network interface.
@param This The protocol instance pointer.
@param HeaderSize The size, in bytes, of the media header to be filled in by
the Transmit() function. If HeaderSize is non-zero, then it
must be equal to This->Mode->MediaHeaderSize and the DestAddr
and Protocol parameters must not be NULL.
@param BufferSize The size, in bytes, of the entire packet (media header and
data) to be transmitted through the network interface.
@param Buffer A pointer to the packet (media header followed by data) to be
transmitted. This parameter cannot be NULL. If HeaderSize is zero,
then the media header in Buffer must already be filled in by the
caller. If HeaderSize is non-zero, then the media header will be
filled in by the Transmit() function.
@param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
This->Mode->CurrentAddress is used for the source HW MAC address.
@param DestAddr The destination HW MAC address. If HeaderSize is zero, then this
parameter is ignored.
@param Protocol The type of header to build. If HeaderSize is zero, then this
parameter is ignored. See RFC 1700, section "Ether Types", for
examples.
@retval EFI_SUCCESS The packet was placed on the transmit queue.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
@retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED This function is not supported by the network interface.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkTransmit (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN UINTN HeaderSize,
IN UINTN BufferSize,
IN VOID *Buffer,
IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
IN UINT16 *Protocol OPTIONAL
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
PXENV_UNDI_TRANSMIT_T XmitInfo;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
if (Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (BufferSize < SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize) {
return EFI_BUFFER_TOO_SMALL;
}
if (HeaderSize != 0) {
if (HeaderSize != SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize) {
return EFI_INVALID_PARAMETER;
}
if (DestAddr == NULL || Protocol == NULL) {
return EFI_INVALID_PARAMETER;
}
if (DestAddr != NULL) {
CopyMem (
Buffer,
DestAddr,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
}
if (SrcAddr == NULL) {
SrcAddr = &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress;
}
CopyMem (
(UINT8 *) Buffer + SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize,
SrcAddr,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
if (Protocol != NULL) {
*(UINT16 *) ((UINT8 *) Buffer + 2 * SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize) = (UINT16) (((*Protocol & 0xFF) << 8) | ((*Protocol >> 8) & 0xFF));
}
}
//
// See if the recycled transmit buffer FIFO is full.
// If it is full, then we can not transmit until the caller calls GetStatus() to pull
// off recycled transmit buffers.
//
if (SimpleNetworkTransmitFifoFull (&(SimpleNetworkDevice->TxBufferFifo))) {
return EFI_NOT_READY;
}
//
// Output debug trace message.
//
DEBUG ((DEBUG_NET, "Undi16SimpleNetworkTransmit\n\r "));
//
// Initialize UNDI WRITE parameter structure.
//
XmitInfo.Status = INIT_PXE_STATUS;
XmitInfo.Protocol = P_UNKNOWN;
XmitInfo.XmitFlag = XMT_DESTADDR;
XmitInfo.DestAddrOffset = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->TxDestAddr & 0x000f);
XmitInfo.DestAddrSegment = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->TxDestAddr >> 4);
XmitInfo.TBDOffset = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->Xmit & 0x000f);
XmitInfo.TBDSegment = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->Xmit >> 4);
XmitInfo.Reserved[0] = 0;
XmitInfo.Reserved[1] = 0;
CopyMem (
SimpleNetworkDevice->TxDestAddr,
Buffer,
SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
);
CopyMem (
SimpleNetworkDevice->TxRealModeMediaHeader,
Buffer,
SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize
);
SimpleNetworkDevice->Xmit->ImmedLength = (UINT16) SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize;
SimpleNetworkDevice->Xmit->DataBlock[0].TDDataLen = (UINT16) (BufferSize - SimpleNetworkDevice->Xmit->ImmedLength);
CopyMem (
SimpleNetworkDevice->TxRealModeDataBuffer,
(UINT8 *) Buffer + SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize,
SimpleNetworkDevice->Xmit->DataBlock[0].TDDataLen
);
//
// Make API call to UNDI TRANSMIT
//
XmitInfo.Status = 0;
Status = PxeUndiTransmit (SimpleNetworkDevice, &XmitInfo);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the status code from the 16 bit UNDI ROM
//
switch (XmitInfo.Status) {
case PXENV_STATUS_OUT_OF_RESOURCES:
return EFI_NOT_READY;
case PXENV_STATUS_SUCCESS:
break;
default:
return EFI_DEVICE_ERROR;
}
//
// Add address of Buffer to the recycled transmit buffer FIFO
//
SimpleNetworkTransmitFifoAdd (&(SimpleNetworkDevice->TxBufferFifo), Buffer);
return EFI_SUCCESS;
}
/**
Receives a packet from a network interface.
@param This The protocol instance pointer.
@param HeaderSize The size, in bytes, of the media header received on the network
interface. If this parameter is NULL, then the media header size
will not be returned.
@param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
bytes, of the packet that was received on the network interface.
@param Buffer A pointer to the data buffer to receive both the media header and
the data.
@param SrcAddr The source HW MAC address. If this parameter is NULL, the
HW MAC source address will not be extracted from the media
header.
@param DestAddr The destination HW MAC address. If this parameter is NULL,
the HW MAC destination address will not be extracted from the
media header.
@param Protocol The media header type. If this parameter is NULL, then the
protocol will not be extracted from the media header. See
RFC 1700 section "Ether Types" for examples.
@retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
been updated to the number of bytes received.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_NOT_READY The network interface is too busy to accept this transmit
request.
@retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED This function is not supported by the network interface.
**/
EFI_STATUS
EFIAPI
Undi16SimpleNetworkReceive (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
OUT UINTN *HeaderSize OPTIONAL,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer,
OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
OUT UINT16 *Protocol OPTIONAL
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
UINTN MediaAddrSize;
UINT8 ProtType;
if (This == NULL || BufferSize == NULL || Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
Status = Undi16SimpleNetworkIsr (
This,
BufferSize,
HeaderSize,
Buffer,
&ProtType,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
if ((SimpleNetworkDevice->InterruptStatus & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT) == 0) {
return EFI_NOT_READY;
}
SimpleNetworkDevice->InterruptStatus &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
MediaAddrSize = This->Mode->HwAddressSize;
if (SrcAddr != NULL) {
CopyMem (SrcAddr, (UINT8 *) Buffer + MediaAddrSize, MediaAddrSize);
}
if (DestAddr != NULL) {
CopyMem (DestAddr, Buffer, MediaAddrSize);
}
if (Protocol != NULL) {
*((UINT8 *) Protocol) = *((UINT8 *) Buffer + (2 * MediaAddrSize) + 1);
*((UINT8 *) Protocol + 1) = *((UINT8 *) Buffer + (2 * MediaAddrSize));
}
DEBUG ((DEBUG_NET, "Packet Received: BufferSize=%d HeaderSize = %d\n", *BufferSize, *HeaderSize));
return Status;
}
//
// WaitForPacket()
//
/**
wait for a packet to be received.
@param Event Event used with WaitForEvent() to wait for a packet to be received.
@param Context Event Context
**/
VOID
EFIAPI
Undi16SimpleNetworkWaitForPacket (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// Someone is waiting on the receive packet event, if there's
// a packet pending, signal the event
//
if (!EFI_ERROR (Undi16SimpleNetworkCheckForPacket (Context))) {
gBS->SignalEvent (Event);
}
}
//
// CheckForPacket()
//
/**
Check whether packet is ready for receive.
@param This The protocol instance pointer.
@retval EFI_SUCCESS Receive data is ready.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_NOT_READY The network interface is too busy to accept this transmit
request.
@retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED This function is not supported by the network interface.
**/
EFI_STATUS
Undi16SimpleNetworkCheckForPacket (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
UINTN FrameLength;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_SUCCESS;
SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
if (SimpleNetworkDevice == NULL) {
return EFI_DEVICE_ERROR;
}
//
// Verify that the current state of the adapter is valid for this call.
//
switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
return EFI_NOT_STARTED;
case EfiSimpleNetworkStarted:
default:
return EFI_DEVICE_ERROR;
}
FrameLength = 0;
Status = Undi16SimpleNetworkIsr (
This,
&FrameLength,
NULL,
NULL,
NULL,
NULL
);
if (Status != EFI_BUFFER_TOO_SMALL) {
if (EFI_ERROR (Status)) {
return Status;
}
}
return ((SimpleNetworkDevice->InterruptStatus & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT) != 0) ? EFI_SUCCESS : EFI_NOT_READY;
}
/**
Signal handlers for ExitBootServices event.
Clean up any Real-mode UNDI residue from the system
@param Event ExitBootServices event
@param Context
**/
VOID
EFIAPI
Undi16SimpleNetworkEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// NOTE: This is not the only way to effect this cleanup. The prescribed mechanism
// would be to perform an UNDI STOP command. This strategam has been attempted
// but results in problems making some of the EFI core services from TPL_CALLBACK.
// This issue needs to be resolved, but the other alternative has been to perform
// the unchain logic explicitly, as done below.
//
RestoreCachedVectorAddress (0x1A);
}
/**
Allocate buffer below 1M for real mode.
@param NumPages The number pages want to be allocated.
@param Buffer On return, allocated buffer.
@return Status of allocating pages.
**/
EFI_STATUS
BiosSnp16AllocatePagesBelowOneMb (
UINTN NumPages,
VOID **Buffer
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS PhysicalAddress;
PhysicalAddress = 0x000fffff;
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiRuntimeServicesData,
NumPages,
&PhysicalAddress
);
if (EFI_ERROR (Status)) {
return Status;
}
*Buffer = (VOID *) (UINTN) PhysicalAddress;
return EFI_SUCCESS;
}