diff options
Diffstat (limited to 'drivers/acpi/acpica/nsxfname.c')
| -rw-r--r-- | drivers/acpi/acpica/nsxfname.c | 323 |
1 files changed, 238 insertions, 85 deletions
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index f23593d6add..8c6c11ce976 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2014, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,8 @@ * POSSIBILITY OF SUCH DAMAGES. */ +#define EXPORT_ACPI_INTERFACES + #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" @@ -51,23 +53,29 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfname") +/* Local prototypes */ +static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, + struct acpi_pnp_device_id *source, + char *string_area); + /****************************************************************************** * * FUNCTION: acpi_get_handle * - * PARAMETERS: Parent - Object to search under (search scope). - * Pathname - Pointer to an asciiz string containing the + * PARAMETERS: parent - Object to search under (search scope). + * pathname - Pointer to an asciiz string containing the * name * ret_handle - Where the return handle is returned * * RETURN: Status * * DESCRIPTION: This routine will search for a caller specified name in the - * name space. The caller can restrict the search region by - * specifying a non NULL parent. The parent value is itself a + * name space. The caller can restrict the search region by + * specifying a non NULL parent. The parent value is itself a * namespace handle. * ******************************************************************************/ + acpi_status acpi_get_handle(acpi_handle parent, acpi_string pathname, acpi_handle * ret_handle) @@ -87,7 +95,7 @@ acpi_get_handle(acpi_handle parent, /* Convert a parent handle to a prefix node */ if (parent) { - prefix_node = acpi_ns_map_handle_to_node(parent); + prefix_node = acpi_ns_validate_handle(parent); if (!prefix_node) { return (AE_BAD_PARAMETER); } @@ -100,7 +108,7 @@ acpi_get_handle(acpi_handle parent, * * Error for <null Parent + relative path> */ - if (acpi_ns_valid_root_prefix(pathname[0])) { + if (ACPI_IS_ROOT_PREFIX(pathname[0])) { /* Pathname is fully qualified (starts with '\') */ @@ -108,7 +116,7 @@ acpi_get_handle(acpi_handle parent, if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { *ret_handle = - acpi_ns_convert_entry_to_handle(acpi_gbl_root_node); + ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node); return (AE_OK); } } else if (!prefix_node) { @@ -123,7 +131,7 @@ acpi_get_handle(acpi_handle parent, status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); if (ACPI_SUCCESS(status)) { - *ret_handle = acpi_ns_convert_entry_to_handle(node); + *ret_handle = ACPI_CAST_PTR(acpi_handle, node); } return (status); @@ -135,14 +143,14 @@ ACPI_EXPORT_SYMBOL(acpi_get_handle) * * FUNCTION: acpi_get_name * - * PARAMETERS: Handle - Handle to be converted to a pathname + * PARAMETERS: handle - Handle to be converted to a pathname * name_type - Full pathname or single segment - * Buffer - Buffer for returned path + * buffer - Buffer for returned path * * RETURN: Pointer to a string containing the fully qualified Name. * * DESCRIPTION: This routine returns the fully qualified name associated with - * the Handle parameter. This and the acpi_pathname_to_handle are + * the Handle parameter. This and the acpi_pathname_to_handle are * complementary functions. * ******************************************************************************/ @@ -151,6 +159,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) { acpi_status status; struct acpi_namespace_node *node; + char *node_name; /* Parameter validation */ @@ -180,7 +189,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) return (status); } - node = acpi_ns_map_handle_to_node(handle); + node = acpi_ns_validate_handle(handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -195,12 +204,12 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) /* Just copy the ACPI name from the Node and zero terminate it */ - ACPI_STRNCPY(buffer->pointer, acpi_ut_get_node_name(node), - ACPI_NAME_SIZE); + node_name = acpi_ut_get_node_name(node); + ACPI_MOVE_NAME(buffer->pointer, node_name); ((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0; status = AE_OK; - unlock_and_exit: +unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); @@ -210,10 +219,39 @@ ACPI_EXPORT_SYMBOL(acpi_get_name) /****************************************************************************** * + * FUNCTION: acpi_ns_copy_device_id + * + * PARAMETERS: dest - Pointer to the destination PNP_DEVICE_ID + * source - Pointer to the source PNP_DEVICE_ID + * string_area - Pointer to where to copy the dest string + * + * RETURN: Pointer to the next string area + * + * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data. + * + ******************************************************************************/ +static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, + struct acpi_pnp_device_id *source, + char *string_area) +{ + + /* Create the destination PNP_DEVICE_ID */ + + dest->string = string_area; + dest->length = source->length; + + /* Copy actual string and return a pointer to the next string area */ + + ACPI_MEMCPY(string_area, source->string, source->length); + return (string_area + source->length); +} + +/****************************************************************************** + * * FUNCTION: acpi_get_object_info * - * PARAMETERS: Handle - Object Handle - * Buffer - Where the info is returned + * PARAMETERS: handle - Object Handle + * return_buffer - Where the info is returned * * RETURN: Status * @@ -221,101 +259,144 @@ ACPI_EXPORT_SYMBOL(acpi_get_name) * namespace node and possibly by running several standard * control methods (Such as in the case of a device.) * + * For Device and Processor objects, run the Device _HID, _UID, _CID, _SUB, + * _STA, _ADR, _sx_w, and _sx_d methods. + * + * Note: Allocates the return buffer, must be freed by the caller. + * ******************************************************************************/ + acpi_status -acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) +acpi_get_object_info(acpi_handle handle, + struct acpi_device_info **return_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; + 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; + char *next_id_string; + acpi_object_type type; + acpi_name name; + u8 param_count = 0; + u8 valid = 0; + u32 info_size; + u32 i; + acpi_status status; /* Parameter validation */ - if (!handle || !buffer) { + if (!handle || !return_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; + return (status); } - node = acpi_ns_map_handle_to_node(handle); + node = acpi_ns_validate_handle(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - status = AE_BAD_PARAMETER; - goto cleanup; + return (AE_BAD_PARAMETER); } - /* Init return structure */ - - size = sizeof(struct acpi_device_info); + /* Get the namespace node data while the namespace is locked */ - info->type = node->type; - info->name = node->name.integer; - info->valid = 0; + info_size = sizeof(struct acpi_device_info); + type = node->type; + name = node->name.integer; if (node->type == ACPI_TYPE_METHOD) { - info->param_count = node->object->method.param_count; + param_count = node->object->method.param_count; } status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - goto cleanup; + return (status); } - /* If not a device, we are all done */ - - if (info->type == ACPI_TYPE_DEVICE) { + if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { /* - * Get extra info for ACPI Devices objects only: - * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods. + * Get extra info for ACPI Device/Processor objects only: + * Run the Device _HID, _UID, _SUB, and _CID 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. + * 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, &info->hardware_id); + status = acpi_ut_execute_HID(node, &hid); if (ACPI_SUCCESS(status)) { - info->valid |= ACPI_VALID_HID; + info_size += hid->length; + valid |= ACPI_VALID_HID; } /* Execute the Device._UID method */ - status = acpi_ut_execute_UID(node, &info->unique_id); + 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->valid |= ACPI_VALID_UID; + 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)) { - size += cid_list->size; - info->valid |= ACPI_VALID_CID; + + /* 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; } + } + + /* + * 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)) { - info->valid |= ACPI_VALID_STA; + valid |= ACPI_VALID_STA; } /* Execute the Device._ADR method */ @@ -323,36 +404,109 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node, &info->address); if (ACPI_SUCCESS(status)) { - info->valid |= ACPI_VALID_ADR; + 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_sxds(node, info->highest_dstates); + status = acpi_ut_execute_power_methods(node, + acpi_gbl_highest_dstate_names, + ACPI_NUM_sx_d_METHODS, + info->highest_dstates); if (ACPI_SUCCESS(status)) { - info->valid |= ACPI_VALID_SXDS; + valid |= ACPI_VALID_SXDS; } } - /* Validate/Allocate/Clear caller buffer */ + /* + * 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) { - status = acpi_ut_initialize_buffer(buffer, size); - if (ACPI_FAILURE(status)) { - goto cleanup; + /* Point past the CID PNP_DEVICE_ID array */ + + next_id_string += + ((acpi_size) cid_list->count * + sizeof(struct acpi_pnp_device_id)); } - /* Populate the return buffer */ + /* + * 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); - return_info = buffer->pointer; - ACPI_MEMCPY(return_info, info, sizeof(struct acpi_device_info)); + 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) { - ACPI_MEMCPY(&return_info->compatibility_id, cid_list, - cid_list->size); + 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; + } + } } - cleanup: - ACPI_FREE(info); + /* 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); } @@ -365,7 +519,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_object_info) * * FUNCTION: acpi_install_method * - * PARAMETERS: Buffer - An ACPI table containing one control method + * PARAMETERS: buffer - An ACPI table containing one control method * * RETURN: Status * @@ -393,14 +547,14 @@ acpi_status acpi_install_method(u8 *buffer) /* Parameter validation */ if (!buffer) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } /* Table must be a DSDT or SSDT */ if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) && !ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { - return AE_BAD_HEADER; + return (AE_BAD_HEADER); } /* First AML opcode in the table must be a control method */ @@ -408,7 +562,7 @@ acpi_status acpi_install_method(u8 *buffer) parser_state.aml = buffer + sizeof(struct acpi_table_header); opcode = acpi_ps_peek_opcode(&parser_state); if (opcode != AML_METHOD_OP) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } /* Extract method information from the raw AML */ @@ -426,13 +580,13 @@ acpi_status acpi_install_method(u8 *buffer) */ aml_buffer = ACPI_ALLOCATE(aml_length); if (!aml_buffer) { - return AE_NO_MEMORY; + return (AE_NO_MEMORY); } method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); if (!method_obj) { ACPI_FREE(aml_buffer); - return AE_NO_MEMORY; + return (AE_NO_MEMORY); } /* Lock namespace for acpi_ns_lookup, we may be creating a new node */ @@ -476,10 +630,9 @@ acpi_status acpi_install_method(u8 *buffer) method_obj->method.param_count = (u8) (method_flags & AML_METHOD_ARG_COUNT); - method_obj->method.method_flags = (u8) - (method_flags & ~AML_METHOD_ARG_COUNT); - if (method_flags & AML_METHOD_SERIALIZED) { + method_obj->method.info_flags = ACPI_METHOD_SERIALIZED; + method_obj->method.sync_level = (u8) ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); } @@ -499,12 +652,12 @@ acpi_status acpi_install_method(u8 *buffer) /* Remove local reference to the method object */ acpi_ut_remove_reference(method_obj); - return status; + return (status); error_exit: ACPI_FREE(aml_buffer); ACPI_FREE(method_obj); - return status; + return (status); } ACPI_EXPORT_SYMBOL(acpi_install_method) |
