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); }
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); }