+/** Add a _PRT entry.\r
+\r
+ AmlCodeGenPrtEntry (0x0FFFF, 0, "LNKA", 0, PrtNameNode) is\r
+ equivalent of the following ASL code:\r
+ Package (4) {\r
+ 0x0FFFF, // Address: Device address (([Device Id] << 16) | 0xFFFF).\r
+ 0, // Pin: PCI pin number of the device (0-INTA, ...).\r
+ LNKA // Source: Name of the device that allocates the interrupt\r
+ // to which the above pin is connected.\r
+ 0 // Source Index: Source is assumed to only describe one\r
+ // interrupt, so let it to index 0.\r
+ }\r
+\r
+ The package is added at the tail of the list of the input _PRT node\r
+ name:\r
+ Name (_PRT, Package () {\r
+ [Pre-existing _PRT entries],\r
+ [Newly created _PRT entry]\r
+ })\r
+\r
+ Cf. ACPI 6.4 specification:\r
+ - s6.2.13 "_PRT (PCI Routing Table)"\r
+ - s6.1.1 "_ADR (Address)"\r
+\r
+ @param [in] Address Address. Cf ACPI 6.4 specification, Table 6.2:\r
+ "ADR Object Address Encodings":\r
+ High word-Device #, Low word-Function #. (for\r
+ example, device 3, function 2 is 0x00030002).\r
+ To refer to all the functions on a device #,\r
+ use a function number of FFFF).\r
+ @param [in] Pin PCI pin number of the device (0-INTA ... 3-INTD).\r
+ Must be between 0-3.\r
+ @param [in] LinkName Link Name, i.e. device in the AML NameSpace\r
+ describing the interrupt used.\r
+ The input string is copied.\r
+ @param [in] SourceIndex Source index or GSIV.\r
+ @param [in] PrtNameNode Prt Named node to add the object to ....\r
+\r
+ @retval EFI_SUCCESS Success.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AmlAddPrtEntry (\r
+ IN UINT32 Address,\r
+ IN UINT8 Pin,\r
+ IN CONST CHAR8 *LinkName,\r
+ IN UINT32 SourceIndex,\r
+ IN AML_OBJECT_NODE_HANDLE PrtNameNode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ AML_OBJECT_NODE *PrtEntryList;\r
+ AML_OBJECT_NODE *PackageNode;\r
+ AML_OBJECT_NODE *NewElementNode;\r
+\r
+ CHAR8 *AmlNameString;\r
+ UINT32 AmlNameStringSize;\r
+ AML_DATA_NODE *DataNode;\r
+\r
+ if ((Pin > 3) ||\r
+ (LinkName == NULL) ||\r
+ (PrtNameNode == NULL) ||\r
+ (AmlGetNodeType ((AML_NODE_HANDLE)PrtNameNode) != EAmlNodeObject) ||\r
+ (!AmlNodeHasOpCode (PrtNameNode, AML_NAME_OP, 0)) ||\r
+ !AmlNameOpCompareName (PrtNameNode, "_PRT"))\r
+ {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NewElementNode = NULL;\r
+ AmlNameString = NULL;\r
+ DataNode = NULL;\r
+\r
+ // Get the Package object node of the _PRT node,\r
+ // which is the 2nd fixed argument (i.e. index 1).\r
+ PrtEntryList = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (\r
+ PrtNameNode,\r
+ EAmlParseIndexTerm1\r
+ );\r
+ if ((PrtEntryList == NULL) ||\r
+ (AmlGetNodeType ((AML_NODE_HANDLE)PrtEntryList) != EAmlNodeObject) ||\r
+ (!AmlNodeHasOpCode (PrtEntryList, AML_PACKAGE_OP, 0)))\r
+ {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // The new _PRT entry.\r
+ Status = AmlCodeGenPackage (&PackageNode);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ return Status;\r
+ }\r
+\r
+ Status = AmlCodeGenInteger (Address, &NewElementNode);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = AmlVarListAddTail (\r
+ (AML_NODE_HANDLE)PackageNode,\r
+ (AML_NODE_HANDLE)NewElementNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ NewElementNode = NULL;\r
+\r
+ Status = AmlCodeGenInteger (Pin, &NewElementNode);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = AmlVarListAddTail (\r
+ (AML_NODE_HANDLE)PackageNode,\r
+ (AML_NODE_HANDLE)NewElementNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ NewElementNode = NULL;\r
+\r
+ Status = ConvertAslNameToAmlName (LinkName, &AmlNameString);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = AmlCreateDataNode (\r
+ EAmlNodeDataTypeNameString,\r
+ (UINT8 *)AmlNameString,\r
+ AmlNameStringSize,\r
+ &DataNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ // AmlNameString will be freed before returning.\r
+\r
+ Status = AmlVarListAddTail (\r
+ (AML_NODE_HANDLE)PackageNode,\r
+ (AML_NODE_HANDLE)DataNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ DataNode = NULL;\r
+\r
+ Status = AmlCodeGenInteger (SourceIndex, &NewElementNode);\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ Status = AmlVarListAddTail (\r
+ (AML_NODE_HANDLE)PackageNode,\r
+ (AML_NODE_HANDLE)NewElementNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ // Append to the the list of _PRT entries.\r
+ Status = AmlVarListAddTail (\r
+ (AML_NODE_HANDLE)PrtEntryList,\r
+ (AML_NODE_HANDLE)PackageNode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (0);\r
+ goto error_handler;\r
+ }\r
+\r
+ // Free AmlNameString before returning as it is copied\r
+ // in the call to AmlCreateDataNode().\r
+ goto exit_handler;\r
+\r
+error_handler:\r
+ AmlDeleteTree ((AML_NODE_HANDLE)PackageNode);\r
+ if (NewElementNode != NULL) {\r
+ AmlDeleteTree ((AML_NODE_HANDLE)NewElementNode);\r
+ }\r
+\r
+ if (DataNode != NULL) {\r
+ AmlDeleteTree ((AML_NODE_HANDLE)DataNode);\r
+ }\r
+\r
+exit_handler:\r
+ if (AmlNameString != NULL) {\r
+ FreePool (AmlNameString);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r