mirror of https://github.com/acidanthera/audk.git
1130 lines
30 KiB
C
1130 lines
30 KiB
C
/*++
|
|
|
|
Copyright (c) 2006 - 2007, 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.
|
|
|
|
Module Name:
|
|
|
|
init.c
|
|
|
|
Abstract:
|
|
|
|
Initialization functions for EFI UNDI32 driver
|
|
|
|
Revision History
|
|
|
|
--*/
|
|
|
|
#include "Undi32.h"
|
|
#include <Library/BaseLib.h>
|
|
//
|
|
// Global Variables
|
|
//
|
|
|
|
PXE_SW_UNDI *pxe_31 = NULL; // 3.1 entry
|
|
UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES];
|
|
NII_TABLE *UndiDataPointer = NULL;
|
|
|
|
VOID
|
|
EFIAPI
|
|
UndiNotifyVirtual (
|
|
EFI_EVENT Event,
|
|
VOID *Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
When address mapping changes to virtual this should make the appropriate
|
|
address conversions.
|
|
|
|
Arguments:
|
|
|
|
(Standard Event handler)
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Context - add argument and description to function comment
|
|
{
|
|
UINT16 Index;
|
|
VOID *Pxe31Pointer;
|
|
|
|
if (pxe_31 != NULL) {
|
|
Pxe31Pointer = (VOID *) pxe_31;
|
|
|
|
EfiConvertPointer (
|
|
EFI_OPTIONAL_POINTER,
|
|
(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_POINTER,
|
|
(VOID **) &(UNDI32DeviceList[Index])
|
|
);
|
|
}
|
|
|
|
EfiConvertPointer (
|
|
EFI_OPTIONAL_POINTER,
|
|
(VOID **) &(pxe_31->EntryPoint)
|
|
);
|
|
pxe_31 = Pxe31Pointer;
|
|
}
|
|
|
|
for (Index = 0; Index <= PXE_OPCODE_LAST_VALID; Index++) {
|
|
EfiConvertPointer (
|
|
EFI_OPTIONAL_POINTER,
|
|
(VOID **) &api_table[Index].api_ptr
|
|
);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
EFIAPI
|
|
UndiNotifyExitBs (
|
|
EFI_EVENT Event,
|
|
VOID *Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
When EFI is shuting down the boot services, we need to install a
|
|
configuration table for UNDI to work at runtime!
|
|
|
|
Arguments:
|
|
|
|
(Standard Event handler)
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Context - add argument and description to function comment
|
|
{
|
|
InstallConfigTable ();
|
|
}
|
|
//
|
|
// UNDI Class Driver Global Variables
|
|
//
|
|
EFI_DRIVER_BINDING_PROTOCOL gUndiDriverBinding = {
|
|
UndiDriverSupported,
|
|
UndiDriverStart,
|
|
UndiDriverStop,
|
|
0xa,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UndiDriverSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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.
|
|
|
|
Arguments:
|
|
|
|
This - Protocol instance pointer.
|
|
|
|
Controller - Handle of device to test.
|
|
|
|
RemainingDevicePath - Not used.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - This driver supports this device.
|
|
|
|
other - This driver does not support this device.
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UndiDriverStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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.
|
|
|
|
Arguments:
|
|
|
|
This - Protocol instance pointer.
|
|
|
|
Controller - Handle of device to work with.
|
|
|
|
RemainingDevicePath - Not used, always produce all possible children.
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - This driver is added to Controller.
|
|
|
|
other - This driver does not support this device.
|
|
|
|
--*/
|
|
{
|
|
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 == TRUE) {
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UndiDriverStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
|
|
closing the DevicePath and PciIo protocols on Controller.
|
|
|
|
Arguments:
|
|
This - Protocol instance pointer.
|
|
Controller - Handle of device to stop driver on.
|
|
NumberOfChildren - How many children need to be stopped.
|
|
ChildHandleBuffer - Not used.
|
|
|
|
Returns:
|
|
EFI_SUCCESS - This driver is removed Controller.
|
|
other - This driver was not removed from this device.
|
|
|
|
--*/
|
|
// TODO: EFI_DEVICE_ERROR - add return value to function comment
|
|
{
|
|
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;
|
|
|
|
}
|
|
|
|
VOID
|
|
TmpDelay (
|
|
IN UINT64 UnqId,
|
|
IN UINTN MicroSeconds
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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.
|
|
|
|
Arguments:
|
|
|
|
UnqId - Runtime O/S routine might use this, this temp routine does not use it
|
|
|
|
MicroSeconds - Determines the length of pause.
|
|
|
|
Returns:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
gBS->Stall ((UINT32) MicroSeconds);
|
|
}
|
|
|
|
VOID
|
|
TmpMemIo (
|
|
IN UINT64 UnqId,
|
|
IN UINT8 ReadWrite,
|
|
IN UINT8 Len,
|
|
IN UINT64 Port,
|
|
IN UINT64 BuffAddr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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.
|
|
|
|
Arguments:
|
|
|
|
UnqId - Runtime O/S routine may use this field, this temp routine does not.
|
|
|
|
ReadWrite - Determine if it is an I/O or Memory Read/Write Operation.
|
|
|
|
Len - Determines the width of the data operation.
|
|
|
|
Port - What port to Read/Write from.
|
|
|
|
BuffAddr - Address to read to or write from.
|
|
|
|
Returns:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
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 ;
|
|
}
|
|
|
|
EFI_STATUS
|
|
AppendMac2DevPath (
|
|
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
|
|
IN NIC_DATA_INSTANCE *AdapterInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
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.
|
|
|
|
Arguments:
|
|
|
|
DevPtr - Pointer which will point to the newly created device path with the MAC node attached.
|
|
|
|
BaseDevPtr - Pointer to the device path which the UNDI device driver is latching on to.
|
|
|
|
AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - A MAC address was successfully appended to the Base Device Path.
|
|
|
|
other - Not enough resources available to create new Device Path node.
|
|
|
|
--*/
|
|
{
|
|
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;
|
|
}
|
|
|
|
EFI_STATUS
|
|
InstallConfigTable (
|
|
IN VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Install a GUID/Pointer pair into the system's configuration table.
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Install a GUID/Pointer pair into the system's configuration table.
|
|
|
|
other - Did not successfully install the GUID/Pointer pair into the configuration table.
|
|
|
|
--*/
|
|
// TODO: VOID - add argument and description to function comment
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
|
|
Install driver binding protocol of UNDI.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval other Some error occurs when executing this entry point.
|
|
|
|
**/
|
|
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->CreateEvent (
|
|
EVT_SIGNAL_EXIT_BOOT_SERVICES,
|
|
TPL_NOTIFY,
|
|
UndiNotifyExitBs,
|
|
NULL,
|
|
&Event
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = gBS->CreateEvent (
|
|
EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
|
|
TPL_NOTIFY,
|
|
UndiNotifyVirtual,
|
|
NULL,
|
|
&Event
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|