static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) { acpi_status status; struct acpi_pnp_device_id *hid; struct acpi_pnp_device_id_list *cid; u32 i; u8 match; /* Get the _HID and check for a PCI Root Bridge */ status = acpi_ut_execute_HID(node, &hid); if (ACPI_FAILURE(status)) { return (FALSE); } match = acpi_ut_is_pci_root_bridge(hid->string); ACPI_FREE(hid); if (match) { return (TRUE); } /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */ status = acpi_ut_execute_CID(node, &cid); if (ACPI_FAILURE(status)) { return (FALSE); } /* Check all _CIDs in the returned list */ for (i = 0; i < cid->count; i++) { if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) { ACPI_FREE(cid); return (TRUE); } } ACPI_FREE(cid); return (FALSE); }
static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) { acpi_status status; struct acpica_device_id hid; struct acpi_compatible_id_list *cid; acpi_native_uint i; /* * Get the _HID and check for a PCI Root Bridge */ status = acpi_ut_execute_HID(node, &hid); if (ACPI_FAILURE(status)) { return (FALSE); } if (acpi_ev_match_pci_root_bridge(hid.value)) { return (TRUE); } /* * The _HID did not match. * Get the _CID and check for a PCI Root Bridge */ status = acpi_ut_execute_CID(node, &cid); if (ACPI_FAILURE(status)) { return (FALSE); } /* Check all _CIDs in the returned list */ for (i = 0; i < cid->count; i++) { if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) { ACPI_FREE(cid); return (TRUE); } } ACPI_FREE(cid); return (FALSE); }
/****************************************************************************** * * FUNCTION: acpi_get_object_info * * PARAMETERS: Handle - Object Handle * Buffer - Where the info is returned * * RETURN: Status * * DESCRIPTION: Returns information about an object as gleaned from the * namespace node and possibly by running several standard * control methods (Such as in the case of a device.) * ******************************************************************************/ acpi_status acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) { acpi_status status; struct acpi_namespace_node *node; struct acpi_device_info *info; struct acpi_device_info *return_info; struct acpi_compatible_id_list *cid_list = NULL; acpi_size size; /* Parameter validation */ if (!handle || !buffer) { return (AE_BAD_PARAMETER); } status = acpi_ut_validate_buffer(buffer); if (ACPI_FAILURE(status)) { return (status); } info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_device_info)); if (!info) { return (AE_NO_MEMORY); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto cleanup; } node = acpi_ns_map_handle_to_node(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); status = AE_BAD_PARAMETER; goto cleanup; } /* Init return structure */ size = sizeof(struct acpi_device_info); info->type = node->type; info->name = node->name.integer; info->valid = 0; if (node->type == ACPI_TYPE_METHOD) { info->param_count = node->object->method.param_count; } status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto cleanup; } /* If not a device, we are all done */ if (info->type == ACPI_TYPE_DEVICE) { /* * Get extra info for ACPI Devices objects only: * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info->Valid bitfield is used * to indicate which methods were found and ran successfully. */ /* Execute the Device._HID method */ status = acpi_ut_execute_HID(node, &info->hardware_id); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_HID; } /* Execute the Device._UID method */ status = acpi_ut_execute_UID(node, &info->unique_id); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_UID; } /* Execute the Device._CID method */ status = acpi_ut_execute_CID(node, &cid_list); if (ACPI_SUCCESS(status)) { size += cid_list->size; info->valid |= ACPI_VALID_CID; } /* Execute the Device._STA method */ status = acpi_ut_execute_STA(node, &info->current_status); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_STA; } /* Execute the Device._ADR method */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node, &info->address); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_ADR; } /* Execute the Device._sx_d methods */ status = acpi_ut_execute_sxds(node, info->highest_dstates); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_SXDS; } } /* Validate/Allocate/Clear caller buffer */ status = acpi_ut_initialize_buffer(buffer, size); if (ACPI_FAILURE(status)) { goto cleanup; } /* Populate the return buffer */ return_info = buffer->pointer; ACPI_MEMCPY(return_info, info, sizeof(struct acpi_device_info)); if (cid_list) { ACPI_MEMCPY(&return_info->compatibility_id, cid_list, cid_list->size); } cleanup: ACPI_FREE(info); if (cid_list) { ACPI_FREE(cid_list); } return (status); }
/******************************************************************************* * * FUNCTION: acpi_ns_get_device_callback * * PARAMETERS: Callback from acpi_get_device * * RETURN: Status * * DESCRIPTION: Takes callbacks from walk_namespace and filters out all non- * present devices, or if they specified a HID, it filters based * on that. * ******************************************************************************/ static acpi_status acpi_ns_get_device_callback(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { struct acpi_get_devices_info *info = context; acpi_status status; struct acpi_namespace_node *node; u32 flags; struct acpi_pnp_device_id *hid; struct acpi_pnp_device_id_list *cid; u32 i; u8 found; int no_match; status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_validate_handle(obj_handle); status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } if (!node) { return (AE_BAD_PARAMETER); } /* * First, filter based on the device HID and CID. * * 01/2010: For this case where a specific HID is requested, we don't * want to run _STA until we have an actual HID match. Thus, we will * not unnecessarily execute _STA on devices for which the caller * doesn't care about. Previously, _STA was executed unconditionally * on all devices found here. * * A side-effect of this change is that now we will continue to search * for a matching HID even under device trees where the parent device * would have returned a _STA that indicates it is not present or * not functioning (thus aborting the search on that branch). */ if (info->hid != NULL) { status = acpi_ut_execute_HID(node, &hid); if (status == AE_NOT_FOUND) { return (AE_OK); } else if (ACPI_FAILURE(status)) { return (AE_CTRL_DEPTH); } no_match = ACPI_STRCMP(hid->string, info->hid); ACPI_FREE(hid); if (no_match) { /* * HID does not match, attempt match within the * list of Compatible IDs (CIDs) */ status = acpi_ut_execute_CID(node, &cid); if (status == AE_NOT_FOUND) { return (AE_OK); } else if (ACPI_FAILURE(status)) { return (AE_CTRL_DEPTH); } /* Walk the CID list */ found = FALSE; for (i = 0; i < cid->count; i++) { if (ACPI_STRCMP(cid->ids[i].string, info->hid) == 0) { /* Found a matching CID */ found = TRUE; break; } } ACPI_FREE(cid); if (!found) { return (AE_OK); } } } /* Run _STA to determine if device is present */ status = acpi_ut_execute_STA(node, &flags); if (ACPI_FAILURE(status)) { return (AE_CTRL_DEPTH); } if (!(flags & ACPI_STA_DEVICE_PRESENT) && !(flags & ACPI_STA_DEVICE_FUNCTIONING)) { /* * Don't examine the children of the device only when the * device is neither present nor functional. See ACPI spec, * description of _STA for more information. */ return (AE_CTRL_DEPTH); } /* We have a valid device, invoke the user function */ status = info->user_function(obj_handle, nesting_level, info->context, return_value); return (status); }
/******************************************************************************* * * FUNCTION: acpi_ns_get_device_callback * * PARAMETERS: Callback from acpi_get_device * * RETURN: Status * * DESCRIPTION: Takes callbacks from walk_namespace and filters out all non- * present devices, or if they specified a HID, it filters based * on that. * ******************************************************************************/ static acpi_status acpi_ns_get_device_callback(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { struct acpi_get_devices_info *info = context; acpi_status status; struct acpi_namespace_node *node; u32 flags; struct acpica_device_id hid; struct acpi_compatible_id_list *cid; acpi_native_uint i; status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_map_handle_to_node(obj_handle); status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } if (!node) { return (AE_BAD_PARAMETER); } /* Run _STA to determine if device is present */ status = acpi_ut_execute_STA(node, &flags); if (ACPI_FAILURE(status)) { return (AE_CTRL_DEPTH); } if (!(flags & ACPI_STA_DEVICE_PRESENT)) { /* Don't examine children of the device if not present */ return (AE_CTRL_DEPTH); } /* Filter based on device HID & CID */ if (info->hid != NULL) { status = acpi_ut_execute_HID(node, &hid); if (status == AE_NOT_FOUND) { return (AE_OK); } else if (ACPI_FAILURE(status)) { return (AE_CTRL_DEPTH); } if (ACPI_STRNCMP(hid.value, info->hid, sizeof(hid.value)) != 0) { /* Get the list of Compatible IDs */ status = acpi_ut_execute_CID(node, &cid); if (status == AE_NOT_FOUND) { return (AE_OK); } else if (ACPI_FAILURE(status)) { return (AE_CTRL_DEPTH); } /* Walk the CID list */ for (i = 0; i < cid->count; i++) { if (ACPI_STRNCMP(cid->id[i].value, info->hid, sizeof(struct acpi_compatible_id)) != 0) { ACPI_FREE(cid); return (AE_OK); } } ACPI_FREE(cid); } } status = info->user_function(obj_handle, nesting_level, info->context, return_value); return (status); }
acpi_status acpi_get_object_info(acpi_handle handle, struct acpi_device_info **return_buffer) { struct acpi_namespace_node *node; struct acpi_device_info *info; struct acpi_pnp_device_id_list *cid_list = NULL; struct acpi_pnp_device_id *hid = NULL; struct acpi_pnp_device_id *uid = NULL; struct acpi_pnp_device_id *sub = NULL; struct acpi_pnp_device_id *cls = NULL; char *next_id_string; acpi_object_type type; acpi_name name; u8 param_count = 0; u16 valid = 0; u32 info_size; u32 i; acpi_status status; /* Parameter validation */ if (!handle || !return_buffer) { return (AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_validate_handle(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } /* Get the namespace node data while the namespace is locked */ info_size = sizeof(struct acpi_device_info); type = node->type; name = node->name.integer; if (node->type == ACPI_TYPE_METHOD) { param_count = node->object->method.param_count; } status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { /* * Get extra info for ACPI Device/Processor objects only: * Run the Device _HID, _UID, _SUB, _CID, and _CLS methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info->Valid bitfield is used * to indicate which methods were found and run successfully. */ /* Execute the Device._HID method */ status = acpi_ut_execute_HID(node, &hid); if (ACPI_SUCCESS(status)) { info_size += hid->length; valid |= ACPI_VALID_HID; } /* Execute the Device._UID method */ status = acpi_ut_execute_UID(node, &uid); if (ACPI_SUCCESS(status)) { info_size += uid->length; valid |= ACPI_VALID_UID; } /* Execute the Device._SUB method */ status = acpi_ut_execute_SUB(node, &sub); if (ACPI_SUCCESS(status)) { info_size += sub->length; valid |= ACPI_VALID_SUB; } /* Execute the Device._CID method */ status = acpi_ut_execute_CID(node, &cid_list); if (ACPI_SUCCESS(status)) { /* Add size of CID strings and CID pointer array */ info_size += (cid_list->list_size - sizeof(struct acpi_pnp_device_id_list)); valid |= ACPI_VALID_CID; } /* Execute the Device._CLS method */ status = acpi_ut_execute_CLS(node, &cls); if (ACPI_SUCCESS(status)) { info_size += cls->length; valid |= ACPI_VALID_CLS; } } /* * Now that we have the variable-length data, we can allocate the * return buffer */ info = ACPI_ALLOCATE_ZEROED(info_size); if (!info) { status = AE_NO_MEMORY; goto cleanup; } /* Get the fixed-length data */ if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { /* * Get extra info for ACPI Device/Processor objects only: * Run the _STA, _ADR and, sx_w, and _sx_d methods. * * Notes: none of these methods are required, so they may or may * not be present for this device. The Info->Valid bitfield is used * to indicate which methods were found and run successfully. * * For _STA, if the method does not exist, then (as per the ACPI * specification), the returned current_status flags will indicate * that the device is present/functional/enabled. Otherwise, the * current_status flags reflect the value returned from _STA. */ /* Execute the Device._STA method */ status = acpi_ut_execute_STA(node, &info->current_status); if (ACPI_SUCCESS(status)) { valid |= ACPI_VALID_STA; } /* Execute the Device._ADR method */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node, &info->address); if (ACPI_SUCCESS(status)) { valid |= ACPI_VALID_ADR; } /* Execute the Device._sx_w methods */ status = acpi_ut_execute_power_methods(node, acpi_gbl_lowest_dstate_names, ACPI_NUM_sx_w_METHODS, info->lowest_dstates); if (ACPI_SUCCESS(status)) { valid |= ACPI_VALID_SXWS; } /* Execute the Device._sx_d methods */ status = acpi_ut_execute_power_methods(node, acpi_gbl_highest_dstate_names, ACPI_NUM_sx_d_METHODS, info->highest_dstates); if (ACPI_SUCCESS(status)) { valid |= ACPI_VALID_SXDS; } } /* * Create a pointer to the string area of the return buffer. * Point to the end of the base struct acpi_device_info structure. */ next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids); if (cid_list) { /* Point past the CID PNP_DEVICE_ID array */ next_id_string += ((acpi_size) cid_list->count * sizeof(struct acpi_pnp_device_id)); } /* * Copy the HID, UID, SUB, and CIDs to the return buffer. * The variable-length strings are copied to the reserved area * at the end of the buffer. * * For HID and CID, check if the ID is a PCI Root Bridge. */ if (hid) { next_id_string = acpi_ns_copy_device_id(&info->hardware_id, hid, next_id_string); if (acpi_ut_is_pci_root_bridge(hid->string)) { info->flags |= ACPI_PCI_ROOT_BRIDGE; } } if (uid) { next_id_string = acpi_ns_copy_device_id(&info->unique_id, uid, next_id_string); } if (sub) { next_id_string = acpi_ns_copy_device_id(&info->subsystem_id, sub, next_id_string); } if (cid_list) { info->compatible_id_list.count = cid_list->count; info->compatible_id_list.list_size = cid_list->list_size; /* Copy each CID */ for (i = 0; i < cid_list->count; i++) { next_id_string = acpi_ns_copy_device_id(&info->compatible_id_list. ids[i], &cid_list->ids[i], next_id_string); if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) { info->flags |= ACPI_PCI_ROOT_BRIDGE; } } } if (cls) { next_id_string = acpi_ns_copy_device_id(&info->class_code, cls, next_id_string); } /* Copy the fixed-length data */ info->info_size = info_size; info->type = type; info->name = name; info->param_count = param_count; info->valid = valid; *return_buffer = info; status = AE_OK; cleanup: if (hid) { ACPI_FREE(hid); } if (uid) { ACPI_FREE(uid); } if (sub) { ACPI_FREE(sub); } if (cid_list) { ACPI_FREE(cid_list); } if (cls) { ACPI_FREE(cls); } return (status); }