162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: utosi - Support for the _OSI predefined control method
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <acpi/acpi.h>
1162306a36Sopenharmony_ci#include "accommon.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define _COMPONENT          ACPI_UTILITIES
1462306a36Sopenharmony_ciACPI_MODULE_NAME("utosi")
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/******************************************************************************
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * ACPICA policy for new _OSI strings:
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * It is the stated policy of ACPICA that new _OSI strings will be integrated
2162306a36Sopenharmony_ci * into this module as soon as possible after they are defined. It is strongly
2262306a36Sopenharmony_ci * recommended that all ACPICA hosts mirror this policy and integrate any
2362306a36Sopenharmony_ci * changes to this module as soon as possible. There are several historical
2462306a36Sopenharmony_ci * reasons behind this policy:
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * 1) New BIOSs tend to test only the case where the host responds TRUE to
2762306a36Sopenharmony_ci *    the latest version of Windows, which would respond to the latest/newest
2862306a36Sopenharmony_ci *    _OSI string. Not responding TRUE to the latest version of Windows will
2962306a36Sopenharmony_ci *    risk executing untested code paths throughout the DSDT and SSDTs.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * 2) If a new _OSI string is recognized only after a significant delay, this
3262306a36Sopenharmony_ci *    has the potential to cause problems on existing working machines because
3362306a36Sopenharmony_ci *    of the possibility that a new and different path through the ASL code
3462306a36Sopenharmony_ci *    will be executed.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * 3) New _OSI strings are tending to come out about once per year. A delay
3762306a36Sopenharmony_ci *    in recognizing a new string for a significant amount of time risks the
3862306a36Sopenharmony_ci *    release of another string which only compounds the initial problem.
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci *****************************************************************************/
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * Strings supported by the _OSI predefined control method (which is
4362306a36Sopenharmony_ci * implemented internally within this module.)
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * March 2009: Removed "Linux" as this host no longer wants to respond true
4662306a36Sopenharmony_ci * for this string. Basically, the only safe OS strings are windows-related
4762306a36Sopenharmony_ci * and in many or most cases represent the only test path within the
4862306a36Sopenharmony_ci * BIOS-provided ASL code.
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci * The last element of each entry is used to track the newest version of
5162306a36Sopenharmony_ci * Windows that the BIOS has requested.
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_cistatic struct acpi_interface_info acpi_default_supported_interfaces[] = {
5462306a36Sopenharmony_ci	/* Operating System Vendor Strings */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	{"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000},	/* Windows 2000 */
5762306a36Sopenharmony_ci	{"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP},	/* Windows XP */
5862306a36Sopenharmony_ci	{"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1},	/* Windows XP SP1 */
5962306a36Sopenharmony_ci	{"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003},	/* Windows Server 2003 */
6062306a36Sopenharmony_ci	{"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2},	/* Windows XP SP2 */
6162306a36Sopenharmony_ci	{"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1},	/* Windows Server 2003 SP1 - Added 03/2006 */
6262306a36Sopenharmony_ci	{"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA},	/* Windows vista - Added 03/2006 */
6362306a36Sopenharmony_ci	{"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008},	/* Windows Server 2008 - Added 09/2009 */
6462306a36Sopenharmony_ci	{"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1},	/* Windows Vista SP1 - Added 09/2009 */
6562306a36Sopenharmony_ci	{"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2},	/* Windows Vista SP2 - Added 09/2010 */
6662306a36Sopenharmony_ci	{"Windows 2009", NULL, 0, ACPI_OSI_WIN_7},	/* Windows 7 and Server 2008 R2 - Added 09/2009 */
6762306a36Sopenharmony_ci	{"Windows 2012", NULL, 0, ACPI_OSI_WIN_8},	/* Windows 8 and Server 2012 - Added 08/2012 */
6862306a36Sopenharmony_ci	{"Windows 2013", NULL, 0, ACPI_OSI_WIN_8_1},	/* Windows 8.1 and Server 2012 R2 - Added 01/2014 */
6962306a36Sopenharmony_ci	{"Windows 2015", NULL, 0, ACPI_OSI_WIN_10},	/* Windows 10 - Added 03/2015 */
7062306a36Sopenharmony_ci	{"Windows 2016", NULL, 0, ACPI_OSI_WIN_10_RS1},	/* Windows 10 version 1607 - Added 12/2017 */
7162306a36Sopenharmony_ci	{"Windows 2017", NULL, 0, ACPI_OSI_WIN_10_RS2},	/* Windows 10 version 1703 - Added 12/2017 */
7262306a36Sopenharmony_ci	{"Windows 2017.2", NULL, 0, ACPI_OSI_WIN_10_RS3},	/* Windows 10 version 1709 - Added 02/2018 */
7362306a36Sopenharmony_ci	{"Windows 2018", NULL, 0, ACPI_OSI_WIN_10_RS4},	/* Windows 10 version 1803 - Added 11/2018 */
7462306a36Sopenharmony_ci	{"Windows 2018.2", NULL, 0, ACPI_OSI_WIN_10_RS5},	/* Windows 10 version 1809 - Added 11/2018 */
7562306a36Sopenharmony_ci	{"Windows 2019", NULL, 0, ACPI_OSI_WIN_10_19H1},	/* Windows 10 version 1903 - Added 08/2019 */
7662306a36Sopenharmony_ci	{"Windows 2020", NULL, 0, ACPI_OSI_WIN_10_20H1},	/* Windows 10 version 2004 - Added 08/2021 */
7762306a36Sopenharmony_ci	{"Windows 2021", NULL, 0, ACPI_OSI_WIN_11},	/* Windows 11 - Added 01/2022 */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* Feature Group Strings */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	{"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0},
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/*
8462306a36Sopenharmony_ci	 * All "optional" feature group strings (features that are implemented
8562306a36Sopenharmony_ci	 * by the host) should be dynamically modified to VALID by the host via
8662306a36Sopenharmony_ci	 * acpi_install_interface or acpi_update_interfaces. Such optional feature
8762306a36Sopenharmony_ci	 * group strings are set as INVALID by default here.
8862306a36Sopenharmony_ci	 */
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	{"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
9162306a36Sopenharmony_ci	{"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
9262306a36Sopenharmony_ci	{"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
9362306a36Sopenharmony_ci	{"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
9462306a36Sopenharmony_ci	{"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}
9562306a36Sopenharmony_ci};
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/*******************************************************************************
9862306a36Sopenharmony_ci *
9962306a36Sopenharmony_ci * FUNCTION:    acpi_ut_initialize_interfaces
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci * PARAMETERS:  None
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * RETURN:      Status
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * DESCRIPTION: Initialize the global _OSI supported interfaces list
10662306a36Sopenharmony_ci *
10762306a36Sopenharmony_ci ******************************************************************************/
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciacpi_status acpi_ut_initialize_interfaces(void)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	acpi_status status;
11262306a36Sopenharmony_ci	u32 i;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
11562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
11662306a36Sopenharmony_ci		return (status);
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	acpi_gbl_supported_interfaces = acpi_default_supported_interfaces;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/* Link the static list of supported interfaces */
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	for (i = 0;
12462306a36Sopenharmony_ci	     i < (ACPI_ARRAY_LENGTH(acpi_default_supported_interfaces) - 1);
12562306a36Sopenharmony_ci	     i++) {
12662306a36Sopenharmony_ci		acpi_default_supported_interfaces[i].next =
12762306a36Sopenharmony_ci		    &acpi_default_supported_interfaces[(acpi_size)i + 1];
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	acpi_os_release_mutex(acpi_gbl_osi_mutex);
13162306a36Sopenharmony_ci	return (AE_OK);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/*******************************************************************************
13562306a36Sopenharmony_ci *
13662306a36Sopenharmony_ci * FUNCTION:    acpi_ut_interface_terminate
13762306a36Sopenharmony_ci *
13862306a36Sopenharmony_ci * PARAMETERS:  None
13962306a36Sopenharmony_ci *
14062306a36Sopenharmony_ci * RETURN:      Status
14162306a36Sopenharmony_ci *
14262306a36Sopenharmony_ci * DESCRIPTION: Delete all interfaces in the global list. Sets
14362306a36Sopenharmony_ci *              acpi_gbl_supported_interfaces to NULL.
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci ******************************************************************************/
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciacpi_status acpi_ut_interface_terminate(void)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	acpi_status status;
15062306a36Sopenharmony_ci	struct acpi_interface_info *next_interface;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
15362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
15462306a36Sopenharmony_ci		return (status);
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	next_interface = acpi_gbl_supported_interfaces;
15862306a36Sopenharmony_ci	while (next_interface) {
15962306a36Sopenharmony_ci		acpi_gbl_supported_interfaces = next_interface->next;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		if (next_interface->flags & ACPI_OSI_DYNAMIC) {
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci			/* Only interfaces added at runtime can be freed */
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci			ACPI_FREE(next_interface->name);
16662306a36Sopenharmony_ci			ACPI_FREE(next_interface);
16762306a36Sopenharmony_ci		} else {
16862306a36Sopenharmony_ci			/* Interface is in static list. Reset it to invalid or valid. */
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci			if (next_interface->flags & ACPI_OSI_DEFAULT_INVALID) {
17162306a36Sopenharmony_ci				next_interface->flags |= ACPI_OSI_INVALID;
17262306a36Sopenharmony_ci			} else {
17362306a36Sopenharmony_ci				next_interface->flags &= ~ACPI_OSI_INVALID;
17462306a36Sopenharmony_ci			}
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci		next_interface = acpi_gbl_supported_interfaces;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	acpi_os_release_mutex(acpi_gbl_osi_mutex);
18162306a36Sopenharmony_ci	return (AE_OK);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/*******************************************************************************
18562306a36Sopenharmony_ci *
18662306a36Sopenharmony_ci * FUNCTION:    acpi_ut_install_interface
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci * PARAMETERS:  interface_name      - The interface to install
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci * RETURN:      Status
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci * DESCRIPTION: Install the interface into the global interface list.
19362306a36Sopenharmony_ci *              Caller MUST hold acpi_gbl_osi_mutex
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci ******************************************************************************/
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciacpi_status acpi_ut_install_interface(acpi_string interface_name)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct acpi_interface_info *interface_info;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Allocate info block and space for the name string */
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	interface_info =
20462306a36Sopenharmony_ci	    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_interface_info));
20562306a36Sopenharmony_ci	if (!interface_info) {
20662306a36Sopenharmony_ci		return (AE_NO_MEMORY);
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	interface_info->name = ACPI_ALLOCATE_ZEROED(strlen(interface_name) + 1);
21062306a36Sopenharmony_ci	if (!interface_info->name) {
21162306a36Sopenharmony_ci		ACPI_FREE(interface_info);
21262306a36Sopenharmony_ci		return (AE_NO_MEMORY);
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* Initialize new info and insert at the head of the global list */
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	strcpy(interface_info->name, interface_name);
21862306a36Sopenharmony_ci	interface_info->flags = ACPI_OSI_DYNAMIC;
21962306a36Sopenharmony_ci	interface_info->next = acpi_gbl_supported_interfaces;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	acpi_gbl_supported_interfaces = interface_info;
22262306a36Sopenharmony_ci	return (AE_OK);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/*******************************************************************************
22662306a36Sopenharmony_ci *
22762306a36Sopenharmony_ci * FUNCTION:    acpi_ut_remove_interface
22862306a36Sopenharmony_ci *
22962306a36Sopenharmony_ci * PARAMETERS:  interface_name      - The interface to remove
23062306a36Sopenharmony_ci *
23162306a36Sopenharmony_ci * RETURN:      Status
23262306a36Sopenharmony_ci *
23362306a36Sopenharmony_ci * DESCRIPTION: Remove the interface from the global interface list.
23462306a36Sopenharmony_ci *              Caller MUST hold acpi_gbl_osi_mutex
23562306a36Sopenharmony_ci *
23662306a36Sopenharmony_ci ******************************************************************************/
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ciacpi_status acpi_ut_remove_interface(acpi_string interface_name)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	struct acpi_interface_info *previous_interface;
24162306a36Sopenharmony_ci	struct acpi_interface_info *next_interface;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	previous_interface = next_interface = acpi_gbl_supported_interfaces;
24462306a36Sopenharmony_ci	while (next_interface) {
24562306a36Sopenharmony_ci		if (!strcmp(interface_name, next_interface->name)) {
24662306a36Sopenharmony_ci			/*
24762306a36Sopenharmony_ci			 * Found: name is in either the static list
24862306a36Sopenharmony_ci			 * or was added at runtime
24962306a36Sopenharmony_ci			 */
25062306a36Sopenharmony_ci			if (next_interface->flags & ACPI_OSI_DYNAMIC) {
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci				/* Interface was added dynamically, remove and free it */
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci				if (previous_interface == next_interface) {
25562306a36Sopenharmony_ci					acpi_gbl_supported_interfaces =
25662306a36Sopenharmony_ci					    next_interface->next;
25762306a36Sopenharmony_ci				} else {
25862306a36Sopenharmony_ci					previous_interface->next =
25962306a36Sopenharmony_ci					    next_interface->next;
26062306a36Sopenharmony_ci				}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci				ACPI_FREE(next_interface->name);
26362306a36Sopenharmony_ci				ACPI_FREE(next_interface);
26462306a36Sopenharmony_ci			} else {
26562306a36Sopenharmony_ci				/*
26662306a36Sopenharmony_ci				 * Interface is in static list. If marked invalid, then
26762306a36Sopenharmony_ci				 * it does not actually exist. Else, mark it invalid.
26862306a36Sopenharmony_ci				 */
26962306a36Sopenharmony_ci				if (next_interface->flags & ACPI_OSI_INVALID) {
27062306a36Sopenharmony_ci					return (AE_NOT_EXIST);
27162306a36Sopenharmony_ci				}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci				next_interface->flags |= ACPI_OSI_INVALID;
27462306a36Sopenharmony_ci			}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci			return (AE_OK);
27762306a36Sopenharmony_ci		}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		previous_interface = next_interface;
28062306a36Sopenharmony_ci		next_interface = next_interface->next;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/* Interface was not found */
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return (AE_NOT_EXIST);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci/*******************************************************************************
28962306a36Sopenharmony_ci *
29062306a36Sopenharmony_ci * FUNCTION:    acpi_ut_update_interfaces
29162306a36Sopenharmony_ci *
29262306a36Sopenharmony_ci * PARAMETERS:  action              - Actions to be performed during the
29362306a36Sopenharmony_ci *                                    update
29462306a36Sopenharmony_ci *
29562306a36Sopenharmony_ci * RETURN:      Status
29662306a36Sopenharmony_ci *
29762306a36Sopenharmony_ci * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor
29862306a36Sopenharmony_ci *              strings or/and feature group strings.
29962306a36Sopenharmony_ci *              Caller MUST hold acpi_gbl_osi_mutex
30062306a36Sopenharmony_ci *
30162306a36Sopenharmony_ci ******************************************************************************/
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ciacpi_status acpi_ut_update_interfaces(u8 action)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct acpi_interface_info *next_interface;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	next_interface = acpi_gbl_supported_interfaces;
30862306a36Sopenharmony_ci	while (next_interface) {
30962306a36Sopenharmony_ci		if (((next_interface->flags & ACPI_OSI_FEATURE) &&
31062306a36Sopenharmony_ci		     (action & ACPI_FEATURE_STRINGS)) ||
31162306a36Sopenharmony_ci		    (!(next_interface->flags & ACPI_OSI_FEATURE) &&
31262306a36Sopenharmony_ci		     (action & ACPI_VENDOR_STRINGS))) {
31362306a36Sopenharmony_ci			if (action & ACPI_DISABLE_INTERFACES) {
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci				/* Mark the interfaces as invalid */
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci				next_interface->flags |= ACPI_OSI_INVALID;
31862306a36Sopenharmony_ci			} else {
31962306a36Sopenharmony_ci				/* Mark the interfaces as valid */
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci				next_interface->flags &= ~ACPI_OSI_INVALID;
32262306a36Sopenharmony_ci			}
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		next_interface = next_interface->next;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return (AE_OK);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci/*******************************************************************************
33262306a36Sopenharmony_ci *
33362306a36Sopenharmony_ci * FUNCTION:    acpi_ut_get_interface
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * PARAMETERS:  interface_name      - The interface to find
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * RETURN:      struct acpi_interface_info if found. NULL if not found.
33862306a36Sopenharmony_ci *
33962306a36Sopenharmony_ci * DESCRIPTION: Search for the specified interface name in the global list.
34062306a36Sopenharmony_ci *              Caller MUST hold acpi_gbl_osi_mutex
34162306a36Sopenharmony_ci *
34262306a36Sopenharmony_ci ******************************************************************************/
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistruct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct acpi_interface_info *next_interface;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	next_interface = acpi_gbl_supported_interfaces;
34962306a36Sopenharmony_ci	while (next_interface) {
35062306a36Sopenharmony_ci		if (!strcmp(interface_name, next_interface->name)) {
35162306a36Sopenharmony_ci			return (next_interface);
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		next_interface = next_interface->next;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return (NULL);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci/*******************************************************************************
36162306a36Sopenharmony_ci *
36262306a36Sopenharmony_ci * FUNCTION:    acpi_ut_osi_implementation
36362306a36Sopenharmony_ci *
36462306a36Sopenharmony_ci * PARAMETERS:  walk_state          - Current walk state
36562306a36Sopenharmony_ci *
36662306a36Sopenharmony_ci * RETURN:      Status
36762306a36Sopenharmony_ci *              Integer: TRUE (0) if input string is matched
36862306a36Sopenharmony_ci *                       FALSE (-1) if string is not matched
36962306a36Sopenharmony_ci *
37062306a36Sopenharmony_ci * DESCRIPTION: Implementation of the _OSI predefined control method. When
37162306a36Sopenharmony_ci *              an invocation of _OSI is encountered in the system AML,
37262306a36Sopenharmony_ci *              control is transferred to this function.
37362306a36Sopenharmony_ci *
37462306a36Sopenharmony_ci * (August 2016)
37562306a36Sopenharmony_ci * Note:  _OSI is now defined to return "Ones" to indicate a match, for
37662306a36Sopenharmony_ci * compatibility with other ACPI implementations. On a 32-bit DSDT, Ones
37762306a36Sopenharmony_ci * is 0xFFFFFFFF. On a 64-bit DSDT, Ones is 0xFFFFFFFFFFFFFFFF
37862306a36Sopenharmony_ci * (ACPI_UINT64_MAX).
37962306a36Sopenharmony_ci *
38062306a36Sopenharmony_ci * This function always returns ACPI_UINT64_MAX for TRUE, and later code
38162306a36Sopenharmony_ci * will truncate this to 32 bits if necessary.
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci ******************************************************************************/
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ciacpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	union acpi_operand_object *string_desc;
38862306a36Sopenharmony_ci	union acpi_operand_object *return_desc;
38962306a36Sopenharmony_ci	struct acpi_interface_info *interface_info;
39062306a36Sopenharmony_ci	acpi_interface_handler interface_handler;
39162306a36Sopenharmony_ci	acpi_status status;
39262306a36Sopenharmony_ci	u64 return_value;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ut_osi_implementation);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Validate the string input argument (from the AML caller) */
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	string_desc = walk_state->arguments[0].object;
39962306a36Sopenharmony_ci	if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
40062306a36Sopenharmony_ci		return_ACPI_STATUS(AE_TYPE);
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/* Create a return object */
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
40662306a36Sopenharmony_ci	if (!return_desc) {
40762306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/* Default return value is 0, NOT SUPPORTED */
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return_value = 0;
41362306a36Sopenharmony_ci	status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
41462306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
41562306a36Sopenharmony_ci		acpi_ut_remove_reference(return_desc);
41662306a36Sopenharmony_ci		return_ACPI_STATUS(status);
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/* Lookup the interface in the global _OSI list */
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	interface_info = acpi_ut_get_interface(string_desc->string.pointer);
42262306a36Sopenharmony_ci	if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) {
42362306a36Sopenharmony_ci		/*
42462306a36Sopenharmony_ci		 * The interface is supported.
42562306a36Sopenharmony_ci		 * Update the osi_data if necessary. We keep track of the latest
42662306a36Sopenharmony_ci		 * version of Windows that has been requested by the BIOS.
42762306a36Sopenharmony_ci		 */
42862306a36Sopenharmony_ci		if (interface_info->value > acpi_gbl_osi_data) {
42962306a36Sopenharmony_ci			acpi_gbl_osi_data = interface_info->value;
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		return_value = ACPI_UINT64_MAX;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	acpi_os_release_mutex(acpi_gbl_osi_mutex);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	/*
43862306a36Sopenharmony_ci	 * Invoke an optional _OSI interface handler. The host OS may wish
43962306a36Sopenharmony_ci	 * to do some interface-specific handling. For example, warn about
44062306a36Sopenharmony_ci	 * certain interfaces or override the true/false support value.
44162306a36Sopenharmony_ci	 */
44262306a36Sopenharmony_ci	interface_handler = acpi_gbl_interface_handler;
44362306a36Sopenharmony_ci	if (interface_handler) {
44462306a36Sopenharmony_ci		if (interface_handler
44562306a36Sopenharmony_ci		    (string_desc->string.pointer, (u32)return_value)) {
44662306a36Sopenharmony_ci			return_value = ACPI_UINT64_MAX;
44762306a36Sopenharmony_ci		}
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
45162306a36Sopenharmony_ci			      "ACPI: BIOS _OSI(\"%s\") is %ssupported\n",
45262306a36Sopenharmony_ci			      string_desc->string.pointer,
45362306a36Sopenharmony_ci			      return_value == 0 ? "not " : ""));
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	/* Complete the return object */
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	return_desc->integer.value = return_value;
45862306a36Sopenharmony_ci	walk_state->return_desc = return_desc;
45962306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
46062306a36Sopenharmony_ci}
461