return (NULL);
}
- /*
- * A Non-null gpe_device means this is a GPE Block Device.
- */
+ /* A Non-NULL gpe_device means this is a GPE Block Device */
+
obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) gpe_device);
if (!obj_desc ||
!obj_desc->device.gpe_block) {
}
}
- if (local_gpe_event_info.flags & ACPI_EVENT_LEVEL_TRIGGERED) {
+ if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) {
/*
* GPE is level-triggered, we clear the GPE status bit after handling
* the event.
* If edge-triggered, clear the GPE status bit now. Note that
* level-triggered events are cleared after the GPE is serviced.
*/
- if (gpe_event_info->flags & ACPI_EVENT_EDGE_TRIGGERED) {
+ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) {
status = acpi_hw_clear_gpe (gpe_event_info);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to clear GPE[%2X]\n",
/* It is now safe to clear level-triggered events. */
- if (gpe_event_info->flags & ACPI_EVENT_LEVEL_TRIGGERED) {
+ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) {
status = acpi_hw_clear_gpe (gpe_event_info);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
* information for quick lookup during GPE dispatch
*
* The name of each GPE control method is of the form:
- * "_Lnn" or "_Enn"
- * Where:
- * L - means that the GPE is level triggered
- * E - means that the GPE is edge triggered
- * nn - is the GPE number [in HEX]
+ * "_Lxx" or "_Exx"
+ * Where:
+ * L - means that the GPE is level triggered
+ * E - means that the GPE is edge triggered
+ * xx - is the GPE number [in HEX]
*
******************************************************************************/
u32 gpe_number;
char name[ACPI_NAME_SIZE + 1];
u8 type;
- acpi_status status;
ACPI_FUNCTION_TRACE ("ev_save_method_info");
- /* Extract the name from the object and convert to a string */
-
+ /*
+ * _Lxx and _Exx GPE method support
+ *
+ * 1) Extract the name from the object and convert to a string
+ */
ACPI_MOVE_32_TO_32 (name,
&((struct acpi_namespace_node *) obj_handle)->name.integer);
name[ACPI_NAME_SIZE] = 0;
/*
- * Edge/Level determination is based on the 2nd character
- * of the method name
+ * 2) Edge/Level determination is based on the 2nd character
+ * of the method name
+ *
+ * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE if a
+ * _PRW object is found that points to this GPE.
*/
switch (name[1]) {
case 'L':
- type = ACPI_EVENT_LEVEL_TRIGGERED;
+ type = ACPI_GPE_LEVEL_TRIGGERED | ACPI_GPE_TYPE_RUNTIME;
break;
case 'E':
- type = ACPI_EVENT_EDGE_TRIGGERED;
+ type = ACPI_GPE_EDGE_TRIGGERED | ACPI_GPE_TYPE_RUNTIME;
break;
default:
/* Unknown method type, just ignore it! */
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Unknown GPE method type: %s (name not of form _Lnn or _Enn)\n",
+ "Unknown GPE method type: %s (name not of form _Lxx or _Exx)\n",
name));
return_ACPI_STATUS (AE_OK);
}
/* Conversion failed; invalid method, just ignore it */
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Could not extract GPE number from name: %s (name is not of form _Lnn or _Enn)\n",
+ "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)\n",
name));
return_ACPI_STATUS (AE_OK);
}
gpe_event_info->flags = type;
gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle;
- /* Enable the GPE (SCIs should be disabled at this point) */
-
- status = acpi_hw_enable_gpe (gpe_event_info);
- if (ACPI_FAILURE (status)) {
- return_ACPI_STATUS (status);
- }
-
ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
"Registered GPE method %s as GPE number 0x%.2X\n",
name, gpe_number));
}
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_get_gpe_type
+ *
+ * PARAMETERS: Callback from walk_namespace
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
+ * Device. Run the _PRW method. If present, extract the GPE
+ * number and mark the GPE as a WAKE GPE.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_get_gpe_type (
+ acpi_handle obj_handle,
+ u32 level,
+ void *info,
+ void **return_value)
+{
+ struct acpi_gpe_walk_info *gpe_info = (void *) info;
+ struct acpi_namespace_node *gpe_device;
+ struct acpi_gpe_block_info *gpe_block;
+ struct acpi_namespace_node *target_gpe_device;
+ struct acpi_gpe_event_info *gpe_event_info;
+ union acpi_operand_object *pkg_desc;
+ union acpi_operand_object *obj_desc;
+ u32 gpe_number;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_get_gpe_type");
+
+
+ /* Check for a _PRW method under this device */
+
+ status = acpi_ut_evaluate_object (obj_handle, METHOD_NAME__PRW,
+ ACPI_BTYPE_PACKAGE, &pkg_desc);
+ if (status == AE_NOT_FOUND) {
+ return_ACPI_STATUS (AE_OK);
+ }
+ else if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* The returned _PRW package must have at least two elements */
+
+ if (pkg_desc->package.count < 2) {
+ goto cleanup;
+ }
+
+ /* Extract pointers from the input context */
+
+ gpe_device = gpe_info->gpe_device;
+ gpe_block = gpe_info->gpe_block;
+
+ /*
+ * The _PRW object must return a package, we are only interested
+ * in the first element
+ */
+ obj_desc = pkg_desc->package.elements[0];
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+ /* Use FADT-defined GPE device (from definition of _PRW) */
+
+ target_gpe_device = acpi_gbl_fadt_gpe_device;
+
+ /* Integer is the GPE number in the FADT described GPE blocks */
+
+ gpe_number = (u32) obj_desc->integer.value;
+ }
+ else if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_PACKAGE) {
+ /* Package contains a GPE reference and GPE number within a GPE block */
+
+ if ((obj_desc->package.count < 2) ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[0]) != ACPI_TYPE_LOCAL_REFERENCE) ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[1]) != ACPI_TYPE_INTEGER)) {
+ goto cleanup;
+ }
+
+ /* Get GPE block reference and decode */
+
+ target_gpe_device = obj_desc->package.elements[0]->reference.node;
+ gpe_number = (u32) obj_desc->package.elements[1]->integer.value;
+ }
+ else {
+ /* Unknown type, just ignore it */
+
+ goto cleanup;
+ }
+
+ /*
+ * Is this GPE within this block?
+ *
+ * TRUE iff these conditions are true:
+ * 1) The GPE devices match.
+ * 2) The GPE index(number) is within the range of the Gpe Block
+ * associated with the GPE device.
+ */
+ if ((gpe_device == target_gpe_device) &&
+ (gpe_number >= gpe_block->block_base_number) &&
+ (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) {
+ /* Mark GPE for WAKE but DISABLED (even for wake) */
+
+ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number];
+ gpe_event_info->flags |= ACPI_GPE_TYPE_WAKE;
+ }
+
+cleanup:
+ acpi_ut_remove_reference (pkg_desc);
+
+ return_ACPI_STATUS (status);
+}
+
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_get_gpe_xrupt_block
struct acpi_gpe_block_info **return_gpe_block)
{
struct acpi_gpe_block_info *gpe_block;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_native_uint i;
+ acpi_native_uint j;
+ u32 wake_gpe_count;
+ u32 gpe_enabled_count;
acpi_status status;
-
+ struct acpi_gpe_walk_info gpe_info;
ACPI_FUNCTION_TRACE ("ev_create_gpe_block");
/* Dump info about this GPE block */
- ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n",
gpe_block->block_base_number,
(u32) (gpe_block->block_base_number +
((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)),
ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, acpi_ev_save_method_info,
gpe_block, NULL);
+ /*
+ * Runtime option: Should Wake GPEs be enabled at runtime? The default is
+ * No,they should only be enabled just as the machine goes to sleep.
+ */
+ if (acpi_gbl_leave_wake_gpes_disabled) {
+ /*
+ * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. (Each
+ * GPE that has one or more _PRWs that reference it is by definition a
+ * WAKE GPE and will not be enabled while the machine is running.)
+ */
+ gpe_info.gpe_block = gpe_block;
+ gpe_info.gpe_device = gpe_device;
+
+ status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_get_gpe_type,
+ &gpe_info, NULL);
+ }
+
+ /*
+ * Enable all GPEs in this block that are 1) "runtime" GPEs, and 2) have
+ * a corresponding _Lxx or _Exx method. All other GPEs must be enabled via
+ * the acpi_enable_gpe() external interface.
+ */
+ wake_gpe_count = 0;
+ gpe_enabled_count = 0;
+
+ for (i = 0; i < gpe_block->register_count; i++) {
+ for (j = 0; j < 8; j++) {
+ /* Get the info block for this particular GPE */
+
+ gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j];
+ if ((gpe_event_info->method_node) &&
+ ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_RUNTIME)) {
+ /* Enable this GPE, it is 1) RUNTIME and 2) has an _Lxx or _Exx method */
+
+ status = acpi_hw_enable_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ gpe_enabled_count++;
+ }
+
+ if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_WAKE) {
+ wake_gpe_count++;
+ }
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "Found %u Wake, Enabled %u Runtime GPEs in this block\n",
+ wake_gpe_count, gpe_enabled_count));
+
/* Return the new block */
if (return_gpe_block) {
******************************************************************************/
acpi_status
-acpi_ev_gpe_initialize (void)
+acpi_ev_gpe_initialize (
+ void)
{
u32 register_count0 = 0;
u32 register_count1 = 0;
u32 gpe_number_max = 0;
- acpi_handle gpe_device;
acpi_status status;
ACPI_FUNCTION_TRACE ("ev_gpe_initialize");
- /* Get a handle to the predefined _GPE object */
-
- status = acpi_get_handle (NULL, "\\_GPE", &gpe_device);
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/*
- * Initialize the GPE Blocks defined in the FADT
+ * Initialize the GPE Block(s) defined in the FADT
*
* Why the GPE register block lengths are divided by 2: From the ACPI Spec,
* section "General-Purpose Event Registers", we have:
/* Install GPE Block 0 */
- status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe0_blk,
+ status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe0_blk,
register_count0, 0, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]);
+
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"Could not create GPE Block 0, %s\n",
else {
/* Install GPE Block 1 */
- status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe1_blk,
+ status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe1_blk,
register_count1, acpi_gbl_FADT->gpe1_base,
acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[1]);
+
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
"Could not create GPE Block 1, %s\n",
/* GPEs are not required by ACPI, this is OK */
ACPI_REPORT_INFO (("There are no GPE blocks defined in the FADT\n"));
- return_ACPI_STATUS (AE_OK);
+ status = AE_OK;
+ goto cleanup;
}
/* Check for Max GPE number out-of-range */
if (gpe_number_max > ACPI_GPE_MAX) {
ACPI_REPORT_ERROR (("Maximum GPE number from FADT is too large: 0x%X\n",
gpe_number_max));
- return_ACPI_STATUS (AE_BAD_VALUE);
+ status = AE_BAD_VALUE;
+ goto cleanup;
}
+cleanup:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return_ACPI_STATUS (AE_OK);
}
*
******************************************************************************/
+#ifdef ACPI_DEBUG_OUTPUT
+static const char *acpi_notify_value_names[] =
+{
+ "Bus Check",
+ "Device Check",
+ "Device Wake",
+ "Eject request",
+ "Device Check Light",
+ "Frequency Mismatch",
+ "Bus Mode Mismatch",
+ "Power Fault"
+};
+#endif
+
acpi_status
acpi_ev_queue_notify_request (
struct acpi_namespace_node *node,
/*
- * For value 1 (Ejection Request), some device method may need to be run.
+ * For value 3 (Ejection Request), some device method may need to be run.
* For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run.
* For value 0x80 (Status Change) on the power button or sleep button,
* initiate soft-off or sleep operation?
ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
"Dispatching Notify(%X) on node %p\n", notify_value, node));
- switch (notify_value) {
- case 0:
- ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Re-enumerate Devices\n"));
- break;
-
- case 1:
- ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Ejection Request\n"));
- break;
-
- case 2:
- ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Device Wake\n"));
- break;
-
- case 0x80:
- ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Status Change\n"));
- break;
-
- default:
- ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unknown Notify Value: %X \n", notify_value));
- break;
+ if (notify_value <= 7) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: %s\n",
+ acpi_notify_value_names[notify_value]));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "notify value: 0x2.2_x **Device Specific**\n",
+ notify_value));
}
/*
goto unlock_and_exit;
}
- /* Enable the requested GPE number */
-
- status = acpi_hw_enable_gpe (gpe_event_info);
- if (ACPI_FAILURE (status)) {
- goto unlock_and_exit;
- }
+ /* Check for Wake vs Runtime GPE */
if (flags & ACPI_EVENT_WAKE_ENABLE) {
+ /* Ensure the requested wake GPE is disabled */
+
+ status = acpi_hw_disable_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Defer Enable of Wake GPE until sleep time */
+
acpi_hw_enable_gpe_for_wakeup (gpe_event_info);
}
+ else {
+ /* Enable the requested runtime GPE */
+
+ status = acpi_hw_enable_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ }
+
unlock_and_exit:
if (flags & ACPI_NOT_ISR) {
alias_node = (struct acpi_namespace_node *) walk_state->operands[0];
target_node = (struct acpi_namespace_node *) walk_state->operands[1];
- if (target_node->type == ACPI_TYPE_LOCAL_ALIAS) {
+ if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) ||
+ (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
/*
* Dereference an existing alias so that we don't create a chain
* of aliases. With this code, we guarantee that an alias is
* always exactly one level of indirection away from the
* actual aliased name.
*/
- target_node = (struct acpi_namespace_node *) target_node->object;
+ target_node = ACPI_CAST_PTR (struct acpi_namespace_node, target_node->object);
}
/*
alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node);
break;
+ case ACPI_TYPE_METHOD:
+
+ /*
+ * The new alias has the type ALIAS and points to the original
+ * NS node, not the object itself. This is because for these
+ * types, the object can change dynamically via a Store.
+ */
+ alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS;
+ alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node);
+ break;
+
default:
/* Attach the original source object to the new Alias Node */
case ACPI_TYPE_LOCAL_ALIAS:
+ case ACPI_TYPE_LOCAL_METHOD_ALIAS:
case ACPI_TYPE_LOCAL_EXTRA:
case ACPI_TYPE_LOCAL_DATA:
default:
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Entry=%p source_desc=%p [%s]\n",
node, source_desc, acpi_ut_get_type_name (entry_type)));
- if (entry_type == ACPI_TYPE_LOCAL_ALIAS) {
+ if ((entry_type == ACPI_TYPE_LOCAL_ALIAS) ||
+ (entry_type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
/* There is always exactly one level of indirection */
- node = (struct acpi_namespace_node *) node->object;
+ node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object);
source_desc = acpi_ns_get_attached_object (node);
entry_type = acpi_ns_get_type ((acpi_handle) node);
*object_ptr = node;
case ACPI_TYPE_LOCAL_ALIAS:
+ case ACPI_TYPE_LOCAL_METHOD_ALIAS:
/*
* Aliases are resolved by acpi_ex_prep_operands
*
* FUNCTION: acpi_hw_enable_gpe
*
- * PARAMETERS: gpe_number - The GPE
+ * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled
*
- * RETURN: None
+ * RETURN: Status
*
* DESCRIPTION: Enable a single GPE.
*
*
* FUNCTION: acpi_hw_enable_gpe_for_wakeup
*
- * PARAMETERS: gpe_number - The GPE
+ * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled
*
* RETURN: None
*
}
/*
- * Set the bit so we will not disable this when sleeping
+ * Set the bit so we will not enable this GPE when sleeping (and disable
+ * it upon wake)
*/
gpe_register_info->wake_enable |= gpe_event_info->bit_mask;
+ gpe_event_info->flags |= (ACPI_GPE_TYPE_WAKE | ACPI_GPE_ENABLED);
}
*
* FUNCTION: acpi_hw_disable_gpe
*
- * PARAMETERS: gpe_number - The GPE
+ * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled
*
- * RETURN: None
+ * RETURN: Status
*
* DESCRIPTION: Disable a single GPE.
*
return (status);
}
+ /* Make sure this GPE is disabled for wake, also */
+
acpi_hw_disable_gpe_for_wakeup (gpe_event_info);
return (AE_OK);
}
*
* FUNCTION: acpi_hw_disable_gpe_for_wakeup
*
- * PARAMETERS: gpe_number - The GPE
+ * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled
*
* RETURN: None
*
return;
}
- /*
- * Clear the bit so we will disable this when sleeping
- */
+ /* Clear the bit so we will disable this when sleeping */
+
gpe_register_info->wake_enable &= ~(gpe_event_info->bit_mask);
}
*
* FUNCTION: acpi_hw_clear_gpe
*
- * PARAMETERS: gpe_number - The GPE
+ * PARAMETERS: gpe_event_info - Info block for the GPE to be cleared
*
- * RETURN: None
+ * RETURN: status_status
*
- * DESCRIPTION: Clear a single GPE.
+ * DESCRIPTION: Clear the status bit for a single GPE.
*
******************************************************************************/
*
* FUNCTION: acpi_hw_get_gpe_status
*
- * PARAMETERS: gpe_number - The GPE
+ * PARAMETERS: gpe_event_info - Info block for the GPE to queried
+ * event_status - Where the GPE status is returned
*
- * RETURN: None
+ * RETURN: Status
*
* DESCRIPTION: Return the status of a single GPE.
*
*
* RETURN: Status
*
- * DESCRIPTION: Clear all GPEs within a GPE block
+ * DESCRIPTION: Clear status bits for all GPEs within a GPE block
*
******************************************************************************/
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
- /* Clear all GPEs in this register */
+ /* Clear status on all GPEs in this register */
status = acpi_hw_low_level_write (8, 0xFF,
&gpe_block->register_info[i].status_address);
/******************************************************************************
*
- * FUNCTION: acpi_hw_disable_non_wakeup_gpe_block
+ * FUNCTION: acpi_hw_prepare_gpe_block_for_sleep
*
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info
* gpe_block - Gpe Block info
*
* RETURN: Status
*
- * DESCRIPTION: Disable all GPEs except wakeup GPEs in a GPE block
+ * DESCRIPTION: Disable all runtime GPEs and enable all wakeup GPEs -- within
+ * a single GPE block
*
******************************************************************************/
static acpi_status
-acpi_hw_disable_non_wakeup_gpe_block (
+acpi_hw_prepare_gpe_block_for_sleep (
struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block)
{
for (i = 0; i < gpe_block->register_count; i++) {
/*
- * Read the enabled status of all GPEs. We
+ * Read the enabled/disabled status of all GPEs. We
* will be using it to restore all the GPEs later.
+ *
+ * NOTE: Wake GPEs are are ALL disabled at this time, so when we wake
+ * and restore this register, they will be automatically disabled.
*/
status = acpi_hw_low_level_read (8, &in_value,
&gpe_register_info->enable_address);
gpe_register_info->enable = (u8) in_value;
/*
- * Disable all GPEs except wakeup GPEs.
+ * 1) Disable all runtime GPEs
+ * 2) Enable all wakeup GPEs
*/
status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable,
&gpe_register_info->enable_address);
return (status);
}
+ /* Point to next GPE register */
+
gpe_register_info++;
}
/******************************************************************************
*
- * FUNCTION: acpi_hw_disable_non_wakeup_gpes
+ * FUNCTION: acpi_hw_prepare_gpes_for_sleep
*
* PARAMETERS: None
*
- * RETURN: None
+ * RETURN: Status
*
- * DESCRIPTION: Disable all non-wakeup GPEs
+ * DESCRIPTION: Disable all runtime GPEs, enable all wake GPEs.
* Called with interrupts disabled. The interrupt handler also
* modifies gpe_register_info->Enable, so it should not be
- * given the chance to run until after non-wake GPEs are
+ * given the chance to run until after the runtime GPEs are
* re-enabled.
*
******************************************************************************/
acpi_status
-acpi_hw_disable_non_wakeup_gpes (
+acpi_hw_prepare_gpes_for_sleep (
void)
{
acpi_status status;
ACPI_FUNCTION_ENTRY ();
- status = acpi_ev_walk_gpe_list (acpi_hw_disable_non_wakeup_gpe_block);
-
+ status = acpi_ev_walk_gpe_list (acpi_hw_prepare_gpe_block_for_sleep);
return (status);
}
/******************************************************************************
*
- * FUNCTION: acpi_hw_enable_non_wakeup_gpe_block
+ * FUNCTION: acpi_hw_restore_gpe_block_on_wake
*
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info
* gpe_block - Gpe Block info
*
* RETURN: Status
*
- * DESCRIPTION: Enable a single GPE.
+ * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in one
+ * GPE block
*
******************************************************************************/
static acpi_status
-acpi_hw_enable_non_wakeup_gpe_block (
+acpi_hw_restore_gpe_block_on_wake (
struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block)
{
}
/*
- * We previously stored the enabled status of all GPEs.
- * Blast them back in.
+ * Restore the GPE Enable register, which will do the following:
+ *
+ * 1) Disable all wakeup GPEs
+ * 2) Enable all runtime GPEs
+ *
+ * (On sleep, we saved the enabled status of all GPEs)
*/
status = acpi_hw_low_level_write (8, gpe_register_info->enable,
&gpe_register_info->enable_address);
return (status);
}
+ /* Point to next GPE register */
+
gpe_register_info++;
}
-
return (AE_OK);
}
/******************************************************************************
*
- * FUNCTION: acpi_hw_enable_non_wakeup_gpes
+ * FUNCTION: acpi_hw_restore_gpes_on_wake
*
* PARAMETERS: None
*
- * RETURN: None
+ * RETURN: Status
*
- * DESCRIPTION: Enable all non-wakeup GPEs we previously enabled.
+ * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in all
+ * GPE blocks
*
******************************************************************************/
acpi_status
-acpi_hw_enable_non_wakeup_gpes (
+acpi_hw_restore_gpes_on_wake (
void)
{
acpi_status status;
ACPI_FUNCTION_ENTRY ();
- status = acpi_ev_walk_gpe_list (acpi_hw_enable_non_wakeup_gpe_block);
-
+ status = acpi_ev_walk_gpe_list (acpi_hw_restore_gpe_block_on_wake);
return (status);
}
}
}
- status = acpi_hw_disable_non_wakeup_gpes ();
+ /*
+ * 1) Disable all runtime GPEs
+ * 2) Enable all wakeup GPEs
+ */
+ status = acpi_hw_prepare_gpes_for_sleep ();
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
return_ACPI_STATUS (status);
}
- status = acpi_hw_disable_non_wakeup_gpes ();
+ /*
+ * 1) Disable all runtime GPEs
+ * 2) Enable all wakeup GPEs
+ */
+ status = acpi_hw_prepare_gpes_for_sleep ();
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status)));
}
+ /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
- /* _WAK returns stuff - do we want to look at it? */
-
- status = acpi_hw_enable_non_wakeup_gpes ();
+ /*
+ * Restore the GPEs:
+ * 1) Disable all wakeup GPEs
+ * 2) Enable all runtime GPEs
+ */
+ status = acpi_hw_restore_gpes_on_wake ();
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
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);
}
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)) {
case ACPI_TYPE_LOCAL_ALIAS:
+ case ACPI_TYPE_LOCAL_METHOD_ALIAS:
acpi_os_printf ("Target %4.4s (%p)\n", acpi_ut_get_node_name (obj_desc), obj_desc);
break;
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
+ /*
+ * For a method alias, we must grab the actual method node
+ * so that proper scoping context will be established
+ * before execution.
+ */
+ if (acpi_ns_get_type (node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+ node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object);
+ }
+
/*
* Two major cases here:
* 1) The object is an actual control method -- execute it.
/* Check for match against the name */
if (next_node->name.integer == target_name) {
+ /* Resolve a control method alias if any */
+
+ if (acpi_ns_get_type (next_node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+ next_node = ACPI_CAST_PTR (struct acpi_namespace_node, next_node->object);
+ }
+
/*
* Found matching entry.
*/
if (!node) {
- ACPI_REPORT_WARNING (("ns_get_type: Null Node ptr"));
+ ACPI_REPORT_WARNING (("ns_get_type: Null Node input pointer\n"));
return_VALUE (ACPI_TYPE_ANY);
}
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
#define _COMPONENT ACPI_NAMESPACE
* FUNCTION: acpi_evaluate_object
*
* PARAMETERS: Handle - Object handle (optional)
- * *Pathname - Object pathname (optional)
- * **external_params - List of parameters to pass to method,
+ * Pathname - Object pathname (optional)
+ * external_params - List of parameters to pass to method,
* terminated by NULL. May be NULL
* if no parameters are being passed.
- * *return_buffer - Where to put method's return value (if
+ * return_buffer - Where to put method's return value (if
* any). If NULL, no value is returned.
*
* RETURN: Status
struct acpi_buffer *return_buffer)
{
acpi_status status;
+ acpi_status status2;
union acpi_operand_object **internal_params = NULL;
union acpi_operand_object *internal_return_obj = NULL;
acpi_size buffer_space_needed;
*/
for (i = 0; i < external_params->count; i++) {
status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i],
- &internal_params[i]);
+ &internal_params[i]);
if (ACPI_FAILURE (status)) {
acpi_ut_delete_internal_object_list (internal_params);
return_ACPI_STATUS (status);
}
}
- /* Delete the return and parameter objects */
-
if (internal_return_obj) {
/*
- * Delete the internal return object. (Or at least
- * decrement the reference count by one)
+ * Delete the internal return object. NOTE: Interpreter
+ * must be locked to avoid race condition.
*/
- acpi_ut_remove_reference (internal_return_obj);
+ status2 = acpi_ex_enter_interpreter ();
+ if (ACPI_SUCCESS (status2)) {
+ /*
+ * Delete the internal return object. (Or at least
+ * decrement the reference count by one)
+ */
+ acpi_ut_remove_reference (internal_return_obj);
+ acpi_ex_exit_interpreter ();
+ }
}
/*
ACPI_FUNCTION_TRACE ("rs_address16_resource");
+
/*
* Point past the Descriptor to get the number of bytes consumed
*/
output_struct->data.address16.attribute.memory.read_write_attribute =
(u16) (temp8 & 0x01);
output_struct->data.address16.attribute.memory.cache_attribute =
- (u16) ((temp8 >> 1) & 0x0F);
+ (u16) ((temp8 >> 1) & 0x03);
}
else {
if (ACPI_IO_RANGE == output_struct->data.address16.resource_type) {
temp8 |=
(linked_list->data.address16.attribute.memory.cache_attribute &
- 0x0F) << 1;
+ 0x03) << 1;
}
else if (ACPI_IO_RANGE == linked_list->data.address16.resource_type) {
temp8 = (u8)
(u16) (temp8 & 0x01);
output_struct->data.address32.attribute.memory.cache_attribute =
- (u16) ((temp8 >> 1) & 0x0F);
+ (u16) ((temp8 >> 1) & 0x03);
}
else {
if (ACPI_IO_RANGE == output_struct->data.address32.resource_type) {
temp8 |=
(linked_list->data.address32.attribute.memory.cache_attribute &
- 0x0F) << 1;
+ 0x03) << 1;
}
else if (ACPI_IO_RANGE == linked_list->data.address32.resource_type) {
temp8 = (u8)
(u16) (temp8 & 0x01);
output_struct->data.address64.attribute.memory.cache_attribute =
- (u16) ((temp8 >> 1) & 0x0F);
+ (u16) ((temp8 >> 1) & 0x03);
}
else {
if (ACPI_IO_RANGE == output_struct->data.address64.resource_type) {
temp8 |=
(linked_list->data.address64.attribute.memory.cache_attribute &
- 0x0F) << 1;
+ 0x03) << 1;
}
else if (ACPI_IO_RANGE == linked_list->data.address64.resource_type) {
temp8 = (u8)
ACPI_NS_NORMAL, /* 19 index_field */
ACPI_NS_NORMAL, /* 20 Reference */
ACPI_NS_NORMAL, /* 21 Alias */
- ACPI_NS_NORMAL, /* 22 Notify */
- ACPI_NS_NORMAL, /* 23 Address Handler */
- ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 24 Resource Desc */
- ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Field */
- ACPI_NS_NEWSCOPE, /* 26 Scope */
- ACPI_NS_NORMAL, /* 27 Extra */
- ACPI_NS_NORMAL, /* 28 Data */
- ACPI_NS_NORMAL /* 29 Invalid */
+ ACPI_NS_NORMAL, /* 22 method_alias */
+ ACPI_NS_NORMAL, /* 23 Notify */
+ ACPI_NS_NORMAL, /* 24 Address Handler */
+ ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Desc */
+ ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 26 Resource Field */
+ ACPI_NS_NEWSCOPE, /* 27 Scope */
+ ACPI_NS_NORMAL, /* 28 Extra */
+ ACPI_NS_NORMAL, /* 29 Data */
+ ACPI_NS_NORMAL /* 30 Invalid */
};
/* 19 */ "index_field",
/* 20 */ "Reference",
/* 21 */ "Alias",
- /* 22 */ "Notify",
- /* 23 */ "addr_handler",
- /* 24 */ "resource_desc",
- /* 25 */ "resource_fld",
- /* 26 */ "Scope",
- /* 27 */ "Extra",
- /* 28 */ "Data",
- /* 39 */ "Invalid"
+ /* 22 */ "method_alias",
+ /* 23 */ "Notify",
+ /* 24 */ "addr_handler",
+ /* 25 */ "resource_desc",
+ /* 26 */ "resource_fld",
+ /* 27 */ "Scope",
+ /* 28 */ "Extra",
+ /* 29 */ "Data",
+ /* 30 */ "Invalid"
};
acpi_ut_get_node_name (
void *object)
{
- struct acpi_namespace_node *node;
+ struct acpi_namespace_node *node = (struct acpi_namespace_node *) object;
if (!object)
return ("NULL NODE");
}
- node = (struct acpi_namespace_node *) object;
+ if (object == ACPI_ROOT_OBJECT)
+ {
+ node = acpi_gbl_root_node;
+ }
if (node->descriptor != ACPI_DESC_TYPE_NAMED)
{
acpi_gbl_create_osi_method = TRUE;
acpi_gbl_all_methods_serialized = FALSE;
+ acpi_gbl_leave_wake_gpes_disabled = TRUE;
/* Memory allocation and cache lists */
return (src_string);
}
+
/*******************************************************************************
*
* FUNCTION: acpi_ut_mutex_initialize
}
}
-
status = acpi_os_create_lock (&acpi_gbl_gpe_lock);
-
- return_ACPI_STATUS (AE_OK);
+ return_ACPI_STATUS (status);
}
/* Version string */
-#define ACPI_CA_VERSION 0x20040311
+#define ACPI_CA_VERSION 0x20040326
/* Maximum objects in the various object caches */
ACPI_EXTERN u8 acpi_gbl_create_osi_method;
ACPI_EXTERN u8 acpi_gbl_all_methods_serialized;
+ACPI_EXTERN u8 acpi_gbl_leave_wake_gpes_disabled;
/*****************************************************************************
*
ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct;
ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node;
+ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device;
extern const u8 acpi_gbl_ns_properties[NUM_NS_TYPES];
extern const struct acpi_predefined_names acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES];
acpi_event_status *event_status);
acpi_status
-acpi_hw_disable_non_wakeup_gpes (
+acpi_hw_prepare_gpes_for_sleep (
void);
acpi_status
-acpi_hw_enable_non_wakeup_gpes (
+acpi_hw_restore_gpes_on_wake (
void);
};
+struct acpi_gpe_walk_info
+{
+ struct acpi_namespace_node *gpe_device;
+ struct acpi_gpe_block_info *gpe_block;
+};
+
+
typedef acpi_status (*ACPI_GPE_CALLBACK) (
struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block);
* of the ACPI object_type() operator (See the ACPI Spec). Therefore,
* only add to the first group if the spec changes.
*
- * Types must be kept in sync with the global acpi_ns_properties
+ * NOTE: Types must be kept in sync with the global acpi_ns_properties
* and acpi_ns_type_names arrays.
*/
typedef u32 acpi_object_type;
#define ACPI_TYPE_LOCAL_INDEX_FIELD 0x13
#define ACPI_TYPE_LOCAL_REFERENCE 0x14 /* Arg#, Local#, Name, Debug, ref_of, Index */
#define ACPI_TYPE_LOCAL_ALIAS 0x15
-#define ACPI_TYPE_LOCAL_NOTIFY 0x16
-#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x17
-#define ACPI_TYPE_LOCAL_RESOURCE 0x18
-#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x19
-#define ACPI_TYPE_LOCAL_SCOPE 0x1A /* 1 Name, multiple object_list Nodes */
+#define ACPI_TYPE_LOCAL_METHOD_ALIAS 0x16
+#define ACPI_TYPE_LOCAL_NOTIFY 0x17
+#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x18
+#define ACPI_TYPE_LOCAL_RESOURCE 0x19
+#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x1A
+#define ACPI_TYPE_LOCAL_SCOPE 0x1B /* 1 Name, multiple object_list Nodes */
-#define ACPI_TYPE_NS_NODE_MAX 0x1A /* Last typecode used within a NS Node */
+#define ACPI_TYPE_NS_NODE_MAX 0x1B /* Last typecode used within a NS Node */
/*
* These are special object types that never appear in
* a Namespace node, only in an union acpi_operand_object
*/
-#define ACPI_TYPE_LOCAL_EXTRA 0x1B
-#define ACPI_TYPE_LOCAL_DATA 0x1C
+#define ACPI_TYPE_LOCAL_EXTRA 0x1C
+#define ACPI_TYPE_LOCAL_DATA 0x1D
-#define ACPI_TYPE_LOCAL_MAX 0x1C
+#define ACPI_TYPE_LOCAL_MAX 0x1D
/* All types above here are invalid */
-#define ACPI_TYPE_INVALID 0x1D
+#define ACPI_TYPE_INVALID 0x1E
#define ACPI_TYPE_NOT_FOUND 0xFF
#define ACPI_WRITE 1
#define ACPI_IO_MASK 1
-
/*
- * Acpi Event Types: Fixed & General Purpose
+ * Event Types: Fixed & General Purpose
*/
typedef u32 acpi_event_type;
#define ACPI_EVENT_MAX 4
#define ACPI_NUM_FIXED_EVENTS ACPI_EVENT_MAX + 1
-#define ACPI_GPE_INVALID 0xFF
-#define ACPI_GPE_MAX 0xFF
-#define ACPI_NUM_GPE 256
-
-#define ACPI_EVENT_LEVEL_TRIGGERED 1
-#define ACPI_EVENT_EDGE_TRIGGERED 2
-
-/*
- * Flags for GPE and Lock interfaces
- */
-#define ACPI_EVENT_WAKE_ENABLE 0x2
-#define ACPI_EVENT_WAKE_DISABLE 0x2
-
-#define ACPI_NOT_ISR 0x1
-#define ACPI_ISR 0x0
-
-
/*
- * acpi_event Status:
+ * Event Status - Per event
* -------------
* The encoding of acpi_event_status is illustrated below.
* Note that a set bit (1) indicates the property is TRUE
#define ACPI_EVENT_FLAG_WAKE_ENABLED (acpi_event_status) 0x02
#define ACPI_EVENT_FLAG_SET (acpi_event_status) 0x04
+/*
+ * General Purpose Events (GPE)
+ */
+#define ACPI_GPE_INVALID 0xFF
+#define ACPI_GPE_MAX 0xFF
+#define ACPI_NUM_GPE 256
+
+/*
+ * GPE info flags - Per GPE
+ * +---------+-+-+-+
+ * |Bits 8:3 |2|1|0|
+ * +---------+-+-+-+
+ * | | | |
+ * | | | +- Edge or Level Triggered
+ * | | +--- Type: Wake or Runtime
+ * | +----- Enabled for wake?
+ * +--------<Reserved>
+ */
+#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 1
+#define ACPI_GPE_LEVEL_TRIGGERED (u8) 1
+#define ACPI_GPE_EDGE_TRIGGERED (u8) 0
+
+#define ACPI_GPE_TYPE_MASK (u8) 2
+#define ACPI_GPE_TYPE_WAKE (u8) 2
+#define ACPI_GPE_TYPE_RUNTIME (u8) 0 /* Default */
+
+#define ACPI_GPE_ENABLE_MASK (u8) 4
+#define ACPI_GPE_ENABLED (u8) 4
+#define ACPI_GPE_DISABLED (u8) 0 /* Default */
+
+/*
+ * Flags for GPE and Lock interfaces
+ */
+#define ACPI_EVENT_WAKE_ENABLE 0x2
+#define ACPI_EVENT_WAKE_DISABLE 0x2
+
+#define ACPI_NOT_ISR 0x1
+#define ACPI_ISR 0x0
+
/* Notify types */
#define METHOD_NAME__PRT "_PRT"
#define METHOD_NAME__CRS "_CRS"
#define METHOD_NAME__PRS "_PRS"
+#define METHOD_NAME__PRW "_PRW"
acpi_status