patch-2.4.6 linux/drivers/acpi/ospm/busmgr/bm.c

Next file: linux/drivers/acpi/ospm/busmgr/bm_osl.c
Previous file: linux/drivers/acpi/ospm/busmgr/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.5/linux/drivers/acpi/ospm/busmgr/bm.c linux/drivers/acpi/ospm/busmgr/bm.c
@@ -0,0 +1,1144 @@
+/******************************************************************************
+ *
+ * Module Name: bm.c
+ *   $Revision: 42 $
+ *
+ *****************************************************************************/
+
+/*
+ *  Copyright (C) 2000, 2001 Andrew Grover
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <acpi.h>
+#include "bm.h"
+
+
+#define _COMPONENT		ACPI_BUS
+	MODULE_NAME		("bm")
+
+
+/****************************************************************************
+ *                                  Globals
+ ****************************************************************************/
+
+extern FADT_DESCRIPTOR_REV2	acpi_fadt;
+/* TBD: Make dynamically sizeable. */
+BM_NODE_LIST			node_list;
+
+
+/****************************************************************************
+ *                            Internal Functions
+ ****************************************************************************/
+
+/*****************************************************************************
+ * 
+ * FUNCTION:    bm_print_object
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+void
+bm_print_object (
+	ACPI_HANDLE		acpi_handle)
+{
+	ACPI_BUFFER		buffer;
+	ACPI_HANDLE		parent;
+	ACPI_OBJECT_TYPE	type;
+
+	buffer.length = 256;
+	buffer.pointer = acpi_os_callocate(buffer.length);
+	if (!buffer.pointer) {
+		return;
+	}
+
+	acpi_get_name(acpi_handle, ACPI_FULL_PATHNAME, &buffer);
+	acpi_get_parent(acpi_handle, &parent);
+	acpi_get_type(acpi_handle, &type);
+
+	/*
+	 * TBD: Hack to get around scope identification problem.
+	 */
+	if (type == ACPI_TYPE_ANY) {
+		if (ACPI_SUCCESS(acpi_get_next_object(ACPI_TYPE_ANY, 
+			acpi_handle, 0, NULL))) {
+			type = INTERNAL_TYPE_SCOPE;
+		}
+	}
+    
+	switch (type)
+	{
+	case INTERNAL_TYPE_SCOPE:
+		acpi_os_printf("SCOPE: ");
+		break;
+	case ACPI_TYPE_INTEGER:
+		acpi_os_printf("SIMPLE (number): ");
+		break;
+	case ACPI_TYPE_STRING:
+		acpi_os_printf("SIMPLE (string): ");
+		break;
+	case ACPI_TYPE_BUFFER:
+		acpi_os_printf("SIMPLE (buffer): ");
+		break;
+	case ACPI_TYPE_PACKAGE:
+		acpi_os_printf("SIMPLE (package): ");
+		break;
+	case ACPI_TYPE_FIELD_UNIT:
+		acpi_os_printf("FIELD UNIT: ");
+		break;
+	case ACPI_TYPE_DEVICE:
+		acpi_os_printf("DEVICE: ");
+		break;
+	case ACPI_TYPE_EVENT:
+		acpi_os_printf("EVENT: ");
+		break;
+	case ACPI_TYPE_METHOD:
+		acpi_os_printf("CONTROL METHOD: ");
+		break;
+	case ACPI_TYPE_MUTEX:
+		acpi_os_printf("MUTEX: ");
+		break;
+	case ACPI_TYPE_REGION:
+		acpi_os_printf("OPERATION REGION: ");
+		break;
+	case ACPI_TYPE_POWER:
+		acpi_os_printf("POWER RESOURCE: ");
+		break;
+	case ACPI_TYPE_PROCESSOR:
+		acpi_os_printf("PROCESSOR: ");
+		break;
+	case ACPI_TYPE_THERMAL:
+		acpi_os_printf("THERMAL ZONE: ");
+		break;
+	case ACPI_TYPE_BUFFER_FIELD:
+		acpi_os_printf("BUFFER FIELD: ");
+		break;
+	case ACPI_TYPE_DDB_HANDLE:
+		acpi_os_printf("DDB HANDLE: ");
+		break;
+	default:
+		acpi_os_printf("OTHER (%d): ", type);
+		break;
+	}
+
+	acpi_os_printf("Object[%p][%s] parent[%p].\n", acpi_handle, (char*)buffer.pointer, parent);
+
+	acpi_os_free(buffer.pointer);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_print_node
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+void
+bm_print_node (
+	BM_NODE			*node,
+	u32                     flags)
+{
+#ifdef ACPI_DEBUG
+	ACPI_BUFFER             buffer;
+	BM_DEVICE		*device = NULL;
+	char                    *type_string = NULL;
+
+	if (!node) {
+		return;
+	}
+
+	device = &(node->device);
+
+	if (flags & BM_PRINT_PRESENT) {
+		if (!BM_DEVICE_PRESENT(device)) {
+			return;
+		}
+	}
+
+	buffer.length = 256;
+	buffer.pointer = acpi_os_callocate(buffer.length);
+	if (!buffer.pointer) {
+		return;
+	}
+
+	acpi_get_name(device->acpi_handle, ACPI_FULL_PATHNAME, &buffer);
+
+	switch(device->id.type) {
+	case BM_TYPE_SYSTEM:
+		type_string = " System";
+		break;
+	case BM_TYPE_SCOPE: 
+		type_string = "  Scope";
+		break;
+	case BM_TYPE_PROCESSOR:
+		type_string = "   Proc";
+		break;
+	case BM_TYPE_THERMAL_ZONE:
+		type_string = "Thermal";
+		break;
+	case BM_TYPE_POWER_RESOURCE:
+		type_string = "  Power";
+		break;
+	case BM_TYPE_FIXED_BUTTON:
+		type_string = " Button";
+		break;
+	case BM_TYPE_DEVICE:
+		type_string = " Device";
+		break;
+	default:
+		type_string = "Unknown";
+		break;
+	}
+
+	if (!(flags & BM_PRINT_GROUP)) {
+		DEBUG_PRINT_RAW(ACPI_INFO, ("+-------------------------------------------------------------------------------\n"));
+	}
+
+	DEBUG_PRINT_RAW(ACPI_INFO, ("| %s[%02x]:[%p] flags[%02x] hid[%s] %s\n", type_string, device->handle, device->acpi_handle, device->flags, (device->id.hid[0] ? device->id.hid : "       "), buffer.pointer));
+
+	if (flags & BM_PRINT_IDENTIFICATION) {
+		DEBUG_PRINT_RAW(ACPI_INFO, ("|   identification: uid[%s] adr[%08x]\n", device->id.uid, device->id.adr));
+	}
+
+	if (flags & BM_PRINT_LINKAGE) {
+		DEBUG_PRINT_RAW(ACPI_INFO, ("|   linkage: this[%p] parent[%p] next[%p]\n", node, node->parent, node->next));
+		DEBUG_PRINT_RAW(ACPI_INFO, ("|     scope.head[%p] scope.tail[%p]\n", node->scope.head, node->scope.tail));
+	}
+
+	if (flags & BM_PRINT_POWER) {
+		DEBUG_PRINT_RAW(ACPI_INFO, ("|   power: state[D%d] flags[%08x]\n", device->power.state, device->power.flags));
+		DEBUG_PRINT_RAW(ACPI_INFO, ("|     S0[%02x] S1[%02x] S2[%02x] S3[%02x] S4[%02x] S5[%02x]\n", device->power.dx_supported[0], device->power.dx_supported[1], device->power.dx_supported[2], device->power.dx_supported[3], device->power.dx_supported[4], device->power.dx_supported[5]));
+	}
+
+	if (!(flags & BM_PRINT_GROUP)) {
+		DEBUG_PRINT_RAW(ACPI_INFO, ("+-------------------------------------------------------------------------------\n"));
+	}
+
+	acpi_os_free(buffer.pointer);
+#endif /*ACPI_DEBUG*/
+
+	return;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_print_hierarchy
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+void
+bm_print_hierarchy (void)
+{
+#ifdef ACPI_DEBUG
+	u32			i = 0;
+
+	FUNCTION_TRACE("bm_print_hierarchy");
+
+	DEBUG_PRINT_RAW(ACPI_INFO, ("+------------------------------------------------------------\n"));
+
+	for (i = 0; i < node_list.count; i++) {
+		bm_print_node(node_list.nodes[i], BM_PRINT_GROUP | BM_PRINT_PRESENT);
+	}
+
+	DEBUG_PRINT_RAW(ACPI_INFO, ("+------------------------------------------------------------\n"));
+#endif /*ACPI_DEBUG*/
+
+	return_VOID;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_get_status
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_get_status (
+	BM_DEVICE		*device)
+{
+	ACPI_STATUS             status = AE_OK;
+
+	if (!device) {
+		return AE_BAD_PARAMETER;
+	}
+
+	device->status = BM_STATUS_UNKNOWN;
+
+	/*
+	 * Dynamic Status?
+	 * ---------------
+	 * If _STA isn't present we just return the default status.
+	 */
+	if (!(device->flags & BM_FLAGS_DYNAMIC_STATUS)) {
+		device->status = BM_STATUS_DEFAULT;
+		return AE_OK;
+	}
+
+	/*
+	 * Evaluate _STA:
+	 * --------------
+	 */
+	status = bm_evaluate_simple_integer(device->acpi_handle, "_STA", 
+		&(device->status));
+
+	return status;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_get_identification
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_get_identification (
+	BM_DEVICE		*device)
+{
+	ACPI_STATUS             status = AE_OK;
+	ACPI_DEVICE_INFO        info;
+
+	if (!device) {
+		return AE_BAD_PARAMETER;
+	}
+
+	if (!(device->flags & BM_FLAGS_IDENTIFIABLE)) {
+		return AE_OK;
+	}
+
+	device->id.uid[0] = BM_UID_UNKNOWN;
+	device->id.hid[0] = BM_HID_UNKNOWN;
+	device->id.adr = BM_ADDRESS_UNKNOWN;
+
+	/*
+	 * Get Object Info:
+	 * ----------------
+	 * Evalute _UID, _HID, and _ADR...
+	 */
+	status = acpi_get_object_info(device->acpi_handle, &info);
+	if (ACPI_FAILURE(status)) {
+		return status;
+	}
+
+	if (info.valid & ACPI_VALID_UID) {
+		MEMCPY((void*)device->id.uid, (void*)info.unique_id, 
+			sizeof(BM_DEVICE_UID));
+	}
+
+	if (info.valid & ACPI_VALID_HID) {
+		MEMCPY((void*)device->id.hid, (void*)info.hardware_id, 
+			sizeof(BM_DEVICE_HID));
+	}
+
+	if (info.valid & ACPI_VALID_ADR) {
+		device->id.adr = info.address;
+	}
+
+	return status;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_get_flags
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_get_flags (
+	BM_DEVICE		*device)
+{
+	ACPI_HANDLE             acpi_handle = NULL;
+
+	if (!device) {
+		return AE_BAD_PARAMETER;
+	}
+
+	device->flags = BM_FLAGS_UNKNOWN;
+
+	switch (device->id.type) {
+
+	case BM_TYPE_DEVICE:
+
+		/*
+		 * Presence of _DCK indicates a docking station.
+		 */
+		if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
+			"_DCK", &acpi_handle))) {
+			device->flags |= BM_FLAGS_DOCKING_STATION;
+		}
+
+		/*
+		 * Presence of _EJD and/or _EJx indicates 'ejectable'.
+		 * TBD: _EJx...
+		 */
+		if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
+			"_EJD", &acpi_handle))) {
+			device->flags |= BM_FLAGS_EJECTABLE;
+		}
+
+		/*
+		 * Presence of _PR0 or _PS0 indicates 'power manageable'.
+		 */
+		if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
+			"_PR0", &acpi_handle)) ||
+			ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
+			"_PS0", &acpi_handle))) {
+			device->flags |= BM_FLAGS_POWER_CONTROL;
+		}
+
+		/*
+		 * Presence of _CRS indicates 'configurable'.
+		 */
+		if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
+			"_CRS", &acpi_handle))) {
+			device->flags |= BM_FLAGS_CONFIGURABLE;
+		}
+
+		/* Fall through to next case statement. */
+
+	case BM_TYPE_PROCESSOR:
+	case BM_TYPE_THERMAL_ZONE:
+	case BM_TYPE_POWER_RESOURCE:
+		/*
+		 * Presence of _HID or _ADR indicates 'identifiable'.
+		 */
+		if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
+			"_HID", &acpi_handle)) ||
+		   ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
+		   "_ADR", &acpi_handle))) {
+			device->flags |= BM_FLAGS_IDENTIFIABLE;
+		}
+
+		/*
+		 * Presence of _STA indicates 'dynamic status'.
+		 */
+		if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle, 
+			"_STA", &acpi_handle))) {
+			device->flags |= BM_FLAGS_DYNAMIC_STATUS;
+		}
+
+		break;
+	}
+
+	return AE_OK;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_add_namespace_device
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_add_namespace_device (
+	ACPI_HANDLE             acpi_handle,
+	ACPI_OBJECT_TYPE        acpi_type,
+	BM_NODE			*parent,
+	BM_NODE			**child)
+{
+	ACPI_STATUS             status = AE_OK;
+	BM_NODE			*node = NULL;
+	BM_DEVICE		*device = NULL;
+
+	FUNCTION_TRACE("bm_add_namespace_device");
+
+	if (!parent || !child) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	if (node_list.count > BM_HANDLES_MAX) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	(*child) = NULL;
+
+	/*
+	 * Create Node:
+	 * ------------
+	 */
+	node = acpi_os_callocate(sizeof(BM_NODE));
+	if (!node) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	node->parent = parent;
+	node->next = NULL;
+
+	device = &(node->device);
+
+	device->handle = node_list.count;
+	device->acpi_handle = acpi_handle;
+
+	/*
+	 * Device Type:
+	 * ------------
+	 */ 
+	switch (acpi_type) {
+	case INTERNAL_TYPE_SCOPE:
+		device->id.type = BM_TYPE_SCOPE;
+		break;
+	case ACPI_TYPE_PROCESSOR:
+		device->id.type = BM_TYPE_PROCESSOR;
+		break;
+	case ACPI_TYPE_THERMAL:
+		device->id.type = BM_TYPE_THERMAL_ZONE;
+		break;
+	case ACPI_TYPE_POWER:
+		device->id.type = BM_TYPE_POWER_RESOURCE;
+		break;
+	case ACPI_TYPE_DEVICE:
+		device->id.type = BM_TYPE_DEVICE;
+		break;
+	}
+
+	/*
+	 * Get Other Device Info:
+	 * ----------------------
+	 * But only if this device's parent is present (which implies
+	 * this device MAY be present).
+	 */
+	if (BM_NODE_PRESENT(node->parent)) {
+		/*
+		 * Device Flags
+		 */
+		status = bm_get_flags(device);
+		if (ACPI_FAILURE(status)) {
+			goto end;
+		}
+
+		/*
+		 * Device Identification
+		 */
+		status = bm_get_identification(device);
+		if (ACPI_FAILURE(status)) {
+			goto end;
+		}
+
+		/*
+		 * Device Status
+		 */
+		status = bm_get_status(device);
+		if (ACPI_FAILURE(status)) {
+			goto end;
+		}
+
+		/*
+		 * Power Management:
+		 * -----------------
+		 * If this node doesn't provide direct power control  
+		 * then we inherit PM capabilities from its parent.
+		 *
+		 * TBD: Inherit!
+		 */
+		if (BM_IS_POWER_CONTROL(device)) {
+			status = bm_get_pm_capabilities(node);
+			if (ACPI_FAILURE(status)) {
+				goto end;
+			}
+		}
+	}
+
+end:
+	if (ACPI_FAILURE(status)) {
+		acpi_os_free(node);
+	}
+	else {
+		/*
+		 * Add to the node_list.
+		 */
+		node_list.nodes[node_list.count++] = node;
+
+		/*
+		 * Formulate Hierarchy:
+		 * --------------------
+		 * Arrange within the namespace by assigning the parent and
+		 * adding to the parent device's list of children (scope).
+		 */
+		if (!parent->scope.head) {
+			parent->scope.head = node;
+		}
+		else {
+			if (!parent->scope.tail) {
+				(parent->scope.head)->next = node;
+			}
+			else {
+				(parent->scope.tail)->next = node;
+			}
+		}
+		parent->scope.tail = node;
+
+		(*child) = node;
+	}
+
+	return_ACPI_STATUS(status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_enumerate_namespace
+ *
+ * PARAMETERS:  <none>
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_enumerate_namespace (void)
+{
+	ACPI_STATUS		status = AE_OK;
+	ACPI_HANDLE             parent_handle = ACPI_ROOT_OBJECT;
+	ACPI_HANDLE             child_handle = NULL;
+	BM_NODE			*parent = NULL;
+	BM_NODE			*child = NULL;
+	ACPI_OBJECT_TYPE        acpi_type = 0;
+	u32                     level = 1;
+
+	FUNCTION_TRACE("bm_enumerate_namespace");
+
+	parent = node_list.nodes[0];
+
+	/*
+	 * Enumerate ACPI Namespace:
+	 * -------------------------
+	 * Parse through the ACPI namespace, identify all 'devices',
+	 * and create a new entry for each in our collection.
+	 */
+	while (level > 0) {
+
+		/*
+		 * Get the next object at this level.
+		 */
+		status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, child_handle, &child_handle);
+		if (ACPI_SUCCESS(status)) {
+			/*
+			 * TBD: This is a hack to get around the problem 
+			 *       identifying scope objects.  Scopes 
+			 *       somehow need to be uniquely identified.
+			 */
+			status = acpi_get_type(child_handle, &acpi_type);
+			if (ACPI_SUCCESS(status) && (acpi_type == ACPI_TYPE_ANY)) {
+				status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL);
+				if (ACPI_SUCCESS(status)) {
+					acpi_type = INTERNAL_TYPE_SCOPE;
+				}
+			}
+
+			/*
+			 * Device?
+			 * -------
+			 * If this object is a 'device', insert into the
+			 * ACPI Bus Manager's local hierarchy and search
+			 * the object's scope for any child devices (a
+			 * depth-first search).
+			 */
+			switch (acpi_type) {
+			case INTERNAL_TYPE_SCOPE:
+			case ACPI_TYPE_DEVICE:
+			case ACPI_TYPE_PROCESSOR:
+			case ACPI_TYPE_THERMAL:
+			case ACPI_TYPE_POWER:
+				status = bm_add_namespace_device(child_handle, acpi_type, parent, &child);
+				if (ACPI_SUCCESS(status)) {
+					status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL);
+					if (ACPI_SUCCESS(status)) {
+						level++;
+						parent_handle = child_handle;
+						child_handle = 0;
+						parent = child;
+					}
+				}
+				break;
+			}
+		}
+
+		/*
+		 * Scope Exhausted:
+		 * ----------------
+		 * No more children in this object's scope, Go back up
+		 * in the namespace tree to the object's parent.
+		 */
+		else {
+			level--;
+			child_handle = parent_handle;
+			acpi_get_parent(parent_handle, 
+				&parent_handle);
+
+			if (parent) {
+				parent = parent->parent;
+			}
+			else {
+				return_ACPI_STATUS(AE_NULL_ENTRY);
+			}
+		}
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_add_fixed_feature_device
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_add_fixed_feature_device (
+	BM_NODE			*parent,
+	BM_DEVICE_TYPE		device_type,
+	char			*device_hid)
+{
+	ACPI_STATUS             status = AE_OK;
+	BM_NODE			*node = NULL;
+
+	FUNCTION_TRACE("bm_add_fixed_feature_device");
+
+	if (!parent) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	if (node_list.count > BM_HANDLES_MAX) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	/*
+	 * Allocate the new device and add to the device array.
+	 */
+	node = acpi_os_callocate(sizeof(BM_NODE));
+	if (!node) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	/*
+	 * Get device info.
+	 */
+	node->device.handle = node_list.count;
+	node->device.acpi_handle = ACPI_ROOT_OBJECT;
+	node->device.id.type = BM_TYPE_FIXED_BUTTON;
+	if (device_hid) {
+		MEMCPY((void*)node->device.id.hid, device_hid, 
+			sizeof(node->device.id.hid));
+	}
+	node->device.flags = BM_FLAGS_FIXED_FEATURE;
+	node->device.status = BM_STATUS_DEFAULT;
+	/* TBD: Device PM capabilities */
+
+	/*
+	 * Add to the node_list.
+	 */
+	node_list.nodes[node_list.count++] = node;
+
+	/*
+	 * Formulate Hierarchy:
+	 * --------------------
+	 * Arrange within the namespace by assigning the parent and
+	 * adding to the parent device's list of children (scope).
+	 */
+	node->parent = parent;
+	node->next = NULL;
+
+	if (parent) {
+		if (!parent->scope.head) {
+			parent->scope.head = node;
+		}
+		else {
+			if (!parent->scope.tail) {
+				(parent->scope.head)->next = node;
+			}
+			else {
+				(parent->scope.tail)->next = node;
+			}
+		}
+		parent->scope.tail = node;
+	}
+
+	return_ACPI_STATUS(status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_enumerate_fixed_features
+ *
+ * PARAMETERS:  <none>
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_enumerate_fixed_features (void)
+{
+	FUNCTION_TRACE("bm_enumerate_fixed_features");
+
+	/*
+	 * Root Object:
+	 * ------------
+	 * Fabricate the root object, which happens to always get a
+	 * device_handle of zero.
+	 */
+	node_list.nodes[0] = acpi_os_callocate(sizeof(BM_NODE));
+	if (NULL == (node_list.nodes[0])) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	node_list.nodes[0]->device.handle = BM_HANDLE_ROOT;
+	node_list.nodes[0]->device.acpi_handle = ACPI_ROOT_OBJECT;
+	node_list.nodes[0]->device.flags = BM_FLAGS_UNKNOWN;
+	node_list.nodes[0]->device.status = BM_STATUS_DEFAULT;
+	node_list.nodes[0]->device.id.type = BM_TYPE_SYSTEM;
+	/* TBD: Get system PM capabilities (Sx states?) */
+
+	node_list.count++;
+
+	/*
+	 * Fixed Features:
+	 * ---------------
+	 * Enumerate fixed-feature devices (e.g. power and sleep buttons).
+	 */
+	if (acpi_fadt.pwr_button == 0) {
+		bm_add_fixed_feature_device(node_list.nodes[0],
+			BM_TYPE_FIXED_BUTTON, BM_HID_POWER_BUTTON);
+	}
+
+	if (acpi_fadt.sleep_button == 0) {
+		bm_add_fixed_feature_device(node_list.nodes[0],
+			BM_TYPE_FIXED_BUTTON, BM_HID_SLEEP_BUTTON);
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_get_handle
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_get_handle (
+	ACPI_HANDLE             acpi_handle,
+	BM_HANDLE               *device_handle)
+{
+	ACPI_STATUS             status = AE_NOT_FOUND;
+	u32			i = 0;
+
+	FUNCTION_TRACE("bm_get_handle");
+
+	if (!device_handle) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	*device_handle = BM_HANDLE_UNKNOWN;
+
+	/*
+	 * Search all devices for a match on the ACPI handle.
+	 */
+	for (i=0; i<node_list.count; i++) {
+
+		if (!node_list.nodes[i]) {
+			DEBUG_PRINT(ACPI_ERROR, ("Invalid (NULL) node entry [%02x] detected.\n", device_handle));
+			status = AE_NULL_ENTRY;
+			break;
+		}
+
+		if (node_list.nodes[i]->device.acpi_handle == acpi_handle) {
+			*device_handle = node_list.nodes[i]->device.handle;
+			status = AE_OK;
+			break;
+		}
+	}
+
+	return_ACPI_STATUS(status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_get_node
+ *
+ * PARAMETERS:  
+ *
+ * RETURN:      
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_get_node (
+	BM_HANDLE               device_handle,
+	ACPI_HANDLE             acpi_handle,
+	BM_NODE			**node)
+{
+	ACPI_STATUS             status = AE_OK;
+
+	FUNCTION_TRACE("bm_get_node");
+
+	if (!node) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	/* busmgr failed to init, but we're being called by subordinate drivers */
+	if (node_list.count < 1) {
+		return_ACPI_STATUS(AE_NOT_FOUND);
+	}
+
+	/*
+	 * If no device handle, resolve acpi handle to device handle.
+	 */
+	if (!device_handle && acpi_handle) {
+		status = bm_get_handle(acpi_handle, &device_handle);
+		if (ACPI_FAILURE(status))
+			return_ACPI_STATUS(status);
+	}
+
+	/*
+	 * Valid device handle?
+	 */
+	if (device_handle > BM_HANDLES_MAX) {
+		DEBUG_PRINT(ACPI_ERROR, ("Invalid node handle [%02x] detected.\n", device_handle));
+		return_ACPI_STATUS(AE_ERROR);
+	}
+
+	*node = node_list.nodes[device_handle];
+
+	/*
+	 * Valid node?
+	 */
+	if (!(*node)) {
+		DEBUG_PRINT(ACPI_ERROR, ("Invalid (NULL) node entry [%02x] detected.\n", device_handle));
+		return_ACPI_STATUS(AE_NULL_ENTRY);
+	}
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+
+/****************************************************************************
+ *                            External Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_initialize
+ *
+ * PARAMETERS:  <none>
+ *
+ * RETURN:      Exception code.
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_initialize (void)
+{
+	ACPI_STATUS             status = AE_OK;
+	u32                     start = 0;
+	u32                     stop = 0;
+	u32                     elapsed = 0;
+
+	FUNCTION_TRACE("bm_initialize");
+
+	MEMSET(&node_list, 0, sizeof(BM_NODE_LIST));
+
+	status = acpi_get_timer(&start);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	DEBUG_PRINT(ACPI_INFO, ("Building device hierarchy.\n"));
+
+	/*
+	 * Enumerate ACPI fixed-feature devices.
+	 */
+	status = bm_enumerate_fixed_features();
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/*
+	 * Enumerate the ACPI namespace.
+	 */
+	status = bm_enumerate_namespace();
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	acpi_get_timer(&stop);
+	acpi_get_timer_duration(start, stop, &elapsed);
+
+	DEBUG_PRINT(ACPI_INFO, ("Building device hierarchy took [%d] microseconds.\n", elapsed));
+
+	/*
+	 * Display hierarchy.
+	 */
+	bm_print_hierarchy();
+
+	/*
+	 * Register for all standard and device-specific notifications.
+	 */
+	DEBUG_PRINT(ACPI_INFO, ("Registering for all device notifications.\n"));
+
+	status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, 
+		ACPI_SYSTEM_NOTIFY, &bm_notify, NULL);
+	if (ACPI_FAILURE(status)) {
+		DEBUG_PRINT(ACPI_ERROR, ("Unable to register for standard notifications.\n"));
+		return_ACPI_STATUS(status);
+	}
+
+	status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, 
+		ACPI_DEVICE_NOTIFY, &bm_notify, NULL);
+	if (ACPI_FAILURE(status)) {
+		DEBUG_PRINT(ACPI_ERROR, ("Unable to register for device-specific notifications.\n"));
+		return_ACPI_STATUS(status);
+	}
+
+	DEBUG_PRINT(ACPI_INFO, ("ACPI Bus Manager enabled.\n"));
+
+	/*
+	 * Initialize built-in power resource driver.
+	 */
+	bm_pr_initialize();
+
+	return_ACPI_STATUS(status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    bm_terminate
+ *
+ * PARAMETERS:  <none>
+ *
+ * RETURN:      Exception code.
+ *
+ * DESCRIPTION: 
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+bm_terminate (void)
+{
+	ACPI_STATUS             status = AE_OK;
+	u32                     i = 0;
+
+	FUNCTION_TRACE("bm_terminate");
+
+	/*
+	 * Terminate built-in power resource driver.
+	 */
+	bm_pr_terminate();
+
+	/*
+	 * Unregister for all notifications.
+	 */
+	DEBUG_PRINT(ACPI_INFO, ("Unregistering for device notifications.\n"));
+
+	status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, 
+		ACPI_SYSTEM_NOTIFY, &bm_notify);
+	if (ACPI_FAILURE(status)) {
+		DEBUG_PRINT(ACPI_ERROR, ("Unable to un-register for standard notifications.\n"));
+	}
+
+	status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, 
+		ACPI_DEVICE_NOTIFY, &bm_notify);
+	if (ACPI_FAILURE(status)) {
+		DEBUG_PRINT(ACPI_ERROR, ("Unable to un-register for device-specific notifications.\n"));
+	}
+
+	/*
+	 * Parse through the device array, freeing all entries.
+	 */
+	DEBUG_PRINT(ACPI_INFO, ("Removing device hierarchy.\n"));
+	for (i = 0; i < node_list.count; i++) {
+		if (node_list.nodes[i]) {
+			acpi_os_free(node_list.nodes[i]);
+		}
+	}
+
+	DEBUG_PRINT(ACPI_INFO, ("ACPI Bus Manager disabled.\n"));
+
+	return_ACPI_STATUS(AE_OK);
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)