Commit b29ea22d authored by Len Brown's avatar Len Brown Committed by Len Brown

[ACPI] Update Linux to ACPICA 20031203 (Bob Moore)

Changed the initialization of Operation Regions during subsystem init to
perform two entire walks of the ACPI namespace; The first to initialize
the regions themselves, the second to execute the _REG methods.  This
fixed some interdependencies across _REG methods found on some machines.

Fixed a problem where a Store(Local0, Local1) could simply update the
object reference count, and not create a new copy of the object if the
Local1 is uninitialized.

Implemented support for the _SST reserved method during sleep
transitions.

Implemented support to clear the SLP_TYP and SLP_EN bits when waking up,
this is apparently required by some machines.

When sleeping, clear the wake status only if SleepState is not S5.

Fixed a problem in AcpiRsExtendedIrqResource() where an incorrect
pointer arithmetic advanced a string pointer too far.

Fixed a problem in AcpiTbGetTablePtr() where a garbage pointer could be
returned if the requested table has not been loaded.

Within the support for IRQ resources, restructured the handling of the
active and edge/level bits.

Fixed a few problems in AcpiPsxExecute() where memory could be leaked
under certain error conditions.

Improved error messages for the cases where the ACPI mode could not be
entered.
parent ea9c6d74
...@@ -567,13 +567,13 @@ acpi_ds_store_object_to_local ( ...@@ -567,13 +567,13 @@ acpi_ds_store_object_to_local (
acpi_status status; acpi_status status;
struct acpi_namespace_node *node; struct acpi_namespace_node *node;
union acpi_operand_object *current_obj_desc; union acpi_operand_object *current_obj_desc;
union acpi_operand_object *new_obj_desc;
ACPI_FUNCTION_TRACE ("ds_store_object_to_local"); ACPI_FUNCTION_TRACE ("ds_store_object_to_local");
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%d Idx=%d Obj=%p\n", ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%d Idx=%d Obj=%p\n",
opcode, index, obj_desc)); opcode, index, obj_desc));
/* Parameter validation */ /* Parameter validation */
if (!obj_desc) { if (!obj_desc) {
...@@ -594,6 +594,19 @@ acpi_ds_store_object_to_local ( ...@@ -594,6 +594,19 @@ acpi_ds_store_object_to_local (
return_ACPI_STATUS (status); 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.
*/
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);
new_obj_desc;
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
/* /*
* If there is an object already in this slot, we either * If there is an object already in this slot, we either
* have to delete it, or if this is an argument and there * have to delete it, or if this is an argument and there
...@@ -637,14 +650,20 @@ acpi_ds_store_object_to_local ( ...@@ -637,14 +650,20 @@ acpi_ds_store_object_to_local (
(current_obj_desc->reference.opcode == AML_REF_OF_OP)) { (current_obj_desc->reference.opcode == AML_REF_OF_OP)) {
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
"Arg (%p) is an obj_ref(Node), storing in node %p\n", "Arg (%p) is an obj_ref(Node), storing in node %p\n",
obj_desc, current_obj_desc)); new_obj_desc, current_obj_desc));
/* /*
* Store this object to the Node * Store this object to the Node
* (perform the indirect store) * (perform the indirect store)
*/ */
status = acpi_ex_store_object_to_node (obj_desc, status = acpi_ex_store_object_to_node (new_obj_desc,
current_obj_desc->reference.object, walk_state); current_obj_desc->reference.object, 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); return_ACPI_STATUS (status);
} }
} }
...@@ -657,12 +676,18 @@ acpi_ds_store_object_to_local ( ...@@ -657,12 +676,18 @@ acpi_ds_store_object_to_local (
} }
/* /*
* Install the obj_stack descriptor (*obj_desc) into * Install the Obj descriptor (*new_obj_desc) into
* the descriptor for the Arg or Local. * the descriptor for the Arg or Local.
* Install the new object in the stack entry
* (increments the object reference count by one) * (increments the object reference count by one)
*/ */
status = acpi_ds_method_data_set_value (opcode, index, obj_desc, walk_state); 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); return_ACPI_STATUS (status);
} }
......
...@@ -167,7 +167,7 @@ acpi_ds_load1_begin_op ( ...@@ -167,7 +167,7 @@ acpi_ds_load1_begin_op (
object_type = walk_state->op_info->object_type; object_type = walk_state->op_info->object_type;
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
"State=%p Op=%p [%s] ", walk_state, op, acpi_ut_get_type_name (object_type))); "State=%p Op=%p [%s]\n", walk_state, op, acpi_ut_get_type_name (object_type)));
switch (walk_state->opcode) { switch (walk_state->opcode) {
case AML_SCOPE_OP: case AML_SCOPE_OP:
...@@ -260,10 +260,12 @@ acpi_ds_load1_begin_op ( ...@@ -260,10 +260,12 @@ acpi_ds_load1_begin_op (
if ((walk_state->opcode != AML_SCOPE_OP) && if ((walk_state->opcode != AML_SCOPE_OP) &&
(!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) { (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) {
flags |= ACPI_NS_ERROR_IF_FOUND; flags |= ACPI_NS_ERROR_IF_FOUND;
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "Cannot already exist\n")); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Cannot already exist\n",
acpi_ut_get_type_name (object_type)));
} }
else { else {
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DISPATCH, "Both Find or Create allowed\n")); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n",
acpi_ut_get_type_name (object_type)));
} }
/* /*
......
...@@ -477,7 +477,7 @@ acpi_ev_install_gpe_block ( ...@@ -477,7 +477,7 @@ acpi_ev_install_gpe_block (
* *
* RETURN: Status * RETURN: Status
* *
* DESCRIPTION: Install new GPE block with mutex support * DESCRIPTION: Remove a GPE block
* *
******************************************************************************/ ******************************************************************************/
......
...@@ -136,7 +136,7 @@ acpi_ev_init_address_spaces ( ...@@ -136,7 +136,7 @@ acpi_ev_init_address_spaces (
* *
******************************************************************************/ ******************************************************************************/
static acpi_status acpi_status
acpi_ev_execute_reg_method ( acpi_ev_execute_reg_method (
union acpi_operand_object *region_obj, union acpi_operand_object *region_obj,
u32 function) u32 function)
...@@ -202,7 +202,7 @@ acpi_ev_execute_reg_method ( ...@@ -202,7 +202,7 @@ acpi_ev_execute_reg_method (
* *
* FUNCTION: acpi_ev_address_space_dispatch * FUNCTION: acpi_ev_address_space_dispatch
* *
* PARAMETERS: region_obj - internal region object * PARAMETERS: region_obj - Internal region object
* space_id - ID of the address space (0-255) * space_id - ID of the address space (0-255)
* Function - Read or Write operation * Function - Read or Write operation
* Address - Where in the space to read or write * Address - Where in the space to read or write
...@@ -243,9 +243,11 @@ acpi_ev_address_space_dispatch ( ...@@ -243,9 +243,11 @@ acpi_ev_address_space_dispatch (
/* Ensure that there is a handler associated with this region */ /* Ensure that there is a handler associated with this region */
handler_desc = region_obj->region.address_space; handler_desc = region_obj->region.handler;
if (!handler_desc) { if (!handler_desc) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "no handler for region(%p) [%s]\n", ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"No handler for Region [%4.4s] (%p) [%s]\n",
acpi_ut_get_node_name (region_obj->region.node),
region_obj, acpi_ut_get_region_name (region_obj->region.space_id))); region_obj, acpi_ut_get_region_name (region_obj->region.space_id)));
return_ACPI_STATUS (AE_NOT_EXIST); return_ACPI_STATUS (AE_NOT_EXIST);
...@@ -320,7 +322,7 @@ acpi_ev_address_space_dispatch ( ...@@ -320,7 +322,7 @@ acpi_ev_address_space_dispatch (
ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n", "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
&region_obj->region.address_space->address_space, handler, &region_obj->region.handler->address_space, handler,
ACPI_FORMAT_UINT64 (address), ACPI_FORMAT_UINT64 (address),
acpi_ut_get_region_name (region_obj->region.space_id))); acpi_ut_get_region_name (region_obj->region.space_id)));
...@@ -359,6 +361,7 @@ acpi_ev_address_space_dispatch ( ...@@ -359,6 +361,7 @@ acpi_ev_address_space_dispatch (
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_ev_detach_region * FUNCTION: acpi_ev_detach_region
...@@ -398,7 +401,7 @@ acpi_ev_detach_region( ...@@ -398,7 +401,7 @@ acpi_ev_detach_region(
/* Get the address handler from the region object */ /* Get the address handler from the region object */
handler_obj = region_obj->region.address_space; handler_obj = region_obj->region.handler;
if (!handler_obj) { if (!handler_obj) {
/* This region has no handler, all done */ /* This region has no handler, all done */
...@@ -472,7 +475,7 @@ acpi_ev_detach_region( ...@@ -472,7 +475,7 @@ acpi_ev_detach_region(
* If the region is on the handler's list * If the region is on the handler's list
* this better be the region's handler * this better be the region's handler
*/ */
region_obj->region.address_space = NULL; region_obj->region.handler = NULL;
acpi_ut_remove_reference (handler_obj); acpi_ut_remove_reference (handler_obj);
return_VOID; return_VOID;
...@@ -515,17 +518,15 @@ acpi_ev_attach_region ( ...@@ -515,17 +518,15 @@ acpi_ev_attach_region (
union acpi_operand_object *region_obj, union acpi_operand_object *region_obj,
u8 acpi_ns_is_locked) u8 acpi_ns_is_locked)
{ {
acpi_status status;
acpi_status status2;
ACPI_FUNCTION_TRACE ("ev_attach_region"); ACPI_FUNCTION_TRACE ("ev_attach_region");
ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
"Adding Region %p to address handler %p [%s]\n", "Adding Region [%4.4s] %p to address handler %p [%s]\n",
region_obj, handler_obj, acpi_ut_get_region_name (region_obj->region.space_id))); acpi_ut_get_node_name (region_obj->region.node),
region_obj, handler_obj,
acpi_ut_get_region_name (region_obj->region.space_id)));
/* Link this region to the front of the handler's list */ /* Link this region to the front of the handler's list */
...@@ -534,34 +535,14 @@ acpi_ev_attach_region ( ...@@ -534,34 +535,14 @@ acpi_ev_attach_region (
/* Install the region's handler */ /* Install the region's handler */
if (region_obj->region.address_space) { if (region_obj->region.handler) {
return_ACPI_STATUS (AE_ALREADY_EXISTS); return_ACPI_STATUS (AE_ALREADY_EXISTS);
} }
region_obj->region.address_space = handler_obj; region_obj->region.handler = handler_obj;
acpi_ut_add_reference (handler_obj); acpi_ut_add_reference (handler_obj);
/* return_ACPI_STATUS (AE_OK);
* Tell all users that this region is usable by running the _REG
* method
*/
if (acpi_ns_is_locked) {
status2 = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status2)) {
return_ACPI_STATUS (status2);
}
}
status = acpi_ev_execute_reg_method (region_obj, 1);
if (acpi_ns_is_locked) {
status2 = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status2)) {
return_ACPI_STATUS (status2);
}
}
return_ACPI_STATUS (status);
} }
...@@ -569,9 +550,7 @@ acpi_ev_attach_region ( ...@@ -569,9 +550,7 @@ acpi_ev_attach_region (
* *
* FUNCTION: acpi_ev_install_handler * FUNCTION: acpi_ev_install_handler
* *
* PARAMETERS: Handle - Node to be dumped * PARAMETERS: walk_namespace callback
* Level - Nesting level of the handle
* Context - Passed into acpi_ns_walk_namespace
* *
* DESCRIPTION: This routine installs an address handler into objects that are * DESCRIPTION: This routine installs an address handler into objects that are
* of type Region or Device. * of type Region or Device.
...@@ -640,7 +619,7 @@ acpi_ev_install_handler ( ...@@ -640,7 +619,7 @@ acpi_ev_install_handler (
if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_DEVICE) { if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_DEVICE) {
/* Check if this Device already has a handler for this address space */ /* Check if this Device already has a handler for this address space */
next_handler_obj = obj_desc->device.address_space; next_handler_obj = obj_desc->device.handler;
while (next_handler_obj) { while (next_handler_obj) {
/* Found a handler, is it for the same address space? */ /* Found a handler, is it for the same address space? */
...@@ -697,4 +676,77 @@ acpi_ev_install_handler ( ...@@ -697,4 +676,77 @@ acpi_ev_install_handler (
return (status); return (status);
} }
/*******************************************************************************
*
* FUNCTION: acpi_ev_reg_run
*
* PARAMETERS: walk_namespace callback
*
* DESCRIPTION: Run _REg method for region objects of the requested space_iD
*
******************************************************************************/
acpi_status
acpi_ev_reg_run (
acpi_handle obj_handle,
u32 level,
void *context,
void **return_value)
{
union acpi_operand_object *handler_obj;
union acpi_operand_object *obj_desc;
struct acpi_namespace_node *node;
acpi_status status;
ACPI_FUNCTION_NAME ("ev_reg_run");
handler_obj = (union acpi_operand_object *) context;
/* Parameter validation */
if (!handler_obj) {
return (AE_OK);
}
/* Convert and validate the device handle */
node = acpi_ns_map_handle_to_node (obj_handle);
if (!node) {
return (AE_BAD_PARAMETER);
}
/*
* We only care about regions.and objects
* that are allowed to have address space handlers
*/
if ((node->type != ACPI_TYPE_REGION) &&
(node != acpi_gbl_root_node)) {
return (AE_OK);
}
/* Check for an existing internal object */
obj_desc = acpi_ns_get_attached_object (node);
if (!obj_desc) {
/* No object, just exit */
return (AE_OK);
}
/* Object is a Region */
if (obj_desc->region.space_id != handler_obj->address_space.space_id) {
/*
* This region is for a different address space
* -- just ignore it
*/
return (AE_OK);
}
status = acpi_ev_execute_reg_method (obj_desc, 1);
return (status);
}
...@@ -177,7 +177,7 @@ acpi_ev_pci_config_region_setup ( ...@@ -177,7 +177,7 @@ acpi_ev_pci_config_region_setup (
ACPI_FUNCTION_TRACE ("ev_pci_config_region_setup"); ACPI_FUNCTION_TRACE ("ev_pci_config_region_setup");
handler_obj = region_obj->region.address_space; handler_obj = region_obj->region.handler;
if (!handler_obj) { if (!handler_obj) {
/* /*
* No installed handler. This shouldn't happen because the dispatch * No installed handler. This shouldn't happen because the dispatch
...@@ -469,7 +469,7 @@ acpi_ev_initialize_region ( ...@@ -469,7 +469,7 @@ acpi_ev_initialize_region (
/* Setup defaults */ /* Setup defaults */
region_obj->region.address_space = NULL; region_obj->region.handler = NULL;
region_obj2->extra.method_REG = NULL; region_obj2->extra.method_REG = NULL;
region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE);
region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED;
...@@ -502,17 +502,17 @@ acpi_ev_initialize_region ( ...@@ -502,17 +502,17 @@ acpi_ev_initialize_region (
switch (node->type) { switch (node->type) {
case ACPI_TYPE_DEVICE: case ACPI_TYPE_DEVICE:
handler_obj = obj_desc->device.address_space; handler_obj = obj_desc->device.handler;
break; break;
case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_PROCESSOR:
handler_obj = obj_desc->processor.address_space; handler_obj = obj_desc->processor.handler;
break; break;
case ACPI_TYPE_THERMAL: case ACPI_TYPE_THERMAL:
handler_obj = obj_desc->thermal_zone.address_space; handler_obj = obj_desc->thermal_zone.handler;
break; break;
default: default:
...@@ -533,6 +533,26 @@ acpi_ev_initialize_region ( ...@@ -533,6 +533,26 @@ acpi_ev_initialize_region (
status = acpi_ev_attach_region (handler_obj, region_obj, status = acpi_ev_attach_region (handler_obj, region_obj,
acpi_ns_locked); acpi_ns_locked);
/*
* Tell all users that this region is usable by running the _REG
* method
*/
if (acpi_ns_locked) {
status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
status = acpi_ev_execute_reg_method (region_obj, 1);
if (acpi_ns_locked) {
status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
}
return_ACPI_STATUS (AE_OK); return_ACPI_STATUS (AE_OK);
} }
......
...@@ -173,7 +173,7 @@ acpi_install_address_space_handler ( ...@@ -173,7 +173,7 @@ acpi_install_address_space_handler (
* The attached device object already exists. * The attached device object already exists.
* Make sure the handler is not already installed. * Make sure the handler is not already installed.
*/ */
handler_obj = obj_desc->device.address_space; handler_obj = obj_desc->device.handler;
/* Walk the handler list for this device */ /* Walk the handler list for this device */
...@@ -268,13 +268,13 @@ acpi_install_address_space_handler ( ...@@ -268,13 +268,13 @@ acpi_install_address_space_handler (
/* Install at head of Device.address_space list */ /* Install at head of Device.address_space list */
handler_obj->address_space.next = obj_desc->device.address_space; handler_obj->address_space.next = obj_desc->device.handler;
/* /*
* The Device object is the first reference on the handler_obj. * The Device object is the first reference on the handler_obj.
* Each region that uses the handler adds a reference. * Each region that uses the handler adds a reference.
*/ */
obj_desc->device.address_space = handler_obj; obj_desc->device.handler = handler_obj;
/* /*
* Walk the namespace finding all of the regions this * Walk the namespace finding all of the regions this
...@@ -292,6 +292,17 @@ acpi_install_address_space_handler ( ...@@ -292,6 +292,17 @@ acpi_install_address_space_handler (
ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler,
handler_obj, NULL); handler_obj, NULL);
/*
* Now we can run the _REG methods for all Regions for this
* space ID. This is a separate walk in order to handle any
* interdependencies between regions and _REG methods. (i.e. handlers
* must be installed for all regions of this Space ID before we
* can run any _REG methods.
*/
status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, ACPI_UINT32_MAX,
ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run,
handler_obj, NULL);
unlock_and_exit: unlock_and_exit:
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
...@@ -358,8 +369,8 @@ acpi_remove_address_space_handler ( ...@@ -358,8 +369,8 @@ acpi_remove_address_space_handler (
/* Find the address handler the user requested */ /* Find the address handler the user requested */
handler_obj = obj_desc->device.address_space; handler_obj = obj_desc->device.handler;
last_obj_ptr = &obj_desc->device.address_space; last_obj_ptr = &obj_desc->device.handler;
while (handler_obj) { while (handler_obj) {
/* We have a handler, see if user requested this one */ /* We have a handler, see if user requested this one */
......
...@@ -631,7 +631,7 @@ acpi_ex_dump_object_descriptor ( ...@@ -631,7 +631,7 @@ acpi_ex_dump_object_descriptor (
case ACPI_TYPE_DEVICE: case ACPI_TYPE_DEVICE:
acpi_ex_out_pointer ("address_space", obj_desc->device.address_space); acpi_ex_out_pointer ("Handler", obj_desc->device.handler);
acpi_ex_out_pointer ("system_notify", obj_desc->device.system_notify); acpi_ex_out_pointer ("system_notify", obj_desc->device.system_notify);
acpi_ex_out_pointer ("device_notify", obj_desc->device.device_notify); acpi_ex_out_pointer ("device_notify", obj_desc->device.device_notify);
break; break;
...@@ -669,7 +669,7 @@ acpi_ex_dump_object_descriptor ( ...@@ -669,7 +669,7 @@ acpi_ex_dump_object_descriptor (
acpi_ex_out_integer ("Flags", obj_desc->region.flags); acpi_ex_out_integer ("Flags", obj_desc->region.flags);
acpi_ex_out_address ("Address", obj_desc->region.address); acpi_ex_out_address ("Address", obj_desc->region.address);
acpi_ex_out_integer ("Length", obj_desc->region.length); acpi_ex_out_integer ("Length", obj_desc->region.length);
acpi_ex_out_pointer ("address_space", obj_desc->region.address_space); acpi_ex_out_pointer ("Handler", obj_desc->region.handler);
acpi_ex_out_pointer ("Next", obj_desc->region.next); acpi_ex_out_pointer ("Next", obj_desc->region.next);
break; break;
...@@ -690,7 +690,7 @@ acpi_ex_dump_object_descriptor ( ...@@ -690,7 +690,7 @@ acpi_ex_dump_object_descriptor (
acpi_ex_out_address ("Address", (acpi_physical_address) obj_desc->processor.address); acpi_ex_out_address ("Address", (acpi_physical_address) obj_desc->processor.address);
acpi_ex_out_pointer ("system_notify", obj_desc->processor.system_notify); acpi_ex_out_pointer ("system_notify", obj_desc->processor.system_notify);
acpi_ex_out_pointer ("device_notify", obj_desc->processor.device_notify); acpi_ex_out_pointer ("device_notify", obj_desc->processor.device_notify);
acpi_ex_out_pointer ("address_space", obj_desc->processor.address_space); acpi_ex_out_pointer ("Handler", obj_desc->processor.handler);
break; break;
...@@ -698,7 +698,7 @@ acpi_ex_dump_object_descriptor ( ...@@ -698,7 +698,7 @@ acpi_ex_dump_object_descriptor (
acpi_ex_out_pointer ("system_notify", obj_desc->thermal_zone.system_notify); acpi_ex_out_pointer ("system_notify", obj_desc->thermal_zone.system_notify);
acpi_ex_out_pointer ("device_notify", obj_desc->thermal_zone.device_notify); acpi_ex_out_pointer ("device_notify", obj_desc->thermal_zone.device_notify);
acpi_ex_out_pointer ("address_space", obj_desc->thermal_zone.address_space); acpi_ex_out_pointer ("Handler", obj_desc->thermal_zone.handler);
break; break;
......
...@@ -119,7 +119,7 @@ acpi_hw_set_mode ( ...@@ -119,7 +119,7 @@ acpi_hw_set_mode (
* system does not support mode transition. * system does not support mode transition.
*/ */
if (!acpi_gbl_FADT->smi_cmd) { if (!acpi_gbl_FADT->smi_cmd) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No SMI_CMD in FADT, mode transition failed.\n")); ACPI_REPORT_ERROR (("No SMI_CMD in FADT, mode transition failed.\n"));
return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE);
} }
...@@ -131,7 +131,7 @@ acpi_hw_set_mode ( ...@@ -131,7 +131,7 @@ acpi_hw_set_mode (
* transitions are not supported. * transitions are not supported.
*/ */
if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) { if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) {
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "No mode transition supported in this system.\n")); ACPI_REPORT_ERROR (("No ACPI mode transition supported in this system (enable/disable both zero)\n"));
return_ACPI_STATUS (AE_OK); return_ACPI_STATUS (AE_OK);
} }
...@@ -162,6 +162,7 @@ acpi_hw_set_mode ( ...@@ -162,6 +162,7 @@ acpi_hw_set_mode (
} }
if (ACPI_FAILURE (status)) { if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("Could not write mode change, %s\n", acpi_format_exception (status)));
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
...@@ -171,18 +172,16 @@ acpi_hw_set_mode ( ...@@ -171,18 +172,16 @@ acpi_hw_set_mode (
*/ */
retry = 3000; retry = 3000;
while (retry) { while (retry) {
status = AE_NO_HARDWARE_RESPONSE;
if (acpi_hw_get_mode() == mode) { if (acpi_hw_get_mode() == mode) {
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode)); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode));
status = AE_OK; return_ACPI_STATUS (AE_OK);
break;
} }
acpi_os_stall(1000); acpi_os_stall(1000);
retry--; retry--;
} }
return_ACPI_STATUS (status); ACPI_REPORT_ERROR (("Hardware never changed modes\n"));
return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE);
} }
......
...@@ -181,6 +181,13 @@ acpi_enter_sleep_state_prep ( ...@@ -181,6 +181,13 @@ acpi_enter_sleep_state_prep (
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
/* Set the system indicators to show the desired sleep state. */
status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL);
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
}
return_ACPI_STATUS (AE_OK); return_ACPI_STATUS (AE_OK);
} }
...@@ -220,10 +227,10 @@ acpi_enter_sleep_state ( ...@@ -220,10 +227,10 @@ acpi_enter_sleep_state (
return_ACPI_STATUS (AE_AML_OPERAND_VALUE); return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
} }
sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A); sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE); sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
if (sleep_state != ACPI_STATE_S5) {
/* Clear wake status */ /* Clear wake status */
status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
...@@ -231,7 +238,7 @@ acpi_enter_sleep_state ( ...@@ -231,7 +238,7 @@ acpi_enter_sleep_state (
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
if (ACPI_FAILURE (status)) { if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
...@@ -242,6 +249,7 @@ acpi_enter_sleep_state ( ...@@ -242,6 +249,7 @@ acpi_enter_sleep_state (
if (ACPI_FAILURE (status)) { if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
}
status = acpi_hw_disable_non_wakeup_gpes(); status = acpi_hw_disable_non_wakeup_gpes();
if (ACPI_FAILURE (status)) { if (ACPI_FAILURE (status)) {
...@@ -297,11 +305,13 @@ acpi_enter_sleep_state ( ...@@ -297,11 +305,13 @@ acpi_enter_sleep_state (
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
/*
* Wait a second, then try again. This is to get S4/5 to work on all machines.
*/
if (sleep_state > ACPI_STATE_S3) { if (sleep_state > ACPI_STATE_S3) {
/* /*
* We wanted to sleep > S3, but it didn't happen (by virtue of the fact that
* we are still executing!)
*
* Wait ten seconds, then try again. This is to get S4/S5 to work on all machines.
*
* We wait so long to allow chipsets that poll this reg very slowly to * We wait so long to allow chipsets that poll this reg very slowly to
* still read the right value. Ideally, this entire block would go * still read the right value. Ideally, this entire block would go
* away entirely. * away entirely.
...@@ -354,6 +364,7 @@ acpi_enter_sleep_state_s4bios ( ...@@ -354,6 +364,7 @@ acpi_enter_sleep_state_s4bios (
ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_s4bios"); ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_s4bios");
acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
...@@ -394,10 +405,33 @@ acpi_leave_sleep_state ( ...@@ -394,10 +405,33 @@ acpi_leave_sleep_state (
struct acpi_object_list arg_list; struct acpi_object_list arg_list;
union acpi_object arg; union acpi_object arg;
acpi_status status; acpi_status status;
struct acpi_bit_register_info *sleep_type_reg_info;
struct acpi_bit_register_info *sleep_enable_reg_info;
u32 pm1x_control;
ACPI_FUNCTION_TRACE ("acpi_leave_sleep_state"); ACPI_FUNCTION_TRACE ("acpi_leave_sleep_state");
/* Some machines require SLP_TYPE and SLP_EN to be cleared */
sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
/* Get current value of PM1A control */
status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
ACPI_REGISTER_PM1_CONTROL, &pm1x_control);
if (ACPI_SUCCESS (status)) {
/* Clear SLP_TYP and SLP_EN */
pm1x_control &= ~(sleep_type_reg_info->access_bit_mask |
sleep_enable_reg_info->access_bit_mask);
acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
ACPI_REGISTER_PM1A_CONTROL, pm1x_control);
acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
ACPI_REGISTER_PM1B_CONTROL, pm1x_control);
}
/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
...@@ -407,12 +441,17 @@ acpi_leave_sleep_state ( ...@@ -407,12 +441,17 @@ acpi_leave_sleep_state (
arg_list.count = 1; arg_list.count = 1;
arg_list.pointer = &arg; arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER; arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = sleep_state;
/* Ignore any errors from these methods */ /* Ignore any errors from these methods */
arg.integer.value = 0;
status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL);
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
}
arg.integer.value = sleep_state;
status = acpi_evaluate_object (NULL, "\\_BFS", &arg_list, NULL); status = acpi_evaluate_object (NULL, "\\_BFS", &arg_list, NULL);
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status))); ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status)));
...@@ -430,8 +469,8 @@ acpi_leave_sleep_state ( ...@@ -430,8 +469,8 @@ acpi_leave_sleep_state (
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
/* Disable BM arbitration */ /* Enable BM arbitration */
status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK);
status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK);
return_ACPI_STATUS (status); return_ACPI_STATUS (status);
} }
...@@ -127,7 +127,8 @@ acpi_psx_execute ( ...@@ -127,7 +127,8 @@ acpi_psx_execute (
op = acpi_ps_create_scope_op (); op = acpi_ps_create_scope_op ();
if (!op) { if (!op) {
return_ACPI_STATUS (AE_NO_MEMORY); status = AE_NO_MEMORY;
goto cleanup1;
} }
/* /*
...@@ -142,20 +143,24 @@ acpi_psx_execute ( ...@@ -142,20 +143,24 @@ acpi_psx_execute (
walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
NULL, NULL, NULL); NULL, NULL, NULL);
if (!walk_state) { if (!walk_state) {
return_ACPI_STATUS (AE_NO_MEMORY); status = AE_NO_MEMORY;
goto cleanup2;
} }
status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start,
obj_desc->method.aml_length, NULL, NULL, 1); obj_desc->method.aml_length, NULL, NULL, 1);
if (ACPI_FAILURE (status)) { if (ACPI_FAILURE (status)) {
acpi_ds_delete_walk_state (walk_state); goto cleanup3;
return_ACPI_STATUS (status);
} }
/* Parse the AML */ /* Parse the AML */
status = acpi_ps_parse_aml (walk_state); status = acpi_ps_parse_aml (walk_state);
acpi_ps_delete_parse_tree (op); acpi_ps_delete_parse_tree (op);
if (ACPI_FAILURE (status)) {
goto cleanup1; /* Walk state is already deleted */
}
/* /*
* 2) Execute the method. Performs second pass parse simultaneously * 2) Execute the method. Performs second pass parse simultaneously
...@@ -168,7 +173,8 @@ acpi_psx_execute ( ...@@ -168,7 +173,8 @@ acpi_psx_execute (
op = acpi_ps_create_scope_op (); op = acpi_ps_create_scope_op ();
if (!op) { if (!op) {
return_ACPI_STATUS (AE_NO_MEMORY); status = AE_NO_MEMORY;
goto cleanup1;
} }
/* Init new op with the method name and pointer back to the NS node */ /* Init new op with the method name and pointer back to the NS node */
...@@ -180,22 +186,30 @@ acpi_psx_execute ( ...@@ -180,22 +186,30 @@ acpi_psx_execute (
walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL); walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL);
if (!walk_state) { if (!walk_state) {
return_ACPI_STATUS (AE_NO_MEMORY); status = AE_NO_MEMORY;
goto cleanup2;
} }
status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start, status = acpi_ds_init_aml_walk (walk_state, op, method_node, obj_desc->method.aml_start,
obj_desc->method.aml_length, params, return_obj_desc, 3); obj_desc->method.aml_length, params, return_obj_desc, 3);
if (ACPI_FAILURE (status)) { if (ACPI_FAILURE (status)) {
acpi_ds_delete_walk_state (walk_state); goto cleanup3;
return_ACPI_STATUS (status);
} }
/* /*
* The walk of the parse tree is where we actually execute the method * The walk of the parse tree is where we actually execute the method
*/ */
status = acpi_ps_parse_aml (walk_state); status = acpi_ps_parse_aml (walk_state);
goto cleanup2; /* Walk state already deleted */
cleanup3:
acpi_ds_delete_walk_state (walk_state);
cleanup2:
acpi_ps_delete_parse_tree (op); acpi_ps_delete_parse_tree (op);
cleanup1:
if (params) { if (params) {
/* Take away the extra reference that we gave the parameters above */ /* Take away the extra reference that we gave the parameters above */
...@@ -206,6 +220,10 @@ acpi_psx_execute ( ...@@ -206,6 +220,10 @@ acpi_psx_execute (
} }
} }
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
/* /*
* If the method has returned an object, signal this to the caller with * If the method has returned an object, signal this to the caller with
* a control exception code * a control exception code
......
...@@ -132,27 +132,29 @@ acpi_rs_irq_resource ( ...@@ -132,27 +132,29 @@ acpi_rs_irq_resource (
temp8 = *buffer; temp8 = *buffer;
/* /*
* Check for HE, LL or HL * Check for HE, LL interrupts
*/ */
if (temp8 & 0x01) { switch (temp8 & 0x09) {
case 0x01: /* HE */
output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE; output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE;
output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH; output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH;
} break;
else {
if (temp8 & 0x8) { case 0x08: /* LL */
output_struct->data.irq.edge_level = ACPI_LEVEL_SENSITIVE; output_struct->data.irq.edge_level = ACPI_LEVEL_SENSITIVE;
output_struct->data.irq.active_high_low = ACPI_ACTIVE_LOW; output_struct->data.irq.active_high_low = ACPI_ACTIVE_LOW;
} break;
else {
default:
/* /*
* Only _LL and _HE polarity/trigger interrupts * Only _LL and _HE polarity/trigger interrupts
* are allowed (ACPI spec v1.0b ection 6.4.2.1), * are allowed (ACPI spec, section "IRQ Format")
* so an error will occur if we reach this point * so 0x00 and 0x09 are illegal.
*/ */
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid interrupt polarity/trigger in resource list\n")); ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Invalid interrupt polarity/trigger in resource list, %X\n", temp8));
return_ACPI_STATUS (AE_BAD_DATA); return_ACPI_STATUS (AE_BAD_DATA);
} }
}
/* /*
* Check for sharable * Check for sharable
...@@ -419,7 +421,7 @@ acpi_rs_extended_irq_resource ( ...@@ -419,7 +421,7 @@ acpi_rs_extended_irq_resource (
* Point the String pointer to the end of this structure. * Point the String pointer to the end of this structure.
*/ */
output_struct->data.extended_irq.resource_source.string_ptr = output_struct->data.extended_irq.resource_source.string_ptr =
(char *)(output_struct + struct_size); (char *)((char *) output_struct + struct_size);
temp_ptr = (u8 *) output_struct->data.extended_irq.resource_source.string_ptr; temp_ptr = (u8 *) output_struct->data.extended_irq.resource_source.string_ptr;
......
...@@ -455,6 +455,7 @@ acpi_tb_get_table_ptr ( ...@@ -455,6 +455,7 @@ acpi_tb_get_table_ptr (
if (instance == 1) { if (instance == 1) {
/* Get the first */ /* Get the first */
*table_ptr_loc = NULL;
if (acpi_gbl_table_lists[table_type].next) { if (acpi_gbl_table_lists[table_type].next) {
*table_ptr_loc = acpi_gbl_table_lists[table_type].next->pointer; *table_ptr_loc = acpi_gbl_table_lists[table_type].next->pointer;
} }
......
...@@ -140,7 +140,7 @@ acpi_ut_delete_internal_obj ( ...@@ -140,7 +140,7 @@ acpi_ut_delete_internal_obj (
/* Walk the handler list for this device */ /* Walk the handler list for this device */
handler_desc = object->device.address_space; handler_desc = object->device.handler;
while (handler_desc) { while (handler_desc) {
next_desc = handler_desc->address_space.next; next_desc = handler_desc->address_space.next;
acpi_ut_remove_reference (handler_desc); acpi_ut_remove_reference (handler_desc);
...@@ -193,7 +193,7 @@ acpi_ut_delete_internal_obj ( ...@@ -193,7 +193,7 @@ acpi_ut_delete_internal_obj (
* default handlers -- and therefore, we created the context object * default handlers -- and therefore, we created the context object
* locally, it was not created by an external caller. * locally, it was not created by an external caller.
*/ */
handler_desc = object->region.address_space; handler_desc = object->region.handler;
if (handler_desc) { if (handler_desc) {
if (handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { if (handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
obj_pointer = second_desc->extra.region_context; obj_pointer = second_desc->extra.region_context;
......
...@@ -562,12 +562,12 @@ acpi_ut_get_node_name ( ...@@ -562,12 +562,12 @@ acpi_ut_get_node_name (
if (node->descriptor != ACPI_DESC_TYPE_NAMED) if (node->descriptor != ACPI_DESC_TYPE_NAMED)
{ {
return ("INVALID NODE"); return ("****");
} }
if (!acpi_ut_valid_acpi_name (* (u32 *) node->name.ascii)) if (!acpi_ut_valid_acpi_name (* (u32 *) node->name.ascii))
{ {
return ("INVALID NODE NAME"); return ("----");
} }
return (node->name.ascii); return (node->name.ascii);
......
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
/* Version string */ /* Version string */
#define ACPI_CA_VERSION 0x20031029 #define ACPI_CA_VERSION 0x20031203
/* Maximum objects in the various object caches */ /* Maximum objects in the various object caches */
......
...@@ -182,6 +182,17 @@ acpi_ev_detach_region ( ...@@ -182,6 +182,17 @@ acpi_ev_detach_region (
union acpi_operand_object *region_obj, union acpi_operand_object *region_obj,
u8 acpi_ns_is_locked); u8 acpi_ns_is_locked);
acpi_status
acpi_ev_execute_reg_method (
union acpi_operand_object *region_obj,
u32 function);
acpi_status
acpi_ev_reg_run (
acpi_handle obj_handle,
u32 level,
void *context,
void **return_value);
/* /*
* Evregini - Region initialization and setup * Evregini - Region initialization and setup
......
...@@ -106,6 +106,9 @@ ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS; ...@@ -106,6 +106,9 @@ ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS;
ACPI_EXTERN u8 acpi_gbl_integer_bit_width; ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
ACPI_EXTERN u8 acpi_gbl_integer_byte_width; ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
/* Keep local copies of these FADT-based registers */
ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
......
...@@ -114,7 +114,7 @@ ...@@ -114,7 +114,7 @@
#define ACPI_COMMON_NOTIFY_INFO \ #define ACPI_COMMON_NOTIFY_INFO \
union acpi_operand_object *system_notify; /* Handler for system notifies */\ union acpi_operand_object *system_notify; /* Handler for system notifies */\
union acpi_operand_object *device_notify; /* Handler for driver notifies */\ union acpi_operand_object *device_notify; /* Handler for driver notifies */\
union acpi_operand_object *address_space; /* Handler for Address space */ union acpi_operand_object *handler; /* Handler for Address space */
/****************************************************************************** /******************************************************************************
...@@ -214,7 +214,7 @@ struct acpi_object_region ...@@ -214,7 +214,7 @@ struct acpi_object_region
ACPI_OBJECT_COMMON_HEADER ACPI_OBJECT_COMMON_HEADER
u8 space_id; u8 space_id;
union acpi_operand_object *address_space; /* Handler for region access */ union acpi_operand_object *handler; /* Handler for region access */
struct acpi_namespace_node *node; /* containing object */ struct acpi_namespace_node *node; /* containing object */
union acpi_operand_object *next; union acpi_operand_object *next;
u32 length; u32 length;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment