ACPI_STATUS AcpiNsInitializeDevices ( void) { ACPI_STATUS Status; ACPI_DEVICE_WALK_INFO Info; ACPI_FUNCTION_TRACE (NsInitializeDevices); /* Init counters */ Info.DeviceCount = 0; Info.Num_STA = 0; Info.Num_INI = 0; ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "Initializing Device/Processor/Thermal objects " "and executing _INI/_STA methods:\n")); /* Tree analysis: find all subtrees that contain _INI methods */ Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, AcpiNsFindIniMethods, NULL, &Info, NULL); if (ACPI_FAILURE (Status)) { goto ErrorExit; } /* Allocate the evaluation information block */ Info.EvaluateInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info.EvaluateInfo) { Status = AE_NO_MEMORY; goto ErrorExit; } /* * Execute the "global" _INI method that may appear at the root. This * support is provided for Windows compatibility (Vista+) and is not * part of the ACPI specification. */ Info.EvaluateInfo->PrefixNode = AcpiGbl_RootNode; Info.EvaluateInfo->RelativePathname = METHOD_NAME__INI; Info.EvaluateInfo->Parameters = NULL; Info.EvaluateInfo->Flags = ACPI_IGNORE_RETURN_VALUE; Status = AcpiNsEvaluate (Info.EvaluateInfo); if (ACPI_SUCCESS (Status)) { Info.Num_INI++; } /* Walk namespace to execute all _INIs on present devices */ Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, AcpiNsInitOneDevice, NULL, &Info, NULL); /* * Any _OSI requests should be completed by now. If the BIOS has * requested any Windows OSI strings, we will always truncate * I/O addresses to 16 bits -- for Windows compatibility. */ if (AcpiGbl_OsiData >= ACPI_OSI_WIN_2000) { AcpiGbl_TruncateIoAddresses = TRUE; } ACPI_FREE (Info.EvaluateInfo); if (ACPI_FAILURE (Status)) { goto ErrorExit; } ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, " Executed %u _INI methods requiring %u _STA executions " "(examined %u objects)\n", Info.Num_INI, Info.Num_STA, Info.DeviceCount)); return_ACPI_STATUS (Status); ErrorExit: ACPI_EXCEPTION ((AE_INFO, Status, "During device initialization")); return_ACPI_STATUS (Status); }
static ACPI_STATUS AcpiNsInitOneDevice ( ACPI_HANDLE ObjHandle, UINT32 NestingLevel, void *Context, void **ReturnValue) { ACPI_DEVICE_WALK_INFO *WalkInfo = ACPI_CAST_PTR (ACPI_DEVICE_WALK_INFO, Context); ACPI_EVALUATE_INFO *Info = WalkInfo->EvaluateInfo; UINT32 Flags; ACPI_STATUS Status; ACPI_NAMESPACE_NODE *DeviceNode; ACPI_FUNCTION_TRACE (NsInitOneDevice); /* We are interested in Devices, Processors and ThermalZones only */ DeviceNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle); if ((DeviceNode->Type != ACPI_TYPE_DEVICE) && (DeviceNode->Type != ACPI_TYPE_PROCESSOR) && (DeviceNode->Type != ACPI_TYPE_THERMAL)) { return_ACPI_STATUS (AE_OK); } /* * Because of an earlier namespace analysis, all subtrees that contain an * _INI method are tagged. * * If this device subtree does not contain any _INI methods, we * can exit now and stop traversing this entire subtree. */ if (!(DeviceNode->Flags & ANOBJ_SUBTREE_HAS_INI)) { return_ACPI_STATUS (AE_CTRL_DEPTH); } /* * Run _STA to determine if this device is present and functioning. We * must know this information for two important reasons (from ACPI spec): * * 1) We can only run _INI if the device is present. * 2) We must abort the device tree walk on this subtree if the device is * not present and is not functional (we will not examine the children) * * The _STA method is not required to be present under the device, we * assume the device is present if _STA does not exist. */ ACPI_DEBUG_EXEC (AcpiUtDisplayInitPathname ( ACPI_TYPE_METHOD, DeviceNode, METHOD_NAME__STA)); Status = AcpiUtExecute_STA (DeviceNode, &Flags); if (ACPI_FAILURE (Status)) { /* Ignore error and move on to next device */ return_ACPI_STATUS (AE_OK); } /* * Flags == -1 means that _STA was not found. In this case, we assume that * the device is both present and functional. * * From the ACPI spec, description of _STA: * * "If a device object (including the processor object) does not have an * _STA object, then OSPM assumes that all of the above bits are set (in * other words, the device is present, ..., and functioning)" */ if (Flags != ACPI_UINT32_MAX) { WalkInfo->Num_STA++; } /* * Examine the PRESENT and FUNCTIONING status bits * * Note: ACPI spec does not seem to specify behavior for the present but * not functioning case, so we assume functioning if present. */ if (!(Flags & ACPI_STA_DEVICE_PRESENT)) { /* Device is not present, we must examine the Functioning bit */ if (Flags & ACPI_STA_DEVICE_FUNCTIONING) { /* * Device is not present but is "functioning". In this case, * we will not run _INI, but we continue to examine the children * of this device. * * From the ACPI spec, description of _STA: (Note - no mention * of whether to run _INI or not on the device in question) * * "_STA may return bit 0 clear (not present) with bit 3 set * (device is functional). This case is used to indicate a valid * device for which no device driver should be loaded (for example, * a bridge device.) Children of this device may be present and * valid. OSPM should continue enumeration below a device whose * _STA returns this bit combination" */ return_ACPI_STATUS (AE_OK); } else { /* * Device is not present and is not functioning. We must abort the * walk of this subtree immediately -- don't look at the children * of such a device. * * From the ACPI spec, description of _INI: * * "If the _STA method indicates that the device is not present, * OSPM will not run the _INI and will not examine the children * of the device for _INI methods" */ return_ACPI_STATUS (AE_CTRL_DEPTH); } } /* * The device is present or is assumed present if no _STA exists. * Run the _INI if it exists (not required to exist) * * Note: We know there is an _INI within this subtree, but it may not be * under this particular device, it may be lower in the branch. */ ACPI_DEBUG_EXEC (AcpiUtDisplayInitPathname ( ACPI_TYPE_METHOD, DeviceNode, METHOD_NAME__INI)); ACPI_MEMSET (Info, 0, sizeof (ACPI_EVALUATE_INFO)); Info->PrefixNode = DeviceNode; Info->RelativePathname = METHOD_NAME__INI; Info->Parameters = NULL; Info->Flags = ACPI_IGNORE_RETURN_VALUE; Status = AcpiNsEvaluate (Info); if (ACPI_SUCCESS (Status)) { WalkInfo->Num_INI++; } #ifdef ACPI_DEBUG_OUTPUT else if (Status != AE_NOT_FOUND) { /* Ignore error and move on to next device */ char *ScopeName = AcpiNsGetExternalPathname (Info->Node); ACPI_EXCEPTION ((AE_INFO, Status, "during %s._INI execution", ScopeName)); ACPI_FREE (ScopeName); } #endif /* Ignore errors from above */ Status = AE_OK; /* * The _INI method has been run if present; call the Global Initialization * Handler for this device. */ if (AcpiGbl_InitHandler) { Status = AcpiGbl_InitHandler (DeviceNode, ACPI_INIT_DEVICE_INI); } return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiEvaluateObject ( ACPI_HANDLE Handle, ACPI_STRING Pathname, ACPI_OBJECT_LIST *ExternalParams, ACPI_BUFFER *ReturnBuffer) { ACPI_STATUS Status; ACPI_EVALUATE_INFO *Info; ACPI_SIZE BufferSpaceNeeded; UINT32 i; ACPI_FUNCTION_TRACE (AcpiEvaluateObject); /* Allocate and initialize the evaluation information block */ Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info) { return_ACPI_STATUS (AE_NO_MEMORY); } /* Convert and validate the device handle */ Info->PrefixNode = AcpiNsValidateHandle (Handle); if (!Info->PrefixNode) { Status = AE_BAD_PARAMETER; goto Cleanup; } /* * Get the actual namespace node for the target object. * Handles these cases: * * 1) Null node, valid pathname from root (absolute path) * 2) Node and valid pathname (path relative to Node) * 3) Node, Null pathname */ if ((Pathname) && (ACPI_IS_ROOT_PREFIX (Pathname[0]))) { /* The path is fully qualified, just evaluate by name */ Info->PrefixNode = NULL; } else if (!Handle) { /* * A handle is optional iff a fully qualified pathname is specified. * Since we've already handled fully qualified names above, this is * an error. */ if (!Pathname) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Both Handle and Pathname are NULL")); } else { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Null Handle with relative pathname [%s]", Pathname)); } Status = AE_BAD_PARAMETER; goto Cleanup; } Info->RelativePathname = Pathname; /* * Convert all external objects passed as arguments to the * internal version(s). */ if (ExternalParams && ExternalParams->Count) { Info->ParamCount = (UINT16) ExternalParams->Count; /* Warn on impossible argument count */ if (Info->ParamCount > ACPI_METHOD_NUM_ARGS) { ACPI_WARN_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS, "Excess arguments (%u) - using only %u", Info->ParamCount, ACPI_METHOD_NUM_ARGS)); Info->ParamCount = ACPI_METHOD_NUM_ARGS; } /* * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ Info->Parameters = ACPI_ALLOCATE_ZEROED ( ((ACPI_SIZE) Info->ParamCount + 1) * sizeof (void *)); if (!Info->Parameters) { Status = AE_NO_MEMORY; goto Cleanup; } /* Convert each external object in the list to an internal object */ for (i = 0; i < Info->ParamCount; i++) { Status = AcpiUtCopyEobjectToIobject ( &ExternalParams->Pointer[i], &Info->Parameters[i]); if (ACPI_FAILURE (Status)) { goto Cleanup; } } Info->Parameters[Info->ParamCount] = NULL; } #if 0 /* * Begin incoming argument count analysis. Check for too few args * and too many args. */ switch (AcpiNsGetType (Info->Node)) { case ACPI_TYPE_METHOD: /* Check incoming argument count against the method definition */ if (Info->ObjDesc->Method.ParamCount > Info->ParamCount) { ACPI_ERROR ((AE_INFO, "Insufficient arguments (%u) - %u are required", Info->ParamCount, Info->ObjDesc->Method.ParamCount)); Status = AE_MISSING_ARGUMENTS; goto Cleanup; } else if (Info->ObjDesc->Method.ParamCount < Info->ParamCount) { ACPI_WARNING ((AE_INFO, "Excess arguments (%u) - only %u are required", Info->ParamCount, Info->ObjDesc->Method.ParamCount)); /* Just pass the required number of arguments */ Info->ParamCount = Info->ObjDesc->Method.ParamCount; } /* * Any incoming external objects to be passed as arguments to the * method must be converted to internal objects */ if (Info->ParamCount) { /* * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ Info->Parameters = ACPI_ALLOCATE_ZEROED ( ((ACPI_SIZE) Info->ParamCount + 1) * sizeof (void *)); if (!Info->Parameters) { Status = AE_NO_MEMORY; goto Cleanup; } /* Convert each external object in the list to an internal object */ for (i = 0; i < Info->ParamCount; i++) { Status = AcpiUtCopyEobjectToIobject ( &ExternalParams->Pointer[i], &Info->Parameters[i]); if (ACPI_FAILURE (Status)) { goto Cleanup; } } Info->Parameters[Info->ParamCount] = NULL; } break; default: /* Warn if arguments passed to an object that is not a method */ if (Info->ParamCount) { ACPI_WARNING ((AE_INFO, "%u arguments were passed to a non-method ACPI object", Info->ParamCount)); } break; } #endif /* Now we can evaluate the object */ Status = AcpiNsEvaluate (Info); /* * If we are expecting a return value, and all went well above, * copy the return value to an external object. */ if (ReturnBuffer) { if (!Info->ReturnObject) { ReturnBuffer->Length = 0; } else { if (ACPI_GET_DESCRIPTOR_TYPE (Info->ReturnObject) == ACPI_DESC_TYPE_NAMED) { /* * If we received a NS Node as a return object, this means that * the object we are evaluating has nothing interesting to * return (such as a mutex, etc.) We return an error because * these types are essentially unsupported by this interface. * We don't check up front because this makes it easier to add * support for various types at a later date if necessary. */ Status = AE_TYPE; Info->ReturnObject = NULL; /* No need to delete a NS Node */ ReturnBuffer->Length = 0; } if (ACPI_SUCCESS (Status)) { /* Dereference Index and RefOf references */ AcpiNsResolveReferences (Info); /* Get the size of the returned object */ Status = AcpiUtGetObjectSize (Info->ReturnObject, &BufferSpaceNeeded); if (ACPI_SUCCESS (Status)) { /* Validate/Allocate/Clear caller buffer */ Status = AcpiUtInitializeBuffer (ReturnBuffer, BufferSpaceNeeded); if (ACPI_FAILURE (Status)) { /* * Caller's buffer is too small or a new one can't * be allocated */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Needed buffer size %X, %s\n", (UINT32) BufferSpaceNeeded, AcpiFormatException (Status))); } else { /* We have enough space for the object, build it */ Status = AcpiUtCopyIobjectToEobject ( Info->ReturnObject, ReturnBuffer); } } } } } if (Info->ReturnObject) { /* * Delete the internal return object. NOTE: Interpreter must be * locked to avoid race condition. */ AcpiExEnterInterpreter (); /* Remove one reference on the return object (should delete it) */ AcpiUtRemoveReference (Info->ReturnObject); AcpiExExitInterpreter (); } Cleanup: /* Free the input parameter list (if we created one) */ if (Info->Parameters) { /* Free the allocated parameter block */ AcpiUtDeleteInternalObjectList (Info->Parameters); } ACPI_FREE (Info); return_ACPI_STATUS (Status); }
static void ACPI_SYSTEM_XFACE AcpiEvAsynchExecuteGpeMethod ( void *Context) { ACPI_GPE_EVENT_INFO *GpeEventInfo = Context; ACPI_STATUS Status = AE_OK; ACPI_EVALUATE_INFO *Info; ACPI_GPE_NOTIFY_INFO *Notify; ACPI_FUNCTION_TRACE (EvAsynchExecuteGpeMethod); /* Do the correct dispatch - normal method or implicit notify */ switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)) { case ACPI_GPE_DISPATCH_NOTIFY: /* * Implicit notify. * Dispatch a DEVICE_WAKE notify to the appropriate handler. * NOTE: the request is queued for execution after this method * completes. The notify handlers are NOT invoked synchronously * from this thread -- because handlers may in turn run other * control methods. * * June 2012: Expand implicit notify mechanism to support * notifies on multiple device objects. */ Notify = GpeEventInfo->Dispatch.NotifyList; while (ACPI_SUCCESS (Status) && Notify) { Status = AcpiEvQueueNotifyRequest ( Notify->DeviceNode, ACPI_NOTIFY_DEVICE_WAKE); Notify = Notify->Next; } break; case ACPI_GPE_DISPATCH_METHOD: /* Allocate the evaluation information block */ Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info) { Status = AE_NO_MEMORY; } else { /* * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the * _Lxx/_Exx control method that corresponds to this GPE */ Info->PrefixNode = GpeEventInfo->Dispatch.MethodNode; Info->Flags = ACPI_IGNORE_RETURN_VALUE; Status = AcpiNsEvaluate (Info); ACPI_FREE (Info); } if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "while evaluating GPE method [%4.4s]", AcpiUtGetNodeName (GpeEventInfo->Dispatch.MethodNode))); } break; default: goto ErrorExit; /* Should never happen */ } /* Defer enabling of GPE until all notify handlers are done */ Status = AcpiOsExecute (OSL_NOTIFY_HANDLER, AcpiEvAsynchEnableGpe, GpeEventInfo); if (ACPI_SUCCESS (Status)) { return_VOID; } ErrorExit: AcpiEvAsynchEnableGpe (GpeEventInfo); return_VOID; }
ACPI_STATUS AcpiNsInitializeDevices ( UINT32 Flags) { ACPI_STATUS Status = AE_OK; ACPI_DEVICE_WALK_INFO Info; ACPI_HANDLE Handle; ACPI_FUNCTION_TRACE (NsInitializeDevices); if (!(Flags & ACPI_NO_DEVICE_INIT)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI Devices\n")); /* Init counters */ Info.DeviceCount = 0; Info.Num_STA = 0; Info.Num_INI = 0; ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "Initializing Device/Processor/Thermal objects " "and executing _INI/_STA methods:\n")); /* Tree analysis: find all subtrees that contain _INI methods */ Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, AcpiNsFindIniMethods, NULL, &Info, NULL); if (ACPI_FAILURE (Status)) { goto ErrorExit; } /* Allocate the evaluation information block */ Info.EvaluateInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info.EvaluateInfo) { Status = AE_NO_MEMORY; goto ErrorExit; } /* * Execute the "global" _INI method that may appear at the root. * This support is provided for Windows compatibility (Vista+) and * is not part of the ACPI specification. */ Info.EvaluateInfo->PrefixNode = AcpiGbl_RootNode; Info.EvaluateInfo->RelativePathname = METHOD_NAME__INI; Info.EvaluateInfo->Parameters = NULL; Info.EvaluateInfo->Flags = ACPI_IGNORE_RETURN_VALUE; Status = AcpiNsEvaluate (Info.EvaluateInfo); if (ACPI_SUCCESS (Status)) { Info.Num_INI++; } /* * Execute \_SB._INI. * There appears to be a strict order requirement for \_SB._INI, * which should be evaluated before any _REG evaluations. */ Status = AcpiGetHandle (NULL, "\\_SB", &Handle); if (ACPI_SUCCESS (Status)) { memset (Info.EvaluateInfo, 0, sizeof (ACPI_EVALUATE_INFO)); Info.EvaluateInfo->PrefixNode = Handle; Info.EvaluateInfo->RelativePathname = METHOD_NAME__INI; Info.EvaluateInfo->Parameters = NULL; Info.EvaluateInfo->Flags = ACPI_IGNORE_RETURN_VALUE; Status = AcpiNsEvaluate (Info.EvaluateInfo); if (ACPI_SUCCESS (Status)) { Info.Num_INI++; } } } /* * Run all _REG methods * * Note: Any objects accessed by the _REG methods will be automatically * initialized, even if they contain executable AML (see the call to * AcpiNsInitializeObjects below). * * Note: According to the ACPI specification, we actually needn't execute * _REG for SystemMemory/SystemIo operation regions, but for PCI_Config * operation regions, it is required to evaluate _REG for those on a PCI * root bus that doesn't contain _BBN object. So this code is kept here * in order not to break things. */ if (!(Flags & ACPI_NO_ADDRESS_SPACE_INIT)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Executing _REG OpRegion methods\n")); Status = AcpiEvInitializeOpRegions (); if (ACPI_FAILURE (Status)) { goto ErrorExit; } } if (!(Flags & ACPI_NO_DEVICE_INIT)) { /* Walk namespace to execute all _INIs on present devices */ Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, AcpiNsInitOneDevice, NULL, &Info, NULL); /* * Any _OSI requests should be completed by now. If the BIOS has * requested any Windows OSI strings, we will always truncate * I/O addresses to 16 bits -- for Windows compatibility. */ if (AcpiGbl_OsiData >= ACPI_OSI_WIN_2000) { AcpiGbl_TruncateIoAddresses = TRUE; } ACPI_FREE (Info.EvaluateInfo); if (ACPI_FAILURE (Status)) { goto ErrorExit; } ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, " Executed %u _INI methods requiring %u _STA executions " "(examined %u objects)\n", Info.Num_INI, Info.Num_STA, Info.DeviceCount)); } return_ACPI_STATUS (Status); ErrorExit: ACPI_EXCEPTION ((AE_INFO, Status, "During device initialization")); return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiEvExecuteRegMethod ( ACPI_OPERAND_OBJECT *RegionObj, UINT32 Function) { ACPI_EVALUATE_INFO *Info; ACPI_OPERAND_OBJECT *Args[3]; ACPI_OPERAND_OBJECT *RegionObj2; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (EvExecuteRegMethod); RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); if (!RegionObj2) { return_ACPI_STATUS (AE_NOT_EXIST); } if (RegionObj2->Extra.Method_REG == NULL) { return_ACPI_STATUS (AE_OK); } /* Allocate and initialize the evaluation information block */ Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info) { return_ACPI_STATUS (AE_NO_MEMORY); } Info->PrefixNode = RegionObj2->Extra.Method_REG; Info->RelativePathname = NULL; Info->Parameters = Args; Info->Flags = ACPI_IGNORE_RETURN_VALUE; /* * The _REG method has two arguments: * * Arg0 - Integer: * Operation region space ID Same value as RegionObj->Region.SpaceId * * Arg1 - Integer: * connection status 1 for connecting the handler, 0 for disconnecting * the handler (Passed as a parameter) */ Args[0] = AcpiUtCreateIntegerObject ((UINT64) RegionObj->Region.SpaceId); if (!Args[0]) { Status = AE_NO_MEMORY; goto Cleanup1; } Args[1] = AcpiUtCreateIntegerObject ((UINT64) Function); if (!Args[1]) { Status = AE_NO_MEMORY; goto Cleanup2; } Args[2] = NULL; /* Terminate list */ /* Execute the method, no return value */ ACPI_DEBUG_EXEC ( AcpiUtDisplayInitPathname (ACPI_TYPE_METHOD, Info->PrefixNode, NULL)); Status = AcpiNsEvaluate (Info); AcpiUtRemoveReference (Args[1]); Cleanup2: AcpiUtRemoveReference (Args[0]); Cleanup1: ACPI_FREE (Info); return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiEvaluateObject ( ACPI_HANDLE Handle, ACPI_STRING Pathname, ACPI_OBJECT_LIST *ExternalParams, ACPI_BUFFER *ReturnBuffer) { ACPI_STATUS Status; ACPI_EVALUATE_INFO *Info; ACPI_SIZE BufferSpaceNeeded; UINT32 i; ACPI_FUNCTION_TRACE (AcpiEvaluateObject); /* Allocate and initialize the evaluation information block */ Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info) { return_ACPI_STATUS (AE_NO_MEMORY); } Info->Pathname = Pathname; /* Convert and validate the device handle */ Info->PrefixNode = AcpiNsValidateHandle (Handle); if (!Info->PrefixNode) { Status = AE_BAD_PARAMETER; goto Cleanup; } /* * If there are parameters to be passed to a control method, the external * objects must all be converted to internal objects */ if (ExternalParams && ExternalParams->Count) { /* * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ Info->Parameters = ACPI_ALLOCATE_ZEROED ( ((ACPI_SIZE) ExternalParams->Count + 1) * sizeof (void *)); if (!Info->Parameters) { Status = AE_NO_MEMORY; goto Cleanup; } /* Convert each external object in the list to an internal object */ for (i = 0; i < ExternalParams->Count; i++) { Status = AcpiUtCopyEobjectToIobject ( &ExternalParams->Pointer[i], &Info->Parameters[i]); if (ACPI_FAILURE (Status)) { goto Cleanup; } } Info->Parameters[ExternalParams->Count] = NULL; } /* * Three major cases: * 1) Fully qualified pathname * 2) No handle, not fully qualified pathname (error) * 3) Valid handle */ if ((Pathname) && (AcpiNsValidRootPrefix (Pathname[0]))) { /* The path is fully qualified, just evaluate by name */ Info->PrefixNode = NULL; Status = AcpiNsEvaluate (Info); } else if (!Handle) { /* * A handle is optional iff a fully qualified pathname is specified. * Since we've already handled fully qualified names above, this is * an error */ if (!Pathname) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Both Handle and Pathname are NULL")); } else { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Null Handle with relative pathname [%s]", Pathname)); } Status = AE_BAD_PARAMETER; } else { /* We have a namespace a node and a possible relative path */ Status = AcpiNsEvaluate (Info); } /* * If we are expecting a return value, and all went well above, * copy the return value to an external object. */ if (ReturnBuffer) { if (!Info->ReturnObject) { ReturnBuffer->Length = 0; } else { if (ACPI_GET_DESCRIPTOR_TYPE (Info->ReturnObject) == ACPI_DESC_TYPE_NAMED) { /* * If we received a NS Node as a return object, this means that * the object we are evaluating has nothing interesting to * return (such as a mutex, etc.) We return an error because * these types are essentially unsupported by this interface. * We don't check up front because this makes it easier to add * support for various types at a later date if necessary. */ Status = AE_TYPE; Info->ReturnObject = NULL; /* No need to delete a NS Node */ ReturnBuffer->Length = 0; } if (ACPI_SUCCESS (Status)) { /* Dereference Index and RefOf references */ AcpiNsResolveReferences (Info); /* Get the size of the returned object */ Status = AcpiUtGetObjectSize (Info->ReturnObject, &BufferSpaceNeeded); if (ACPI_SUCCESS (Status)) { /* Validate/Allocate/Clear caller buffer */ Status = AcpiUtInitializeBuffer (ReturnBuffer, BufferSpaceNeeded); if (ACPI_FAILURE (Status)) { /* * Caller's buffer is too small or a new one can't * be allocated */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Needed buffer size %X, %s\n", (UINT32) BufferSpaceNeeded, AcpiFormatException (Status))); } else { /* We have enough space for the object, build it */ Status = AcpiUtCopyIobjectToEobject (Info->ReturnObject, ReturnBuffer); } } } } } if (Info->ReturnObject) { /* * Delete the internal return object. NOTE: Interpreter must be * locked to avoid race condition. */ AcpiExEnterInterpreter (); /* Remove one reference on the return object (should delete it) */ AcpiUtRemoveReference (Info->ReturnObject); AcpiExExitInterpreter (); } Cleanup: /* Free the input parameter list (if we created one) */ if (Info->Parameters) { /* Free the allocated parameter block */ AcpiUtDeleteInternalObjectList (Info->Parameters); } ACPI_FREE (Info); return_ACPI_STATUS (Status); }
static void AcpiNsExecModuleCode ( ACPI_OPERAND_OBJECT *MethodObj, ACPI_EVALUATE_INFO *Info) { ACPI_OPERAND_OBJECT *ParentObj; ACPI_NAMESPACE_NODE *ParentNode; ACPI_OBJECT_TYPE Type; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (NsExecModuleCode); /* * Get the parent node. We cheat by using the NextObject field * of the method object descriptor. */ ParentNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, MethodObj->Method.NextObject); Type = AcpiNsGetType (ParentNode); /* * Get the region handler and save it in the method object. We may need * this if an operation region declaration causes a _REG method to be run. * * We can't do this in AcpiPsLinkModuleCode because * AcpiGbl_RootNode->Object is NULL at PASS1. */ if ((Type == ACPI_TYPE_DEVICE) && ParentNode->Object) { MethodObj->Method.Dispatch.Handler = ParentNode->Object->Device.Handler; } /* Must clear NextObject (AcpiNsAttachObject needs the field) */ MethodObj->Method.NextObject = NULL; /* Initialize the evaluation information block */ ACPI_MEMSET (Info, 0, sizeof (ACPI_EVALUATE_INFO)); Info->PrefixNode = ParentNode; /* * Get the currently attached parent object. Add a reference, because the * ref count will be decreased when the method object is installed to * the parent node. */ ParentObj = AcpiNsGetAttachedObject (ParentNode); if (ParentObj) { AcpiUtAddReference (ParentObj); } /* Install the method (module-level code) in the parent node */ Status = AcpiNsAttachObject (ParentNode, MethodObj, ACPI_TYPE_METHOD); if (ACPI_FAILURE (Status)) { goto Exit; } /* Execute the parent node as a control method */ Status = AcpiNsEvaluate (Info); ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Executed module-level code at %p\n", MethodObj->Method.AmlStart)); /* Delete a possible implicit return value (in slack mode) */ if (Info->ReturnObject) { AcpiUtRemoveReference (Info->ReturnObject); } /* Detach the temporary method object */ AcpiNsDetachObject (ParentNode); /* Restore the original parent object */ if (ParentObj) { Status = AcpiNsAttachObject (ParentNode, ParentObj, Type); } else { ParentNode->Type = (UINT8) Type; } Exit: if (ParentObj) { AcpiUtRemoveReference (ParentObj); } return_VOID; }
ACPI_STATUS AcpiEvExecuteRegMethod ( ACPI_OPERAND_OBJECT *RegionObj, UINT32 Function) { ACPI_EVALUATE_INFO *Info; ACPI_OPERAND_OBJECT *Args[3]; ACPI_OPERAND_OBJECT *RegionObj2; const ACPI_NAME *RegNamePtr = ACPI_CAST_PTR (ACPI_NAME, METHOD_NAME__REG); ACPI_NAMESPACE_NODE *MethodNode; ACPI_NAMESPACE_NODE *Node; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (EvExecuteRegMethod); if (!AcpiGbl_NamespaceInitialized || RegionObj->Region.Handler == NULL) { return_ACPI_STATUS (AE_OK); } RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); if (!RegionObj2) { return_ACPI_STATUS (AE_NOT_EXIST); } /* * Find any "_REG" method associated with this region definition. * The method should always be updated as this function may be * invoked after a namespace change. */ Node = RegionObj->Region.Node->Parent; Status = AcpiNsSearchOneScope ( *RegNamePtr, Node, ACPI_TYPE_METHOD, &MethodNode); if (ACPI_SUCCESS (Status)) { /* * The _REG method is optional and there can be only one per * region definition. This will be executed when the handler is * attached or removed. */ RegionObj2->Extra.Method_REG = MethodNode; } if (RegionObj2->Extra.Method_REG == NULL) { return_ACPI_STATUS (AE_OK); } /* _REG(DISCONNECT) should be paired with _REG(CONNECT) */ if ((Function == ACPI_REG_CONNECT && RegionObj->Common.Flags & AOPOBJ_REG_CONNECTED) || (Function == ACPI_REG_DISCONNECT && !(RegionObj->Common.Flags & AOPOBJ_REG_CONNECTED))) { return_ACPI_STATUS (AE_OK); } /* Allocate and initialize the evaluation information block */ Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info) { return_ACPI_STATUS (AE_NO_MEMORY); } Info->PrefixNode = RegionObj2->Extra.Method_REG; Info->RelativePathname = NULL; Info->Parameters = Args; Info->Flags = ACPI_IGNORE_RETURN_VALUE; /* * The _REG method has two arguments: * * Arg0 - Integer: * Operation region space ID Same value as RegionObj->Region.SpaceId * * Arg1 - Integer: * connection status 1 for connecting the handler, 0 for disconnecting * the handler (Passed as a parameter) */ Args[0] = AcpiUtCreateIntegerObject ((UINT64) RegionObj->Region.SpaceId); if (!Args[0]) { Status = AE_NO_MEMORY; goto Cleanup1; } Args[1] = AcpiUtCreateIntegerObject ((UINT64) Function); if (!Args[1]) { Status = AE_NO_MEMORY; goto Cleanup2; } Args[2] = NULL; /* Terminate list */ /* Execute the method, no return value */ ACPI_DEBUG_EXEC ( AcpiUtDisplayInitPathname (ACPI_TYPE_METHOD, Info->PrefixNode, NULL)); Status = AcpiNsEvaluate (Info); AcpiUtRemoveReference (Args[1]); if (ACPI_FAILURE (Status)) { goto Cleanup2; } if (Function == ACPI_REG_CONNECT) { RegionObj->Common.Flags |= AOPOBJ_REG_CONNECTED; } else { RegionObj->Common.Flags &= ~AOPOBJ_REG_CONNECTED; } Cleanup2: AcpiUtRemoveReference (Args[0]); Cleanup1: ACPI_FREE (Info); return_ACPI_STATUS (Status); }
static void ACPI_SYSTEM_XFACE AcpiEvAsynchExecuteGpeMethod ( void *Context) { ACPI_GPE_EVENT_INFO *GpeEventInfo = Context; ACPI_STATUS Status; ACPI_GPE_EVENT_INFO *LocalGpeEventInfo; ACPI_EVALUATE_INFO *Info; ACPI_GPE_NOTIFY_INFO *Notify; ACPI_FUNCTION_TRACE (EvAsynchExecuteGpeMethod); /* Allocate a local GPE block */ LocalGpeEventInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_EVENT_INFO)); if (!LocalGpeEventInfo) { ACPI_EXCEPTION ((AE_INFO, AE_NO_MEMORY, "while handling a GPE")); return_VOID; } Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (Status)) { ACPI_FREE (LocalGpeEventInfo); return_VOID; } /* Must revalidate the GpeNumber/GpeBlock */ if (!AcpiEvValidGpeEvent (GpeEventInfo)) { Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS); ACPI_FREE (LocalGpeEventInfo); return_VOID; } /* * Take a snapshot of the GPE info for this level - we copy the info to * prevent a race condition with RemoveHandler/RemoveBlock. */ ACPI_MEMCPY (LocalGpeEventInfo, GpeEventInfo, sizeof (ACPI_GPE_EVENT_INFO)); Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (Status)) { ACPI_FREE (LocalGpeEventInfo); return_VOID; } /* Do the correct dispatch - normal method or implicit notify */ switch (LocalGpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) { case ACPI_GPE_DISPATCH_NOTIFY: /* * Implicit notify. * Dispatch a DEVICE_WAKE notify to the appropriate handler. * NOTE: the request is queued for execution after this method * completes. The notify handlers are NOT invoked synchronously * from this thread -- because handlers may in turn run other * control methods. * * June 2012: Expand implicit notify mechanism to support * notifies on multiple device objects. */ Notify = LocalGpeEventInfo->Dispatch.NotifyList; while (ACPI_SUCCESS (Status) && Notify) { Status = AcpiEvQueueNotifyRequest (Notify->DeviceNode, ACPI_NOTIFY_DEVICE_WAKE); Notify = Notify->Next; } break; case ACPI_GPE_DISPATCH_METHOD: /* Allocate the evaluation information block */ Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info) { Status = AE_NO_MEMORY; } else { /* * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the * _Lxx/_Exx control method that corresponds to this GPE */ Info->PrefixNode = LocalGpeEventInfo->Dispatch.MethodNode; Info->Flags = ACPI_IGNORE_RETURN_VALUE; Status = AcpiNsEvaluate (Info); ACPI_FREE (Info); } if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "while evaluating GPE method [%4.4s]", AcpiUtGetNodeName (LocalGpeEventInfo->Dispatch.MethodNode))); } break; default: return_VOID; /* Should never happen */ } /* Defer enabling of GPE until all notify handlers are done */ Status = AcpiOsExecute (OSL_NOTIFY_HANDLER, AcpiEvAsynchEnableGpe, LocalGpeEventInfo); if (ACPI_FAILURE (Status)) { ACPI_FREE (LocalGpeEventInfo); } return_VOID; }
ACPI_STATUS AcpiUtEvaluateObject ( ACPI_NAMESPACE_NODE *PrefixNode, char *Path, UINT32 ExpectedReturnBtypes, ACPI_OPERAND_OBJECT **ReturnDesc) { ACPI_EVALUATE_INFO *Info; ACPI_STATUS Status; UINT32 ReturnBtype; ACPI_FUNCTION_TRACE (UtEvaluateObject); /* Allocate the evaluation information block */ Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info) { return_ACPI_STATUS (AE_NO_MEMORY); } Info->PrefixNode = PrefixNode; Info->Pathname = Path; /* Evaluate the object/method */ Status = AcpiNsEvaluate (Info); if (ACPI_FAILURE (Status)) { if (Status == AE_NOT_FOUND) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s.%s] was not found\n", AcpiUtGetNodeName (PrefixNode), Path)); } else { ACPI_ERROR_METHOD ("Method execution failed", PrefixNode, Path, Status); } goto Cleanup; } /* Did we get a return object? */ if (!Info->ReturnObject) { if (ExpectedReturnBtypes) { ACPI_ERROR_METHOD ("No object was returned from", PrefixNode, Path, AE_NOT_EXIST); Status = AE_NOT_EXIST; } goto Cleanup; } /* Map the return object type to the bitmapped type */ switch ((Info->ReturnObject)->Common.Type) { case ACPI_TYPE_INTEGER: ReturnBtype = ACPI_BTYPE_INTEGER; break; case ACPI_TYPE_BUFFER: ReturnBtype = ACPI_BTYPE_BUFFER; break; case ACPI_TYPE_STRING: ReturnBtype = ACPI_BTYPE_STRING; break; case ACPI_TYPE_PACKAGE: ReturnBtype = ACPI_BTYPE_PACKAGE; break; default: ReturnBtype = 0; break; } if ((AcpiGbl_EnableInterpreterSlack) && (!ExpectedReturnBtypes)) { /* * We received a return object, but one was not expected. This can * happen frequently if the "implicit return" feature is enabled. * Just delete the return object and return AE_OK. */ AcpiUtRemoveReference (Info->ReturnObject); goto Cleanup; } /* Is the return object one of the expected types? */ if (!(ExpectedReturnBtypes & ReturnBtype)) { ACPI_ERROR_METHOD ("Return object type is incorrect", PrefixNode, Path, AE_TYPE); ACPI_ERROR ((AE_INFO, "Type returned from %s was incorrect: %s, expected Btypes: %X", Path, AcpiUtGetObjectTypeName (Info->ReturnObject), ExpectedReturnBtypes)); /* On error exit, we must delete the return object */ AcpiUtRemoveReference (Info->ReturnObject); Status = AE_TYPE; goto Cleanup; } /* Object type is OK, return it */ *ReturnDesc = Info->ReturnObject; Cleanup: ACPI_FREE (Info); return_ACPI_STATUS (Status); }