/** @file Main file for support of shell consist mapping. Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "UefiShellCommandLib.h" #include #include #include #include #include #include typedef enum { MTDTypeUnknown, MTDTypeFloppy, MTDTypeHardDisk, MTDTypeCDRom, MTDTypeEnd } MTD_TYPE; typedef struct { CHAR16 *Str; UINTN Len; } POOL_PRINT; typedef struct { UINTN Hi; MTD_TYPE Mtd; POOL_PRINT Csd; BOOLEAN Digital; } DEVICE_CONSIST_MAPPING_INFO; typedef struct { MTD_TYPE MTDType; CHAR16 *Name; } MTD_NAME; /** Serial Decode function. @param DevPath The Device path info. @param MapInfo The map info. @param OrigDevPath The original device path protocol. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ typedef EFI_STATUS (*SERIAL_DECODE_FUNCTION) ( EFI_DEVICE_PATH_PROTOCOL *DevPath, DEVICE_CONSIST_MAPPING_INFO *MapInfo, EFI_DEVICE_PATH_PROTOCOL *OrigDevPath ); typedef struct { UINT8 Type; UINT8 SubType; SERIAL_DECODE_FUNCTION SerialFun; INTN (EFIAPI *CompareFun) (EFI_DEVICE_PATH_PROTOCOL *DevPath, EFI_DEVICE_PATH_PROTOCOL *DevPath2); } DEV_PATH_CONSIST_MAPPING_TABLE; /** Concatenates a formatted unicode string to allocated pool. The caller must free the resulting buffer. @param Str Tracks the allocated pool, size in use, and amount of pool allocated. @param Fmt The format string @param ... The data will be printed. @retval EFI_SUCCESS The string is concatenated successfully. @retval EFI_OUT_OF_RESOURCES Out of resources. **/ EFI_STATUS EFIAPI CatPrint ( IN OUT POOL_PRINT *Str, IN CHAR16 *Fmt, ... ) { UINT16 *AppendStr; VA_LIST Args; UINTN StringSize; CHAR16 *NewStr; AppendStr = AllocateZeroPool (0x1000); if (AppendStr == NULL) { return EFI_OUT_OF_RESOURCES; } VA_START (Args, Fmt); UnicodeVSPrint (AppendStr, 0x1000, Fmt, Args); VA_END (Args); if (NULL == Str->Str) { StringSize = StrSize (AppendStr); NewStr = AllocateZeroPool (StringSize); } else { StringSize = StrSize (AppendStr); StringSize += (StrSize (Str->Str) - sizeof (UINT16)); NewStr = ReallocatePool ( StrSize (Str->Str), StringSize, Str->Str ); } if (NewStr == NULL) { FreePool (AppendStr); return EFI_OUT_OF_RESOURCES; } Str->Str = NewStr; StrCatS (Str->Str, StringSize/sizeof(CHAR16), AppendStr); Str->Len = StringSize; FreePool (AppendStr); return EFI_SUCCESS; } MTD_NAME mMTDName[] = { { MTDTypeUnknown, L"F" }, { MTDTypeFloppy, L"FP" }, { MTDTypeHardDisk, L"HD" }, { MTDTypeCDRom, L"CD" }, { MTDTypeEnd, NULL } }; /** Function to append a 64 bit number / 25 onto the string. @param[in, out] Str The string so append onto. @param[in] Num The number to divide and append. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS AppendCSDNum2 ( IN OUT POOL_PRINT *Str, IN UINT64 Num ) { EFI_STATUS Status; UINT64 Result; UINT32 Rem; ASSERT (Str != NULL); Result = DivU64x32Remainder (Num, 25, &Rem); if (Result > 0) { Status = AppendCSDNum2 (Str, Result); if (EFI_ERROR (Status)) { return Status; } } return CatPrint (Str, L"%c", Rem + 'a'); } /** Function to append a 64 bit number onto the mapping info. @param[in, out] MappingItem The mapping info object to append onto. @param[in] Num The info to append. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS AppendCSDNum ( IN OUT DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN UINT64 Num ) { EFI_STATUS Status; ASSERT (MappingItem != NULL); if (MappingItem->Digital) { Status = CatPrint (&MappingItem->Csd, L"%ld", Num); } else { Status = AppendCSDNum2 (&MappingItem->Csd, Num); } if (!EFI_ERROR (Status)) { MappingItem->Digital = (BOOLEAN) !(MappingItem->Digital); } return Status; } /** Function to append string into the mapping info. @param[in, out] MappingItem The mapping info object to append onto. @param[in] Str The info to append. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS AppendCSDStr ( IN OUT DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN CHAR16 *Str ) { CHAR16 *Index; EFI_STATUS Status; ASSERT (Str != NULL && MappingItem != NULL); Status = EFI_SUCCESS; if (MappingItem->Digital) { // // To aVOID mult-meaning, the mapping is: // 0 1 2 3 4 5 6 7 8 9 a b c d e f // 0 16 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // for (Index = Str; *Index != 0; Index++) { switch (*Index) { case '0': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': Status = CatPrint (&MappingItem->Csd, L"%c", *Index); break; case '1': Status = CatPrint (&MappingItem->Csd, L"16"); break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': Status = CatPrint (&MappingItem->Csd, L"1%c", *Index - 'a' + '0'); break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': Status = CatPrint (&MappingItem->Csd, L"1%c", *Index - 'A' + '0'); break; } if (EFI_ERROR (Status)) { return Status; } } } else { for (Index = Str; *Index != 0; Index++) { // // The mapping is: // 0 1 2 3 4 5 6 7 8 9 a b c d e f // a b c d e f g h i j k l m n o p // if (*Index >= '0' && *Index <= '9') { Status = CatPrint (&MappingItem->Csd, L"%c", *Index - '0' + 'a'); } else if (*Index >= 'a' && *Index <= 'f') { Status = CatPrint (&MappingItem->Csd, L"%c", *Index - 'a' + 'k'); } else if (*Index >= 'A' && *Index <= 'F') { Status = CatPrint (&MappingItem->Csd, L"%c", *Index - 'A' + 'k'); } if (EFI_ERROR (Status)) { return Status; } } } MappingItem->Digital = (BOOLEAN)!(MappingItem->Digital); return (EFI_SUCCESS); } /** Function to append a Guid to the mapping item. @param[in, out] MappingItem The item to append onto. @param[in] Guid The guid to append. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS AppendCSDGuid ( DEVICE_CONSIST_MAPPING_INFO *MappingItem, EFI_GUID *Guid ) { CHAR16 Buffer[64]; ASSERT (Guid != NULL && MappingItem != NULL); UnicodeSPrint ( Buffer, 0, L"%g", Guid ); return AppendCSDStr (MappingItem, Buffer); } /** Function to compare 2 APCI device paths. @param[in] DevicePath1 The first device path to compare. @param[in] DevicePath2 The second device path to compare. @retval 0 The device paths represent the same device. @return Non zero if the devices are different, zero otherwise. **/ INTN EFIAPI DevPathCompareAcpi ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 ) { ACPI_HID_DEVICE_PATH *Acpi1; ACPI_HID_DEVICE_PATH *Acpi2; if (DevicePath1 == NULL || DevicePath2 == NULL) { return (-2); } Acpi1 = (ACPI_HID_DEVICE_PATH *) DevicePath1; Acpi2 = (ACPI_HID_DEVICE_PATH *) DevicePath2; if (Acpi1->HID > Acpi2->HID || (Acpi1->HID == Acpi2->HID && Acpi1->UID > Acpi2->UID)) { return 1; } if (Acpi1->HID == Acpi2->HID && Acpi1->UID == Acpi2->UID) { return 0; } return -1; } /** Function to compare 2 PCI device paths. @param[in] DevicePath1 The first device path to compare. @param[in] DevicePath2 The second device path to compare. @retval 0 The device paths represent the same device. @return Non zero if the devices are different, zero otherwise. **/ INTN EFIAPI DevPathComparePci ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 ) { PCI_DEVICE_PATH *Pci1; PCI_DEVICE_PATH *Pci2; ASSERT(DevicePath1 != NULL); ASSERT(DevicePath2 != NULL); Pci1 = (PCI_DEVICE_PATH *) DevicePath1; Pci2 = (PCI_DEVICE_PATH *) DevicePath2; if (Pci1->Device > Pci2->Device || (Pci1->Device == Pci2->Device && Pci1->Function > Pci2->Function)) { return 1; } if (Pci1->Device == Pci2->Device && Pci1->Function == Pci2->Function) { return 0; } return -1; } /** Do a comparison on 2 device paths. @param[in] DevicePath1 The first device path. @param[in] DevicePath2 The second device path. @retval 0 The 2 device paths are the same. @retval <0 DevicePath2 is greater than DevicePath1. @retval >0 DevicePath1 is greater than DevicePath2. **/ INTN EFIAPI DevPathCompareDefault ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 ) { UINTN DevPathSize1; UINTN DevPathSize2; ASSERT(DevicePath1 != NULL); ASSERT(DevicePath2 != NULL); DevPathSize1 = DevicePathNodeLength (DevicePath1); DevPathSize2 = DevicePathNodeLength (DevicePath2); if (DevPathSize1 > DevPathSize2) { return 1; } else if (DevPathSize1 < DevPathSize2) { return -1; } else { return CompareMem (DevicePath1, DevicePath2, DevPathSize1); } } /** DevicePathNode must be SerialHDD Channel type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialHardDrive ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { HARDDRIVE_DEVICE_PATH *Hd; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Hd = (HARDDRIVE_DEVICE_PATH *) DevicePathNode; if (MappingItem->Mtd == MTDTypeUnknown) { MappingItem->Mtd = MTDTypeHardDisk; } return AppendCSDNum (MappingItem, Hd->PartitionNumber); } /** DevicePathNode must be SerialAtapi Channel type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialAtapi ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { ATAPI_DEVICE_PATH *Atapi; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Atapi = (ATAPI_DEVICE_PATH *) DevicePathNode; return AppendCSDNum (MappingItem, (Atapi->PrimarySecondary * 2 + Atapi->SlaveMaster)); } /** DevicePathNode must be SerialCDROM Channel type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialCdRom ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { CDROM_DEVICE_PATH *Cd; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Cd = (CDROM_DEVICE_PATH *) DevicePathNode; MappingItem->Mtd = MTDTypeCDRom; return AppendCSDNum (MappingItem, Cd->BootEntry); } /** DevicePathNode must be SerialFibre Channel type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialFibre ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; FIBRECHANNEL_DEVICE_PATH *Fibre; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Fibre = (FIBRECHANNEL_DEVICE_PATH *) DevicePathNode; Status = AppendCSDNum (MappingItem, Fibre->WWN); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Fibre->Lun); } return Status; } /** DevicePathNode must be SerialUart type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialUart ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; UART_DEVICE_PATH *Uart; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Uart = (UART_DEVICE_PATH *) DevicePathNode; Status = AppendCSDNum (MappingItem, Uart->BaudRate); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Uart->DataBits); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Uart->Parity); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Uart->StopBits); } return Status; } /** DevicePathNode must be SerialUSB type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialUsb ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { USB_DEVICE_PATH *Usb; EFI_USB_IO_PROTOCOL *UsbIo; EFI_HANDLE TempHandle; EFI_STATUS Status; USB_INTERFACE_DESCRIPTOR InterfaceDesc; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Usb = (USB_DEVICE_PATH *) DevicePathNode; Status = AppendCSDNum (MappingItem, Usb->ParentPortNumber); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Usb->InterfaceNumber); } if (EFI_ERROR (Status)) { return Status; } if (PcdGetBool(PcdUsbExtendedDecode)) { Status = gBS->LocateDevicePath( &gEfiUsbIoProtocolGuid, &DevicePath, &TempHandle ); UsbIo = NULL; if (!EFI_ERROR(Status)) { Status = gBS->OpenProtocol(TempHandle, &gEfiUsbIoProtocolGuid, (VOID**)&UsbIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); } if (!EFI_ERROR(Status)) { ASSERT(UsbIo != NULL); Status = UsbIo->UsbGetInterfaceDescriptor(UsbIo, &InterfaceDesc); if (!EFI_ERROR(Status)) { if (InterfaceDesc.InterfaceClass == USB_MASS_STORE_CLASS && MappingItem->Mtd == MTDTypeUnknown) { switch (InterfaceDesc.InterfaceSubClass){ case USB_MASS_STORE_SCSI: MappingItem->Mtd = MTDTypeHardDisk; break; case USB_MASS_STORE_8070I: case USB_MASS_STORE_UFI: MappingItem->Mtd = MTDTypeFloppy; break; case USB_MASS_STORE_8020I: MappingItem->Mtd = MTDTypeCDRom; break; } } } } } return Status; } /** DevicePathNode must be SerialVendor type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialVendor ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; VENDOR_DEVICE_PATH *Vendor; SAS_DEVICE_PATH *Sas; UINTN TargetNameLength; UINTN Index; CHAR16 *Buffer; CHAR16 *NewBuffer; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Vendor = (VENDOR_DEVICE_PATH *) DevicePathNode; Status = AppendCSDGuid (MappingItem, &Vendor->Guid); if (EFI_ERROR (Status)) { return Status; } if (CompareGuid (&gEfiSasDevicePathGuid, &Vendor->Guid)) { Sas = (SAS_DEVICE_PATH *) Vendor; Status = AppendCSDNum (MappingItem, Sas->SasAddress); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Sas->Lun); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Sas->DeviceTopology); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Sas->RelativeTargetPort); } } else { TargetNameLength = MIN(DevicePathNodeLength (DevicePathNode) - sizeof (VENDOR_DEVICE_PATH), PcdGet32(PcdShellVendorExtendedDecode)); if (TargetNameLength != 0) { // // String is 2 chars per data byte, plus NULL terminator // Buffer = AllocateZeroPool (((TargetNameLength * 2) + 1) * sizeof(CHAR16)); if (Buffer == NULL) { return EFI_OUT_OF_RESOURCES; } // // Build the string data // for (Index = 0; Index < TargetNameLength; Index++) { NewBuffer = CatSPrint (Buffer, L"%02x", *((UINT8*)Vendor + sizeof (VENDOR_DEVICE_PATH) + Index)); if (NewBuffer == NULL) { Status = EFI_OUT_OF_RESOURCES; break; } Buffer = NewBuffer; } // // Append the new data block // if (!EFI_ERROR (Status)) { Status = AppendCSDStr (MappingItem, Buffer); } FreePool(Buffer); } } return Status; } /** DevicePathNode must be SerialLun type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialLun ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { DEVICE_LOGICAL_UNIT_DEVICE_PATH *Lun; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Lun = (DEVICE_LOGICAL_UNIT_DEVICE_PATH *) DevicePathNode; return AppendCSDNum (MappingItem, Lun->Lun); } /** DevicePathNode must be SerialSata type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialSata ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; SATA_DEVICE_PATH *Sata; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Sata = (SATA_DEVICE_PATH *) DevicePathNode; Status = AppendCSDNum (MappingItem, Sata->HBAPortNumber); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Sata->PortMultiplierPortNumber); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Sata->Lun); } return Status; } /** DevicePathNode must be SerialSCSI type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialIScsi ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; ISCSI_DEVICE_PATH *IScsi; UINT8 *IScsiTargetName; CHAR16 *TargetName; UINTN TargetNameLength; UINTN Index; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Status = EFI_SUCCESS; if (PcdGetBool(PcdShellDecodeIScsiMapNames)) { IScsi = (ISCSI_DEVICE_PATH *) DevicePathNode; Status = AppendCSDNum (MappingItem, IScsi->NetworkProtocol); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, IScsi->LoginOption); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, IScsi->Lun); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, IScsi->TargetPortalGroupTag); } if (EFI_ERROR (Status)) { return Status; } TargetNameLength = DevicePathNodeLength (DevicePathNode) - sizeof (ISCSI_DEVICE_PATH); if (TargetNameLength > 0) { TargetName = AllocateZeroPool ((TargetNameLength + 1) * sizeof (CHAR16)); if (TargetName == NULL) { Status = EFI_OUT_OF_RESOURCES; } else { IScsiTargetName = (UINT8 *) (IScsi + 1); for (Index = 0; Index < TargetNameLength; Index++) { TargetName[Index] = (CHAR16) IScsiTargetName[Index]; } Status = AppendCSDStr (MappingItem, TargetName); FreePool (TargetName); } } } return Status; } /** DevicePathNode must be SerialI20 type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialI2O ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { I2O_DEVICE_PATH *DevicePath_I20; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); DevicePath_I20 = (I2O_DEVICE_PATH *) DevicePathNode; return AppendCSDNum (MappingItem, DevicePath_I20->Tid); } /** DevicePathNode must be Mac Address type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialMacAddr ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { MAC_ADDR_DEVICE_PATH *Mac; UINTN HwAddressSize; UINTN Index; CHAR16 Buffer[64]; CHAR16 *PBuffer; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Mac = (MAC_ADDR_DEVICE_PATH *) DevicePathNode; HwAddressSize = sizeof (EFI_MAC_ADDRESS); if (Mac->IfType == 0x01 || Mac->IfType == 0x00) { HwAddressSize = 6; } for (Index = 0, PBuffer = Buffer; Index < HwAddressSize; Index++, PBuffer += 2) { UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) Mac->MacAddress.Addr[Index]); } return AppendCSDStr (MappingItem, Buffer); } /** DevicePathNode must be InfiniBand type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialInfiniBand ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; INFINIBAND_DEVICE_PATH *InfiniBand; UINTN Index; CHAR16 Buffer[64]; CHAR16 *PBuffer; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); InfiniBand = (INFINIBAND_DEVICE_PATH *) DevicePathNode; for (Index = 0, PBuffer = Buffer; Index < 16; Index++, PBuffer += 2) { UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) InfiniBand->PortGid[Index]); } Status = AppendCSDStr (MappingItem, Buffer); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, InfiniBand->ServiceId); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, InfiniBand->TargetPortId); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, InfiniBand->DeviceId); } return Status; } /** DevicePathNode must be IPv4 type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialIPv4 ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; IPv4_DEVICE_PATH *Ip; CHAR16 Buffer[10]; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Ip = (IPv4_DEVICE_PATH *) DevicePathNode; UnicodeSPrint ( Buffer, 0, L"%02x%02x%02x%02x", (UINTN) Ip->LocalIpAddress.Addr[0], (UINTN) Ip->LocalIpAddress.Addr[1], (UINTN) Ip->LocalIpAddress.Addr[2], (UINTN) Ip->LocalIpAddress.Addr[3] ); Status = AppendCSDStr (MappingItem, Buffer); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Ip->LocalPort); } if (!EFI_ERROR (Status)) { UnicodeSPrint ( Buffer, 0, L"%02x%02x%02x%02x", (UINTN) Ip->RemoteIpAddress.Addr[0], (UINTN) Ip->RemoteIpAddress.Addr[1], (UINTN) Ip->RemoteIpAddress.Addr[2], (UINTN) Ip->RemoteIpAddress.Addr[3] ); Status = AppendCSDStr (MappingItem, Buffer); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Ip->RemotePort); } return Status; } /** DevicePathNode must be IPv6 type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialIPv6 ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; IPv6_DEVICE_PATH *Ip; UINTN Index; CHAR16 Buffer[64]; CHAR16 *PBuffer; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Ip = (IPv6_DEVICE_PATH *) DevicePathNode; for (Index = 0, PBuffer = Buffer; Index < 16; Index++, PBuffer += 2) { UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) Ip->LocalIpAddress.Addr[Index]); } Status = AppendCSDStr (MappingItem, Buffer); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Ip->LocalPort); } if (!EFI_ERROR (Status)) { for (Index = 0, PBuffer = Buffer; Index < 16; Index++, PBuffer += 2) { UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) Ip->RemoteIpAddress.Addr[Index]); } Status = AppendCSDStr (MappingItem, Buffer); } if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Ip->RemotePort); } return Status; } /** DevicePathNode must be SCSI type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialScsi ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; SCSI_DEVICE_PATH *Scsi; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Scsi = (SCSI_DEVICE_PATH *) DevicePathNode; Status = AppendCSDNum (MappingItem, Scsi->Pun); if (!EFI_ERROR (Status)) { Status = AppendCSDNum (MappingItem, Scsi->Lun); } return Status; } /** DevicePathNode must be 1394 type and this will populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerial1394 ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { F1394_DEVICE_PATH *DevicePath_F1394; CHAR16 Buffer[20]; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); DevicePath_F1394 = (F1394_DEVICE_PATH *) DevicePathNode; UnicodeSPrint (Buffer, 0, L"%lx", DevicePath_F1394->Guid); return AppendCSDStr (MappingItem, Buffer); } /** If the node is floppy type then populate the MappingItem. @param[in] DevicePathNode The node to get info on. @param[in] MappingItem The info item to populate. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialAcpi ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { ACPI_HID_DEVICE_PATH *Acpi; ASSERT(DevicePathNode != NULL); ASSERT(MappingItem != NULL); Acpi = (ACPI_HID_DEVICE_PATH *) DevicePathNode; if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) { MappingItem->Mtd = MTDTypeFloppy; return AppendCSDNum (MappingItem, Acpi->UID); } } return EFI_SUCCESS; } /** Empty function used for unknown devices. @param[in] DevicePathNode Ignored. @param[in] MappingItem Ignored. @param[in] DevicePath Ignored. @retval EFI_OUT_OF_RESOURCES Out of resources. @retval EFI_SUCCESS The appending was successful. **/ EFI_STATUS DevPathSerialDefault ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { return EFI_SUCCESS; } DEV_PATH_CONSIST_MAPPING_TABLE DevPathConsistMappingTable[] = { { HARDWARE_DEVICE_PATH, HW_PCI_DP, DevPathSerialDefault, DevPathComparePci }, { ACPI_DEVICE_PATH, ACPI_DP, DevPathSerialAcpi, DevPathCompareAcpi }, { MESSAGING_DEVICE_PATH, MSG_ATAPI_DP, DevPathSerialAtapi, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_SCSI_DP, DevPathSerialScsi, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_FIBRECHANNEL_DP, DevPathSerialFibre, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_1394_DP, DevPathSerial1394, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_USB_DP, DevPathSerialUsb, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_I2O_DP, DevPathSerialI2O, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, DevPathSerialMacAddr, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_IPv4_DP, DevPathSerialIPv4, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_IPv6_DP, DevPathSerialIPv6, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_INFINIBAND_DP, DevPathSerialInfiniBand, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_UART_DP, DevPathSerialUart, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_VENDOR_DP, DevPathSerialVendor, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_DEVICE_LOGICAL_UNIT_DP, DevPathSerialLun, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_SATA_DP, DevPathSerialSata, DevPathCompareDefault }, { MESSAGING_DEVICE_PATH, MSG_ISCSI_DP, DevPathSerialIScsi, DevPathCompareDefault }, { MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP, DevPathSerialHardDrive, DevPathCompareDefault }, { MEDIA_DEVICE_PATH, MEDIA_CDROM_DP, DevPathSerialCdRom, DevPathCompareDefault }, { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, DevPathSerialVendor, DevPathCompareDefault }, { 0, 0, NULL, NULL } }; /** Function to determine if a device path node is Hi or not. @param[in] DevicePathNode The node to check. @retval TRUE The node is Hi. @retval FALSE The node is not Hi. **/ BOOLEAN IsHIDevicePathNode ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode ) { ACPI_HID_DEVICE_PATH *Acpi; ASSERT(DevicePathNode != NULL); if (DevicePathNode->Type == HARDWARE_DEVICE_PATH) { return TRUE; } if (DevicePathNode->Type == ACPI_DEVICE_PATH) { Acpi = (ACPI_HID_DEVICE_PATH *) DevicePathNode; switch (EISA_ID_TO_NUM (Acpi->HID)) { case 0x0301: case 0x0401: case 0x0501: case 0x0604: return FALSE; } return TRUE; } return FALSE; } /** Function to convert a standard device path structure into a Hi version. @param[in] DevicePath The device path to convert. @return the device path portion that is Hi. **/ EFI_DEVICE_PATH_PROTOCOL * GetHIDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { UINTN NonHIDevicePathNodeCount; UINTN Index; EFI_DEV_PATH Node; EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; ASSERT(DevicePath != NULL); NonHIDevicePathNodeCount = 0; HIDevicePath = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL)); SetDevicePathEndNode (HIDevicePath); Node.DevPath.Type = END_DEVICE_PATH_TYPE; Node.DevPath.SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE; Node.DevPath.Length[0] = (UINT8)sizeof (EFI_DEVICE_PATH_PROTOCOL); Node.DevPath.Length[1] = 0; while (!IsDevicePathEnd (DevicePath)) { if (IsHIDevicePathNode (DevicePath)) { for (Index = 0; Index < NonHIDevicePathNodeCount; Index++) { TempDevicePath = AppendDevicePathNode (HIDevicePath, &Node.DevPath); FreePool (HIDevicePath); HIDevicePath = TempDevicePath; } TempDevicePath = AppendDevicePathNode (HIDevicePath, DevicePath); FreePool (HIDevicePath); HIDevicePath = TempDevicePath; } else { NonHIDevicePathNodeCount++; } // // Next device path node // DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) NextDevicePathNode (DevicePath); } return HIDevicePath; } /** Function to walk the device path looking for a dumpable node. @param[in] MappingItem The Item to fill with data. @param[in] DevicePath The path of the item to get data on. @return EFI_SUCCESS Always returns success. **/ EFI_STATUS GetDeviceConsistMappingInfo ( IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { EFI_STATUS Status; SERIAL_DECODE_FUNCTION SerialFun; UINTN Index; EFI_DEVICE_PATH_PROTOCOL *OriginalDevicePath; ASSERT(DevicePath != NULL); ASSERT(MappingItem != NULL); SetMem (&MappingItem->Csd, sizeof (POOL_PRINT), 0); OriginalDevicePath = DevicePath; while (!IsDevicePathEnd (DevicePath)) { // // Find the handler to dump this device path node and // initialize with generic function in case nothing is found // for (SerialFun = DevPathSerialDefault, Index = 0; DevPathConsistMappingTable[Index].SerialFun != NULL; Index += 1) { if (DevicePathType (DevicePath) == DevPathConsistMappingTable[Index].Type && DevicePathSubType (DevicePath) == DevPathConsistMappingTable[Index].SubType ) { SerialFun = DevPathConsistMappingTable[Index].SerialFun; break; } } Status = SerialFun (DevicePath, MappingItem, OriginalDevicePath); if (EFI_ERROR (Status)) { SHELL_FREE_NON_NULL (MappingItem->Csd.Str); return Status; } // // Next device path node // DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) NextDevicePathNode (DevicePath); } return EFI_SUCCESS; } /** Function to initialize the table for creating consistent map names. @param[out] Table The pointer to pointer to pointer to DevicePathProtocol object. @retval EFI_SUCCESS The table was created successfully. **/ EFI_STATUS EFIAPI ShellCommandConsistMappingInitialize ( OUT EFI_DEVICE_PATH_PROTOCOL ***Table ) { EFI_HANDLE *HandleBuffer; UINTN HandleNum; UINTN HandleLoop; EFI_DEVICE_PATH_PROTOCOL **TempTable; EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; UINTN Index; EFI_STATUS Status; HandleBuffer = NULL; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &HandleNum, &HandleBuffer ); ASSERT_EFI_ERROR(Status); TempTable = AllocateZeroPool ((HandleNum + 1) * sizeof (EFI_DEVICE_PATH_PROTOCOL *)); if (TempTable == NULL) { return EFI_OUT_OF_RESOURCES; } for (HandleLoop = 0 ; HandleLoop < HandleNum ; HandleLoop++) { DevicePath = DevicePathFromHandle (HandleBuffer[HandleLoop]); if (DevicePath == NULL) { continue; } HIDevicePath = GetHIDevicePath (DevicePath); if (HIDevicePath == NULL) { continue; } Status = gBS->HandleProtocol( HandleBuffer[HandleLoop], &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo ); if (EFI_ERROR(Status)) { Status = gBS->HandleProtocol( HandleBuffer[HandleLoop], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&SimpleFileSystem ); if (EFI_ERROR(Status)) { FreePool (HIDevicePath); continue; } } for (Index = 0; TempTable[Index] != NULL; Index++) { if (DevicePathCompare (&TempTable[Index], &HIDevicePath) == 0) { FreePool (HIDevicePath); break; } } if (TempTable[Index] == NULL) { TempTable[Index] = HIDevicePath; } } for (Index = 0; TempTable[Index] != NULL; Index++); PerformQuickSort(TempTable, Index, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare); *Table = TempTable; if (HandleBuffer != NULL) { FreePool (HandleBuffer); } return EFI_SUCCESS; } /** Function to uninitialize the table for creating consistent map names. The parameter must have been received from ShellCommandConsistMappingInitialize. @param[out] Table The pointer to pointer to DevicePathProtocol object. @retval EFI_SUCCESS The table was deleted successfully. **/ EFI_STATUS EFIAPI ShellCommandConsistMappingUnInitialize ( EFI_DEVICE_PATH_PROTOCOL **Table ) { UINTN Index; ASSERT(Table != NULL); for (Index = 0; Table[Index] != NULL; Index++) { FreePool (Table[Index]); } FreePool (Table); return EFI_SUCCESS; } /** Create a consistent mapped name for the device specified by DevicePath based on the Table. This must be called after ShellCommandConsistMappingInitialize() and before ShellCommandConsistMappingUnInitialize() is called. @param[in] DevicePath The pointer to the dev path for the device. @param[in] Table The Table of mapping information. @retval NULL A consistent mapped name could not be created. @return A pointer to a string allocated from pool with the device name. **/ CHAR16 * EFIAPI ShellCommandConsistMappingGenMappingName ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN EFI_DEVICE_PATH_PROTOCOL **Table ) { EFI_STATUS Status; POOL_PRINT Str; DEVICE_CONSIST_MAPPING_INFO MappingInfo; EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; UINTN Index; ASSERT(DevicePath != NULL); ASSERT(Table != NULL); HIDevicePath = GetHIDevicePath (DevicePath); if (HIDevicePath == NULL) { return NULL; } for (Index = 0; Table[Index] != NULL; Index++) { if (DevicePathCompare (&Table[Index], &HIDevicePath) == 0) { break; } } FreePool (HIDevicePath); if (Table[Index] == NULL) { return NULL; } MappingInfo.Hi = Index; MappingInfo.Mtd = MTDTypeUnknown; MappingInfo.Digital = FALSE; Status = GetDeviceConsistMappingInfo (&MappingInfo, DevicePath); if (EFI_ERROR (Status)) { return NULL; } SetMem (&Str, sizeof (Str), 0); for (Index = 0; mMTDName[Index].MTDType != MTDTypeEnd; Index++) { if (MappingInfo.Mtd == mMTDName[Index].MTDType) { break; } } if (mMTDName[Index].MTDType != MTDTypeEnd) { Status = CatPrint (&Str, L"%s", mMTDName[Index].Name); } if (!EFI_ERROR (Status)) { Status = CatPrint (&Str, L"%d", (UINTN) MappingInfo.Hi); } if (!EFI_ERROR (Status) && MappingInfo.Csd.Str != NULL) { Status = CatPrint (&Str, L"%s", MappingInfo.Csd.Str); FreePool (MappingInfo.Csd.Str); } if (!EFI_ERROR (Status) && Str.Str != NULL) { Status = CatPrint (&Str, L":"); } if (EFI_ERROR (Status)) { SHELL_FREE_NON_NULL (Str.Str); return NULL; } return Str.Str; } /** Function to search the list of mappings for the node on the list based on the key. @param[in] MapKey String Key to search for on the map @return the node on the list. **/ SHELL_MAP_LIST * EFIAPI ShellCommandFindMapItem ( IN CONST CHAR16 *MapKey ) { SHELL_MAP_LIST *MapListItem; for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) ; !IsNull(&gShellMapList.Link, &MapListItem->Link) ; MapListItem = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListItem->Link) ){ if (gUnicodeCollation->StriColl(gUnicodeCollation,MapListItem->MapName,(CHAR16*)MapKey) == 0) { return (MapListItem); } } return (NULL); }