// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
 *
 * Module Name: utpredef - support functions for predefined names
 *
 * Copyright (C) 2000 - 2018, Intel Corp.
 *
 *****************************************************************************/

#include <acpi/acpi.h>
#include "accommon.h"
#include "acpredef.h"

#define _COMPONENT          ACPI_UTILITIES
ACPI_MODULE_NAME("utpredef")

/*
 * Names for the types that can be returned by the predefined objects.
 * Used for warning messages. Must be in the same order as the ACPI_RTYPEs
 */
static const char *ut_rtype_names[] = {
	"/Integer",
	"/String",
	"/Buffer",
	"/Package",
	"/Reference",
};

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_get_next_predefined_method
 *
 * PARAMETERS:  this_name           - Entry in the predefined method/name table
 *
 * RETURN:      Pointer to next entry in predefined table.
 *
 * DESCRIPTION: Get the next entry in the predefine method table. Handles the
 *              cases where a package info entry follows a method name that
 *              returns a package.
 *
 ******************************************************************************/

const union acpi_predefined_info *acpi_ut_get_next_predefined_method(const union
								     acpi_predefined_info
								     *this_name)
{

	/*
	 * Skip next entry in the table if this name returns a Package
	 * (next entry contains the package info)
	 */
	if ((this_name->info.expected_btypes & ACPI_RTYPE_PACKAGE) &&
	    (this_name->info.expected_btypes != ACPI_RTYPE_ALL)) {
		this_name++;
	}

	this_name++;
	return (this_name);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_match_predefined_method
 *
 * PARAMETERS:  name                - Name to find
 *
 * RETURN:      Pointer to entry in predefined table. NULL indicates not found.
 *
 * DESCRIPTION: Check an object name against the predefined object list.
 *
 ******************************************************************************/

const union acpi_predefined_info *acpi_ut_match_predefined_method(char *name)
{
	const union acpi_predefined_info *this_name;

	/* Quick check for a predefined name, first character must be underscore */

	if (name[0] != '_') {
		return (NULL);
	}

	/* Search info table for a predefined method/object name */

	this_name = acpi_gbl_predefined_methods;
	while (this_name->info.name[0]) {
		if (ACPI_COMPARE_NAME(name, this_name->info.name)) {
			return (this_name);
		}

		this_name = acpi_ut_get_next_predefined_method(this_name);
	}

	return (NULL);		/* Not found */
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_get_expected_return_types
 *
 * PARAMETERS:  buffer              - Where the formatted string is returned
 *              expected_Btypes     - Bitfield of expected data types
 *
 * RETURN:      Formatted string in Buffer.
 *
 * DESCRIPTION: Format the expected object types into a printable string.
 *
 ******************************************************************************/

void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes)
{
	u32 this_rtype;
	u32 i;
	u32 j;

	if (!expected_btypes) {
		strcpy(buffer, "NONE");
		return;
	}

	j = 1;
	buffer[0] = 0;
	this_rtype = ACPI_RTYPE_INTEGER;

	for (i = 0; i < ACPI_NUM_RTYPES; i++) {

		/* If one of the expected types, concatenate the name of this type */

		if (expected_btypes & this_rtype) {
			strcat(buffer, &ut_rtype_names[i][j]);
			j = 0;	/* Use name separator from now on */
		}

		this_rtype <<= 1;	/* Next Rtype */
	}
}

/*******************************************************************************
 *
 * The remaining functions are used by iASL and acpi_help only
 *
 ******************************************************************************/

#if (defined ACPI_ASL_COMPILER || defined ACPI_HELP_APP)

/* Local prototypes */

static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types);

/* Types that can be returned externally by a predefined name */

static const char *ut_external_type_names[] =	/* Indexed by ACPI_TYPE_* */
{
	", UNSUPPORTED-TYPE",
	", Integer",
	", String",
	", Buffer",
	", Package"
};

/* Bit widths for resource descriptor predefined names */

static const char *ut_resource_type_names[] = {
	"/1",
	"/2",
	"/3",
	"/8",
	"/16",
	"/32",
	"/64",
	"/variable",
};

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_match_resource_name
 *
 * PARAMETERS:  name                - Name to find
 *
 * RETURN:      Pointer to entry in the resource table. NULL indicates not
 *              found.
 *
 * DESCRIPTION: Check an object name against the predefined resource
 *              descriptor object list.
 *
 ******************************************************************************/

