ACPICA: Fix several acpi_attach_data problems

Handler was never invoked. Now invoked if/when host node is deleted.
Data object was not automatically deleted when host node was deleted.
Interface to handler had an unused parameter, removed it.
ACPICA BZ 778.

http://acpica.org/bugzilla/show_bug.cgi?id=778

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index efc971a..8a58a1b 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -96,17 +96,68 @@
  *
  * RETURN:      None
  *
- * DESCRIPTION: Delete a namespace node
+ * DESCRIPTION: Delete a namespace node. All node deletions must come through
+ *              here. Detaches any attached objects, including any attached
+ *              data. If a handler is associated with attached data, it is
+ *              invoked before the node is deleted.
  *
  ******************************************************************************/
 
 void acpi_ns_delete_node(struct acpi_namespace_node *node)
 {
+	union acpi_operand_object *obj_desc;
+
+	ACPI_FUNCTION_NAME(ns_delete_node);
+
+	/* Detach an object if there is one */
+
+	acpi_ns_detach_object(node);
+
+	/*
+	 * Delete an attached data object if present (an object that was created
+	 * and attached via acpi_attach_data). Note: After any normal object is
+	 * detached above, the only possible remaining object is a data object.
+	 */
+	obj_desc = node->object;
+	if (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) {
+
+		/* Invoke the attached data deletion handler if present */
+
+		if (obj_desc->data.handler) {
+			obj_desc->data.handler(node, obj_desc->data.pointer);
+		}
+
+		acpi_ut_remove_reference(obj_desc);
+	}
+
+	/* Now we can delete the node */
+
+	(void)acpi_os_release_object(acpi_gbl_namespace_cache, node);
+
+	ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
+	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n",
+			  node, acpi_gbl_current_node_count));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_remove_node
+ *
+ * PARAMETERS:  Node            - Node to be removed/deleted
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Remove (unlink) and delete a namespace node
+ *
+ ******************************************************************************/
+
+void acpi_ns_remove_node(struct acpi_namespace_node *node)
+{
 	struct acpi_namespace_node *parent_node;
 	struct acpi_namespace_node *prev_node;
 	struct acpi_namespace_node *next_node;
 
-	ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node);
+	ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node);
 
 	parent_node = acpi_ns_get_parent_node(node);
 
@@ -142,12 +193,9 @@
 		}
 	}
 
-	ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
+	/* Delete the node and any attached objects */
 
-	/* Detach an object if there is one, then delete the node */
-
-	acpi_ns_detach_object(node);
-	(void)acpi_os_release_object(acpi_gbl_namespace_cache, node);
+	acpi_ns_delete_node(node);
 	return_VOID;
 }
 
@@ -273,25 +321,11 @@
 				    parent_node, child_node));
 		}
 
-		/* Now we can free this child object */
-
-		ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++);
-
-		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
-				  "Object %p, Remaining %X\n", child_node,
-				  acpi_gbl_current_node_count));
-
-		/* Detach an object if there is one, then free the child node */
-
-		acpi_ns_detach_object(child_node);
-
-		/* Now we can delete the node */
-
-		(void)acpi_os_release_object(acpi_gbl_namespace_cache,
-					     child_node);
-
-		/* And move on to the next child in the list */
-
+		/*
+		 * Delete this child node and move on to the next child in the list.
+		 * No need to unlink the node since we are deleting the entire branch.
+		 */
+		acpi_ns_delete_node(child_node);
 		child_node = next_node;
 
 	} while (!(flags & ANOBJ_END_OF_PEER_LIST));
@@ -433,7 +467,7 @@
 
 		if (deletion_node) {
 			acpi_ns_delete_children(deletion_node);
-			acpi_ns_delete_node(deletion_node);
+			acpi_ns_remove_node(deletion_node);
 			deletion_node = NULL;
 		}