1 /******************************************************************************
6 *****************************************************************************/
9 * Copyright (C) 2000, 2001 Andrew Grover
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #define _COMPONENT ACPI_BUS_MANAGER
35 /****************************************************************************
37 ****************************************************************************/
39 extern FADT_DESCRIPTOR_REV2 acpi_fadt;
40 /* TODO: Make dynamically sizeable. */
41 static BM_NODE_LIST node_list;
44 /****************************************************************************
46 ****************************************************************************/
48 /****************************************************************************
58 ****************************************************************************/
66 BM_DEVICE *device = NULL;
67 char *type_string = NULL;
73 device = &(node->device);
75 if (flags & BM_PRINT_PRESENT) {
76 if (!BM_DEVICE_PRESENT(device)) {
82 buffer.pointer = acpi_os_callocate(buffer.length);
83 if (!buffer.pointer) {
87 acpi_get_name(device->acpi_handle, ACPI_FULL_PATHNAME, &buffer);
89 switch(device->id.type) {
91 type_string = "System";
94 type_string = "Scope";
96 case BM_TYPE_PROCESSOR:
97 type_string = "Processor";
99 case BM_TYPE_THERMAL_ZONE:
100 type_string = "ThermalZone";
102 case BM_TYPE_POWER_RESOURCE:
103 type_string = "PowerResource";
105 case BM_TYPE_FIXED_BUTTON:
106 type_string = "Button";
109 type_string = "Device";
112 type_string = "Unknown";
116 if (!(flags & BM_PRINT_GROUP)) {
117 DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
120 DEBUG_PRINT(ACPI_INFO, ("%s[0x%02x] hid[%s] %s\n", type_string, device->handle, device->id.hid, buffer.pointer));
121 DEBUG_PRINT(ACPI_INFO, (" acpi_handle[0x%08x] flags[0x%02x] status[0x%02x]\n", device->acpi_handle, device->flags, device->status));
123 if (flags & BM_PRINT_IDENTIFICATION) {
124 DEBUG_PRINT(ACPI_INFO, (" identification: uid[%s] adr[0x%08x]\n", device->id.uid, device->id.adr));
127 if (flags & BM_PRINT_LINKAGE) {
128 DEBUG_PRINT(ACPI_INFO, (" linkage: this[%p] parent[%p] next[%p]\n", node, node->parent, node->next));
129 DEBUG_PRINT(ACPI_INFO, (" scope.head[%p] scope.tail[%p]\n", node->scope.head, node->scope.tail));
132 if (flags & BM_PRINT_POWER) {
133 DEBUG_PRINT(ACPI_INFO, (" power: state[D%d] flags[0x%08X]\n", device->power.state, device->power.flags));
134 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]));
135 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]));
138 if (!(flags & BM_PRINT_GROUP)) {
139 DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
142 acpi_os_free(buffer.pointer);
148 /****************************************************************************
150 * FUNCTION: bm_print_hierarchy
158 ****************************************************************************/
161 bm_print_hierarchy (void)
165 FUNCTION_TRACE("bm_print_hierarchy");
167 DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
169 for (i = 0; i < node_list.count; i++) {
170 bm_print(node_list.nodes[i], BM_PRINT_GROUP | BM_PRINT_PRESENT);
173 DEBUG_PRINT(ACPI_INFO, ("+------------------------------------------------------------\n"));
179 /****************************************************************************
181 * FUNCTION: bm_get_status
189 ****************************************************************************/
195 ACPI_STATUS status = AE_OK;
198 return AE_BAD_PARAMETER;
201 device->status = BM_STATUS_UNKNOWN;
206 * If _STA isn't present we just return the default status.
208 if (!(device->flags & BM_FLAGS_DYNAMIC_STATUS)) {
209 device->status = BM_STATUS_DEFAULT;
217 status = bm_evaluate_simple_integer(device->acpi_handle, "_STA",
224 /****************************************************************************
226 * FUNCTION: bm_get_identification
234 ****************************************************************************/
237 bm_get_identification (
240 ACPI_STATUS status = AE_OK;
241 ACPI_DEVICE_INFO info;
244 return AE_BAD_PARAMETER;
247 if (!(device->flags & BM_FLAGS_IDENTIFIABLE)) {
251 MEMSET(&(device->id.uid), 0, sizeof(device->id.uid));
252 MEMSET(&(device->id.hid), 0, sizeof(device->id.hid));
253 device->id.adr = BM_ADDRESS_UNKNOWN;
258 * Evalute _UID, _HID, _ADR, and _STA...
260 status = acpi_get_object_info(device->acpi_handle, &info);
261 if (ACPI_FAILURE(status)) {
265 if (info.valid & ACPI_VALID_UID) {
266 MEMCPY((void*)device->id.uid, (void*)info.unique_id,
267 sizeof(BM_DEVICE_UID));
270 if (info.valid & ACPI_VALID_HID) {
271 MEMCPY((void*)device->id.hid, (void*)info.hardware_id,
272 sizeof(BM_DEVICE_HID));
275 if (info.valid & ACPI_VALID_ADR) {
276 device->id.adr = info.address;
283 /****************************************************************************
285 * FUNCTION: bm_get_flags
293 ****************************************************************************/
299 ACPI_HANDLE acpi_handle = NULL;
302 return AE_BAD_PARAMETER;
305 device->flags = BM_FLAGS_UNKNOWN;
307 switch (device->id.type) {
312 * Presence of _DCK indicates a docking station.
314 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle,
315 "_DCK", &acpi_handle))) {
316 device->flags |= BM_FLAGS_DOCKING_STATION;
320 * Presence of _EJD and/or _EJx indicates 'ejectable'.
323 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle,
324 "_EJD", &acpi_handle))) {
325 device->flags |= BM_FLAGS_EJECTABLE;
329 * Presence of _PR0 or _PS0 indicates 'power manageable'.
331 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle,
332 "_PR0", &acpi_handle)) ||
333 ACPI_SUCCESS(acpi_get_handle(device->acpi_handle,
334 "_PS0", &acpi_handle))) {
335 device->flags |= BM_FLAGS_POWER_CONTROL;
339 * Presence of _CRS indicates 'configurable'.
341 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle,
342 "_CRS", &acpi_handle))) {
343 device->flags |= BM_FLAGS_CONFIGURABLE;
346 /* Fall through to next case statement. */
348 case BM_TYPE_PROCESSOR:
349 case BM_TYPE_THERMAL_ZONE:
350 case BM_TYPE_POWER_RESOURCE:
352 * Presence of _HID or _ADR indicates 'identifiable'.
354 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle,
355 "_HID", &acpi_handle)) ||
356 ACPI_SUCCESS(acpi_get_handle(device->acpi_handle,
357 "_ADR", &acpi_handle))) {
358 device->flags |= BM_FLAGS_IDENTIFIABLE;
362 * Presence of _STA indicates 'dynamic status'.
364 if (ACPI_SUCCESS(acpi_get_handle(device->acpi_handle,
365 "_STA", &acpi_handle))) {
366 device->flags |= BM_FLAGS_DYNAMIC_STATUS;
376 /****************************************************************************
378 * FUNCTION: bm_add_namespace_device
386 ****************************************************************************/
389 bm_add_namespace_device (
390 ACPI_HANDLE acpi_handle,
391 ACPI_OBJECT_TYPE acpi_type,
395 ACPI_STATUS status = AE_OK;
396 BM_NODE *node = NULL;
397 BM_DEVICE *device = NULL;
399 FUNCTION_TRACE("bm_add_namespace_device");
401 if (!parent || !child) {
402 return_ACPI_STATUS(AE_BAD_PARAMETER);
405 if (node_list.count > BM_HANDLES_MAX) {
406 return_ACPI_STATUS(AE_NO_MEMORY);
415 node = acpi_os_callocate(sizeof(BM_NODE));
417 return_ACPI_STATUS(AE_NO_MEMORY);
420 node->parent = parent;
423 device = &(node->device);
425 device->handle = node_list.count;
426 device->acpi_handle = acpi_handle;
433 case INTERNAL_TYPE_SCOPE:
434 device->id.type = BM_TYPE_SCOPE;
436 case ACPI_TYPE_PROCESSOR:
437 device->id.type = BM_TYPE_PROCESSOR;
439 case ACPI_TYPE_THERMAL:
440 device->id.type = BM_TYPE_THERMAL_ZONE;
442 case ACPI_TYPE_POWER:
443 device->id.type = BM_TYPE_POWER_RESOURCE;
445 case ACPI_TYPE_DEVICE:
446 device->id.type = BM_TYPE_DEVICE;
451 * Get Other Device Info:
452 * ----------------------
453 * But only if this device's parent is present (which implies
454 * this device MAY be present).
456 if (BM_NODE_PRESENT(node->parent)) {
460 status = bm_get_flags(device);
461 if (ACPI_FAILURE(status)) {
466 * Device Identification
468 status = bm_get_identification(device);
469 if (ACPI_FAILURE(status)) {
476 status = bm_get_status(device);
477 if (ACPI_FAILURE(status)) {
484 * If this node doesn't provide direct power control
485 * then we inherit PM capabilities from its parent.
489 if (device->flags & BM_FLAGS_POWER_CONTROL) {
490 status = bm_get_pm_capabilities(node);
491 if (ACPI_FAILURE(status)) {
498 if (ACPI_FAILURE(status)) {
503 * Add to the node_list.
505 node_list.nodes[node_list.count++] = node;
508 * Formulate Hierarchy:
509 * --------------------
510 * Arrange within the namespace by assigning the parent and
511 * adding to the parent device's list of children (scope).
513 if (!parent->scope.head) {
514 parent->scope.head = node;
517 if (!parent->scope.tail) {
518 (parent->scope.head)->next = node;
521 (parent->scope.tail)->next = node;
524 parent->scope.tail = node;
529 return_ACPI_STATUS(status);
533 /****************************************************************************
535 * FUNCTION: bm_enumerate_namespace
543 ****************************************************************************/
546 bm_enumerate_namespace (void)
548 ACPI_STATUS status = AE_OK;
549 ACPI_HANDLE parent_handle = ACPI_ROOT_OBJECT;
550 ACPI_HANDLE child_handle = NULL;
551 BM_NODE *parent = NULL;
552 BM_NODE *child = NULL;
553 ACPI_OBJECT_TYPE acpi_type = 0;
556 FUNCTION_TRACE("bm_enumerate_namespace");
558 parent = node_list.nodes[0];
561 * Enumerate ACPI Namespace:
562 * -------------------------
563 * Parse through the ACPI namespace, identify all 'devices',
564 * and create a new entry for each in our collection.
569 * Get the next object at this level.
571 status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, child_handle, &child_handle);
572 if (ACPI_SUCCESS(status)) {
575 * TODO: This is a hack to get around the problem
576 * identifying scope objects. Scopes
577 * somehow need to be uniquely identified.
579 status = acpi_get_type(child_handle, &acpi_type);
580 if (ACPI_SUCCESS(status) && (acpi_type == ACPI_TYPE_ANY)) {
581 status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL);
582 if (ACPI_SUCCESS(status)) {
583 acpi_type = INTERNAL_TYPE_SCOPE;
590 * If this object is a 'device', insert into the
591 * ACPI Bus Manager's local hierarchy and search
592 * the object's scope for any child devices (a
593 * depth-first search).
596 case INTERNAL_TYPE_SCOPE:
597 case ACPI_TYPE_DEVICE:
598 case ACPI_TYPE_PROCESSOR:
599 case ACPI_TYPE_THERMAL:
600 case ACPI_TYPE_POWER:
601 status = bm_add_namespace_device(child_handle, acpi_type, parent, &child);
602 if (ACPI_SUCCESS(status)) {
603 status = acpi_get_next_object(ACPI_TYPE_ANY, child_handle, 0, NULL);
604 if (ACPI_SUCCESS(status)) {
606 parent_handle = child_handle;
618 * No more children in this object's scope, Go back up
619 * in the namespace tree to the object's parent.
623 child_handle = parent_handle;
624 acpi_get_parent(parent_handle,
628 parent = parent->parent;
631 return_ACPI_STATUS(AE_NULL_ENTRY);
636 return_ACPI_STATUS(AE_OK);
640 /****************************************************************************
642 * FUNCTION: bm_add_fixed_feature_device
650 ****************************************************************************/
653 bm_add_fixed_feature_device (
655 BM_DEVICE_TYPE device_type,
658 ACPI_STATUS status = AE_OK;
659 BM_NODE *node = NULL;
661 FUNCTION_TRACE("bm_add_fixed_feature_device");
664 return_ACPI_STATUS(AE_BAD_PARAMETER);
667 if (node_list.count > BM_HANDLES_MAX) {
668 return_ACPI_STATUS(AE_NO_MEMORY);
672 * Allocate the new device and add to the device array.
674 node = acpi_os_callocate(sizeof(BM_NODE));
676 return_ACPI_STATUS(AE_NO_MEMORY);
682 node->device.handle = node_list.count;
683 node->device.acpi_handle = ACPI_ROOT_OBJECT;
684 node->device.id.type = BM_TYPE_FIXED_BUTTON;
686 MEMCPY((void*)node->device.id.hid, device_hid,
687 sizeof(node->device.id.hid));
689 node->device.flags = BM_FLAGS_FIXED_FEATURE;
690 node->device.status = BM_STATUS_DEFAULT;
691 /* TODO: Device PM capabilities */
694 * Add to the node_list.
696 node_list.nodes[node_list.count++] = node;
699 * Formulate Hierarchy:
700 * --------------------
701 * Arrange within the namespace by assigning the parent and
702 * adding to the parent device's list of children (scope).
704 node->parent = parent;
708 if (!parent->scope.head) {
709 parent->scope.head = node;
712 if (!parent->scope.tail) {
713 (parent->scope.head)->next = node;
716 (parent->scope.tail)->next = node;
719 parent->scope.tail = node;
722 return_ACPI_STATUS(status);
726 /****************************************************************************
728 * FUNCTION: bm_enumerate_fixed_features
736 ****************************************************************************/
739 bm_enumerate_fixed_features (void)
741 FUNCTION_TRACE("bm_enumerate_fixed_features");
746 * Fabricate the root object, which happens to always get a
747 * device_handle of zero.
749 node_list.nodes[0] = acpi_os_callocate(sizeof(BM_NODE));
750 if (NULL == (node_list.nodes[0])) {
751 return_ACPI_STATUS(AE_NO_MEMORY);
754 node_list.nodes[0]->device.handle = BM_HANDLE_ROOT;
755 node_list.nodes[0]->device.acpi_handle = ACPI_ROOT_OBJECT;
756 node_list.nodes[0]->device.flags = BM_FLAGS_UNKNOWN;
757 node_list.nodes[0]->device.status = BM_STATUS_DEFAULT;
758 node_list.nodes[0]->device.id.type = BM_TYPE_SYSTEM;
759 /* TODO: Get system PM capabilities (Sx states?) */
766 * Enumerate fixed-feature devices (e.g. power and sleep buttons).
768 if (acpi_fadt.pwr_button == 0) {
769 bm_add_fixed_feature_device(node_list.nodes[0],
770 BM_TYPE_FIXED_BUTTON, BM_HID_POWER_BUTTON);
773 if (acpi_fadt.sleep_button == 0) {
774 bm_add_fixed_feature_device(node_list.nodes[0],
775 BM_TYPE_FIXED_BUTTON, BM_HID_SLEEP_BUTTON);
778 return_ACPI_STATUS(AE_OK);
782 /****************************************************************************
784 * FUNCTION: bm_get_handle
792 ****************************************************************************/
796 ACPI_HANDLE acpi_handle,
797 BM_HANDLE *device_handle)
799 ACPI_STATUS status = AE_OK;
802 FUNCTION_TRACE("bm_get_handle");
804 if (!device_handle) {
805 return_ACPI_STATUS(AE_BAD_PARAMETER);
808 *device_handle = BM_HANDLE_UNKNOWN;
811 * Search all devices for a match on the ACPI handle.
813 for (i=0; i<node_list.count; i++) {
815 if (!node_list.nodes[i]) {
816 DEBUG_PRINT(ACPI_ERROR, ("Invalid (NULL) node entry [0x%02x] detected.\n", device_handle));
817 status = AE_NULL_ENTRY;
821 if (node_list.nodes[i]->device.acpi_handle == acpi_handle) {
822 *device_handle = node_list.nodes[i]->device.handle;
827 return_ACPI_STATUS(status);
831 /****************************************************************************
833 * FUNCTION: bm_get_node
841 ****************************************************************************/
845 BM_HANDLE device_handle,
846 ACPI_HANDLE acpi_handle,
849 ACPI_STATUS status = AE_OK;
851 FUNCTION_TRACE("bm_get_node");
854 return_ACPI_STATUS(AE_BAD_PARAMETER);
858 * If no device handle, resolve acpi handle to device handle.
860 if (!device_handle && acpi_handle) {
861 status = bm_get_handle(acpi_handle, &device_handle);
862 if (ACPI_FAILURE(status))
863 return_ACPI_STATUS(status);
867 * Valid device handle?
869 if (device_handle > BM_HANDLES_MAX) {
870 DEBUG_PRINT(ACPI_ERROR, ("Invalid node handle [0x%02x] detected.\n", device_handle));
871 return_ACPI_STATUS(AE_ERROR);
874 *node = node_list.nodes[device_handle];
880 DEBUG_PRINT(ACPI_ERROR, ("Invalid (NULL) node entry [0x%02x] detected.\n", device_handle));
881 return_ACPI_STATUS(AE_NULL_ENTRY);
884 return_ACPI_STATUS(AE_OK);
888 /****************************************************************************
890 ****************************************************************************/
892 /****************************************************************************
894 * FUNCTION: bm_initialize
898 * RETURN: Exception code.
902 ****************************************************************************/
907 ACPI_STATUS status = AE_OK;
912 FUNCTION_TRACE("bm_initialize");
914 MEMSET(&node_list, 0, sizeof(BM_HANDLE_LIST));
916 acpi_get_timer(&start);
918 DEBUG_PRINT(ACPI_INFO, ("Building device hierarchy.\n"));
921 * Enumerate ACPI fixed-feature devices.
923 status = bm_enumerate_fixed_features();
924 if (ACPI_FAILURE(status)) {
925 return_ACPI_STATUS(status);
929 * Enumerate the ACPI namespace.
931 status = bm_enumerate_namespace();
932 if (ACPI_FAILURE(status)) {
933 return_ACPI_STATUS(status);
936 acpi_get_timer(&stop);
937 acpi_get_timer_duration(start, stop, &elapsed);
939 DEBUG_PRINT(ACPI_INFO, ("Device heirarchy build took [%d] microseconds.\n", elapsed));
945 bm_print_hierarchy();
946 #endif /*ACPI_DEBUG*/
949 * Register for all standard and device-specific notifications.
951 DEBUG_PRINT(ACPI_INFO, ("Registering for all device notifications.\n"));
953 status = acpi_install_notify_handler(ACPI_ROOT_OBJECT,
954 ACPI_SYSTEM_NOTIFY, &bm_notify, NULL);
955 if (ACPI_FAILURE(status)) {
956 DEBUG_PRINT(ACPI_ERROR, ("Unable to register for standard notifications.\n"));
957 return_ACPI_STATUS(status);
960 status = acpi_install_notify_handler(ACPI_ROOT_OBJECT,
961 ACPI_DEVICE_NOTIFY, &bm_notify, NULL);
962 if (ACPI_FAILURE(status)) {
963 DEBUG_PRINT(ACPI_ERROR, ("Unable to register for device-specific notifications.\n"));
964 return_ACPI_STATUS(status);
968 * Initialize /proc interface.
970 //DEBUG_PRINT(ACPI_INFO, ("Initializing /proc interface.\n"));
971 //status = bm_proc_initialize();
973 DEBUG_PRINT(ACPI_INFO, ("ACPI Bus Manager enabled.\n"));
976 * Initialize built-in power resource driver.
980 return_ACPI_STATUS(status);
984 /****************************************************************************
986 * FUNCTION: bm_terminate
990 * RETURN: Exception code.
994 ****************************************************************************/
999 ACPI_STATUS status = AE_OK;
1002 FUNCTION_TRACE("bm_terminate");
1005 * Terminate built-in power resource driver.
1010 * Remove the /proc interface.
1012 //DEBUG_PRINT(ACPI_INFO, ("Removing /proc interface.\n"));
1013 //status = bm_proc_terminate();
1017 * Unregister for all notifications.
1020 DEBUG_PRINT(ACPI_INFO, ("Unregistering for device notifications.\n"));
1022 status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
1023 ACPI_SYSTEM_NOTIFY, &bm_notify);
1024 if (ACPI_FAILURE(status)) {
1025 DEBUG_PRINT(ACPI_ERROR, ("Unable to un-register for standard notifications.\n"));
1028 status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
1029 ACPI_DEVICE_NOTIFY, &bm_notify);
1030 if (ACPI_FAILURE(status)) {
1031 DEBUG_PRINT(ACPI_ERROR, ("Unable to un-register for device-specific notifications.\n"));
1035 * Parse through the device array, freeing all entries.
1037 DEBUG_PRINT(ACPI_INFO, ("Removing device hierarchy.\n"));
1038 for (i = 0; i < node_list.count; i++) {
1039 if (node_list.nodes[i]) {
1040 acpi_os_free(node_list.nodes[i]);
1044 DEBUG_PRINT(ACPI_INFO, ("ACPI Bus Manager disabled.\n"));
1046 return_ACPI_STATUS(AE_OK);