const union acpi_predefined_info *acpi_ut_match_resource_name(char *name)
{
	const union acpi_predefined_info *this_name;

	/*
	 * Quick check for a predefined name, first character must
	 * be underscore
	 */
	if (name[0] != '_') {
		return (NULL);
	}

	/* Search info table for a predefined method/object name */

	this_name = acpi_gbl_resource_names;
	while (this_name->info.name[0]) {
		if (ACPI_COMPARE_NAME(name, this_name->info.name)) {
			return (this_name);
		}

		this_name++;
	}

	return (NULL);		/* Not found */
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_display_predefined_method
 *
 * PARAMETERS:  buffer              - Scratch buffer for this function
 *              this_name           - Entry in the predefined method/name table
 *              multi_line          - TRUE if output should be on >1 line
 *
 * RETURN:      None
 *
 * DESCRIPTION: Display information about a predefined method. Number and
 *              type of the input arguments, and expected type(s) for the
 *              return value, if any.
 *
 ******************************************************************************/

void
acpi_ut_display_predefined_method(char *buffer,
				  const union acpi_predefined_info *this_name,
				  u8 multi_line)
{
	u32 arg_count;

	/*
	 * Get the argument count and the string buffer
	 * containing all argument types
	 */
	arg_count = acpi_ut_get_argument_types(buffer,
					       this_name->info.argument_list);

	if (multi_line) {
		printf("      ");
	}

	printf("%4.4s    Requires %s%u argument%s",
	       this_name->info.name,
	       (this_name->info.argument_list & ARG_COUNT_IS_MINIMUM) ?
	       "(at least) " : "", arg_count, arg_count != 1 ? "s" : "");

	/* Display the types for any arguments */

	if (arg_count > 0) {
		printf(" (%s)", buffer);
	}

	if (multi_line) {
		printf("\n    ");
	}

	/* Get the return value type(s) allowed */

	if (this_name->info.expected_btypes) {
		acpi_ut_get_expected_return_types(buffer,
						  this_name->info.
						  expected_btypes);
		printf("  Return value types: %s\n", buffer);
	} else {
		printf("  No return value\n");
	}
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_get_argument_types
 *
 * PARAMETERS:  buffer              - Where to return the formatted types
 *              argument_types      - Types field for this method
 *
 * RETURN:      count - the number of arguments required for this method
 *
 * DESCRIPTION: Format the required data types for this method (Integer,
 *              String, Buffer, or Package) and return the required argument
 *              count.
 *
 ******************************************************************************/

static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
{
	u16 this_argument_type;
	u16 sub_index;
	u16 arg_count;
	u32 i;

	*buffer = 0;
	sub_index = 2;

	/* First field in the types list is the count of args to follow */

	arg_count = METHOD_GET_ARG_COUNT(argument_types);
	if (arg_count > METHOD_PREDEF_ARGS_MAX) {
		printf("**** Invalid argument count (%u) "
		       "in predefined info structure\n", arg_count);
		return (arg_count);
	}

	/* Get each argument from the list, convert to ascii, store to buffer */

	for (i = 0; i < arg_count; i++) {
		this_argument_type = METHOD_GET_NEXT_TYPE(argument_types);

		if (!this_argument_type
		    || (this_argument_type > METHOD_MAX_ARG_TYPE)) {
			printf("**** Invalid argument type (%u) "
			       "in predefined info structure\n",
			       this_argument_type);
			return (arg_count);
		}

		strcat(buffer,
		       ut_external_type_names[this_argument_type] + sub_index);
		sub_index = 0;
	}

	return (arg_count);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_get_resource_bit_width
 *
 * PARAMETERS:  buffer              - Where the formatted string is returned
 *              types               - Bitfield of expected data types
 *
 * RETURN:      Count of return types. Formatted string in Buffer.
 *
 * DESCRIPTION: Format the resource bit widths into a printable string.
 *
 ******************************************************************************/

u32 acpi_ut_get_resource_bit_width(char *buffer, u16 types)
{
	u32 i;
	u16 sub_index;
	u32 found;

	*buffer = 0;
	sub_index = 1;
	found = 0;

	for (i = 0; i < NUM_RESOURCE_WIDTHS; i++) {
		if (types & 1) {
			strcat(buffer, &(ut_resource_type_names[i][sub_index]));
			sub_index = 0;
			found++;
		}

		types >>= 1;
	}

	return (found);
}
#endif
