/** @file | |
Acpi Helper | |
Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Library/BaseLib.h> | |
#include <Library/DebugLib.h> | |
// Module specific include files. | |
#include <Library/AcpiHelperLib.h> | |
/** Convert a hex number to its ASCII code. | |
@param [in] Hex Hex number to convert. | |
Must be 0 <= x < 16. | |
@return The ASCII code corresponding to x. | |
-1 if error. | |
**/ | |
UINT8 | |
EFIAPI | |
AsciiFromHex ( | |
IN UINT8 Hex | |
) | |
{ | |
if (Hex < 10) { | |
return (UINT8)(Hex + '0'); | |
} | |
if (Hex < 16) { | |
return (UINT8)(Hex - 10 + 'A'); | |
} | |
ASSERT (FALSE); | |
return (UINT8)-1; | |
} | |
/** Convert an ASCII char representing an hexadecimal number | |
to its integer value. | |
@param [in] Char Char to convert. | |
Must be between '0'-'9' or 'A'-'F' or 'a'-'f'. | |
@return The corresponding integer (between 0-16). | |
-1 if error. | |
**/ | |
UINT8 | |
EFIAPI | |
HexFromAscii ( | |
IN CHAR8 Char | |
) | |
{ | |
if ((Char >= '0') && (Char <= '9')) { | |
return (UINT8)(Char - '0'); | |
} | |
if ((Char >= 'A') && (Char <= 'F')) { | |
return (UINT8)(Char - 'A' + 10); | |
} | |
if ((Char >= 'a') && (Char <= 'f')) { | |
return (UINT8)(Char - 'a' + 10); | |
} | |
ASSERT (FALSE); | |
return (UINT8)-1; | |
} | |
/** Check if a HID is a valid PNP ID. | |
@param [in] Hid The Hid to validate. | |
@retval TRUE The Hid is a valid PNP ID. | |
@retval FALSE The Hid is not a valid PNP ID. | |
**/ | |
BOOLEAN | |
IsValidPnpId ( | |
IN CONST CHAR8 *Hid | |
) | |
{ | |
UINTN Index; | |
if (AsciiStrLen (Hid) != 7) { | |
return FALSE; | |
} | |
// A valid PNP ID must be of the form "AAA####" | |
// where A is an uppercase letter and # is a hex digit. | |
for (Index = 0; Index < 3; Index++) { | |
if (!IS_UPPER_CHAR (Hid[Index])) { | |
return FALSE; | |
} | |
} | |
for (Index = 3; Index < 7; Index++) { | |
if (!IS_UPPER_HEX (Hid[Index])) { | |
return FALSE; | |
} | |
} | |
return TRUE; | |
} | |
/** Check if a HID is a valid ACPI ID. | |
@param [in] Hid The Hid to validate. | |
@retval TRUE The Hid is a valid ACPI ID. | |
@retval FALSE The Hid is not a valid ACPI ID. | |
**/ | |
BOOLEAN | |
IsValidAcpiId ( | |
IN CONST CHAR8 *Hid | |
) | |
{ | |
UINTN Index; | |
if (AsciiStrLen (Hid) != 8) { | |
return FALSE; | |
} | |
// A valid ACPI ID must be of the form "NNNN####" | |
// where N is an uppercase letter or a digit ('0'-'9') | |
// and # is a hex digit. | |
for (Index = 0; Index < 4; Index++) { | |
if (!(IS_UPPER_CHAR (Hid[Index]) || IS_DIGIT (Hid[Index]))) { | |
return FALSE; | |
} | |
} | |
for (Index = 4; Index < 8; Index++) { | |
if (!IS_UPPER_HEX (Hid[Index])) { | |
return FALSE; | |
} | |
} | |
return TRUE; | |
} | |
/** Convert a EisaId string to its compressed UINT32 equivalent. | |
Cf. ACPI 6.4 specification, s19.3.4 "ASL Macros": "Eisaid" | |
@param [in] EisaIdStr Input EisaId string. | |
@param [out] EisaIdInt Output EisaId UINT32 (compressed). | |
@retval EFI_SUCCESS The function completed successfully. | |
@retval EFI_INVALID_PARAMETER Invalid parameter. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
AmlGetEisaIdFromString ( | |
IN CONST CHAR8 *EisaIdStr, | |
OUT UINT32 *EisaIdInt | |
) | |
{ | |
if ((EisaIdStr == NULL) || | |
(!IsValidPnpId (EisaIdStr)) || | |
(EisaIdInt == NULL)) | |
{ | |
ASSERT (0); | |
return EFI_INVALID_PARAMETER; | |
} | |
/* Cf. ACPI 6.4 specification, s19.3.4 "ASL Macros": "Eisaid" | |
Converts and compresses the 7-character text argument into its corresponding | |
4-byte numeric EISA ID encoding (Integer). This can be used when declaring | |
IDs for devices that are EISA IDs. | |
The algorithm used to convert the TextID is as shown in the following | |
example: | |
Starting with a seven character input string "PNP0303", we want to create | |
a DWordConst. This string contains a three character manufacturer code | |
"PNP", a three character hex product identifier "030", and a one character | |
revision identifier "3". | |
The compressed manufacturer code is created as follows: | |
1) Find hex ASCII value for each letter | |
2) Subtract 40h from each ASCII value | |
3) Retain 5 least significant bits for each letter and discard remaining | |
0's: | |
Byte 0: | |
Bit 7: reserved (0) | |
Bit 6-2: 1st character of compressed mfg code "P" | |
Bit 1-0: Upper 2 bits of 2nd character of mfg code "N" | |
Byte 1: | |
Bit 7-5: Lower 3 bits of 2nd character of mfg code "N" | |
Bit 4-0: 3rd character of mfg code "P" | |
Byte 2: | |
Bit 7-4: 1st hex digit of product number "0" | |
Bit 3-0: 2nd hex digit of product number "3" | |
Byte 3: | |
Bit 7-4: 3rd hex digit of product number "0" | |
Bit 3-0: 4th hex digit of product number "3" | |
*/ | |
*EisaIdInt = SwapBytes32 ( | |
((EisaIdStr[0] - 0x40) << 26) | | |
((EisaIdStr[1] - 0x40) << 21) | | |
((EisaIdStr[2] - 0x40) << 16) | | |
(HexFromAscii (EisaIdStr[3]) << 12) | | |
(HexFromAscii (EisaIdStr[4]) << 8) | | |
(HexFromAscii (EisaIdStr[5]) << 4) | | |
(HexFromAscii (EisaIdStr[6])) | |
); | |
return EFI_SUCCESS; | |
} |