ACPI_STATUS AcpiDsRestartControlMethod ( ACPI_WALK_STATE *WalkState, ACPI_OPERAND_OBJECT *ReturnDesc) { ACPI_STATUS Status; int SameAsImplicitReturn; ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", AcpiUtGetNodeName (WalkState->MethodNode), WalkState->MethodCallOp, ReturnDesc)); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", WalkState->ReturnUsed, WalkState->Results, WalkState)); /* Did the called method return a value? */ if (ReturnDesc) { /* Is the implicit return object the same as the return desc? */ SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc); /* Are we actually going to use the return value? */ if (WalkState->ReturnUsed) { /* Save the return value from the previous method */ Status = AcpiDsResultPush (ReturnDesc, WalkState); if (ACPI_FAILURE (Status)) { AcpiUtRemoveReference (ReturnDesc); return_ACPI_STATUS (Status); } /* * Save as THIS method's return value in case it is returned * immediately to yet another method */ WalkState->ReturnDesc = ReturnDesc; } /* * The following code is the optional support for the so-called * "implicit return". Some AML code assumes that the last value of the * method is "implicitly" returned to the caller, in the absence of an * explicit return value. * * Just save the last result of the method as the return value. * * NOTE: this is optional because the ASL language does not actually * support this behavior. */ else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || SameAsImplicitReturn) { /* * Delete the return value if it will not be used by the * calling method or remove one reference if the explicit return * is the same as the implicit return value. */ AcpiUtRemoveReference (ReturnDesc); } } return_ACPI_STATUS (AE_OK); }
acpi_status acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, union acpi_parse_object *op) { acpi_status status; union acpi_operand_object *obj_desc; union acpi_operand_object *operand_desc; struct acpi_namespace_node *node; union acpi_parse_object *next_op; ACPI_FUNCTION_TRACE_PTR(ds_eval_region_operands, op); /* * This is where we evaluate the address and length fields of the * op_region declaration */ node = op->common.node; /* next_op points to the op that holds the space_iD */ next_op = op->common.value.arg; /* next_op points to address op */ next_op = next_op->common.next; /* Evaluate/create the address and length operands */ status = acpi_ds_create_operands(walk_state, next_op); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Resolve the length and address operands to numbers */ status = acpi_ex_resolve_operands(op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { return_ACPI_STATUS(AE_NOT_EXIST); } /* * Get the length operand and save it * (at Top of stack) */ operand_desc = walk_state->operands[walk_state->num_operands - 1]; obj_desc->region.length = (u32) operand_desc->integer.value; acpi_ut_remove_reference(operand_desc); /* * Get the address and save it * (at top of stack - 1) */ operand_desc = walk_state->operands[walk_state->num_operands - 2]; obj_desc->region.address = (acpi_physical_address) operand_desc->integer.value; acpi_ut_remove_reference(operand_desc); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", obj_desc, ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address), obj_desc->region.length)); /* Now the address and length are valid for this opregion */ obj_desc->region.flags |= AOPOBJ_DATA_VALID; return_ACPI_STATUS(status); }
ACPI_STATUS AcpiRsConvertAmlToResources ( UINT8 *Aml, UINT32 Length, UINT32 Offset, UINT8 ResourceIndex, void **Context) { ACPI_RESOURCE **ResourcePtr = ACPI_CAST_INDIRECT_PTR ( ACPI_RESOURCE, Context); ACPI_RESOURCE *Resource; AML_RESOURCE *AmlResource; ACPI_RSCONVERT_INFO *ConversionTable; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (RsConvertAmlToResources); /* * Check that the input buffer and all subsequent pointers into it * are aligned on a native word boundary. Most important on IA64 */ Resource = *ResourcePtr; if (ACPI_IS_MISALIGNED (Resource)) { ACPI_WARNING ((AE_INFO, "Misaligned resource pointer %p", Resource)); } /* Get the appropriate conversion info table */ AmlResource = ACPI_CAST_PTR (AML_RESOURCE, Aml); if (AcpiUtGetResourceType (Aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) { if (AmlResource->CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE) { ConversionTable = NULL; } else { /* This is an I2C, SPI, or UART SerialBus descriptor */ ConversionTable = AcpiGbl_ConvertResourceSerialBusDispatch [ AmlResource->CommonSerialBus.Type]; } } else { ConversionTable = AcpiGbl_GetResourceDispatch[ResourceIndex]; } if (!ConversionTable) { ACPI_ERROR ((AE_INFO, "Invalid/unsupported resource descriptor: Type 0x%2.2X", ResourceIndex)); return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); } /* Convert the AML byte stream resource to a local resource struct */ Status = AcpiRsConvertAmlToResource ( Resource, AmlResource, ConversionTable); if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "Could not convert AML resource (Type 0x%X)", *Aml)); return_ACPI_STATUS (Status); } ACPI_DEBUG_PRINT ((ACPI_DB_RESOURCES, "Type %.2X, AmlLength %.2X InternalLength %.2X\n", AcpiUtGetResourceType (Aml), Length, Resource->Length)); /* Point to the next structure in the output buffer */ *ResourcePtr = ACPI_NEXT_RESOURCE (Resource); return_ACPI_STATUS (AE_OK); }
static int acpi_processor_get_psd(struct acpi_processor *pr) { int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"}; struct acpi_buffer state = {0, NULL}; union acpi_object *psd = NULL; struct acpi_psd_package *pdomain; status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer); if (ACPI_FAILURE(status)) { return -ENODEV; } psd = (union acpi_object *) buffer.pointer; if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; goto end; } if (psd->package.count != 1) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; goto end; } pdomain = &(pr->performance->domain_info); state.length = sizeof(struct acpi_psd_package); state.pointer = pdomain; status = acpi_extract_package(&(psd->package.elements[0]), &format, &state); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; goto end; } if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n")); result = -EFAULT; goto end; } if (pdomain->revision != ACPI_PSD_REV0_REVISION) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n")); result = -EFAULT; goto end; } if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL && pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY && pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD:coord_type\n")); result = -EFAULT; goto end; } end: kfree(buffer.pointer); return result; }
/******************************************************************************* * * FUNCTION: ns_one_complete_parse * * PARAMETERS: pass_number - 1 or 2 * table_desc - The table to be parsed. * * RETURN: Status * * DESCRIPTION: Perform one complete parse of an ACPI/AML table. * ******************************************************************************/ acpi_status acpi_ns_one_complete_parse(u32 pass_number, u32 table_index, struct acpi_namespace_node *start_node) { union acpi_parse_object *parse_root; acpi_status status; u32 aml_length; u8 *aml_start; struct acpi_walk_state *walk_state; struct acpi_table_header *table; acpi_owner_id owner_id; ACPI_FUNCTION_TRACE(ns_one_complete_parse); status = acpi_tb_get_owner_id(table_index, &owner_id); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Create and init a Root Node */ parse_root = acpi_ps_create_scope_op(); if (!parse_root) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Create and initialize a new walk state */ walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL); if (!walk_state) { acpi_ps_free_op(parse_root); return_ACPI_STATUS(AE_NO_MEMORY); } status = acpi_get_table_by_index(table_index, &table); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); acpi_ps_free_op(parse_root); return_ACPI_STATUS(status); } /* Table must consist of at least a complete header */ if (table->length < sizeof(struct acpi_table_header)) { status = AE_BAD_HEADER; } else { aml_start = (u8 *) table + sizeof(struct acpi_table_header); aml_length = table->length - sizeof(struct acpi_table_header); status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, aml_start, aml_length, NULL, (u8) pass_number); } if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); goto cleanup; } /* start_node is the default location to load the table */ if (start_node && start_node != acpi_gbl_root_node) { status = acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD, walk_state); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); goto cleanup; } } /* Parse the AML */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n", (unsigned)pass_number)); status = acpi_ps_parse_aml(walk_state); cleanup: acpi_ps_delete_parse_tree(parse_root); return_ACPI_STATUS(status); }
ACPI_STATUS AcpiRemoveNotifyHandler ( ACPI_HANDLE Device, UINT32 HandlerType, ACPI_NOTIFY_HANDLER Handler) { ACPI_OPERAND_OBJECT *NotifyObj; ACPI_OPERAND_OBJECT *ObjDesc; ACPI_NAMESPACE_NODE *Node; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (AcpiRemoveNotifyHandler); /* Parameter validation */ if ((!Device) || (!Handler) || (HandlerType > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Convert and validate the device handle */ Node = AcpiNsMapHandleToNode (Device); if (!Node) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* Root Object */ if (Device == ACPI_ROOT_OBJECT) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for namespace root object\n")); if (((HandlerType & ACPI_SYSTEM_NOTIFY) && !AcpiGbl_SystemNotify.Handler) || ((HandlerType & ACPI_DEVICE_NOTIFY) && !AcpiGbl_DeviceNotify.Handler)) { Status = AE_NOT_EXIST; goto UnlockAndExit; } if (HandlerType & ACPI_SYSTEM_NOTIFY) { AcpiGbl_SystemNotify.Node = NULL; AcpiGbl_SystemNotify.Handler = NULL; AcpiGbl_SystemNotify.Context = NULL; } if (HandlerType & ACPI_DEVICE_NOTIFY) { AcpiGbl_DeviceNotify.Node = NULL; AcpiGbl_DeviceNotify.Handler = NULL; AcpiGbl_DeviceNotify.Context = NULL; } } /* All Other Objects */ else { /* Notifies allowed on this object? */ if (!AcpiEvIsNotifyObject (Node)) { Status = AE_TYPE; goto UnlockAndExit; } /* Check for an existing internal object */ ObjDesc = AcpiNsGetAttachedObject (Node); if (!ObjDesc) { Status = AE_NOT_EXIST; goto UnlockAndExit; } /* Object exists - make sure there's an existing handler */ if (HandlerType & ACPI_SYSTEM_NOTIFY) { NotifyObj = ObjDesc->CommonNotify.SystemNotify; if (!NotifyObj) { Status = AE_NOT_EXIST; goto UnlockAndExit; } if (NotifyObj->Notify.Handler != Handler) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* Remove the handler */ ObjDesc->CommonNotify.SystemNotify = NULL; AcpiUtRemoveReference (NotifyObj); } if (HandlerType & ACPI_DEVICE_NOTIFY) { NotifyObj = ObjDesc->CommonNotify.DeviceNotify; if (!NotifyObj) { Status = AE_NOT_EXIST; goto UnlockAndExit; } if (NotifyObj->Notify.Handler != Handler) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* Remove the handler */ ObjDesc->CommonNotify.DeviceNotify = NULL; AcpiUtRemoveReference (NotifyObj); } } UnlockAndExit: (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (Status); }
static int acpi_processor_get_performance_states(struct acpi_processor *pr) { int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer format = { sizeof("NNNNNN"), "NNNNNN" }; struct acpi_buffer state = { 0, NULL }; union acpi_object *pss = NULL; int i; status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PSS")); return -ENODEV; } pss = (union acpi_object *)buffer.pointer; if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) { printk(KERN_ERR PREFIX "Invalid _PSS data\n"); result = -EFAULT; goto end; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n", pss->package.count)); pr->performance->state_count = pss->package.count; pr->performance->states = kmalloc(sizeof(struct acpi_processor_px) * pss->package.count, GFP_KERNEL); if (!pr->performance->states) { result = -ENOMEM; goto end; } for (i = 0; i < pr->performance->state_count; i++) { struct acpi_processor_px *px = &(pr->performance->states[i]); state.length = sizeof(struct acpi_processor_px); state.pointer = px; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); status = acpi_extract_package(&(pss->package.elements[i]), &format, &state); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSS data")); result = -EFAULT; kfree(pr->performance->states); goto end; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n", i, (u32) px->core_frequency, (u32) px->power, (u32) px->transition_latency, (u32) px->bus_master_latency, (u32) px->control, (u32) px->status)); /* * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq */ if (!px->core_frequency || ((u32)(px->core_frequency * 1000) != (px->core_frequency * 1000))) { printk(KERN_ERR PREFIX "Invalid BIOS _PSS frequency: 0x%llx MHz\n", px->core_frequency); result = -EFAULT; kfree(pr->performance->states); goto end; } } end: kfree(buffer.pointer); return result; }
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) { union acpi_operand_object *obj_desc; union acpi_operand_object *second_desc = NULL; u32 type; acpi_status status; ACPI_FUNCTION_TRACE(ex_prep_field_value); if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { if (!info->region_node) { ACPI_ERROR((AE_INFO, "Null RegionNode")); return_ACPI_STATUS(AE_AML_NO_OPERAND); } type = acpi_ns_get_type(info->region_node); if (type != ACPI_TYPE_REGION) { ACPI_ERROR((AE_INFO, "Needed Region, found type %X (%s)", type, acpi_ut_get_type_name(type))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } } obj_desc = acpi_ut_create_internal_object(info->field_type); if (!obj_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } obj_desc->common_field.node = info->field_node; status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags, info->attribute, info->field_bit_position, info->field_bit_length); if (ACPI_FAILURE(status)) { acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(status); } switch (info->field_type) { case ACPI_TYPE_LOCAL_REGION_FIELD: obj_desc->field.region_obj = acpi_ns_get_attached_object(info->region_node); acpi_ut_add_reference(obj_desc->field.region_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->field.region_obj)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: obj_desc->bank_field.value = info->bank_value; obj_desc->bank_field.region_obj = acpi_ns_get_attached_object(info->region_node); obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object(info->register_node); acpi_ut_add_reference(obj_desc->bank_field.region_obj); acpi_ut_add_reference(obj_desc->bank_field.bank_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", obj_desc->bank_field.start_field_bit_offset, obj_desc->bank_field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->bank_field.region_obj, obj_desc->bank_field.bank_obj)); second_desc = obj_desc->common.next_object; second_desc->extra.aml_start = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.data; second_desc->extra.aml_length = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.length; break; case ACPI_TYPE_LOCAL_INDEX_FIELD: obj_desc->index_field.index_obj = acpi_ns_get_attached_object(info->register_node); obj_desc->index_field.data_obj = acpi_ns_get_attached_object(info->data_register_node); if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { ACPI_ERROR((AE_INFO, "Null Index Object during field prep")); acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(AE_AML_INTERNAL); } acpi_ut_add_reference(obj_desc->index_field.data_obj); acpi_ut_add_reference(obj_desc->index_field.index_obj); obj_desc->index_field.value = (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position), obj_desc->index_field. access_byte_width); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", obj_desc->index_field.start_field_bit_offset, obj_desc->index_field.base_byte_offset, obj_desc->index_field.value, obj_desc->field.access_byte_width, obj_desc->index_field.index_obj, obj_desc->index_field.data_obj)); break; default: break; } status = acpi_ns_attach_object(info->field_node, obj_desc, acpi_ns_get_type(info->field_node)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n", info->field_node, acpi_ut_get_node_name(info->field_node), obj_desc)); acpi_ut_remove_reference(obj_desc); return_ACPI_STATUS(status); }
static u32 acpi_ex_generate_access(u32 field_bit_offset, u32 field_bit_length, u32 region_length) { u32 field_byte_length; u32 field_byte_offset; u32 field_byte_end_offset; u32 access_byte_width; u32 field_start_offset; u32 field_end_offset; u32 minimum_access_width = 0xFFFFFFFF; u32 minimum_accesses = 0xFFFFFFFF; u32 accesses; ACPI_FUNCTION_TRACE(ex_generate_access); field_byte_offset = ACPI_DIV_8(ACPI_ROUND_DOWN(field_bit_offset, 8)); field_byte_end_offset = ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + field_bit_offset, 8)); field_byte_length = field_byte_end_offset - field_byte_offset; ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Bit length %d, Bit offset %d\n", field_bit_length, field_bit_offset)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Byte Length %d, Byte Offset %d, End Offset %d\n", field_byte_length, field_byte_offset, field_byte_end_offset)); for (access_byte_width = 1; access_byte_width <= 8; access_byte_width <<= 1) { if (ACPI_ROUND_UP(field_byte_end_offset, access_byte_width) <= region_length) { field_start_offset = ACPI_ROUND_DOWN(field_byte_offset, access_byte_width) / access_byte_width; field_end_offset = ACPI_ROUND_UP((field_byte_length + field_byte_offset), access_byte_width) / access_byte_width; accesses = field_end_offset - field_start_offset; ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "AccessWidth %d end is within region\n", access_byte_width)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Field Start %d, Field End %d -- requires %d accesses\n", field_start_offset, field_end_offset, accesses)); if (accesses <= 1) { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Entire field can be accessed with one operation of size %d\n", access_byte_width)); return_VALUE(access_byte_width); } if (accesses < minimum_accesses) { minimum_accesses = accesses; minimum_access_width = access_byte_width; } } else { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "AccessWidth %d end is NOT within region\n", access_byte_width)); if (access_byte_width == 1) { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Field goes beyond end-of-region!\n")); return_VALUE(0); } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Backing off to previous optimal access width of %d\n", minimum_access_width)); return_VALUE(minimum_access_width); } } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Cannot access field in one operation, using width 8\n")); return_VALUE(8); }
acpi_status acpi_ds_init_one_object ( acpi_handle obj_handle, u32 level, void *context, void **return_value) { acpi_object_type type; acpi_status status; struct acpi_init_walk_info *info = (struct acpi_init_walk_info *) context; ACPI_FUNCTION_NAME ("ds_init_one_object"); /* * We are only interested in objects owned by the table that * was just loaded */ if (((struct acpi_namespace_node *) obj_handle)->owner_id != info->table_desc->table_id) { return (AE_OK); } info->object_count++; /* And even then, we are only interested in a few object types */ type = acpi_ns_get_type (obj_handle); switch (type) { case ACPI_TYPE_REGION: status = acpi_ds_initialize_region (obj_handle); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n", obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); } info->op_region_count++; break; case ACPI_TYPE_METHOD: info->method_count++; /* Print a dot for each method unless we are going to print the entire pathname */ if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); } /* * Set the execution data width (32 or 64) based upon the * revision number of the parent ACPI table. * TBD: This is really for possible future support of integer width * on a per-table basis. Currently, we just use a global for the width. */ if (info->table_desc->pointer->revision == 1) { ((struct acpi_namespace_node *) obj_handle)->flags |= ANOBJ_DATA_WIDTH_32; } /* * Always parse methods to detect errors, we will delete * the parse tree below */ status = acpi_ds_parse_method (obj_handle); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n", obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); /* This parse failed, but we will continue parsing more methods */ break; } /* * Delete the parse tree. We simply re-parse the method * for every execution since there isn't much overhead */ acpi_ns_delete_namespace_subtree (obj_handle); acpi_ns_delete_namespace_by_owner (((struct acpi_namespace_node *) obj_handle)->object->method.owning_id); break; case ACPI_TYPE_DEVICE: info->device_count++; break; default: break; } /* * We ignore errors from above, and always return OK, since * we don't want to abort the walk on a single error. */ return (AE_OK); }
ACPI_STATUS AcpiUtGetSimpleObjectSize ( ACPI_OPERAND_OBJECT *InternalObject, ACPI_SIZE *ObjLength) { ACPI_SIZE Length; ACPI_STATUS Status = AE_OK; ACPI_FUNCTION_TRACE_PTR ("UtGetSimpleObjectSize", InternalObject); /* Handle a null object (Could be a uninitialized package element -- which is legal) */ if (!InternalObject) { *ObjLength = 0; return_ACPI_STATUS (AE_OK); } /* Start with the length of the Acpi object */ Length = sizeof (ACPI_OBJECT); if (ACPI_GET_DESCRIPTOR_TYPE (InternalObject) == ACPI_DESC_TYPE_NAMED) { /* Object is a named object (reference), just return the length */ *ObjLength = ACPI_ROUND_UP_TO_NATIVE_WORD (Length); return_ACPI_STATUS (Status); } /* * The final length depends on the object type * Strings and Buffers are packed right up against the parent object and * must be accessed bytewise or there may be alignment problems on * certain processors */ switch (ACPI_GET_OBJECT_TYPE (InternalObject)) { case ACPI_TYPE_STRING: Length += (ACPI_SIZE) InternalObject->String.Length + 1; break; case ACPI_TYPE_BUFFER: Length += (ACPI_SIZE) InternalObject->Buffer.Length; break; case ACPI_TYPE_INTEGER: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_POWER: /* * No extra data for these types */ break; case ACPI_TYPE_LOCAL_REFERENCE: switch (InternalObject->Reference.Opcode) { case AML_INT_NAMEPATH_OP: /* * Get the actual length of the full pathname to this object. * The reference will be converted to the pathname to the object */ Length += ACPI_ROUND_UP_TO_NATIVE_WORD (AcpiNsGetPathnameLength (InternalObject->Reference.Node)); break; default: /* * No other reference opcodes are supported. * Notably, Locals and Args are not supported, but this may be * required eventually. */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode=%X in object %p\n", InternalObject->Reference.Opcode, InternalObject)); Status = AE_TYPE; break; } break; default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported type=%X in object %p\n", ACPI_GET_OBJECT_TYPE (InternalObject), InternalObject)); Status = AE_TYPE; break; } /* * Account for the space required by the object rounded up to the next * multiple of the machine word size. This keeps each object aligned * on a machine word boundary. (preventing alignment faults on some * machines.) */ *ObjLength = ACPI_ROUND_UP_TO_NATIVE_WORD (Length); return_ACPI_STATUS (Status); }
/******************************************************************************* * * FUNCTION: acpi_ns_root_initialize * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Allocate and initialize the default root named objects * * MUTEX: Locks namespace for entire execution * ******************************************************************************/ acpi_status acpi_ns_root_initialize(void) { acpi_status status; const struct acpi_predefined_names *init_val = NULL; struct acpi_namespace_node *new_node; union acpi_operand_object *obj_desc; acpi_string val = NULL; ACPI_FUNCTION_TRACE("ns_root_initialize"); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * The global root ptr is initially NULL, so a non-NULL value indicates * that acpi_ns_root_initialize() has already been called; just return. */ if (acpi_gbl_root_node) { status = AE_OK; goto unlock_and_exit; } /* * Tell the rest of the subsystem that the root is initialized * (This is OK because the namespace is locked) */ acpi_gbl_root_node = &acpi_gbl_root_node_struct; /* Enter the pre-defined names in the name table */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Entering predefined entries into namespace\n")); for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { /* _OSI is optional for now, will be permanent later */ if (!ACPI_STRCMP(init_val->name, "_OSI") && !acpi_gbl_create_osi_method) { continue; } status = acpi_ns_lookup(NULL, init_val->name, init_val->type, ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, NULL, &new_node); if (ACPI_FAILURE(status) || (!new_node)) { /* Must be on same line for code converter */ ACPI_EXCEPTION((AE_INFO, status, "Could not create predefined name %s", init_val->name)); } /* * Name entered successfully. * If entry in pre_defined_names[] specifies an * initial value, create the initial value. */ if (init_val->val) { status = acpi_os_predefined_override(init_val, &val); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not override predefined %s", init_val->name)); } if (!val) { val = init_val->val; } /* * Entry requests an initial value, allocate a * descriptor for it. */ obj_desc = acpi_ut_create_internal_object(init_val->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* * Convert value string from table entry to * internal representation. Only types actually * used for initial values are implemented here. */ switch (init_val->type) { case ACPI_TYPE_METHOD: obj_desc->method.param_count = (u8) ACPI_TO_INTEGER(val); obj_desc->common.flags |= AOPOBJ_DATA_VALID; #if defined (ACPI_ASL_COMPILER) /* save the parameter count for the i_aSL compiler */ new_node->value = obj_desc->method.param_count; #else /* Mark this as a very SPECIAL method */ obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY; #ifndef ACPI_DUMP_APP obj_desc->method.implementation = acpi_ut_osi_implementation; #endif #endif break; case ACPI_TYPE_INTEGER: obj_desc->integer.value = ACPI_TO_INTEGER(val); break; case ACPI_TYPE_STRING: /* * Build an object around the static string */ obj_desc->string.length = (u32) ACPI_STRLEN(val); obj_desc->string.pointer = val; obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; break; case ACPI_TYPE_MUTEX: obj_desc->mutex.node = new_node; obj_desc->mutex.sync_level = (u8) (ACPI_TO_INTEGER(val) - 1); if (ACPI_STRCMP(init_val->name, "_GL_") == 0) { /* * Create a counting semaphore for the * global lock */ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 1, &obj_desc->mutex.semaphore); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference (obj_desc); goto unlock_and_exit; } /* * We just created the mutex for the * global lock, save it */ acpi_gbl_global_lock_semaphore = obj_desc->mutex.semaphore; } else { /* Create a mutex */ status = acpi_os_create_semaphore(1, 1, &obj_desc-> mutex. semaphore); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference (obj_desc); goto unlock_and_exit; } } break; default: ACPI_ERROR((AE_INFO, "Unsupported initial type value %X", init_val->type)); acpi_ut_remove_reference(obj_desc); obj_desc = NULL; continue; } /* Store pointer to value descriptor in the Node */ status = acpi_ns_attach_object(new_node, obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc)); /* Remove local reference to the object */ acpi_ut_remove_reference(obj_desc); } } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); /* Save a handle to "_GPE", it is always present */ if (ACPI_SUCCESS(status)) { status = acpi_ns_get_node_by_path("\\_GPE", NULL, ACPI_NS_NO_UPSEARCH, &acpi_gbl_fadt_gpe_device); } return_ACPI_STATUS(status); }
acpi_status acpi_ns_lookup(union acpi_generic_state *scope_info, char *pathname, acpi_object_type type, acpi_interpreter_mode interpreter_mode, u32 flags, struct acpi_walk_state *walk_state, struct acpi_namespace_node **return_node) { acpi_status status; char *path = pathname; struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *current_node = NULL; struct acpi_namespace_node *this_node = NULL; u32 num_segments; u32 num_carats; acpi_name simple_name; acpi_object_type type_to_check_for; acpi_object_type this_search_type; u32 search_parent_flag = ACPI_NS_SEARCH_PARENT; u32 local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_SEARCH_PARENT); ACPI_FUNCTION_TRACE("ns_lookup"); if (!return_node) { return_ACPI_STATUS(AE_BAD_PARAMETER); } acpi_gbl_ns_lookup_count++; *return_node = ACPI_ENTRY_NOT_FOUND; if (!acpi_gbl_root_node) { return_ACPI_STATUS(AE_NO_NAMESPACE); } /* * Get the prefix scope. * A null scope means use the root scope */ if ((!scope_info) || (!scope_info->scope.node)) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Null scope prefix, using root node (%p)\n", acpi_gbl_root_node)); prefix_node = acpi_gbl_root_node; } else { prefix_node = scope_info->scope.node; if (ACPI_GET_DESCRIPTOR_TYPE(prefix_node) != ACPI_DESC_TYPE_NAMED) { ACPI_ERROR((AE_INFO, "%p is not a namespace node [%s]", prefix_node, acpi_ut_get_descriptor_name(prefix_node))); return_ACPI_STATUS(AE_AML_INTERNAL); } /* * This node might not be a actual "scope" node (such as a * Device/Method, etc.) It could be a Package or other object node. * Backup up the tree to find the containing scope node. */ while (!acpi_ns_opens_scope(prefix_node->type) && prefix_node->type != ACPI_TYPE_ANY) { prefix_node = acpi_ns_get_parent_node(prefix_node); } } /* Save type TBD: may be no longer necessary */ type_to_check_for = type; /* * Begin examination of the actual pathname */ if (!pathname) { /* A Null name_path is allowed and refers to the root */ num_segments = 0; this_node = acpi_gbl_root_node; path = ""; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Null Pathname (Zero segments), Flags=%X\n", flags)); } else { /* * Name pointer is valid (and must be in internal name format) * * Check for scope prefixes: * * As represented in the AML stream, a namepath consists of an * optional scope prefix followed by a name segment part. * * If present, the scope prefix is either a Root Prefix (in * which case the name is fully qualified), or one or more * Parent Prefixes (in which case the name's scope is relative * to the current scope). */ if (*path == (u8) AML_ROOT_PREFIX) { /* Pathname is fully qualified, start from the root */ this_node = acpi_gbl_root_node; search_parent_flag = ACPI_NS_NO_UPSEARCH; /* Point to name segment part */ path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Path is absolute from root [%p]\n", this_node)); } else { /* Pathname is relative to current scope, start there */ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Searching relative to prefix scope [%4.4s] (%p)\n", acpi_ut_get_node_name(prefix_node), prefix_node)); /* * Handle multiple Parent Prefixes (carat) by just getting * the parent node for each prefix instance. */ this_node = prefix_node; num_carats = 0; while (*path == (u8) AML_PARENT_PREFIX) { /* Name is fully qualified, no search rules apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; /* * Point past this prefix to the name segment * part or the next Parent Prefix */ path++; /* Backup to the parent node */ num_carats++; this_node = acpi_ns_get_parent_node(this_node); if (!this_node) { /* Current scope has no parent scope */ ACPI_ERROR((AE_INFO, "ACPI path has too many parent prefixes (^) - reached beyond root node")); return_ACPI_STATUS(AE_NOT_FOUND); } } if (search_parent_flag == ACPI_NS_NO_UPSEARCH) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Search scope is [%4.4s], path has %d carat(s)\n", acpi_ut_get_node_name (this_node), num_carats)); } } /* * Determine the number of ACPI name segments in this pathname. * * The segment part consists of either: * - A Null name segment (0) * - A dual_name_prefix followed by two 4-byte name segments * - A multi_name_prefix followed by a byte indicating the * number of segments and the segments themselves. * - A single 4-byte name segment * * Examine the name prefix opcode, if any, to determine the number of * segments. */ switch (*path) { case 0: /* * Null name after a root or parent prefixes. We already * have the correct target node and there are no name segments. */ num_segments = 0; type = this_node->type; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Prefix-only Pathname (Zero name segments), Flags=%X\n", flags)); break; case AML_DUAL_NAME_PREFIX: /* More than one name_seg, search rules do not apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; /* Two segments, point to first name segment */ num_segments = 2; path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Dual Pathname (2 segments, Flags=%X)\n", flags)); break; case AML_MULTI_NAME_PREFIX_OP: /* More than one name_seg, search rules do not apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; /* Extract segment count, point to first name segment */ path++; num_segments = (u32) (u8) * path; path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Multi Pathname (%d Segments, Flags=%X)\n", num_segments, flags)); break; default: /* * Not a Null name, no Dual or Multi prefix, hence there is * only one name segment and Pathname is already pointing to it. */ num_segments = 1; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Simple Pathname (1 segment, Flags=%X)\n", flags)); break; } ACPI_DEBUG_EXEC(acpi_ns_print_pathname(num_segments, path)); } /* * Search namespace for each segment of the name. Loop through and * verify (or add to the namespace) each name segment. * * The object type is significant only at the last name * segment. (We don't care about the types along the path, only * the type of the final target object.) */ this_search_type = ACPI_TYPE_ANY; current_node = this_node; while (num_segments && current_node) { num_segments--; if (!num_segments) { /* * This is the last segment, enable typechecking */ this_search_type = type; /* * Only allow automatic parent search (search rules) if the caller * requested it AND we have a single, non-fully-qualified name_seg */ if ((search_parent_flag != ACPI_NS_NO_UPSEARCH) && (flags & ACPI_NS_SEARCH_PARENT)) { local_flags |= ACPI_NS_SEARCH_PARENT; } /* Set error flag according to caller */ if (flags & ACPI_NS_ERROR_IF_FOUND) { local_flags |= ACPI_NS_ERROR_IF_FOUND; } } /* Extract one ACPI name from the front of the pathname */ ACPI_MOVE_32_TO_32(&simple_name, path); /* Try to find the single (4 character) ACPI name */ status = acpi_ns_search_and_enter(simple_name, walk_state, current_node, interpreter_mode, this_search_type, local_flags, &this_node); if (ACPI_FAILURE(status)) { if (status == AE_NOT_FOUND) { /* Name not found in ACPI namespace */ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Name [%4.4s] not found in scope [%4.4s] %p\n", (char *)&simple_name, (char *)¤t_node->name, current_node)); } *return_node = this_node; return_ACPI_STATUS(status); } /* * Sanity typecheck of the target object: * * If 1) This is the last segment (num_segments == 0) * 2) And we are looking for a specific type * (Not checking for TYPE_ANY) * 3) Which is not an alias * 4) Which is not a local type (TYPE_SCOPE) * 5) And the type of target object is known (not TYPE_ANY) * 6) And target object does not match what we are looking for * * Then we have a type mismatch. Just warn and ignore it. */ if ((num_segments == 0) && (type_to_check_for != ACPI_TYPE_ANY) && (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) && (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) && (this_node->type != ACPI_TYPE_ANY) && (this_node->type != type_to_check_for)) { /* Complain about a type mismatch */ ACPI_WARNING((AE_INFO, "ns_lookup: Type mismatch on %4.4s (%s), searching for (%s)", ACPI_CAST_PTR(char, &simple_name), acpi_ut_get_type_name(this_node->type), acpi_ut_get_type_name (type_to_check_for))); } /* * If this is the last name segment and we are not looking for a * specific type, but the type of found object is known, use that type * to see if it opens a scope. */ if ((num_segments == 0) && (type == ACPI_TYPE_ANY)) { type = this_node->type; } /* Point to next name segment and make this node current */ path += ACPI_NAME_SIZE; current_node = this_node; }
void AcpiDsTerminateControlMethod ( ACPI_OPERAND_OBJECT *MethodDesc, ACPI_WALK_STATE *WalkState) { ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState); /* MethodDesc is required, WalkState is optional */ if (!MethodDesc) { return_VOID; } if (WalkState) { /* Delete all arguments and locals */ AcpiDsMethodDataDeleteAll (WalkState); /* * If method is serialized, release the mutex and restore the * current sync level for this thread */ if (MethodDesc->Method.Mutex) { /* Acquisition Depth handles recursive calls */ MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--; if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth) { WalkState->Thread->CurrentSyncLevel = MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel; AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex); MethodDesc->Method.Mutex->Mutex.ThreadId = 0; } } /* * Delete any namespace objects created anywhere within the * namespace by the execution of this method. Unless: * 1) This method is a module-level executable code method, in which * case we want make the objects permanent. * 2) There are other threads executing the method, in which case we * will wait until the last thread has completed. */ if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) && (MethodDesc->Method.ThreadCount == 1)) { /* Delete any direct children of (created by) this method */ AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode); /* * Delete any objects that were created by this method * elsewhere in the namespace (if any were created). * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the * deletion such that we don't have to perform an entire * namespace walk for every control method execution. */ if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE) { AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId); MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_MODIFIED_NAMESPACE; } } } /* Decrement the thread count on the method */ if (MethodDesc->Method.ThreadCount) { MethodDesc->Method.ThreadCount--; } else { ACPI_ERROR ((AE_INFO, "Invalid zero thread count in method")); } /* Are there any other threads currently executing this method? */ if (MethodDesc->Method.ThreadCount) { /* * Additional threads. Do not release the OwnerId in this case, * we immediately reuse it for the next thread executing this method */ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "*** Completed execution of one thread, %u threads remaining\n", MethodDesc->Method.ThreadCount)); } else { /* This is the only executing thread for this method */ /* * Support to dynamically change a method from NotSerialized to * Serialized if it appears that the method is incorrectly written and * does not support multiple thread execution. The best example of this * is if such a method creates namespace objects and blocks. A second * thread will fail with an AE_ALREADY_EXISTS exception. * * This code is here because we must wait until the last thread exits * before marking the method as serialized. */ if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING) { if (WalkState) { ACPI_INFO ((AE_INFO, "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", WalkState->MethodNode->Name.Ascii)); } /* * Method tried to create an object twice and was marked as * "pending serialized". The probable cause is that the method * cannot handle reentrancy. * * The method was created as NotSerialized, but it tried to create * a named object and then blocked, causing the second thread * entrance to begin and then fail. Workaround this problem by * marking the method permanently as Serialized when the last * thread exits here. */ MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_SERIALIZED_PENDING; MethodDesc->Method.InfoFlags |= (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); MethodDesc->Method.SyncLevel = 0; } /* No more threads, we can free the OwnerId */ if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL)) { AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId); } } return_VOID; }
acpi_status acpi_ex_setup_region ( union acpi_operand_object *obj_desc, u32 field_datum_byte_offset) { acpi_status status = AE_OK; union acpi_operand_object *rgn_desc; ACPI_FUNCTION_TRACE_U32 ("ex_setup_region", field_datum_byte_offset); rgn_desc = obj_desc->common_field.region_obj; /* We must have a valid region */ if (ACPI_GET_OBJECT_TYPE (rgn_desc) != ACPI_TYPE_REGION) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n", ACPI_GET_OBJECT_TYPE (rgn_desc), acpi_ut_get_object_type_name (rgn_desc))); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } /* * If the Region Address and Length have not been previously evaluated, * evaluate them now and save the results. */ if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_region_arguments (rgn_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { /* SMBus has a non-linear address space */ return_ACPI_STATUS (AE_OK); } #ifdef ACPI_UNDER_DEVELOPMENT /* * If the Field access is any_acc, we can now compute the optimal * access (because we know know the length of the parent region) */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } #endif /* * Validate the request. The entire request from the byte offset for a * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + field_datum_byte_offset + obj_desc->common_field.access_byte_width)) { if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) { /* * This is the case where the access_type (acc_word, etc.) is wider * than the region itself. For example, a region of length one * byte, and a field with Dword access specified. */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", acpi_ut_get_node_name (obj_desc->common_field.node), obj_desc->common_field.access_byte_width, acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); } /* * Offset rounded up to next multiple of field width * exceeds region length, indicate an error */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n", acpi_ut_get_node_name (obj_desc->common_field.node), obj_desc->common_field.base_byte_offset, field_datum_byte_offset, obj_desc->common_field.access_byte_width, acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); if (!acpi_strict) { /* * Allow access to the field if it is within the region size * rounded up to a multiple of the access byte width. This * overcomes "off-by-one" programming errors in the AML often * found in Toshiba laptops. These errors were allowed by * the Microsoft ASL compiler. */ u32 rounded_length = ACPI_ROUND_UP(rgn_desc->region.length, obj_desc->common_field.access_byte_width); if (rounded_length < (obj_desc->common_field.base_byte_offset + field_datum_byte_offset + obj_desc->common_field.access_byte_width)) { return_ACPI_STATUS (AE_AML_REGION_LIMIT); } else { static int warn_once = 1; if (warn_once) { // Could also associate a flag with each field, and // warn once for each field. ACPI_REPORT_WARNING(( "The ACPI AML in your computer contains errors, " "please nag the manufacturer to correct it.\n")); ACPI_REPORT_WARNING(( "Allowing relaxed access to fields; " "turn on CONFIG_ACPI_DEBUG for details.\n")); warn_once = 0; } return_ACPI_STATUS (AE_OK); } } else { return_ACPI_STATUS (AE_AML_REGION_LIMIT); } } return_ACPI_STATUS (AE_OK); }
int acpi_pci_bind(struct acpi_device *device) { int result = 0; acpi_status status; struct acpi_pci_data *data; struct acpi_pci_data *pdata; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_handle handle; if (!device || !device->parent) return -EINVAL; data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); if (!data) return -ENOMEM; status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); if (ACPI_FAILURE(status)) { kfree(data); return -ENODEV; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", (char *)buffer.pointer)); /* * Segment & Bus * ------------- * These are obtained via the parent device's ACPI-PCI context. */ status = acpi_get_data(device->parent->handle, acpi_pci_data_handler, (void **)&pdata); if (ACPI_FAILURE(status) || !pdata || !pdata->bus) { ACPI_EXCEPTION((AE_INFO, status, "Invalid ACPI-PCI context for parent device %s", acpi_device_bid(device->parent))); result = -ENODEV; goto end; } data->id.segment = pdata->id.segment; data->id.bus = pdata->bus->number; /* * Device & Function * ----------------- * These are simply obtained from the device's _ADR method. Note * that a value of zero is valid. */ data->id.device = device->pnp.bus_address >> 16; data->id.function = device->pnp.bus_address & 0xFFFF; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n", data->id.segment, data->id.bus, data->id.device, data->id.function)); /* * TBD: Support slot devices (e.g. function=0xFFFF). */ /* * Locate PCI Device * ----------------- * Locate matching device in PCI namespace. If it doesn't exist * this typically means that the device isn't currently inserted * (e.g. docking station, port replicator, etc.). */ data->dev = pci_get_slot(pdata->bus, PCI_DEVFN(data->id.device, data->id.function)); if (!data->dev) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %04x:%02x:%02x.%d not present in PCI namespace\n", data->id.segment, data->id.bus, data->id.device, data->id.function)); result = -ENODEV; goto end; } if (!data->dev->bus) { printk(KERN_ERR PREFIX "Device %04x:%02x:%02x.%d has invalid 'bus' field\n", data->id.segment, data->id.bus, data->id.device, data->id.function); result = -ENODEV; goto end; } /* * PCI Bridge? * ----------- * If so, set the 'bus' field and install the 'bind' function to * facilitate callbacks for all of its children. */ if (data->dev->subordinate) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %04x:%02x:%02x.%d is a PCI bridge\n", data->id.segment, data->id.bus, data->id.device, data->id.function)); data->bus = data->dev->subordinate; device->ops.bind = acpi_pci_bind; device->ops.unbind = acpi_pci_unbind; } /* * Attach ACPI-PCI Context * ----------------------- * Thus binding the ACPI and PCI devices. */ status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to attach ACPI-PCI context to device %s", acpi_device_bid(device))); result = -ENODEV; goto end; } /* * PCI Routing Table * ----------------- * Evaluate and parse _PRT, if exists. This code is independent of * PCI bridges (above) to allow parsing of _PRT objects within the * scope of non-bridge devices. Note that _PRTs within the scope of * a PCI bridge assume the bridge's subordinate bus number. * * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? */ status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); if (ACPI_SUCCESS(status)) { if (data->bus) /* PCI-PCI bridge */ acpi_pci_irq_add_prt(device->handle, data->id.segment, data->bus->number); else /* non-bridge PCI device */ acpi_pci_irq_add_prt(device->handle, data->id.segment, data->id.bus); } end: kfree(buffer.pointer); if (result) { pci_dev_put(data->dev); kfree(data); } return result; }
acpi_status acpi_ex_extract_from_field ( union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { acpi_status status; u32 field_datum_byte_offset; u32 buffer_datum_offset; acpi_integer previous_raw_datum = 0; acpi_integer this_raw_datum = 0; acpi_integer merged_datum = 0; u32 byte_field_length; u32 datum_count; u32 i; ACPI_FUNCTION_TRACE ("ex_extract_from_field"); /* * The field must fit within the caller's buffer */ byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); if (byte_field_length > buffer_length) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Field size %X (bytes) too large for buffer (%X)\n", byte_field_length, buffer_length)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } /* Convert field byte count to datum count, round up if necessary */ datum_count = ACPI_ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); /* * If the field is not aligned on a datum boundary and does not * fit within a single datum, we must read an extra datum. * * We could just split the aligned and non-aligned cases since the * aligned case is so very simple, but this would require more code. */ if ((obj_desc->common_field.end_field_valid_bits != 0) && (!(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM))) { datum_count++; } ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "byte_len %X, datum_len %X, byte_gran %X\n", byte_field_length, datum_count,obj_desc->common_field.access_byte_width)); /* * Clear the caller's buffer (the whole buffer length as given) * This is very important, especially in the cases where the buffer * is longer than the size of the field. */ ACPI_MEMSET (buffer, 0, buffer_length); field_datum_byte_offset = 0; buffer_datum_offset= 0; /* Read the entire field */ for (i = 0; i < datum_count; i++) { status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, &this_raw_datum, ACPI_READ); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* We might actually be done if the request fits in one datum */ if ((datum_count == 1) && (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) { /* 1) Shift the valid data bits down to start at bit 0 */ merged_datum = (this_raw_datum >> obj_desc->common_field.start_field_bit_offset); /* 2) Mask off any upper unused bits (bits not part of the field) */ if (obj_desc->common_field.end_buffer_valid_bits) { merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); } /* Store the datum to the caller buffer */ acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); return_ACPI_STATUS (AE_OK); } /* Special handling for the last datum to ignore extra bits */ if ((i >= (datum_count -1)) && (obj_desc->common_field.end_field_valid_bits)) { /* * This is the last iteration of the loop. We need to clear * any unused bits (bits that are not part of this field) before * we store the final merged datum into the caller buffer. */ this_raw_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); } /* * Create the (possibly) merged datum to be stored to the caller buffer */ if (obj_desc->common_field.start_field_bit_offset == 0) { /* Field is not skewed and we can just copy the datum */ acpi_ex_set_buffer_datum (this_raw_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); buffer_datum_offset++; } else { /* Not aligned -- on the first iteration, just save the datum */ if (i != 0) { /* * Put together the appropriate bits of the two raw data to make a * single complete field datum * * 1) Normalize the first datum down to bit 0 */ merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); /* 2) Insert the second datum "above" the first datum */ merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits); acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); buffer_datum_offset++; } /* * Save the raw datum that was just acquired since it may contain bits * of the *next* field datum */ previous_raw_datum = this_raw_datum; }
acpi_status acpi_ex_name_segment ( u8 **in_aml_address, NATIVE_CHAR *name_string) { u8 *aml_address = *in_aml_address; acpi_status status = AE_OK; u32 index; NATIVE_CHAR char_buf[5]; FUNCTION_TRACE ("Ex_name_segment"); /* * If first character is a digit, then we know that we aren't looking at a * valid name segment */ char_buf[0] = *aml_address; if ('0' <= char_buf[0] && char_buf[0] <= '9') { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "leading digit: %c\n", char_buf[0])); return_ACPI_STATUS (AE_CTRL_PENDING); } ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Bytes from stream:\n")); for (index = 4; (index > 0) && (acpi_ut_valid_acpi_character (*aml_address)); --index) { char_buf[4 - index] = *aml_address++; ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "%c\n", char_buf[4 - index])); } /* Valid name segment */ if (0 == index) { /* Found 4 valid characters */ char_buf[4] = '\0'; if (name_string) { STRCAT (name_string, char_buf); ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Appended to - %s \n", name_string)); } else { ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "No Name string - %s \n", char_buf)); } } else if (4 == index) { /* * First character was not a valid name character, * so we are looking at something other than a name. */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Leading character is not alpha: %02Xh (not a name)\n", char_buf[0])); status = AE_CTRL_PENDING; } else { /* Segment started with one or more valid characters, but fewer than 4 */ status = AE_AML_BAD_NAME; ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad character %02x in name, at %p\n", *aml_address, aml_address)); } *in_aml_address = aml_address; return_ACPI_STATUS (status); }
static ACPI_STATUS AcpiDmCreateNewExternal ( char *ExternalPath, char *InternalPath, UINT8 Type, UINT32 Value, UINT16 Flags) { ACPI_EXTERNAL_LIST *NewExternal; ACPI_EXTERNAL_LIST *NextExternal; ACPI_EXTERNAL_LIST *PrevExternal = NULL; ACPI_FUNCTION_TRACE (DmCreateNewExternal); /* Check all existing externals to ensure no duplicates */ NextExternal = AcpiGbl_ExternalList; while (NextExternal) { /* Check for duplicates */ if (!strcmp (ExternalPath, NextExternal->Path)) { /* * If this external came from an External() opcode, we are * finished with this one. (No need to check any further). */ if (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_OPCODE) { return_ACPI_STATUS (AE_ALREADY_EXISTS); } /* Allow upgrade of type from ANY */ else if ((NextExternal->Type == ACPI_TYPE_ANY) && (Type != ACPI_TYPE_ANY)) { NextExternal->Type = Type; } /* Update the argument count as necessary */ if (Value < NextExternal->Value) { NextExternal->Value = Value; } /* Update flags. */ NextExternal->Flags |= Flags; NextExternal->Flags &= ~ACPI_EXT_INTERNAL_PATH_ALLOCATED; return_ACPI_STATUS (AE_ALREADY_EXISTS); } NextExternal = NextExternal->Next; } /* Allocate and init a new External() descriptor */ NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST)); if (!NewExternal) { return_ACPI_STATUS (AE_NO_MEMORY); } ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Adding external reference node (%s) type [%s]\n", ExternalPath, AcpiUtGetTypeName (Type))); NewExternal->Flags = Flags; NewExternal->Value = Value; NewExternal->Path = ExternalPath; NewExternal->Type = Type; NewExternal->Length = (UINT16) strlen (ExternalPath); NewExternal->InternalPath = InternalPath; /* Link the new descriptor into the global list, alphabetically ordered */ NextExternal = AcpiGbl_ExternalList; while (NextExternal) { if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0) { if (PrevExternal) { PrevExternal->Next = NewExternal; } else { AcpiGbl_ExternalList = NewExternal; } NewExternal->Next = NextExternal; return_ACPI_STATUS (AE_OK); } PrevExternal = NextExternal; NextExternal = NextExternal->Next; } if (PrevExternal) { PrevExternal->Next = NewExternal; } else { AcpiGbl_ExternalList = NewExternal; } return_ACPI_STATUS (AE_OK); }
acpi_status acpi_ex_get_name_string ( acpi_object_type8 data_type, u8 *in_aml_address, NATIVE_CHAR **out_name_string, u32 *out_name_length) { acpi_status status = AE_OK; u8 *aml_address = in_aml_address; NATIVE_CHAR *name_string = NULL; u32 num_segments; u32 prefix_count = 0; u8 prefix = 0; u8 has_prefix = FALSE; FUNCTION_TRACE_PTR ("Ex_get_name_string", aml_address); if (INTERNAL_TYPE_REGION_FIELD == data_type || INTERNAL_TYPE_BANK_FIELD == data_type || INTERNAL_TYPE_INDEX_FIELD == data_type) { /* Disallow prefixes for types associated with Field_unit names */ name_string = acpi_ex_allocate_name_string (0, 1); if (!name_string) { status = AE_NO_MEMORY; } else { status = acpi_ex_name_segment (&aml_address, name_string); } } else { /* * Data_type is not a field name. * Examine first character of name for root or parent prefix operators */ switch (*aml_address) { case AML_ROOT_PREFIX: prefix = *aml_address++; ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Root_prefix: %x\n", prefix)); /* * Remember that we have a Root_prefix -- * see comment in Acpi_ex_allocate_name_string() */ prefix_count = (u32) -1; has_prefix = TRUE; break; case AML_PARENT_PREFIX: /* Increment past possibly multiple parent prefixes */ do { prefix = *aml_address++; ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Parent_prefix: %x\n", prefix)); ++prefix_count; } while (*aml_address == AML_PARENT_PREFIX); has_prefix = TRUE; break; default: break; } /* Examine first character of name for name segment prefix operator */ switch (*aml_address) { case AML_DUAL_NAME_PREFIX: prefix = *aml_address++; ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Dual_name_prefix: %x\n", prefix)); name_string = acpi_ex_allocate_name_string (prefix_count, 2); if (!name_string) { status = AE_NO_MEMORY; break; } /* Indicate that we processed a prefix */ has_prefix = TRUE; status = acpi_ex_name_segment (&aml_address, name_string); if (ACPI_SUCCESS (status)) { status = acpi_ex_name_segment (&aml_address, name_string); } break; case AML_MULTI_NAME_PREFIX_OP: prefix = *aml_address++; ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Multi_name_prefix: %x\n", prefix)); /* Fetch count of segments remaining in name path */ num_segments = *aml_address++; name_string = acpi_ex_allocate_name_string (prefix_count, num_segments); if (!name_string) { status = AE_NO_MEMORY; break; } /* Indicate that we processed a prefix */ has_prefix = TRUE; while (num_segments && (status = acpi_ex_name_segment (&aml_address, name_string)) == AE_OK) { --num_segments; } break; case 0: /* Null_name valid as of 8-12-98 ASL/AML Grammar Update */ if (-1 == prefix_count) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Name_seg is \"\\\" followed by NULL\n")); } /* Consume the NULL byte */ aml_address++; name_string = acpi_ex_allocate_name_string (prefix_count, 0); if (!name_string) { status = AE_NO_MEMORY; break; } break; default: /* Name segment string */ name_string = acpi_ex_allocate_name_string (prefix_count, 1); if (!name_string) { status = AE_NO_MEMORY; break; } status = acpi_ex_name_segment (&aml_address, name_string); break; } /* Switch (Peek_op ()) */ } if (AE_CTRL_PENDING == status && has_prefix) { /* Ran out of segments after processing a prefix */ REPORT_ERROR ( ("Ex_do_name: Malformed Name at %p\n", name_string)); status = AE_AML_BAD_NAME; } *out_name_string = name_string; *out_name_length = (u32) (aml_address - in_aml_address); return_ACPI_STATUS (status); }
int acpi_processor_notify_smm(struct module *calling_module) { acpi_status status; static int is_done = 0; if (!(acpi_processor_ppc_status & PPC_REGISTERED)) return -EBUSY; if (!try_module_get(calling_module)) return -EINVAL; /* is_done is set to negative if an error occured, * and to postitive if _no_ error occured, but SMM * was already notified. This avoids double notification * which might lead to unexpected results... */ if (is_done > 0) { module_put(calling_module); return 0; } else if (is_done < 0) { module_put(calling_module); return is_done; } is_done = -EIO; /* Can't write pstate_cnt to smi_cmd if either value is zero */ if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_cnt\n")); module_put(calling_module); return 0; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n", acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd)); /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use * it anyway, so we need to support it... */ if (acpi_fadt_is_v1) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Using v1.0 FADT reserved value for pstate_cnt\n")); } status = acpi_os_write_port(acpi_fadt.smi_cmd, (u32) acpi_fadt.pstate_cnt, 8); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Failed to write pstate_cnt [0x%x] to " "smi_cmd [0x%x]", acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd)); module_put(calling_module); return status; } /* Success. If there's no _PPC, we need to fear nothing, so * we can allow the cpufreq driver to be rmmod'ed. */ is_done = 1; if (!(acpi_processor_ppc_status & PPC_IN_USE)) module_put(calling_module); return 0; }
const ACPI_OPCODE_INFO * AcpiPsGetOpcodeInfo ( UINT16 Opcode) { #ifdef ACPI_DEBUG_OUTPUT const char *OpcodeName = "Unknown AML opcode"; #endif ACPI_FUNCTION_NAME (PsGetOpcodeInfo); /* * Detect normal 8-bit opcode or extended 16-bit opcode */ if (!(Opcode & 0xFF00)) { /* Simple (8-bit) opcode: 0-255, can't index beyond table */ return (&AcpiGbl_AmlOpInfo [AcpiGbl_ShortOpIndex [(UINT8) Opcode]]); } if (((Opcode & 0xFF00) == AML_EXTENDED_OPCODE) && (((UINT8) Opcode) <= MAX_EXTENDED_OPCODE)) { /* Valid extended (16-bit) opcode */ return (&AcpiGbl_AmlOpInfo [AcpiGbl_LongOpIndex [(UINT8) Opcode]]); } #if defined ACPI_ASL_COMPILER && defined ACPI_DEBUG_OUTPUT #include "asldefine.h" switch (Opcode) { case AML_RAW_DATA_BYTE: OpcodeName = "-Raw Data Byte-"; break; case AML_RAW_DATA_WORD: OpcodeName = "-Raw Data Word-"; break; case AML_RAW_DATA_DWORD: OpcodeName = "-Raw Data Dword-"; break; case AML_RAW_DATA_QWORD: OpcodeName = "-Raw Data Qword-"; break; case AML_RAW_DATA_BUFFER: OpcodeName = "-Raw Data Buffer-"; break; case AML_RAW_DATA_CHAIN: OpcodeName = "-Raw Data Buffer Chain-"; break; case AML_PACKAGE_LENGTH: OpcodeName = "-Package Length-"; break; case AML_UNASSIGNED_OPCODE: OpcodeName = "-Unassigned Opcode-"; break; case AML_DEFAULT_ARG_OP: OpcodeName = "-Default Arg-"; break; default: break; } #endif /* Unknown AML opcode */ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s [%4.4X]\n", OpcodeName, Opcode)); return (&AcpiGbl_AmlOpInfo [_UNK]); }
acpi_status acpi_ds_store_object_to_local(u16 opcode, u32 index, union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { acpi_status status; struct acpi_namespace_node *node; union acpi_operand_object *current_obj_desc; union acpi_operand_object *new_obj_desc; ACPI_FUNCTION_TRACE(ds_store_object_to_local); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n", opcode, index, obj_desc)); /* Parameter validation */ if (!obj_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Get the namespace node for the arg/local */ status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } current_obj_desc = acpi_ns_get_attached_object(node); if (current_obj_desc == obj_desc) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n", obj_desc)); return_ACPI_STATUS(status); } /* * If the reference count on the object is more than one, we must * take a copy of the object before we store. A reference count * of exactly 1 means that the object was just created during the * evaluation of an expression, and we can safely use it since it * is not used anywhere else. */ new_obj_desc = obj_desc; if (obj_desc->common.reference_count > 1) { status = acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc, walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } /* * If there is an object already in this slot, we either * have to delete it, or if this is an argument and there * is an object reference stored there, we have to do * an indirect store! */ if (current_obj_desc) { /* * Check for an indirect store if an argument * contains an object reference (stored as an Node). * We don't allow this automatic dereferencing for * locals, since a store to a local should overwrite * anything there, including an object reference. * * If both Arg0 and Local0 contain ref_of (Local4): * * Store (1, Arg0) - Causes indirect store to local4 * Store (1, Local0) - Stores 1 in local0, overwriting * the reference to local4 * Store (1, de_refof (Local0)) - Causes indirect store to local4 * * Weird, but true. */ if (opcode == AML_ARG_OP) { /* * If we have a valid reference object that came from ref_of(), * do the indirect store */ if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) == ACPI_DESC_TYPE_OPERAND) && (current_obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) && (current_obj_desc->reference.opcode == AML_REF_OF_OP)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Arg (%p) is an ObjRef(Node), storing in node %p\n", new_obj_desc, current_obj_desc)); /* * Store this object to the Node (perform the indirect store) * NOTE: No implicit conversion is performed, as per the ACPI * specification rules on storing to Locals/Args. */ status = acpi_ex_store_object_to_node(new_obj_desc, current_obj_desc-> reference. object, walk_state, ACPI_NO_IMPLICIT_CONVERSION); /* Remove local reference if we copied the object above */ if (new_obj_desc != obj_desc) { acpi_ut_remove_reference(new_obj_desc); } return_ACPI_STATUS(status); } } /* * Delete the existing object * before storing the new one */ acpi_ds_method_data_delete_value(opcode, index, walk_state); } /* * Install the Obj descriptor (*new_obj_desc) into * the descriptor for the Arg or Local. * (increments the object reference count by one) */ status = acpi_ds_method_data_set_value(opcode, index, new_obj_desc, walk_state); /* Remove local reference if we copied the object above */ if (new_obj_desc != obj_desc) { acpi_ut_remove_reference(new_obj_desc); } return_ACPI_STATUS(status); }
acpi_status acpi_ex_access_region ( union acpi_operand_object *obj_desc, u32 field_datum_byte_offset, acpi_integer *value, u32 function) { acpi_status status; union acpi_operand_object *rgn_desc; acpi_physical_address address; ACPI_FUNCTION_TRACE ("ex_access_region"); /* * Ensure that the region operands are fully evaluated and verify * the validity of the request */ status = acpi_ex_setup_region (obj_desc, field_datum_byte_offset); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* * The physical address of this field datum is: * * 1) The base of the region, plus * 2) The base offset of the field, plus * 3) The current offset into the field */ rgn_desc = obj_desc->common_field.region_obj; address = rgn_desc->region.address + obj_desc->common_field.base_byte_offset + field_datum_byte_offset; if ((function & ACPI_IO_MASK) == ACPI_READ) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); } else { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); } ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, " Region [%s:%X], Width %X, byte_base %X, Offset %X at %8.8X%8.8X\n", acpi_ut_get_region_name (rgn_desc->region.space_id), rgn_desc->region.space_id, obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, field_datum_byte_offset, ACPI_FORMAT_UINT64 (address))); /* Invoke the appropriate address_space/op_region handler */ status = acpi_ev_address_space_dispatch (rgn_desc, function, address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value); if (ACPI_FAILURE (status)) { if (status == AE_NOT_IMPLEMENTED) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %s(%X) not implemented\n", acpi_ut_get_region_name (rgn_desc->region.space_id), rgn_desc->region.space_id)); } else if (status == AE_NOT_EXIST) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %s(%X) has no handler\n", acpi_ut_get_region_name (rgn_desc->region.space_id), rgn_desc->region.space_id)); } } return_ACPI_STATUS (status); }
static ACPI_STATUS acpi_parse_resource(ACPI_RESOURCE *res, void *context) { struct acpi_parse_resource_set *set; struct acpi_resource_context *arc; UINT64 min, max, length, gran; #ifdef ACPI_DEBUG const char *name; #endif device_t dev; arc = context; dev = arc->dev; set = arc->set; switch (res->Type) { case ACPI_RESOURCE_TYPE_END_TAG: ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n")); break; case ACPI_RESOURCE_TYPE_FIXED_IO: if (res->Data.FixedIo.AddressLength <= 0) break; ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n", res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength)); set->set_ioport(dev, arc->context, res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength); break; case ACPI_RESOURCE_TYPE_IO: if (res->Data.Io.AddressLength <= 0) break; if (res->Data.Io.Minimum == res->Data.Io.Maximum) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n", res->Data.Io.Minimum, res->Data.Io.AddressLength)); set->set_ioport(dev, arc->context, res->Data.Io.Minimum, res->Data.Io.AddressLength); } else { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n", res->Data.Io.Minimum, res->Data.Io.Maximum, res->Data.Io.AddressLength)); set->set_iorange(dev, arc->context, res->Data.Io.Minimum, res->Data.Io.Maximum, res->Data.Io.AddressLength, res->Data.Io.Alignment); } break; case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: if (res->Data.FixedMemory32.AddressLength <= 0) break; ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n", res->Data.FixedMemory32.Address, res->Data.FixedMemory32.AddressLength)); set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address, res->Data.FixedMemory32.AddressLength); break; case ACPI_RESOURCE_TYPE_MEMORY32: if (res->Data.Memory32.AddressLength <= 0) break; if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n", res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength)); set->set_memory(dev, arc->context, res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength); } else { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n", res->Data.Memory32.Minimum, res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength)); set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum, res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength, res->Data.Memory32.Alignment); } break; case ACPI_RESOURCE_TYPE_MEMORY24: if (res->Data.Memory24.AddressLength <= 0) break; if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n", res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength)); set->set_memory(dev, arc->context, res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength); } else { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n", res->Data.Memory24.Minimum, res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength)); set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum, res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength, res->Data.Memory24.Alignment); } break; case ACPI_RESOURCE_TYPE_IRQ: /* * from 1.0b 6.4.2 * "This structure is repeated for each separate interrupt * required" */ set->set_irq(dev, arc->context, res->Data.Irq.Interrupts, res->Data.Irq.InterruptCount, res->Data.Irq.Triggering, res->Data.Irq.Polarity); break; case ACPI_RESOURCE_TYPE_DMA: /* * from 1.0b 6.4.3 * "This structure is repeated for each separate DMA channel * required" */ set->set_drq(dev, arc->context, res->Data.Dma.Channels, res->Data.Dma.ChannelCount); break; case ACPI_RESOURCE_TYPE_START_DEPENDENT: ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n")); set->set_start_dependent(dev, arc->context, res->Data.StartDpf.CompatibilityPriority); break; case ACPI_RESOURCE_TYPE_END_DEPENDENT: ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n")); set->set_end_dependent(dev, arc->context); break; case ACPI_RESOURCE_TYPE_ADDRESS16: case ACPI_RESOURCE_TYPE_ADDRESS32: case ACPI_RESOURCE_TYPE_ADDRESS64: case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: switch (res->Type) { case ACPI_RESOURCE_TYPE_ADDRESS16: gran = res->Data.Address16.Granularity; min = res->Data.Address16.Minimum; max = res->Data.Address16.Maximum; length = res->Data.Address16.AddressLength; #ifdef ACPI_DEBUG name = "Address16"; #endif break; case ACPI_RESOURCE_TYPE_ADDRESS32: gran = res->Data.Address32.Granularity; min = res->Data.Address32.Minimum; max = res->Data.Address32.Maximum; length = res->Data.Address32.AddressLength; #ifdef ACPI_DEBUG name = "Address32"; #endif break; case ACPI_RESOURCE_TYPE_ADDRESS64: gran = res->Data.Address64.Granularity; min = res->Data.Address64.Minimum; max = res->Data.Address64.Maximum; length = res->Data.Address64.AddressLength; #ifdef ACPI_DEBUG name = "Address64"; #endif break; default: KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64, ("should never happen")); gran = res->Data.ExtAddress64.Granularity; min = res->Data.ExtAddress64.Minimum; max = res->Data.ExtAddress64.Maximum; length = res->Data.ExtAddress64.AddressLength; #ifdef ACPI_DEBUG name = "ExtAddress64"; #endif break; } if (length <= 0) break; if (res->Data.Address.ProducerConsumer != ACPI_CONSUMER) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s %s producer\n", name, acpi_address_range_name(res->Data.Address.ResourceType))); break; } if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE && res->Data.Address.ResourceType != ACPI_IO_RANGE) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s for non-memory, non-I/O\n", name)); break; } #ifdef __i386__ if (min > ULONG_MAX || (res->Data.Address.MaxAddressFixed && max > ULONG_MAX)) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s above 4G\n", name)); break; } if (max > ULONG_MAX) max = ULONG_MAX; #endif if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED && res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) { if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n", name, (uintmax_t)min, (uintmax_t)length)); set->set_memory(dev, arc->context, min, length); } else { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name, (uintmax_t)min, (uintmax_t)length)); set->set_ioport(dev, arc->context, min, length); } } else { if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length)); set->set_memoryrange(dev, arc->context, min, max, length, gran); } else { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length)); set->set_iorange(dev, arc->context, min, max, length, gran); } } break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n")); break; } set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts, res->Data.ExtendedIrq.InterruptCount, res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity); break; case ACPI_RESOURCE_TYPE_VENDOR: ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "unimplemented VendorSpecific resource\n")); break; default: break; } return (AE_OK); }
acpi_status acpi_ex_field_datum_io ( union acpi_operand_object *obj_desc, u32 field_datum_byte_offset, acpi_integer *value, u32 read_write) { acpi_status status; acpi_integer local_value; ACPI_FUNCTION_TRACE_U32 ("ex_field_datum_io", field_datum_byte_offset); if (read_write == ACPI_READ) { if (!value) { local_value = 0; value = &local_value; /* To support reads without saving return value */ } /* Clear the entire return buffer first, [Very Important!] */ *value = 0; } /* * The four types of fields are: * * buffer_field - Read/write from/to a Buffer * region_field - Read/write from/to a Operation Region. * bank_field - Write to a Bank Register, then read/write from/to an op_region * index_field - Write to an Index Register, then read/write from/to a Data Register */ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { case ACPI_TYPE_BUFFER_FIELD: /* * If the buffer_field arguments have not been previously evaluated, * evaluate them now and save the results. */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments (obj_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } if (read_write == ACPI_READ) { /* * Copy the data from the source buffer. * Length is the field width in bytes. */ ACPI_MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer + obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset, obj_desc->common_field.access_byte_width); } else { /* * Copy the data to the target buffer. * Length is the field width in bytes. */ ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer + obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset, value, obj_desc->common_field.access_byte_width); } status = AE_OK; break; case ACPI_TYPE_LOCAL_BANK_FIELD: /* Ensure that the bank_value is not beyond the capacity of the register */ if (acpi_ex_register_overflow (obj_desc->bank_field.bank_obj, (acpi_integer) obj_desc->bank_field.value)) { return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); } /* * For bank_fields, we must write the bank_value to the bank_register * (itself a region_field) before we can access the data. */ status = acpi_ex_insert_into_field (obj_desc->bank_field.bank_obj, &obj_desc->bank_field.value, sizeof (obj_desc->bank_field.value)); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* * Now that the Bank has been selected, fall through to the * region_field case and write the datum to the Operation Region */ /*lint -fallthrough */ case ACPI_TYPE_LOCAL_REGION_FIELD: /* * For simple region_fields, we just directly access the owning * Operation Region. */ status = acpi_ex_access_region (obj_desc, field_datum_byte_offset, value, read_write); break; case ACPI_TYPE_LOCAL_INDEX_FIELD: /* Ensure that the index_value is not beyond the capacity of the register */ if (acpi_ex_register_overflow (obj_desc->index_field.index_obj, (acpi_integer) obj_desc->index_field.value)) { return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); } /* Write the index value to the index_register (itself a region_field) */ field_datum_byte_offset += obj_desc->index_field.value; ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Write to Index Register: Value %8.8X\n", field_datum_byte_offset)); status = acpi_ex_insert_into_field (obj_desc->index_field.index_obj, &field_datum_byte_offset, sizeof (field_datum_byte_offset)); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "I/O to Data Register: value_ptr %p\n", value)); if (read_write == ACPI_READ) { /* Read the datum from the data_register */ status = acpi_ex_extract_from_field (obj_desc->index_field.data_obj, value, sizeof (acpi_integer)); } else { /* Write the datum to the data_register */ status = acpi_ex_insert_into_field (obj_desc->index_field.data_obj, value, sizeof (acpi_integer)); } break; default: ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n", ACPI_GET_OBJECT_TYPE (obj_desc))); status = AE_AML_INTERNAL; break; } if (ACPI_SUCCESS (status)) { if (read_write == ACPI_READ) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n", ACPI_FORMAT_UINT64 (*value), obj_desc->common_field.access_byte_width)); } else { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n", ACPI_FORMAT_UINT64 (*value), obj_desc->common_field.access_byte_width)); } } return_ACPI_STATUS (status); }
acpi_status acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, union acpi_parse_object *op) { acpi_status status; union acpi_operand_object *obj_desc; union acpi_operand_object **operand; struct acpi_namespace_node *node; union acpi_parse_object *next_op; u32 table_index; struct acpi_table_header *table; ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op); /* * This is where we evaluate the signature_string and oem_iDString * and oem_table_iDString of the data_table_region declaration */ node = op->common.node; /* next_op points to signature_string op */ next_op = op->common.value.arg; /* * Evaluate/create the signature_string and oem_iDString * and oem_table_iDString operands */ status = acpi_ds_create_operands(walk_state, next_op); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * Resolve the signature_string and oem_iDString * and oem_table_iDString operands */ status = acpi_ex_resolve_operands(op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } operand = &walk_state->operands[0]; /* Find the ACPI table */ status = acpi_tb_find_table(operand[0]->string.pointer, operand[1]->string.pointer, operand[2]->string.pointer, &table_index); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } acpi_ut_remove_reference(operand[0]); acpi_ut_remove_reference(operand[1]); acpi_ut_remove_reference(operand[2]); status = acpi_get_table_by_index(table_index, &table); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { return_ACPI_STATUS(AE_NOT_EXIST); } obj_desc->region.address = (acpi_physical_address) ACPI_TO_INTEGER(table); obj_desc->region.length = table->length; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", obj_desc, ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address), obj_desc->region.length)); /* Now the address and length are valid for this opregion */ obj_desc->region.flags |= AOPOBJ_DATA_VALID; return_ACPI_STATUS(status); }
acpi_status acpi_ex_write_with_update_rule ( union acpi_operand_object *obj_desc, acpi_integer mask, acpi_integer field_value, u32 field_datum_byte_offset) { acpi_status status = AE_OK; acpi_integer merged_value; acpi_integer current_value; ACPI_FUNCTION_TRACE_U32 ("ex_write_with_update_rule", mask); /* Start with the new bits */ merged_value = field_value; /* If the mask is all ones, we don't need to worry about the update rule */ if (mask != ACPI_INTEGER_MAX) { /* Decode the update rule */ switch (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK) { case AML_FIELD_UPDATE_PRESERVE: /* * Check if update rule needs to be applied (not if mask is all * ones) The left shift drops the bits we want to ignore. */ if ((~mask << (ACPI_MUL_8 (sizeof (mask)) - ACPI_MUL_8 (obj_desc->common_field.access_byte_width))) != 0) { /* * Read the current contents of the byte/word/dword containing * the field, and merge with the new field value. */ status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, ¤t_value, ACPI_READ); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } merged_value |= (current_value & ~mask); } break; case AML_FIELD_UPDATE_WRITE_AS_ONES: /* Set positions outside the field to all ones */ merged_value |= ~mask; break; case AML_FIELD_UPDATE_WRITE_AS_ZEROS: /* Set positions outside the field to all zeros */ merged_value &= mask; break; default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "write_with_update_rule: Unknown update_rule setting: %X\n", (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK))); return_ACPI_STATUS (AE_AML_OPERAND_VALUE); } } ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Mask %8.8X%8.8X, datum_offset %X, Width %X, Value %8.8X%8.8X, merged_value %8.8X%8.8X\n", ACPI_FORMAT_UINT64 (mask), field_datum_byte_offset, obj_desc->common_field.access_byte_width, ACPI_FORMAT_UINT64 (field_value), ACPI_FORMAT_UINT64 (merged_value))); /* Write the merged value */ status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, &merged_value, ACPI_WRITE); return_ACPI_STATUS (status); }
/* * TODO: The kernel doesn't have a 'down_timeout' function -- had to * improvise. The process is to sleep for one scheduler quantum * until the semaphore becomes available. Downside is that this * may result in starvation for timeout-based waits when there's * lots of semaphore activity. * * TODO: Support for units > 1? */ acpi_status acpi_os_wait_semaphore( acpi_handle handle, u32 units, u16 timeout) { acpi_status status = AE_OK; struct semaphore *sem = (struct semaphore*)handle; int ret = 0; ACPI_FUNCTION_TRACE ("os_wait_semaphore"); if (!sem || (units < 1)) return_ACPI_STATUS (AE_BAD_PARAMETER); if (units > 1) return_ACPI_STATUS (AE_SUPPORT); ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); if (in_atomic()) timeout = 0; switch (timeout) { /* * No Wait: * -------- * A zero timeout value indicates that we shouldn't wait - just * acquire the semaphore if available otherwise return AE_TIME * (a.k.a. 'would block'). */ case 0: if(down_trylock(sem)) status = AE_TIME; break; /* * Wait Indefinitely: * ------------------ */ case ACPI_WAIT_FOREVER: down(sem); break; /* * Wait w/ Timeout: * ---------------- */ default: // TODO: A better timeout algorithm? { int i = 0; static const int quantum_ms = 1000/HZ; ret = down_trylock(sem); for (i = timeout; (i > 0 && ret < 0); i -= quantum_ms) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); ret = down_trylock(sem); } if (ret != 0) status = AE_TIME; } break; } if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Failed to acquire semaphore[%p|%d|%d], %s\n", handle, units, timeout, acpi_format_exception(status))); } else { ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Acquired semaphore[%p|%d|%d]\n", handle, units, timeout)); } return_ACPI_STATUS (status); }
ACPI_STATUS AcpiDsCallControlMethod ( ACPI_THREAD_STATE *Thread, ACPI_WALK_STATE *ThisWalkState, ACPI_PARSE_OBJECT *Op) { ACPI_STATUS Status; ACPI_NAMESPACE_NODE *MethodNode; ACPI_WALK_STATE *NextWalkState = NULL; ACPI_OPERAND_OBJECT *ObjDesc; ACPI_EVALUATE_INFO *Info; UINT32 i; ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n", ThisWalkState->PrevOp, ThisWalkState)); /* * Get the namespace entry for the control method we are about to call */ MethodNode = ThisWalkState->MethodCallNode; if (!MethodNode) { return_ACPI_STATUS (AE_NULL_ENTRY); } ObjDesc = AcpiNsGetAttachedObject (MethodNode); if (!ObjDesc) { return_ACPI_STATUS (AE_NULL_OBJECT); } /* Init for new method, possibly wait on method mutex */ Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc, ThisWalkState); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Begin method parse/execution. Create a new walk state */ NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread); if (!NextWalkState) { Status = AE_NO_MEMORY; goto Cleanup; } /* * The resolved arguments were put on the previous walk state's operand * stack. Operands on the previous walk state stack always * start at index 0. Also, null terminate the list of arguments */ ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL; /* * Allocate and initialize the evaluation information block * TBD: this is somewhat inefficient, should change interface to * DsInitAmlWalk. For now, keeps this struct off the CPU stack */ Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); if (!Info) { Status = AE_NO_MEMORY; goto Cleanup; } Info->Parameters = &ThisWalkState->Operands[0]; Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode, ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, Info, ACPI_IMODE_EXECUTE); ACPI_FREE (Info); if (ACPI_FAILURE (Status)) { goto Cleanup; } /* * Delete the operands on the previous walkstate operand stack * (they were copied to new objects) */ for (i = 0; i < ObjDesc->Method.ParamCount; i++) { AcpiUtRemoveReference (ThisWalkState->Operands [i]); ThisWalkState->Operands [i] = NULL; } /* Clear the operand stack */ ThisWalkState->NumOperands = 0; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", MethodNode->Name.Ascii, NextWalkState)); /* Invoke an internal method if necessary */ if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY) { Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState); if (Status == AE_OK) { Status = AE_CTRL_TERMINATE; } } return_ACPI_STATUS (Status); Cleanup: /* On error, we must terminate the method properly */ AcpiDsTerminateControlMethod (ObjDesc, NextWalkState); if (NextWalkState) { AcpiDsDeleteWalkState (NextWalkState); } return_ACPI_STATUS (Status); }