| /** @file | |
| Initialization functions for EFI UNDI32 driver. | |
| Copyright (c) 2006 - 2015, 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 | |
| UndiNotifyReadyToBoot ( | |
| 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 = TRUE; | |
| 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; | |
| UNDI32Device->Aip.GetInformation = UndiAipGetInfo; | |
| UNDI32Device->Aip.SetInformation = UndiAipSetInfo; | |
| UNDI32Device->Aip.GetSupportedTypes = UndiAipGetSupportedTypes; | |
| // | |
| // install both the 3.0 and 3.1 NII protocols. | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &UNDI32Device->DeviceHandle, | |
| &gEfiNetworkInterfaceIdentifierProtocolGuid_31, | |
| &UNDI32Device->NIIProtocol_31, | |
| &gEfiDevicePathProtocolGuid, | |
| UNDI32Device->Undi32DevPath, | |
| &gEfiAdapterInformationProtocolGuid, | |
| &UNDI32Device->Aip, | |
| 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, | |
| &gEfiAdapterInformationProtocolGuid, | |
| &UNDI32Device->Aip, | |
| 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, | |
| UndiNotifyReadyToBoot, | |
| NULL, | |
| &gEfiEventReadyToBootGuid, | |
| &Event | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = gBS->CreateEventEx ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| UndiNotifyVirtual, | |
| NULL, | |
| &gEfiEventVirtualAddressChangeGuid, | |
| &Event | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } |