162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: hwxface - Public ACPICA hardware interfaces 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define EXPORT_ACPI_INTERFACES 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <acpi/acpi.h> 1362306a36Sopenharmony_ci#include "accommon.h" 1462306a36Sopenharmony_ci#include "acnamesp.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define _COMPONENT ACPI_HARDWARE 1762306a36Sopenharmony_ciACPI_MODULE_NAME("hwxface") 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/****************************************************************************** 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * FUNCTION: acpi_reset 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * PARAMETERS: None 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * RETURN: Status 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * DESCRIPTION: Set reset register in memory or IO space. Note: Does not 2862306a36Sopenharmony_ci * support reset register in PCI config space, this must be 2962306a36Sopenharmony_ci * handled separately. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci ******************************************************************************/ 3262306a36Sopenharmony_ciacpi_status acpi_reset(void) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct acpi_generic_address *reset_reg; 3562306a36Sopenharmony_ci acpi_status status; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(acpi_reset); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci reset_reg = &acpi_gbl_FADT.reset_register; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* Check if the reset register is supported */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || 4462306a36Sopenharmony_ci !reset_reg->address) { 4562306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_EXIST); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (reset_reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { 4962306a36Sopenharmony_ci /* 5062306a36Sopenharmony_ci * For I/O space, write directly to the OSL. This bypasses the port 5162306a36Sopenharmony_ci * validation mechanism, which may block a valid write to the reset 5262306a36Sopenharmony_ci * register. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * NOTE: 5562306a36Sopenharmony_ci * The ACPI spec requires the reset register width to be 8, so we 5662306a36Sopenharmony_ci * hardcode it here and ignore the FADT value. This maintains 5762306a36Sopenharmony_ci * compatibility with other ACPI implementations that have allowed 5862306a36Sopenharmony_ci * BIOS code with bad register width values to go unnoticed. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci status = acpi_os_write_port((acpi_io_address)reset_reg->address, 6162306a36Sopenharmony_ci acpi_gbl_FADT.reset_value, 6262306a36Sopenharmony_ci ACPI_RESET_REGISTER_WIDTH); 6362306a36Sopenharmony_ci } else { 6462306a36Sopenharmony_ci /* Write the reset value to the reset register */ 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci status = acpi_hw_write(acpi_gbl_FADT.reset_value, reset_reg); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return_ACPI_STATUS(status); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_reset) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/****************************************************************************** 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * FUNCTION: acpi_read 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * PARAMETERS: value - Where the value is returned 7962306a36Sopenharmony_ci * reg - GAS register structure 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * RETURN: Status 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * DESCRIPTION: Read from either memory or IO space. 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * LIMITATIONS: <These limitations also apply to acpi_write> 8662306a36Sopenharmony_ci * bit_width must be exactly 8, 16, 32, or 64. 8762306a36Sopenharmony_ci * space_ID must be system_memory or system_IO. 8862306a36Sopenharmony_ci * bit_offset and access_width are currently ignored, as there has 8962306a36Sopenharmony_ci * not been a need to implement these. 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci ******************************************************************************/ 9262306a36Sopenharmony_ciacpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci acpi_status status; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci ACPI_FUNCTION_NAME(acpi_read); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci status = acpi_hw_read(return_value, reg); 9962306a36Sopenharmony_ci return (status); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_read) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/****************************************************************************** 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * FUNCTION: acpi_write 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * PARAMETERS: value - Value to be written 10962306a36Sopenharmony_ci * reg - GAS register structure 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * RETURN: Status 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * DESCRIPTION: Write to either memory or IO space. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci ******************************************************************************/ 11662306a36Sopenharmony_ciacpi_status acpi_write(u64 value, struct acpi_generic_address *reg) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci acpi_status status; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci ACPI_FUNCTION_NAME(acpi_write); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci status = acpi_hw_write(value, reg); 12362306a36Sopenharmony_ci return (status); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_write) 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#if (!ACPI_REDUCED_HARDWARE) 12962306a36Sopenharmony_ci/******************************************************************************* 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * FUNCTION: acpi_read_bit_register 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * PARAMETERS: register_id - ID of ACPI Bit Register to access 13462306a36Sopenharmony_ci * return_value - Value that was read from the register, 13562306a36Sopenharmony_ci * normalized to bit position zero. 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * RETURN: Status and the value read from the specified Register. Value 13862306a36Sopenharmony_ci * returned is normalized to bit0 (is shifted all the way right) 13962306a36Sopenharmony_ci * 14062306a36Sopenharmony_ci * DESCRIPTION: ACPI bit_register read function. Does not acquire the HW lock. 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * SUPPORTS: Bit fields in PM1 Status, PM1 Enable, PM1 Control, and 14362306a36Sopenharmony_ci * PM2 Control. 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci * Note: The hardware lock is not required when reading the ACPI bit registers 14662306a36Sopenharmony_ci * since almost all of them are single bit and it does not matter that 14762306a36Sopenharmony_ci * the parent hardware register can be split across two physical 14862306a36Sopenharmony_ci * registers. The only multi-bit field is SLP_TYP in the PM1 control 14962306a36Sopenharmony_ci * register, but this field does not cross an 8-bit boundary (nor does 15062306a36Sopenharmony_ci * it make much sense to actually read this field.) 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci ******************************************************************************/ 15362306a36Sopenharmony_ciacpi_status acpi_read_bit_register(u32 register_id, u32 *return_value) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct acpi_bit_register_info *bit_reg_info; 15662306a36Sopenharmony_ci u32 register_value; 15762306a36Sopenharmony_ci u32 value; 15862306a36Sopenharmony_ci acpi_status status; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_U32(acpi_read_bit_register, register_id); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Get the info structure corresponding to the requested ACPI Register */ 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci bit_reg_info = acpi_hw_get_bit_register_info(register_id); 16562306a36Sopenharmony_ci if (!bit_reg_info) { 16662306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* Read the entire parent register */ 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci status = acpi_hw_register_read(bit_reg_info->parent_register, 17262306a36Sopenharmony_ci ®ister_value); 17362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 17462306a36Sopenharmony_ci return_ACPI_STATUS(status); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Normalize the value that was read, mask off other bits */ 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci value = ((register_value & bit_reg_info->access_bit_mask) 18062306a36Sopenharmony_ci >> bit_reg_info->bit_position); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_IO, 18362306a36Sopenharmony_ci "BitReg %X, ParentReg %X, Actual %8.8X, ReturnValue %8.8X\n", 18462306a36Sopenharmony_ci register_id, bit_reg_info->parent_register, 18562306a36Sopenharmony_ci register_value, value)); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci *return_value = value; 18862306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_read_bit_register) 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/******************************************************************************* 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * FUNCTION: acpi_write_bit_register 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * PARAMETERS: register_id - ID of ACPI Bit Register to access 19862306a36Sopenharmony_ci * value - Value to write to the register, in bit 19962306a36Sopenharmony_ci * position zero. The bit is automatically 20062306a36Sopenharmony_ci * shifted to the correct position. 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci * RETURN: Status 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * DESCRIPTION: ACPI Bit Register write function. Acquires the hardware lock 20562306a36Sopenharmony_ci * since most operations require a read/modify/write sequence. 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * SUPPORTS: Bit fields in PM1 Status, PM1 Enable, PM1 Control, and 20862306a36Sopenharmony_ci * PM2 Control. 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * Note that at this level, the fact that there may be actually two 21162306a36Sopenharmony_ci * hardware registers (A and B - and B may not exist) is abstracted. 21262306a36Sopenharmony_ci * 21362306a36Sopenharmony_ci ******************************************************************************/ 21462306a36Sopenharmony_ciacpi_status acpi_write_bit_register(u32 register_id, u32 value) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct acpi_bit_register_info *bit_reg_info; 21762306a36Sopenharmony_ci acpi_cpu_flags lock_flags; 21862306a36Sopenharmony_ci u32 register_value; 21962306a36Sopenharmony_ci acpi_status status = AE_OK; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_U32(acpi_write_bit_register, register_id); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Get the info structure corresponding to the requested ACPI Register */ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci bit_reg_info = acpi_hw_get_bit_register_info(register_id); 22662306a36Sopenharmony_ci if (!bit_reg_info) { 22762306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci lock_flags = acpi_os_acquire_raw_lock(acpi_gbl_hardware_lock); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* 23362306a36Sopenharmony_ci * At this point, we know that the parent register is one of the 23462306a36Sopenharmony_ci * following: PM1 Status, PM1 Enable, PM1 Control, or PM2 Control 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci if (bit_reg_info->parent_register != ACPI_REGISTER_PM1_STATUS) { 23762306a36Sopenharmony_ci /* 23862306a36Sopenharmony_ci * 1) Case for PM1 Enable, PM1 Control, and PM2 Control 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * Perform a register read to preserve the bits that we are not 24162306a36Sopenharmony_ci * interested in 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_ci status = acpi_hw_register_read(bit_reg_info->parent_register, 24462306a36Sopenharmony_ci ®ister_value); 24562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 24662306a36Sopenharmony_ci goto unlock_and_exit; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* 25062306a36Sopenharmony_ci * Insert the input bit into the value that was just read 25162306a36Sopenharmony_ci * and write the register 25262306a36Sopenharmony_ci */ 25362306a36Sopenharmony_ci ACPI_REGISTER_INSERT_VALUE(register_value, 25462306a36Sopenharmony_ci bit_reg_info->bit_position, 25562306a36Sopenharmony_ci bit_reg_info->access_bit_mask, 25662306a36Sopenharmony_ci value); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci status = acpi_hw_register_write(bit_reg_info->parent_register, 25962306a36Sopenharmony_ci register_value); 26062306a36Sopenharmony_ci } else { 26162306a36Sopenharmony_ci /* 26262306a36Sopenharmony_ci * 2) Case for PM1 Status 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * The Status register is different from the rest. Clear an event 26562306a36Sopenharmony_ci * by writing 1, writing 0 has no effect. So, the only relevant 26662306a36Sopenharmony_ci * information is the single bit we're interested in, all others 26762306a36Sopenharmony_ci * should be written as 0 so they will be left unchanged. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci register_value = ACPI_REGISTER_PREPARE_BITS(value, 27062306a36Sopenharmony_ci bit_reg_info-> 27162306a36Sopenharmony_ci bit_position, 27262306a36Sopenharmony_ci bit_reg_info-> 27362306a36Sopenharmony_ci access_bit_mask); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* No need to write the register if value is all zeros */ 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (register_value) { 27862306a36Sopenharmony_ci status = 27962306a36Sopenharmony_ci acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, 28062306a36Sopenharmony_ci register_value); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_IO, 28562306a36Sopenharmony_ci "BitReg %X, ParentReg %X, Value %8.8X, Actual %8.8X\n", 28662306a36Sopenharmony_ci register_id, bit_reg_info->parent_register, value, 28762306a36Sopenharmony_ci register_value)); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ciunlock_and_exit: 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci acpi_os_release_raw_lock(acpi_gbl_hardware_lock, lock_flags); 29262306a36Sopenharmony_ci return_ACPI_STATUS(status); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_write_bit_register) 29662306a36Sopenharmony_ci#endif /* !ACPI_REDUCED_HARDWARE */ 29762306a36Sopenharmony_ci/******************************************************************************* 29862306a36Sopenharmony_ci * 29962306a36Sopenharmony_ci * FUNCTION: acpi_get_sleep_type_data 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * PARAMETERS: sleep_state - Numeric sleep state 30262306a36Sopenharmony_ci * *sleep_type_a - Where SLP_TYPa is returned 30362306a36Sopenharmony_ci * *sleep_type_b - Where SLP_TYPb is returned 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * RETURN: Status 30662306a36Sopenharmony_ci * 30762306a36Sopenharmony_ci * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested 30862306a36Sopenharmony_ci * sleep state via the appropriate \_Sx object. 30962306a36Sopenharmony_ci * 31062306a36Sopenharmony_ci * The sleep state package returned from the corresponding \_Sx_ object 31162306a36Sopenharmony_ci * must contain at least one integer. 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * March 2005: 31462306a36Sopenharmony_ci * Added support for a package that contains two integers. This 31562306a36Sopenharmony_ci * goes against the ACPI specification which defines this object as a 31662306a36Sopenharmony_ci * package with one encoded DWORD integer. However, existing practice 31762306a36Sopenharmony_ci * by many BIOS vendors is to return a package with 2 or more integer 31862306a36Sopenharmony_ci * elements, at least one per sleep type (A/B). 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * January 2013: 32162306a36Sopenharmony_ci * Therefore, we must be prepared to accept a package with either a 32262306a36Sopenharmony_ci * single integer or multiple integers. 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * The single integer DWORD format is as follows: 32562306a36Sopenharmony_ci * BYTE 0 - Value for the PM1A SLP_TYP register 32662306a36Sopenharmony_ci * BYTE 1 - Value for the PM1B SLP_TYP register 32762306a36Sopenharmony_ci * BYTE 2-3 - Reserved 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * The dual integer format is as follows: 33062306a36Sopenharmony_ci * Integer 0 - Value for the PM1A SLP_TYP register 33162306a36Sopenharmony_ci * Integer 1 - Value for the PM1A SLP_TYP register 33262306a36Sopenharmony_ci * 33362306a36Sopenharmony_ci ******************************************************************************/ 33462306a36Sopenharmony_ciacpi_status 33562306a36Sopenharmony_ciacpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci acpi_status status; 33862306a36Sopenharmony_ci struct acpi_evaluate_info *info; 33962306a36Sopenharmony_ci union acpi_operand_object **elements; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Validate parameters */ 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) { 34662306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Allocate the evaluation information block */ 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); 35262306a36Sopenharmony_ci if (!info) { 35362306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* 35762306a36Sopenharmony_ci * Evaluate the \_Sx namespace object containing the register values 35862306a36Sopenharmony_ci * for this state 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci info->relative_pathname = acpi_gbl_sleep_state_names[sleep_state]; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci status = acpi_ns_evaluate(info); 36362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 36462306a36Sopenharmony_ci if (status == AE_NOT_FOUND) { 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* The _Sx states are optional, ignore NOT_FOUND */ 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci goto final_cleanup; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci goto warning_cleanup; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* Must have a return object */ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!info->return_object) { 37762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]", 37862306a36Sopenharmony_ci info->relative_pathname)); 37962306a36Sopenharmony_ci status = AE_AML_NO_RETURN_VALUE; 38062306a36Sopenharmony_ci goto warning_cleanup; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Return object must be of type Package */ 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (info->return_object->common.type != ACPI_TYPE_PACKAGE) { 38662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 38762306a36Sopenharmony_ci "Sleep State return object is not a Package")); 38862306a36Sopenharmony_ci status = AE_AML_OPERAND_TYPE; 38962306a36Sopenharmony_ci goto return_value_cleanup; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* 39362306a36Sopenharmony_ci * Any warnings about the package length or the object types have 39462306a36Sopenharmony_ci * already been issued by the predefined name module -- there is no 39562306a36Sopenharmony_ci * need to repeat them here. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_ci elements = info->return_object->package.elements; 39862306a36Sopenharmony_ci switch (info->return_object->package.count) { 39962306a36Sopenharmony_ci case 0: 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci status = AE_AML_PACKAGE_LIMIT; 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci case 1: 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (elements[0]->common.type != ACPI_TYPE_INTEGER) { 40762306a36Sopenharmony_ci status = AE_AML_OPERAND_TYPE; 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* A valid _Sx_ package with one integer */ 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci *sleep_type_a = (u8)elements[0]->integer.value; 41462306a36Sopenharmony_ci *sleep_type_b = (u8)(elements[0]->integer.value >> 8); 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci case 2: 41862306a36Sopenharmony_ci default: 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if ((elements[0]->common.type != ACPI_TYPE_INTEGER) || 42162306a36Sopenharmony_ci (elements[1]->common.type != ACPI_TYPE_INTEGER)) { 42262306a36Sopenharmony_ci status = AE_AML_OPERAND_TYPE; 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* A valid _Sx_ package with two integers */ 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci *sleep_type_a = (u8)elements[0]->integer.value; 42962306a36Sopenharmony_ci *sleep_type_b = (u8)elements[1]->integer.value; 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cireturn_value_cleanup: 43462306a36Sopenharmony_ci acpi_ut_remove_reference(info->return_object); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ciwarning_cleanup: 43762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 43862306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 43962306a36Sopenharmony_ci "While evaluating Sleep State [%s]", 44062306a36Sopenharmony_ci info->relative_pathname)); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cifinal_cleanup: 44462306a36Sopenharmony_ci ACPI_FREE(info); 44562306a36Sopenharmony_ci return_ACPI_STATUS(status); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data) 449