summaryrefslogtreecommitdiff
path: root/OptionRomPkg/UndiRuntimeDxe/Init.c
diff options
context:
space:
mode:
Diffstat (limited to 'OptionRomPkg/UndiRuntimeDxe/Init.c')
-rw-r--r--OptionRomPkg/UndiRuntimeDxe/Init.c1055
1 files changed, 1055 insertions, 0 deletions
diff --git a/OptionRomPkg/UndiRuntimeDxe/Init.c b/OptionRomPkg/UndiRuntimeDxe/Init.c
new file mode 100644
index 0000000000..42dd5fd21f
--- /dev/null
+++ b/OptionRomPkg/UndiRuntimeDxe/Init.c
@@ -0,0 +1,1055 @@
+/** @file
+ Initialization functions for EFI UNDI32 driver.
+
+Copyright (c) 2006 - 2008, Intel Corporation
+All rights reserved. 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 "Undi32.h"
+//
+// Global Variables
+//
+
+PXE_SW_UNDI *pxe_31 = NULL; // 3.1 entry
+UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES];
+NII_TABLE *UndiDataPointer = NULL;
+
+//
+// UNDI Class Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gUndiDriverBinding = {
+ UndiDriverSupported,
+ UndiDriverStart,
+ UndiDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+
+/**
+ When address mapping changes to virtual this should make the appropriate
+ address conversions.
+
+ (Standard Event handler)
+
+ @return None
+
+**/
+VOID
+EFIAPI
+UndiNotifyVirtual (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ UINT16 Index;
+ VOID *Pxe31Pointer;
+
+ if (pxe_31 != NULL) {
+ Pxe31Pointer = (VOID *) pxe_31;
+
+ EfiConvertPointer (
+ EFI_OPTIONAL_PTR,
+ (VOID **) &Pxe31Pointer
+ );
+
+ //
+ // UNDI32DeviceList is an array of pointers
+ //
+ for (Index = 0; Index < pxe_31->IFcnt; Index++) {
+ UNDI32DeviceList[Index]->NIIProtocol_31.Id = (UINT64) (UINTN) Pxe31Pointer;
+ EfiConvertPointer (
+ EFI_OPTIONAL_PTR,
+ (VOID **) &(UNDI32DeviceList[Index])
+ );
+ }
+
+ EfiConvertPointer (
+ EFI_OPTIONAL_PTR,
+ (VOID **) &(pxe_31->EntryPoint)
+ );
+ pxe_31 = Pxe31Pointer;
+ }
+
+ for (Index = 0; Index <= PXE_OPCODE_LAST_VALID; Index++) {
+ EfiConvertPointer (
+ EFI_OPTIONAL_PTR,
+ (VOID **) &api_table[Index].api_ptr
+ );
+ }
+}
+
+
+/**
+ When EFI is shuting down the boot services, we need to install a
+ configuration table for UNDI to work at runtime!
+
+ (Standard Event handler)
+
+ @return None
+
+**/
+VOID
+EFIAPI
+UndiNotifyExitBs (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ InstallConfigTable ();
+}
+
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086,
+ and DeviceId of (D100_DEVICE_ID || D102_DEVICE_ID || ICH3_DEVICE_ID_1 ||
+ ICH3_DEVICE_ID_2 || ICH3_DEVICE_ID_3 || ICH3_DEVICE_ID_4 || ICH3_DEVICE_ID_5 ||
+ ICH3_DEVICE_ID_6 || ICH3_DEVICE_ID_7 || ICH3_DEVICE_ID_8) can be supported.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to test.
+ @param RemainingDevicePath Not used.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+UndiDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PCI_CONFIG_HEADER),
+ &Pci
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+
+ if (Pci.Hdr.ClassCode[2] == 0x02 && Pci.Hdr.VendorId == PCI_VENDOR_ID_INTEL) {
+ switch (Pci.Hdr.DeviceId) {
+ case D100_DEVICE_ID:
+ case D102_DEVICE_ID:
+ case ICH3_DEVICE_ID_1:
+ case ICH3_DEVICE_ID_2:
+ case ICH3_DEVICE_ID_3:
+ case ICH3_DEVICE_ID_4:
+ case ICH3_DEVICE_ID_5:
+ case ICH3_DEVICE_ID_6:
+ case ICH3_DEVICE_ID_7:
+ case ICH3_DEVICE_ID_8:
+ case 0x1039:
+ case 0x103A:
+ case 0x103B:
+ case 0x103C:
+ case 0x103D:
+ case 0x103E:
+ case 0x1050:
+ case 0x1051:
+ case 0x1052:
+ case 0x1053:
+ case 0x1054:
+ case 0x1055:
+ case 0x1056:
+ case 0x1057:
+ case 0x1059:
+ case 0x1064:
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Start this driver on Controller by opening PciIo and DevicePath protocol.
+ Initialize PXE structures, create a copy of the Controller Device Path with the
+ NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol
+ on the newly created Device Path.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to work with.
+ @param RemainingDevicePath Not used, always produce all possible children.
+
+ @retval EFI_SUCCESS This driver is added to Controller.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+UndiDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
+ PCI_CONFIG_HEADER *CfgHdr;
+ UNDI32_DEV *UNDI32Device;
+ UINT16 NewCommand;
+ UINT8 *TmpPxePointer;
+ EFI_PCI_IO_PROTOCOL *PciIoFncs;
+ UINTN Len;
+ UINT64 Supports;
+ BOOLEAN PciAttributesSaved;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIoFncs,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &UndiDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+ }
+
+ PciAttributesSaved = FALSE;
+
+ Status = gBS->AllocatePool (
+ EfiRuntimeServicesData,
+ sizeof (UNDI32_DEV),
+ (VOID **) &UNDI32Device
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto UndiError;
+ }
+
+ ZeroMem ((CHAR8 *) UNDI32Device, sizeof (UNDI32_DEV));
+
+ //
+ // Get original PCI attributes
+ //
+ Status = PciIoFncs->Attributes (
+ PciIoFncs,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &UNDI32Device->NicInfo.OriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto UndiErrorDeleteDevice;
+ }
+ PciAttributesSaved = TRUE;
+
+ //
+ // allocate and initialize both (old and new) the !pxe structures here,
+ // there should only be one copy of each of these structure for any number
+ // of NICs this undi supports. Also, these structures need to be on a
+ // paragraph boundary as per the spec. so, while allocating space for these,
+ // make sure that there is space for 2 !pxe structures (old and new) and a
+ // 32 bytes padding for alignment adjustment (in case)
+ //
+ TmpPxePointer = NULL;
+ if (pxe_31 == NULL) {
+ Status = gBS->AllocatePool (
+ EfiRuntimeServicesData,
+ (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32),
+ (VOID **) &TmpPxePointer
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto UndiErrorDeleteDevice;
+ }
+
+ ZeroMem (
+ TmpPxePointer,
+ sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32
+ );
+ //
+ // check for paragraph alignment here, assuming that the pointer is
+ // already 8 byte aligned.
+ //
+ if (((UINTN) TmpPxePointer & 0x0F) != 0) {
+ pxe_31 = (PXE_SW_UNDI *) ((UINTN) (TmpPxePointer + 8));
+ } else {
+ pxe_31 = (PXE_SW_UNDI *) TmpPxePointer;
+ }
+
+ PxeStructInit (pxe_31);
+ }
+
+ UNDI32Device->NIIProtocol_31.Id = (UINT64) (UINTN) (pxe_31);
+
+ Status = PciIoFncs->Attributes (
+ PciIoFncs,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIoFncs->Attributes (
+ PciIoFncs,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+ //
+ // Read all the registers from device's PCI Configuration space
+ //
+ Status = PciIoFncs->Pci.Read (
+ PciIoFncs,
+ EfiPciIoWidthUint32,
+ 0,
+ MAX_PCI_CONFIG_LEN,
+ &UNDI32Device->NicInfo.Config
+ );
+
+ CfgHdr = (PCI_CONFIG_HEADER *) &(UNDI32Device->NicInfo.Config[0]);
+
+ //
+ // make sure that this device is a PCI bus master
+ //
+
+ NewCommand = (UINT16) (CfgHdr->Command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
+ if (CfgHdr->Command != NewCommand) {
+ PciIoFncs->Pci.Write (
+ PciIoFncs,
+ EfiPciIoWidthUint16,
+ PCI_COMMAND,
+ 1,
+ &NewCommand
+ );
+ CfgHdr->Command = NewCommand;
+ }
+
+ //
+ // make sure that the latency timer is at least 32
+ //
+ if (CfgHdr->LatencyTimer < 32) {
+ CfgHdr->LatencyTimer = 32;
+ PciIoFncs->Pci.Write (
+ PciIoFncs,
+ EfiPciIoWidthUint8,
+ PCI_LATENCY_TIMER,
+ 1,
+ &CfgHdr->LatencyTimer
+ );
+ }
+ //
+ // the IfNum index for the current interface will be the total number
+ // of interfaces initialized so far
+ //
+ UNDI32Device->NIIProtocol_31.IfNum = pxe_31->IFcnt;
+
+ PxeUpdate (&UNDI32Device->NicInfo, pxe_31);
+
+ UNDI32Device->NicInfo.Io_Function = PciIoFncs;
+ UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = UNDI32Device;
+ UNDI32Device->Undi32BaseDevPath = UndiDevicePath;
+
+ Status = AppendMac2DevPath (
+ &UNDI32Device->Undi32DevPath,
+ UNDI32Device->Undi32BaseDevPath,
+ &UNDI32Device->NicInfo
+ );
+
+ if (Status != 0) {
+ goto UndiErrorDeletePxe;
+ }
+
+ UNDI32Device->Signature = UNDI_DEV_SIGNATURE;
+
+ UNDI32Device->NIIProtocol_31.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31;
+ UNDI32Device->NIIProtocol_31.Type = EfiNetworkInterfaceUndi;
+ UNDI32Device->NIIProtocol_31.MajorVer = PXE_ROMID_MAJORVER;
+ UNDI32Device->NIIProtocol_31.MinorVer = PXE_ROMID_MINORVER_31;
+ UNDI32Device->NIIProtocol_31.ImageSize = 0;
+ UNDI32Device->NIIProtocol_31.ImageAddr = 0;
+ UNDI32Device->NIIProtocol_31.Ipv6Supported = FALSE;
+
+ UNDI32Device->NIIProtocol_31.StringId[0] = 'U';
+ UNDI32Device->NIIProtocol_31.StringId[1] = 'N';
+ UNDI32Device->NIIProtocol_31.StringId[2] = 'D';
+ UNDI32Device->NIIProtocol_31.StringId[3] = 'I';
+
+ UNDI32Device->DeviceHandle = NULL;
+
+ //
+ // install both the 3.0 and 3.1 NII protocols.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &UNDI32Device->DeviceHandle,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ &UNDI32Device->NIIProtocol_31,
+ &gEfiDevicePathProtocolGuid,
+ UNDI32Device->Undi32DevPath,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ //
+ // if the table exists, free it and alloc again, or alloc it directly
+ //
+ if (UndiDataPointer != NULL) {
+ Status = gBS->FreePool(UndiDataPointer);
+ }
+ if (EFI_ERROR (Status)) {
+ goto UndiErrorDeleteDevicePath;
+ }
+
+ Len = (pxe_31->IFcnt * sizeof (NII_ENTRY)) + sizeof (UndiDataPointer);
+ Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UndiDataPointer);
+
+ if (EFI_ERROR (Status)) {
+ goto UndiErrorAllocDataPointer;
+ }
+
+ //
+ // Open For Child Device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIoFncs,
+ This->DriverBindingHandle,
+ UNDI32Device->DeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ return EFI_SUCCESS;
+UndiErrorAllocDataPointer:
+ gBS->UninstallMultipleProtocolInterfaces (
+ &UNDI32Device->DeviceHandle,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ &UNDI32Device->NIIProtocol_31,
+ &gEfiDevicePathProtocolGuid,
+ UNDI32Device->Undi32DevPath,
+ NULL
+ );
+
+UndiErrorDeleteDevicePath:
+ UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = NULL;
+ gBS->FreePool (UNDI32Device->Undi32DevPath);
+
+UndiErrorDeletePxe:
+ PxeUpdate (NULL, pxe_31);
+ if (TmpPxePointer != NULL) {
+ gBS->FreePool (TmpPxePointer);
+
+ }
+
+UndiErrorDeleteDevice:
+ if (PciAttributesSaved) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIoFncs->Attributes (
+ PciIoFncs,
+ EfiPciIoAttributeOperationSet,
+ UNDI32Device->NicInfo.OriginalPciAttributes,
+ NULL
+ );
+ }
+
+ gBS->FreePool (UNDI32Device);
+
+UndiError:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
+ closing the DevicePath and PciIo protocols on Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on.
+ @param NumberOfChildren How many children need to be stopped.
+ @param ChildHandleBuffer Not used.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval other This driver was not removed from this device.
+
+**/
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+EFI_STATUS
+EFIAPI
+UndiDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ UNDI32_DEV *UNDI32Device;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // 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->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ (VOID **) &NIIProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+
+ UNDI32Device = UNDI_DEV_FROM_THIS (NIIProtocol);
+
+ //
+ // Restore original PCI attributes
+ //
+ Status = UNDI32Device->NicInfo.Io_Function->Attributes (
+ UNDI32Device->NicInfo.Io_Function,
+ EfiPciIoAttributeOperationSet,
+ UNDI32Device->NicInfo.OriginalPciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ UNDI32Device->Undi32DevPath,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ &UNDI32Device->NIIProtocol_31,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ gBS->FreePool (UNDI32Device->Undi32DevPath);
+ gBS->FreePool (UNDI32Device);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Use the EFI boot services to produce a pause. This is also the routine which
+ gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can
+ do it's own pause.
+
+ @param UnqId Runtime O/S routine might use this, this temp
+ routine does not use it
+ @param MicroSeconds Determines the length of pause.
+
+ @return none
+
+**/
+VOID
+TmpDelay (
+ IN UINT64 UnqId,
+ IN UINTN MicroSeconds
+ )
+{
+ gBS->Stall ((UINT32) MicroSeconds);
+}
+
+
+/**
+ Use the PCI IO abstraction to issue memory or I/O reads and writes. This is also the routine which
+ gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can do it's own I/O abstractions.
+
+ @param UnqId Runtime O/S routine may use this field, this temp
+ routine does not.
+ @param ReadWrite Determine if it is an I/O or Memory Read/Write
+ Operation.
+ @param Len Determines the width of the data operation.
+ @param Port What port to Read/Write from.
+ @param BuffAddr Address to read to or write from.
+
+ @return none
+
+**/
+VOID
+TmpMemIo (
+ IN UINT64 UnqId,
+ IN UINT8 ReadWrite,
+ IN UINT8 Len,
+ IN UINT64 Port,
+ IN UINT64 BuffAddr
+ )
+{
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
+ NIC_DATA_INSTANCE *AdapterInfo;
+
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
+ AdapterInfo = (NIC_DATA_INSTANCE *) (UINTN) UnqId;
+ switch (Len) {
+ case 2:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
+ break;
+
+ case 4:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
+ break;
+
+ case 8:
+ Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
+ break;
+ }
+
+ switch (ReadWrite) {
+ case PXE_IO_READ:
+ AdapterInfo->Io_Function->Io.Read (
+ AdapterInfo->Io_Function,
+ Width,
+ 1,
+ Port,
+ 1,
+ (VOID *) (UINTN) (BuffAddr)
+ );
+ break;
+
+ case PXE_IO_WRITE:
+ AdapterInfo->Io_Function->Io.Write (
+ AdapterInfo->Io_Function,
+ Width,
+ 1,
+ Port,
+ 1,
+ (VOID *) (UINTN) (BuffAddr)
+ );
+ break;
+
+ case PXE_MEM_READ:
+ AdapterInfo->Io_Function->Mem.Read (
+ AdapterInfo->Io_Function,
+ Width,
+ 0,
+ Port,
+ 1,
+ (VOID *) (UINTN) (BuffAddr)
+ );
+ break;
+
+ case PXE_MEM_WRITE:
+ AdapterInfo->Io_Function->Mem.Write (
+ AdapterInfo->Io_Function,
+ Width,
+ 0,
+ Port,
+ 1,
+ (VOID *) (UINTN) (BuffAddr)
+ );
+ break;
+ }
+
+ return ;
+}
+
+
+/**
+ Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space
+ for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr)
+ and an added MAC node.
+
+ @param DevPtr Pointer which will point to the newly created device
+ path with the MAC node attached.
+ @param BaseDevPtr Pointer to the device path which the UNDI device
+ driver is latching on to.
+ @param AdapterInfo Pointer to the NIC data structure information which
+ the UNDI driver is layering on..
+
+ @retval EFI_SUCCESS A MAC address was successfully appended to the Base
+ Device Path.
+ @retval other Not enough resources available to create new Device
+ Path node.
+
+**/
+EFI_STATUS
+AppendMac2DevPath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr,
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
+ IN NIC_DATA_INSTANCE *AdapterInfo
+ )
+{
+ EFI_MAC_ADDRESS MACAddress;
+ PCI_CONFIG_HEADER *CfgHdr;
+ INT32 Val;
+ INT32 Index;
+ INT32 Index2;
+ UINT8 AddrLen;
+ MAC_ADDR_DEVICE_PATH MacAddrNode;
+ EFI_DEVICE_PATH_PROTOCOL *EndNode;
+ UINT8 *DevicePtr;
+ UINT16 TotalPathLen;
+ UINT16 BasePathLen;
+ EFI_STATUS Status;
+
+ //
+ // set the environment ready (similar to UNDI_Start call) so that we can
+ // execute the other UNDI_ calls to get the mac address
+ // we are using undi 3.1 style
+ //
+ AdapterInfo->Delay = TmpDelay;
+ AdapterInfo->Virt2Phys = (VOID *) 0;
+ AdapterInfo->Block = (VOID *) 0;
+ AdapterInfo->Map_Mem = (VOID *) 0;
+ AdapterInfo->UnMap_Mem = (VOID *) 0;
+ AdapterInfo->Sync_Mem = (VOID *) 0;
+ AdapterInfo->Mem_Io = TmpMemIo;
+ //
+ // these tmp call-backs follow 3.1 undi style
+ // i.e. they have the unique_id parameter.
+ //
+ AdapterInfo->VersionFlag = 0x31;
+ AdapterInfo->Unique_ID = (UINT64) (UINTN) AdapterInfo;
+
+ //
+ // undi init portion
+ //
+ CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);
+ AdapterInfo->ioaddr = 0;
+ AdapterInfo->RevID = CfgHdr->RevID;
+
+ AddrLen = E100bGetEepromAddrLen (AdapterInfo);
+
+ for (Index = 0, Index2 = 0; Index < 3; Index++) {
+ Val = E100bReadEeprom (AdapterInfo, Index, AddrLen);
+ MACAddress.Addr[Index2++] = (UINT8) Val;
+ MACAddress.Addr[Index2++] = (UINT8) (Val >> 8);
+ }
+
+ SetMem (MACAddress.Addr + Index2, sizeof (EFI_MAC_ADDRESS) - Index2, 0);
+ //for (; Index2 < sizeof (EFI_MAC_ADDRESS); Index2++) {
+ // MACAddress.Addr[Index2] = 0;
+ //}
+ //
+ // stop undi
+ //
+ AdapterInfo->Delay = (VOID *) 0;
+ AdapterInfo->Mem_Io = (VOID *) 0;
+
+ //
+ // fill the mac address node first
+ //
+ ZeroMem ((CHAR8 *) &MacAddrNode, sizeof MacAddrNode);
+ CopyMem (
+ (CHAR8 *) &MacAddrNode.MacAddress,
+ (CHAR8 *) &MACAddress,
+ sizeof (EFI_MAC_ADDRESS)
+ );
+
+ MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
+ MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
+ MacAddrNode.Header.Length[0] = sizeof (MacAddrNode);
+ MacAddrNode.Header.Length[1] = 0;
+
+ //
+ // find the size of the base dev path.
+ //
+ EndNode = BaseDevPtr;
+
+ while (!IsDevicePathEnd (EndNode)) {
+ EndNode = NextDevicePathNode (EndNode);
+ }
+
+ BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr));
+
+ //
+ // create space for full dev path
+ //
+ TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
+
+ Status = gBS->AllocatePool (
+ EfiRuntimeServicesData,
+ TotalPathLen,
+ (VOID **) &DevicePtr
+ );
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+ //
+ // copy the base path, mac addr and end_dev_path nodes
+ //
+ *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr;
+ CopyMem (DevicePtr, (CHAR8 *) BaseDevPtr, BasePathLen);
+ DevicePtr += BasePathLen;
+ CopyMem (DevicePtr, (CHAR8 *) &MacAddrNode, sizeof (MacAddrNode));
+ DevicePtr += sizeof (MacAddrNode);
+ CopyMem (DevicePtr, (CHAR8 *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Install a GUID/Pointer pair into the system's configuration table.
+
+ none
+
+ @retval EFI_SUCCESS Install a GUID/Pointer pair into the system's
+ configuration table.
+ @retval other Did not successfully install the GUID/Pointer pair
+ into the configuration table.
+
+**/
+// TODO: VOID - add argument and description to function comment
+EFI_STATUS
+InstallConfigTable (
+ IN VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_CONFIGURATION_TABLE *CfgPtr;
+ NII_TABLE *TmpData;
+ UINT16 Index;
+ NII_TABLE *UndiData;
+
+ if (pxe_31 == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if(UndiDataPointer == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ UndiData = (NII_TABLE *)UndiDataPointer;
+
+ UndiData->NumEntries = pxe_31->IFcnt;
+ UndiData->NextLink = NULL;
+
+ for (Index = 0; Index < pxe_31->IFcnt; Index++) {
+ UndiData->NiiEntry[Index].InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31;
+ UndiData->NiiEntry[Index].DevicePathPointer = UNDI32DeviceList[Index]->Undi32DevPath;
+ }
+
+ //
+ // see if there is an entry in the config table already
+ //
+ CfgPtr = gST->ConfigurationTable;
+
+ for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
+ Status = CompareGuid (
+ &CfgPtr->VendorGuid,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31
+ );
+ if (Status != EFI_SUCCESS) {
+ break;
+ }
+
+ CfgPtr++;
+ }
+
+ if (Index < gST->NumberOfTableEntries) {
+ TmpData = (NII_TABLE *) CfgPtr->VendorTable;
+
+ //
+ // go to the last link
+ //
+ while (TmpData->NextLink != NULL) {
+ TmpData = TmpData->NextLink;
+ }
+
+ TmpData->NextLink = UndiData;
+
+ //
+ // 1st one in chain
+ //
+ UndiData = (NII_TABLE *) CfgPtr->VendorTable;
+ }
+
+ //
+ // create an entry in the configuration table for our GUID
+ //
+ Status = gBS->InstallConfigurationTable (
+ &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
+ UndiData
+ );
+ return Status;
+}
+
+/**
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeUndi(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_EVENT Event;
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBinding (
+ ImageHandle,
+ SystemTable,
+ &gUndiDriverBinding,
+ ImageHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UndiNotifyExitBs,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UndiNotifyVirtual,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}