mirror of
https://github.com/reactos/reactos.git
synced 2024-09-20 09:40:52 +00:00
c501d8112c
svn path=/branches/aicom-network-fixes/; revision=34994
1048 lines
23 KiB
C
1048 lines
23 KiB
C
/******************************************************************************
|
|
*
|
|
* Module Name: bm.c
|
|
* $Revision: 1.1 $
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
* 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 <acpi.h>
|
|
|
|
|
|
|
|
#define _COMPONENT ACPI_BUS_MANAGER
|
|
MODULE_NAME ("bm")
|
|
|
|
|
|
/****************************************************************************
|
|
* Globals
|
|
****************************************************************************/
|
|
|
|
extern FADT_DESCRIPTOR_REV2 acpi_fadt;
|
|
/* TODO: Make dynamically sizeable. */
|
|
static BM_NODE_LIST node_list;
|
|
|
|
|
|
/****************************************************************************
|
|
* Internal Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: bm_print
|
|
*
|
|
* PARAMETERS: <TBD>
|
|
*
|
|
* RETURN: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
void
|
|
bm_print (
|
|
BM_NODE *node,
|
|
u32 flags)
|
|
{
|
|
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 = "Processor";
|
|
break;
|
|
case BM_TYPE_THERMAL_ZONE:
|
|
type_string = "ThermalZone";
|
|
break;
|
|
case BM_TYPE_POWER_RESOURCE:
|
|
type_string = "PowerResource";
|
|
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(ACPI_INFO, ("+------------------------------------------------------------\n"));
|
|
}
|
|
|
|
DEBUG_PRINT(ACPI_INFO, ("%s[0x%02x] hid[%s] %s\n", type_string, device->handle, device->id.hid, buffer.pointer));
|
|
DEBUG_PRINT(ACPI_INFO, (" acpi_handle[0x%08x] flags[0x%02x] status[0x%02x]\n", device->acpi_handle, device->flags, device->status));
|
|
|
|
if (flags & BM_PRINT_IDENTIFICATION) {
|
|
DEBUG_PRINT(ACPI_INFO, (" identification: uid[%s] adr[0x%08x]\n", device->id.uid, device->id.adr));
|
|
}
|
|
|
|
if (flags & BM_PRINT_LINKAGE) {
|
|
DEBUG_PRINT(ACPI_INFO, (" linkage: this[%p] parent[%p] next[%p]\n", node, node->parent, node->next));
|
|
DEBUG_PRINT(ACPI_INFO, (" scope.head[%p] scope.tail[%p]\n", node->scope.head, node->scope.tail));
|
|
}
|
|
|
|
if (flags & BM_PRINT_POWER) {
|
|
DEBUG_PRINT(ACPI_INFO, (" power: state[D%d] flags[0x%08X]\n", device->power.state, device->power.flags));
|
|
DEBUG_PRINT(ACPI_INFO, (" S0[0x%02x] S1[0x%02x] S2[0x%02x]\n", device->power.dx_supported[0], device->power.dx_supported[1], device->power.dx_supported[2]));
|
|
DEBUG_PRINT(ACPI_INFO, (" S3[0x%02x] S4[0x%02x] S5[0x%02x]\n", device->power.dx_supported[3], device->power.dx_supported[4], device->power.dx_supported[5]));
|
|
}
|
|
|
|
if (!(flags & BM_PRINT_GROUP)) {
|
|
DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
|
|
}
|
|
|
|
acpi_os_free(buffer.pointer);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: bm_print_hierarchy
|
|
*
|
|
* PARAMETERS: <TBD>
|
|
*
|
|
* RETURN: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
void
|
|
bm_print_hierarchy (void)
|
|
{
|
|
u32 i = 0;
|
|
|
|
FUNCTION_TRACE("bm_print_hierarchy");
|
|
|
|
DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
|
|
|
|
for (i = 0; i < node_list.count; i++) {
|
|
bm_print(node_list.nodes[i], BM_PRINT_GROUP | BM_PRINT_PRESENT);
|
|
}
|
|
|
|
DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
|
|
|
|
return_VOID;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: bm_get_status
|
|
*
|
|
* PARAMETERS: <TBD>
|
|
*
|
|
* RETURN: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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: <TBD>
|
|
*
|
|
* RETURN: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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;
|
|
}
|
|
|
|
MEMSET(&(device->id.uid), 0, sizeof(device->id.uid));
|
|
MEMSET(&(device->id.hid), 0, sizeof(device->id.hid));
|
|
device->id.adr = BM_ADDRESS_UNKNOWN;
|
|
|
|
/*
|
|
* Get Object Info:
|
|
* ----------------
|
|
* Evalute _UID, _HID, _ADR, and _STA...
|
|
*/
|
|
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: <TBD>
|
|
*
|
|
* RETURN: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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'.
|
|
* TODO: _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: <TBD>
|
|
*
|
|
* RETURN: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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.
|
|
*
|
|
* TODO: Inherit!
|
|
*/
|
|
if (device->flags & BM_FLAGS_POWER_CONTROL) {
|
|
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: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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)) {
|
|
|
|
/*
|
|
* TODO: 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: <TBD>
|
|
*
|
|
* RETURN: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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;
|
|
/* TODO: 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: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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;
|
|
/* TODO: 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: <TBD>
|
|
*
|
|
* RETURN: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
ACPI_STATUS
|
|
bm_get_handle (
|
|
ACPI_HANDLE acpi_handle,
|
|
BM_HANDLE *device_handle)
|
|
{
|
|
ACPI_STATUS status = AE_OK;
|
|
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 [0x%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;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return_ACPI_STATUS(status);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: bm_get_node
|
|
*
|
|
* PARAMETERS: <TBD>
|
|
*
|
|
* RETURN: <TBD>
|
|
*
|
|
* DESCRIPTION: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* 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 [0x%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 [0x%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: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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_HANDLE_LIST));
|
|
|
|
acpi_get_timer(&start);
|
|
|
|
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, ("Device heirarchy build took [%d] microseconds.\n", elapsed));
|
|
|
|
/*
|
|
* Display hierarchy.
|
|
*/
|
|
#ifdef ACPI_DEBUG
|
|
bm_print_hierarchy();
|
|
#endif /*ACPI_DEBUG*/
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
|
|
/*
|
|
* Initialize /proc interface.
|
|
*/
|
|
//DEBUG_PRINT(ACPI_INFO, ("Initializing /proc interface.\n"));
|
|
//status = bm_proc_initialize();
|
|
|
|
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: <TBD>
|
|
*
|
|
****************************************************************************/
|
|
|
|
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();
|
|
|
|
/*
|
|
* Remove the /proc interface.
|
|
*/
|
|
//DEBUG_PRINT(ACPI_INFO, ("Removing /proc interface.\n"));
|
|
//status = bm_proc_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);
|
|
}
|