/** @file | |
Initialization functions for EFI UNDI32 driver. | |
Copyright (c) 2006 - 2013, 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 "Undi32.h" | |
// | |
// Global Variables | |
// | |
PXE_SW_UNDI *pxe_31 = NULL; // 3.1 entry | |
UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES]; | |
UNDI_CONFIG_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 | pxe_31->IFcntExt << 8); 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 | pxe_31->IFcntExt << 8; | |
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|pxe_31->IFcntExt << 8)* sizeof (UndiDataPointer->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; | |
// | |
// 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); | |
Status = gBS->CloseProtocol ( | |
Controller, | |
&gEfiPciIoProtocolGuid, | |
This->DriverBindingHandle, | |
ChildHandleBuffer[Index] | |
); | |
if (!EFI_ERROR (Status)) { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ChildHandleBuffer[Index], | |
&gEfiDevicePathProtocolGuid, | |
UNDI32Device->Undi32DevPath, | |
&gEfiNetworkInterfaceIdentifierProtocolGuid_31, | |
&UNDI32Device->NIIProtocol_31, | |
NULL | |
); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Restore original PCI attributes | |
// | |
Status = UNDI32Device->NicInfo.Io_Function->Attributes ( | |
UNDI32Device->NicInfo.Io_Function, | |
EfiPciIoAttributeOperationSet, | |
UNDI32Device->NicInfo.OriginalPciAttributes, | |
NULL | |
); | |
ASSERT_EFI_ERROR (Status); | |
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] = (UINT8) 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; | |
UNDI_CONFIG_TABLE *TmpData; | |
UINT16 Index; | |
UNDI_CONFIG_TABLE *UndiData; | |
if (pxe_31 == NULL) { | |
return EFI_SUCCESS; | |
} | |
if(UndiDataPointer == NULL) { | |
return EFI_SUCCESS; | |
} | |
UndiData = (UNDI_CONFIG_TABLE *)UndiDataPointer; | |
UndiData->NumberOfInterfaces = (pxe_31->IFcnt | pxe_31->IFcntExt << 8); | |
UndiData->nextlink = NULL; | |
for (Index = 0; Index < (pxe_31->IFcnt | pxe_31->IFcntExt << 8); Index++) { | |
UndiData->NII_entry[Index].NII_InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31; | |
UndiData->NII_entry[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 = (UNDI_CONFIG_TABLE *) CfgPtr->VendorTable; | |
// | |
// go to the last link | |
// | |
while (TmpData->nextlink != NULL) { | |
TmpData = TmpData->nextlink; | |
} | |
TmpData->nextlink = UndiData; | |
// | |
// 1st one in chain | |
// | |
UndiData = (UNDI_CONFIG_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 = EfiLibInstallDriverBindingComponentName2 ( | |
ImageHandle, | |
SystemTable, | |
&gUndiDriverBinding, | |
ImageHandle, | |
&gUndiComponentName, | |
&gUndiComponentName2 | |
); | |
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; | |
} |