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