Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
/******************************************************************************
 *
 * 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);
}
Ejemplo n.º 4
0
/*******************************************************************************
 *
 * 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);
}
Ejemplo n.º 5
0
/*******************************************************************************
 *
 * 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);
}
Ejemplo n.º 6
0
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);
}