195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 295b482a8SLen Brown /******************************************************************************* 395b482a8SLen Brown * 495b482a8SLen Brown * Module Name: rsmisc - Miscellaneous resource descriptors 595b482a8SLen Brown * 695b482a8SLen Brown ******************************************************************************/ 795b482a8SLen Brown 895b482a8SLen Brown #include <acpi/acpi.h> 9e2f7a777SLen Brown #include "accommon.h" 10e2f7a777SLen Brown #include "acresrc.h" 1195b482a8SLen Brown 1295b482a8SLen Brown #define _COMPONENT ACPI_RESOURCES 1395b482a8SLen Brown ACPI_MODULE_NAME("rsmisc") 1495b482a8SLen Brown #define INIT_RESOURCE_TYPE(i) i->resource_offset 1595b482a8SLen Brown #define INIT_RESOURCE_LENGTH(i) i->aml_offset 1695b482a8SLen Brown #define INIT_TABLE_LENGTH(i) i->value 1795b482a8SLen Brown #define COMPARE_OPCODE(i) i->resource_offset 1895b482a8SLen Brown #define COMPARE_TARGET(i) i->aml_offset 1995b482a8SLen Brown #define COMPARE_VALUE(i) i->value 2095b482a8SLen Brown /******************************************************************************* 2195b482a8SLen Brown * 2295b482a8SLen Brown * FUNCTION: acpi_rs_convert_aml_to_resource 2395b482a8SLen Brown * 24ba494beeSBob Moore * PARAMETERS: resource - Pointer to the resource descriptor 25ba494beeSBob Moore * aml - Where the AML descriptor is returned 26ba494beeSBob Moore * info - Pointer to appropriate conversion table 2795b482a8SLen Brown * 2895b482a8SLen Brown * RETURN: Status 2995b482a8SLen Brown * 3095b482a8SLen Brown * DESCRIPTION: Convert an external AML resource descriptor to the corresponding 3195b482a8SLen Brown * internal resource descriptor 3295b482a8SLen Brown * 3395b482a8SLen Brown ******************************************************************************/ 3495b482a8SLen Brown acpi_status 3595b482a8SLen Brown acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, 3695b482a8SLen Brown union aml_resource *aml, 3795b482a8SLen Brown struct acpi_rsconvert_info *info) 3895b482a8SLen Brown { 3995b482a8SLen Brown acpi_rs_length aml_resource_length; 4095b482a8SLen Brown void *source; 4195b482a8SLen Brown void *destination; 4295b482a8SLen Brown char *target; 4395b482a8SLen Brown u8 count; 4495b482a8SLen Brown u8 flags_mode = FALSE; 4595b482a8SLen Brown u16 item_count = 0; 4695b482a8SLen Brown u16 temp16 = 0; 4795b482a8SLen Brown 4895b482a8SLen Brown ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource); 4995b482a8SLen Brown 50e0fe0a8dSLin Ming if (!info) { 51e0fe0a8dSLin Ming return_ACPI_STATUS(AE_BAD_PARAMETER); 52e0fe0a8dSLin Ming } 53e0fe0a8dSLin Ming 5495b482a8SLen Brown if (((acpi_size)resource) & 0x3) { 5595b482a8SLen Brown 5695b482a8SLen Brown /* Each internal resource struct is expected to be 32-bit aligned */ 5795b482a8SLen Brown 5895b482a8SLen Brown ACPI_WARNING((AE_INFO, 59f6a22b0bSBob Moore "Misaligned resource pointer (get): %p Type 0x%2.2X Length %u", 6095b482a8SLen Brown resource, resource->type, resource->length)); 6195b482a8SLen Brown } 6295b482a8SLen Brown 6395b482a8SLen Brown /* Extract the resource Length field (does not include header length) */ 6495b482a8SLen Brown 6595b482a8SLen Brown aml_resource_length = acpi_ut_get_resource_length(aml); 6695b482a8SLen Brown 6795b482a8SLen Brown /* 6895b482a8SLen Brown * First table entry must be ACPI_RSC_INITxxx and must contain the 6995b482a8SLen Brown * table length (# of table entries) 7095b482a8SLen Brown */ 7195b482a8SLen Brown count = INIT_TABLE_LENGTH(info); 7295b482a8SLen Brown while (count) { 73a2befbb2SBob Moore target = NULL; 74a2befbb2SBob Moore 7595b482a8SLen Brown /* 7695b482a8SLen Brown * Source is the external AML byte stream buffer, 7795b482a8SLen Brown * destination is the internal resource descriptor 7895b482a8SLen Brown */ 7995b482a8SLen Brown source = ACPI_ADD_PTR(void, aml, info->aml_offset); 8095b482a8SLen Brown destination = 8195b482a8SLen Brown ACPI_ADD_PTR(void, resource, info->resource_offset); 8295b482a8SLen Brown 8395b482a8SLen Brown switch (info->opcode) { 8495b482a8SLen Brown case ACPI_RSC_INITGET: 8595b482a8SLen Brown /* 8695b482a8SLen Brown * Get the resource type and the initial (minimum) length 8795b482a8SLen Brown */ 884fa4616eSBob Moore memset(resource, 0, INIT_RESOURCE_LENGTH(info)); 8995b482a8SLen Brown resource->type = INIT_RESOURCE_TYPE(info); 9095b482a8SLen Brown resource->length = INIT_RESOURCE_LENGTH(info); 9195b482a8SLen Brown break; 9295b482a8SLen Brown 9395b482a8SLen Brown case ACPI_RSC_INITSET: 9495b482a8SLen Brown break; 9595b482a8SLen Brown 9695b482a8SLen Brown case ACPI_RSC_FLAGINIT: 9795b482a8SLen Brown 9895b482a8SLen Brown flags_mode = TRUE; 9995b482a8SLen Brown break; 10095b482a8SLen Brown 10195b482a8SLen Brown case ACPI_RSC_1BITFLAG: 10295b482a8SLen Brown /* 10395b482a8SLen Brown * Mask and shift the flag bit 10495b482a8SLen Brown */ 10557bf6aefSLv Zheng ACPI_SET8(destination, 10657bf6aefSLv Zheng ((ACPI_GET8(source) >> info->value) & 0x01)); 10795b482a8SLen Brown break; 10895b482a8SLen Brown 10995b482a8SLen Brown case ACPI_RSC_2BITFLAG: 11095b482a8SLen Brown /* 11195b482a8SLen Brown * Mask and shift the flag bits 11295b482a8SLen Brown */ 11357bf6aefSLv Zheng ACPI_SET8(destination, 11457bf6aefSLv Zheng ((ACPI_GET8(source) >> info->value) & 0x03)); 11595b482a8SLen Brown break; 11695b482a8SLen Brown 117e0fe0a8dSLin Ming case ACPI_RSC_3BITFLAG: 118e0fe0a8dSLin Ming /* 119e0fe0a8dSLin Ming * Mask and shift the flag bits 120e0fe0a8dSLin Ming */ 12157bf6aefSLv Zheng ACPI_SET8(destination, 12257bf6aefSLv Zheng ((ACPI_GET8(source) >> info->value) & 0x07)); 123e0fe0a8dSLin Ming break; 124e0fe0a8dSLin Ming 125a2befbb2SBob Moore case ACPI_RSC_6BITFLAG: 126a2befbb2SBob Moore /* 127a2befbb2SBob Moore * Mask and shift the flag bits 128a2befbb2SBob Moore */ 129a2befbb2SBob Moore ACPI_SET8(destination, 130a2befbb2SBob Moore ((ACPI_GET8(source) >> info->value) & 0x3F)); 131a2befbb2SBob Moore break; 132a2befbb2SBob Moore 13395b482a8SLen Brown case ACPI_RSC_COUNT: 13495b482a8SLen Brown 13595b482a8SLen Brown item_count = ACPI_GET8(source); 13657bf6aefSLv Zheng ACPI_SET8(destination, item_count); 13795b482a8SLen Brown 13895b482a8SLen Brown resource->length = resource->length + 13995b482a8SLen Brown (info->value * (item_count - 1)); 14095b482a8SLen Brown break; 14195b482a8SLen Brown 14295b482a8SLen Brown case ACPI_RSC_COUNT16: 14395b482a8SLen Brown 14495b482a8SLen Brown item_count = aml_resource_length; 14557bf6aefSLv Zheng ACPI_SET16(destination, item_count); 14695b482a8SLen Brown 14795b482a8SLen Brown resource->length = resource->length + 14895b482a8SLen Brown (info->value * (item_count - 1)); 14995b482a8SLen Brown break; 15095b482a8SLen Brown 151e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_PIN: 152e0fe0a8dSLin Ming 153e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, info->value); 154e0fe0a8dSLin Ming item_count = ACPI_GET16(target) - ACPI_GET16(source); 155e0fe0a8dSLin Ming 156e0fe0a8dSLin Ming resource->length = resource->length + item_count; 157e0fe0a8dSLin Ming item_count = item_count / 2; 15857bf6aefSLv Zheng ACPI_SET16(destination, item_count); 159e0fe0a8dSLin Ming break; 160e0fe0a8dSLin Ming 161e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_VEN: 162e0fe0a8dSLin Ming 163e0fe0a8dSLin Ming item_count = ACPI_GET8(source); 16457bf6aefSLv Zheng ACPI_SET8(destination, item_count); 165e0fe0a8dSLin Ming 1661fad8738SBob Moore resource->length = 1671fad8738SBob Moore resource->length + (info->value * item_count); 168e0fe0a8dSLin Ming break; 169e0fe0a8dSLin Ming 170e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_RES: 171e0fe0a8dSLin Ming /* 172e0fe0a8dSLin Ming * Vendor data is optional (length/offset may both be zero) 173e0fe0a8dSLin Ming * Examine vendor data length field first 174e0fe0a8dSLin Ming */ 175e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, (info->value + 2)); 176e0fe0a8dSLin Ming if (ACPI_GET16(target)) { 177e0fe0a8dSLin Ming 178e0fe0a8dSLin Ming /* Use vendor offset to get resource source length */ 179e0fe0a8dSLin Ming 180e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, info->value); 181e0fe0a8dSLin Ming item_count = 182e0fe0a8dSLin Ming ACPI_GET16(target) - ACPI_GET16(source); 183e0fe0a8dSLin Ming } else { 184e0fe0a8dSLin Ming /* No vendor data to worry about */ 185e0fe0a8dSLin Ming 186e0fe0a8dSLin Ming item_count = aml->large_header.resource_length + 187e0fe0a8dSLin Ming sizeof(struct aml_resource_large_header) - 188e0fe0a8dSLin Ming ACPI_GET16(source); 189e0fe0a8dSLin Ming } 190e0fe0a8dSLin Ming 191e0fe0a8dSLin Ming resource->length = resource->length + item_count; 19257bf6aefSLv Zheng ACPI_SET16(destination, item_count); 193e0fe0a8dSLin Ming break; 194e0fe0a8dSLin Ming 195e0fe0a8dSLin Ming case ACPI_RSC_COUNT_SERIAL_VEN: 196e0fe0a8dSLin Ming 197*d0a874cbSTamir Duberstein ACPI_MOVE_16_TO_16(&temp16, source); 198*d0a874cbSTamir Duberstein item_count = temp16 - info->value; 199e0fe0a8dSLin Ming 200e0fe0a8dSLin Ming resource->length = resource->length + item_count; 20157bf6aefSLv Zheng ACPI_SET16(destination, item_count); 202e0fe0a8dSLin Ming break; 203e0fe0a8dSLin Ming 204e0fe0a8dSLin Ming case ACPI_RSC_COUNT_SERIAL_RES: 205e0fe0a8dSLin Ming 206*d0a874cbSTamir Duberstein ACPI_MOVE_16_TO_16(&temp16, source); 207e0fe0a8dSLin Ming item_count = (aml_resource_length + 208e0fe0a8dSLin Ming sizeof(struct aml_resource_large_header)) 209*d0a874cbSTamir Duberstein - temp16 - info->value; 210e0fe0a8dSLin Ming 211e0fe0a8dSLin Ming resource->length = resource->length + item_count; 21257bf6aefSLv Zheng ACPI_SET16(destination, item_count); 213e0fe0a8dSLin Ming break; 214e0fe0a8dSLin Ming 21595b482a8SLen Brown case ACPI_RSC_LENGTH: 21695b482a8SLen Brown 21795b482a8SLen Brown resource->length = resource->length + info->value; 21895b482a8SLen Brown break; 21995b482a8SLen Brown 22095b482a8SLen Brown case ACPI_RSC_MOVE8: 22195b482a8SLen Brown case ACPI_RSC_MOVE16: 22295b482a8SLen Brown case ACPI_RSC_MOVE32: 22395b482a8SLen Brown case ACPI_RSC_MOVE64: 22495b482a8SLen Brown /* 22595b482a8SLen Brown * Raw data move. Use the Info value field unless item_count has 22695b482a8SLen Brown * been previously initialized via a COUNT opcode 22795b482a8SLen Brown */ 22895b482a8SLen Brown if (info->value) { 22995b482a8SLen Brown item_count = info->value; 23095b482a8SLen Brown } 23195b482a8SLen Brown acpi_rs_move_data(destination, source, item_count, 23295b482a8SLen Brown info->opcode); 23395b482a8SLen Brown break; 23495b482a8SLen Brown 235e0fe0a8dSLin Ming case ACPI_RSC_MOVE_GPIO_PIN: 236e0fe0a8dSLin Ming 237e0fe0a8dSLin Ming /* Generate and set the PIN data pointer */ 238e0fe0a8dSLin Ming 239e0fe0a8dSLin Ming target = (char *)ACPI_ADD_PTR(void, resource, 240e0fe0a8dSLin Ming (resource->length - 241e0fe0a8dSLin Ming item_count * 2)); 242e0fe0a8dSLin Ming *(u16 **)destination = ACPI_CAST_PTR(u16, target); 243e0fe0a8dSLin Ming 244e0fe0a8dSLin Ming /* Copy the PIN data */ 245e0fe0a8dSLin Ming 246e0fe0a8dSLin Ming source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); 247e0fe0a8dSLin Ming acpi_rs_move_data(target, source, item_count, 248e0fe0a8dSLin Ming info->opcode); 249e0fe0a8dSLin Ming break; 250e0fe0a8dSLin Ming 251e0fe0a8dSLin Ming case ACPI_RSC_MOVE_GPIO_RES: 252e0fe0a8dSLin Ming 253e0fe0a8dSLin Ming /* Generate and set the resource_source string pointer */ 254e0fe0a8dSLin Ming 255e0fe0a8dSLin Ming target = (char *)ACPI_ADD_PTR(void, resource, 256e0fe0a8dSLin Ming (resource->length - 257e0fe0a8dSLin Ming item_count)); 258e0fe0a8dSLin Ming *(u8 **)destination = ACPI_CAST_PTR(u8, target); 259e0fe0a8dSLin Ming 260e0fe0a8dSLin Ming /* Copy the resource_source string */ 261e0fe0a8dSLin Ming 262e0fe0a8dSLin Ming source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); 263e0fe0a8dSLin Ming acpi_rs_move_data(target, source, item_count, 264e0fe0a8dSLin Ming info->opcode); 265e0fe0a8dSLin Ming break; 266e0fe0a8dSLin Ming 267e0fe0a8dSLin Ming case ACPI_RSC_MOVE_SERIAL_VEN: 268e0fe0a8dSLin Ming 269e0fe0a8dSLin Ming /* Generate and set the Vendor Data pointer */ 270e0fe0a8dSLin Ming 271e0fe0a8dSLin Ming target = (char *)ACPI_ADD_PTR(void, resource, 272e0fe0a8dSLin Ming (resource->length - 273e0fe0a8dSLin Ming item_count)); 274e0fe0a8dSLin Ming *(u8 **)destination = ACPI_CAST_PTR(u8, target); 275e0fe0a8dSLin Ming 276e0fe0a8dSLin Ming /* Copy the Vendor Data */ 277e0fe0a8dSLin Ming 278e0fe0a8dSLin Ming source = ACPI_ADD_PTR(void, aml, info->value); 279e0fe0a8dSLin Ming acpi_rs_move_data(target, source, item_count, 280e0fe0a8dSLin Ming info->opcode); 281e0fe0a8dSLin Ming break; 282e0fe0a8dSLin Ming 283e0fe0a8dSLin Ming case ACPI_RSC_MOVE_SERIAL_RES: 284e0fe0a8dSLin Ming 285e0fe0a8dSLin Ming /* Generate and set the resource_source string pointer */ 286e0fe0a8dSLin Ming 287e0fe0a8dSLin Ming target = (char *)ACPI_ADD_PTR(void, resource, 288e0fe0a8dSLin Ming (resource->length - 289e0fe0a8dSLin Ming item_count)); 290e0fe0a8dSLin Ming *(u8 **)destination = ACPI_CAST_PTR(u8, target); 291e0fe0a8dSLin Ming 292e0fe0a8dSLin Ming /* Copy the resource_source string */ 293e0fe0a8dSLin Ming 294*d0a874cbSTamir Duberstein ACPI_MOVE_16_TO_16(&temp16, source); 295e0fe0a8dSLin Ming source = 296*d0a874cbSTamir Duberstein ACPI_ADD_PTR(void, aml, (temp16 + info->value)); 297e0fe0a8dSLin Ming acpi_rs_move_data(target, source, item_count, 298e0fe0a8dSLin Ming info->opcode); 299e0fe0a8dSLin Ming break; 300e0fe0a8dSLin Ming 30195b482a8SLen Brown case ACPI_RSC_SET8: 30295b482a8SLen Brown 3034fa4616eSBob Moore memset(destination, info->aml_offset, info->value); 30495b482a8SLen Brown break; 30595b482a8SLen Brown 30695b482a8SLen Brown case ACPI_RSC_DATA8: 30795b482a8SLen Brown 30895b482a8SLen Brown target = ACPI_ADD_PTR(char, resource, info->value); 3094fa4616eSBob Moore memcpy(destination, source, ACPI_GET16(target)); 31095b482a8SLen Brown break; 31195b482a8SLen Brown 31295b482a8SLen Brown case ACPI_RSC_ADDRESS: 31395b482a8SLen Brown /* 31495b482a8SLen Brown * Common handler for address descriptor flags 31595b482a8SLen Brown */ 31695b482a8SLen Brown if (!acpi_rs_get_address_common(resource, aml)) { 31795b482a8SLen Brown return_ACPI_STATUS 31895b482a8SLen Brown (AE_AML_INVALID_RESOURCE_TYPE); 31995b482a8SLen Brown } 32095b482a8SLen Brown break; 32195b482a8SLen Brown 32295b482a8SLen Brown case ACPI_RSC_SOURCE: 32395b482a8SLen Brown /* 32495b482a8SLen Brown * Optional resource_source (Index and String) 32595b482a8SLen Brown */ 32695b482a8SLen Brown resource->length += 32795b482a8SLen Brown acpi_rs_get_resource_source(aml_resource_length, 32895b482a8SLen Brown info->value, 32995b482a8SLen Brown destination, aml, NULL); 33095b482a8SLen Brown break; 33195b482a8SLen Brown 33295b482a8SLen Brown case ACPI_RSC_SOURCEX: 33395b482a8SLen Brown /* 33495b482a8SLen Brown * Optional resource_source (Index and String). This is the more 33595b482a8SLen Brown * complicated case used by the Interrupt() macro 33695b482a8SLen Brown */ 337e0fe0a8dSLin Ming target = ACPI_ADD_PTR(char, resource, 338e0fe0a8dSLin Ming info->aml_offset + 339e0fe0a8dSLin Ming (item_count * 4)); 34095b482a8SLen Brown 34195b482a8SLen Brown resource->length += 34295b482a8SLen Brown acpi_rs_get_resource_source(aml_resource_length, 343e0fe0a8dSLin Ming (acpi_rs_length) 344e0fe0a8dSLin Ming (((item_count - 345e0fe0a8dSLin Ming 1) * sizeof(u32)) + 346e0fe0a8dSLin Ming info->value), 347e0fe0a8dSLin Ming destination, aml, 348e0fe0a8dSLin Ming target); 34995b482a8SLen Brown break; 35095b482a8SLen Brown 35195b482a8SLen Brown case ACPI_RSC_BITMASK: 35295b482a8SLen Brown /* 35395b482a8SLen Brown * 8-bit encoded bitmask (DMA macro) 35495b482a8SLen Brown */ 35595b482a8SLen Brown item_count = 35695b482a8SLen Brown acpi_rs_decode_bitmask(ACPI_GET8(source), 35795b482a8SLen Brown destination); 35895b482a8SLen Brown if (item_count) { 35995b482a8SLen Brown resource->length += (item_count - 1); 36095b482a8SLen Brown } 36195b482a8SLen Brown 36295b482a8SLen Brown target = ACPI_ADD_PTR(char, resource, info->value); 36357bf6aefSLv Zheng ACPI_SET8(target, item_count); 36495b482a8SLen Brown break; 36595b482a8SLen Brown 36695b482a8SLen Brown case ACPI_RSC_BITMASK16: 36795b482a8SLen Brown /* 36895b482a8SLen Brown * 16-bit encoded bitmask (IRQ macro) 36995b482a8SLen Brown */ 37095b482a8SLen Brown ACPI_MOVE_16_TO_16(&temp16, source); 37195b482a8SLen Brown 37295b482a8SLen Brown item_count = 37395b482a8SLen Brown acpi_rs_decode_bitmask(temp16, destination); 37495b482a8SLen Brown if (item_count) { 37595b482a8SLen Brown resource->length += (item_count - 1); 37695b482a8SLen Brown } 37795b482a8SLen Brown 37895b482a8SLen Brown target = ACPI_ADD_PTR(char, resource, info->value); 37957bf6aefSLv Zheng ACPI_SET8(target, item_count); 38095b482a8SLen Brown break; 38195b482a8SLen Brown 38295b482a8SLen Brown case ACPI_RSC_EXIT_NE: 38395b482a8SLen Brown /* 384ba494beeSBob Moore * control - Exit conversion if not equal 38595b482a8SLen Brown */ 38695b482a8SLen Brown switch (info->resource_offset) { 38795b482a8SLen Brown case ACPI_RSC_COMPARE_AML_LENGTH: 3881d1ea1b7SChao Guan 38995b482a8SLen Brown if (aml_resource_length != info->value) { 39095b482a8SLen Brown goto exit; 39195b482a8SLen Brown } 39295b482a8SLen Brown break; 39395b482a8SLen Brown 39495b482a8SLen Brown case ACPI_RSC_COMPARE_VALUE: 3951d1ea1b7SChao Guan 39695b482a8SLen Brown if (ACPI_GET8(source) != info->value) { 39795b482a8SLen Brown goto exit; 39895b482a8SLen Brown } 39995b482a8SLen Brown break; 40095b482a8SLen Brown 40195b482a8SLen Brown default: 40295b482a8SLen Brown 40395b482a8SLen Brown ACPI_ERROR((AE_INFO, 40495b482a8SLen Brown "Invalid conversion sub-opcode")); 40595b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 40695b482a8SLen Brown } 40795b482a8SLen Brown break; 40895b482a8SLen Brown 40995b482a8SLen Brown default: 41095b482a8SLen Brown 41195b482a8SLen Brown ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); 41295b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 41395b482a8SLen Brown } 41495b482a8SLen Brown 41595b482a8SLen Brown count--; 41695b482a8SLen Brown info++; 41795b482a8SLen Brown } 41895b482a8SLen Brown 41995b482a8SLen Brown exit: 42095b482a8SLen Brown if (!flags_mode) { 42195b482a8SLen Brown 42295b482a8SLen Brown /* Round the resource struct length up to the next boundary (32 or 64) */ 42395b482a8SLen Brown 4241fad8738SBob Moore resource->length = (u32) 4251fad8738SBob Moore ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); 42695b482a8SLen Brown } 42795b482a8SLen Brown return_ACPI_STATUS(AE_OK); 42895b482a8SLen Brown } 42995b482a8SLen Brown 43095b482a8SLen Brown /******************************************************************************* 43195b482a8SLen Brown * 43295b482a8SLen Brown * FUNCTION: acpi_rs_convert_resource_to_aml 43395b482a8SLen Brown * 434ba494beeSBob Moore * PARAMETERS: resource - Pointer to the resource descriptor 435ba494beeSBob Moore * aml - Where the AML descriptor is returned 436ba494beeSBob Moore * info - Pointer to appropriate conversion table 43795b482a8SLen Brown * 43895b482a8SLen Brown * RETURN: Status 43995b482a8SLen Brown * 44095b482a8SLen Brown * DESCRIPTION: Convert an internal resource descriptor to the corresponding 44195b482a8SLen Brown * external AML resource descriptor. 44295b482a8SLen Brown * 44395b482a8SLen Brown ******************************************************************************/ 44495b482a8SLen Brown 44595b482a8SLen Brown acpi_status 44695b482a8SLen Brown acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, 44795b482a8SLen Brown union aml_resource *aml, 44895b482a8SLen Brown struct acpi_rsconvert_info *info) 44995b482a8SLen Brown { 45095b482a8SLen Brown void *source = NULL; 45195b482a8SLen Brown void *destination; 452e0fe0a8dSLin Ming char *target; 45395b482a8SLen Brown acpi_rsdesc_size aml_length = 0; 45495b482a8SLen Brown u8 count; 45595b482a8SLen Brown u16 temp16 = 0; 45695b482a8SLen Brown u16 item_count = 0; 45795b482a8SLen Brown 45895b482a8SLen Brown ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml); 45995b482a8SLen Brown 460e0fe0a8dSLin Ming if (!info) { 461e0fe0a8dSLin Ming return_ACPI_STATUS(AE_BAD_PARAMETER); 462e0fe0a8dSLin Ming } 463e0fe0a8dSLin Ming 46495b482a8SLen Brown /* 46595b482a8SLen Brown * First table entry must be ACPI_RSC_INITxxx and must contain the 46695b482a8SLen Brown * table length (# of table entries) 46795b482a8SLen Brown */ 46895b482a8SLen Brown count = INIT_TABLE_LENGTH(info); 46995b482a8SLen Brown 47095b482a8SLen Brown while (count) { 47195b482a8SLen Brown /* 47295b482a8SLen Brown * Source is the internal resource descriptor, 47395b482a8SLen Brown * destination is the external AML byte stream buffer 47495b482a8SLen Brown */ 47595b482a8SLen Brown source = ACPI_ADD_PTR(void, resource, info->resource_offset); 47695b482a8SLen Brown destination = ACPI_ADD_PTR(void, aml, info->aml_offset); 47795b482a8SLen Brown 47895b482a8SLen Brown switch (info->opcode) { 47995b482a8SLen Brown case ACPI_RSC_INITSET: 48095b482a8SLen Brown 4814fa4616eSBob Moore memset(aml, 0, INIT_RESOURCE_LENGTH(info)); 48295b482a8SLen Brown aml_length = INIT_RESOURCE_LENGTH(info); 48395b482a8SLen Brown acpi_rs_set_resource_header(INIT_RESOURCE_TYPE(info), 48495b482a8SLen Brown aml_length, aml); 48595b482a8SLen Brown break; 48695b482a8SLen Brown 48795b482a8SLen Brown case ACPI_RSC_INITGET: 48895b482a8SLen Brown break; 48995b482a8SLen Brown 49095b482a8SLen Brown case ACPI_RSC_FLAGINIT: 49195b482a8SLen Brown /* 49295b482a8SLen Brown * Clear the flag byte 49395b482a8SLen Brown */ 49457bf6aefSLv Zheng ACPI_SET8(destination, 0); 49595b482a8SLen Brown break; 49695b482a8SLen Brown 49795b482a8SLen Brown case ACPI_RSC_1BITFLAG: 49895b482a8SLen Brown /* 49995b482a8SLen Brown * Mask and shift the flag bit 50095b482a8SLen Brown */ 50157bf6aefSLv Zheng ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) 50257bf6aefSLv Zheng ((ACPI_GET8(source) & 0x01) << info-> 50357bf6aefSLv Zheng value)); 50495b482a8SLen Brown break; 50595b482a8SLen Brown 50695b482a8SLen Brown case ACPI_RSC_2BITFLAG: 50795b482a8SLen Brown /* 50895b482a8SLen Brown * Mask and shift the flag bits 50995b482a8SLen Brown */ 51057bf6aefSLv Zheng ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) 51157bf6aefSLv Zheng ((ACPI_GET8(source) & 0x03) << info-> 51257bf6aefSLv Zheng value)); 51395b482a8SLen Brown break; 51495b482a8SLen Brown 515e0fe0a8dSLin Ming case ACPI_RSC_3BITFLAG: 516e0fe0a8dSLin Ming /* 517e0fe0a8dSLin Ming * Mask and shift the flag bits 518e0fe0a8dSLin Ming */ 51957bf6aefSLv Zheng ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) 52057bf6aefSLv Zheng ((ACPI_GET8(source) & 0x07) << info-> 52157bf6aefSLv Zheng value)); 522e0fe0a8dSLin Ming break; 523e0fe0a8dSLin Ming 524a2befbb2SBob Moore case ACPI_RSC_6BITFLAG: 525a2befbb2SBob Moore /* 526a2befbb2SBob Moore * Mask and shift the flag bits 527a2befbb2SBob Moore */ 528a2befbb2SBob Moore ACPI_SET_BIT(*ACPI_CAST8(destination), (u8) 529a2befbb2SBob Moore ((ACPI_GET8(source) & 0x3F) << info-> 530a2befbb2SBob Moore value)); 531a2befbb2SBob Moore break; 532a2befbb2SBob Moore 53395b482a8SLen Brown case ACPI_RSC_COUNT: 53495b482a8SLen Brown 53595b482a8SLen Brown item_count = ACPI_GET8(source); 53657bf6aefSLv Zheng ACPI_SET8(destination, item_count); 53795b482a8SLen Brown 5381fad8738SBob Moore aml_length = (u16) 5391fad8738SBob Moore (aml_length + (info->value * (item_count - 1))); 54095b482a8SLen Brown break; 54195b482a8SLen Brown 54295b482a8SLen Brown case ACPI_RSC_COUNT16: 54395b482a8SLen Brown 54495b482a8SLen Brown item_count = ACPI_GET16(source); 54595b482a8SLen Brown aml_length = (u16) (aml_length + item_count); 54695b482a8SLen Brown acpi_rs_set_resource_length(aml_length, aml); 54795b482a8SLen Brown break; 54895b482a8SLen Brown 549e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_PIN: 550e0fe0a8dSLin Ming 551e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 55257bf6aefSLv Zheng ACPI_SET16(destination, aml_length); 553e0fe0a8dSLin Ming 554e0fe0a8dSLin Ming aml_length = (u16)(aml_length + item_count * 2); 555e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, info->value); 55657bf6aefSLv Zheng ACPI_SET16(target, aml_length); 557e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 558e0fe0a8dSLin Ming break; 559e0fe0a8dSLin Ming 560e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_VEN: 561e0fe0a8dSLin Ming 562e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 56357bf6aefSLv Zheng ACPI_SET16(destination, item_count); 564e0fe0a8dSLin Ming 565e0fe0a8dSLin Ming aml_length = 566e0fe0a8dSLin Ming (u16)(aml_length + (info->value * item_count)); 567e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 568e0fe0a8dSLin Ming break; 569e0fe0a8dSLin Ming 570e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_RES: 571e0fe0a8dSLin Ming 572e0fe0a8dSLin Ming /* Set resource source string length */ 573e0fe0a8dSLin Ming 574e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 57557bf6aefSLv Zheng ACPI_SET16(destination, aml_length); 576e0fe0a8dSLin Ming 577e0fe0a8dSLin Ming /* Compute offset for the Vendor Data */ 578e0fe0a8dSLin Ming 579e0fe0a8dSLin Ming aml_length = (u16)(aml_length + item_count); 580e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, info->value); 581e0fe0a8dSLin Ming 582e0fe0a8dSLin Ming /* Set vendor offset only if there is vendor data */ 583e0fe0a8dSLin Ming 58457bf6aefSLv Zheng ACPI_SET16(target, aml_length); 585e0fe0a8dSLin Ming 586e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 587e0fe0a8dSLin Ming break; 588e0fe0a8dSLin Ming 589e0fe0a8dSLin Ming case ACPI_RSC_COUNT_SERIAL_VEN: 590e0fe0a8dSLin Ming 591e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 59257bf6aefSLv Zheng ACPI_SET16(destination, item_count + info->value); 593e0fe0a8dSLin Ming aml_length = (u16)(aml_length + item_count); 594e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 595e0fe0a8dSLin Ming break; 596e0fe0a8dSLin Ming 597e0fe0a8dSLin Ming case ACPI_RSC_COUNT_SERIAL_RES: 598e0fe0a8dSLin Ming 599e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 600e0fe0a8dSLin Ming aml_length = (u16)(aml_length + item_count); 601e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 602e0fe0a8dSLin Ming break; 603e0fe0a8dSLin Ming 60495b482a8SLen Brown case ACPI_RSC_LENGTH: 60595b482a8SLen Brown 60695b482a8SLen Brown acpi_rs_set_resource_length(info->value, aml); 60795b482a8SLen Brown break; 60895b482a8SLen Brown 60995b482a8SLen Brown case ACPI_RSC_MOVE8: 61095b482a8SLen Brown case ACPI_RSC_MOVE16: 61195b482a8SLen Brown case ACPI_RSC_MOVE32: 61295b482a8SLen Brown case ACPI_RSC_MOVE64: 61395b482a8SLen Brown 61495b482a8SLen Brown if (info->value) { 61595b482a8SLen Brown item_count = info->value; 61695b482a8SLen Brown } 61795b482a8SLen Brown acpi_rs_move_data(destination, source, item_count, 61895b482a8SLen Brown info->opcode); 61995b482a8SLen Brown break; 62095b482a8SLen Brown 621e0fe0a8dSLin Ming case ACPI_RSC_MOVE_GPIO_PIN: 622e0fe0a8dSLin Ming 623e0fe0a8dSLin Ming destination = (char *)ACPI_ADD_PTR(void, aml, 624e0fe0a8dSLin Ming ACPI_GET16 625e0fe0a8dSLin Ming (destination)); 626e0fe0a8dSLin Ming source = *(u16 **)source; 627e0fe0a8dSLin Ming acpi_rs_move_data(destination, source, item_count, 628e0fe0a8dSLin Ming info->opcode); 629e0fe0a8dSLin Ming break; 630e0fe0a8dSLin Ming 631e0fe0a8dSLin Ming case ACPI_RSC_MOVE_GPIO_RES: 632e0fe0a8dSLin Ming 633e0fe0a8dSLin Ming /* Used for both resource_source string and vendor_data */ 634e0fe0a8dSLin Ming 635e0fe0a8dSLin Ming destination = (char *)ACPI_ADD_PTR(void, aml, 636e0fe0a8dSLin Ming ACPI_GET16 637e0fe0a8dSLin Ming (destination)); 638e0fe0a8dSLin Ming source = *(u8 **)source; 639e0fe0a8dSLin Ming acpi_rs_move_data(destination, source, item_count, 640e0fe0a8dSLin Ming info->opcode); 641e0fe0a8dSLin Ming break; 642e0fe0a8dSLin Ming 643e0fe0a8dSLin Ming case ACPI_RSC_MOVE_SERIAL_VEN: 644e0fe0a8dSLin Ming 645e0fe0a8dSLin Ming destination = (char *)ACPI_ADD_PTR(void, aml, 646e0fe0a8dSLin Ming (aml_length - 647e0fe0a8dSLin Ming item_count)); 648e0fe0a8dSLin Ming source = *(u8 **)source; 649e0fe0a8dSLin Ming acpi_rs_move_data(destination, source, item_count, 650e0fe0a8dSLin Ming info->opcode); 651e0fe0a8dSLin Ming break; 652e0fe0a8dSLin Ming 653e0fe0a8dSLin Ming case ACPI_RSC_MOVE_SERIAL_RES: 654e0fe0a8dSLin Ming 655e0fe0a8dSLin Ming destination = (char *)ACPI_ADD_PTR(void, aml, 656e0fe0a8dSLin Ming (aml_length - 657e0fe0a8dSLin Ming item_count)); 658e0fe0a8dSLin Ming source = *(u8 **)source; 659e0fe0a8dSLin Ming acpi_rs_move_data(destination, source, item_count, 660e0fe0a8dSLin Ming info->opcode); 661e0fe0a8dSLin Ming break; 662e0fe0a8dSLin Ming 66395b482a8SLen Brown case ACPI_RSC_ADDRESS: 66495b482a8SLen Brown 66595b482a8SLen Brown /* Set the Resource Type, General Flags, and Type-Specific Flags */ 66695b482a8SLen Brown 66795b482a8SLen Brown acpi_rs_set_address_common(aml, resource); 66895b482a8SLen Brown break; 66995b482a8SLen Brown 67095b482a8SLen Brown case ACPI_RSC_SOURCEX: 67195b482a8SLen Brown /* 67295b482a8SLen Brown * Optional resource_source (Index and String) 67395b482a8SLen Brown */ 67495b482a8SLen Brown aml_length = 6753e8214e5SLv Zheng acpi_rs_set_resource_source(aml, 6763e8214e5SLv Zheng (acpi_rs_length) 67795b482a8SLen Brown aml_length, source); 67895b482a8SLen Brown acpi_rs_set_resource_length(aml_length, aml); 67995b482a8SLen Brown break; 68095b482a8SLen Brown 68195b482a8SLen Brown case ACPI_RSC_SOURCE: 68295b482a8SLen Brown /* 68395b482a8SLen Brown * Optional resource_source (Index and String). This is the more 68495b482a8SLen Brown * complicated case used by the Interrupt() macro 68595b482a8SLen Brown */ 68695b482a8SLen Brown aml_length = 68795b482a8SLen Brown acpi_rs_set_resource_source(aml, info->value, 68895b482a8SLen Brown source); 68995b482a8SLen Brown acpi_rs_set_resource_length(aml_length, aml); 69095b482a8SLen Brown break; 69195b482a8SLen Brown 69295b482a8SLen Brown case ACPI_RSC_BITMASK: 69395b482a8SLen Brown /* 69495b482a8SLen Brown * 8-bit encoded bitmask (DMA macro) 69595b482a8SLen Brown */ 69657bf6aefSLv Zheng ACPI_SET8(destination, 69795b482a8SLen Brown acpi_rs_encode_bitmask(source, 69857bf6aefSLv Zheng *ACPI_ADD_PTR(u8, 69957bf6aefSLv Zheng resource, 70057bf6aefSLv Zheng info-> 70157bf6aefSLv Zheng value))); 70295b482a8SLen Brown break; 70395b482a8SLen Brown 70495b482a8SLen Brown case ACPI_RSC_BITMASK16: 70595b482a8SLen Brown /* 70695b482a8SLen Brown * 16-bit encoded bitmask (IRQ macro) 70795b482a8SLen Brown */ 7081fad8738SBob Moore temp16 = 7091fad8738SBob Moore acpi_rs_encode_bitmask(source, 7101fad8738SBob Moore *ACPI_ADD_PTR(u8, resource, 7111fad8738SBob Moore info->value)); 71295b482a8SLen Brown ACPI_MOVE_16_TO_16(destination, &temp16); 71395b482a8SLen Brown break; 71495b482a8SLen Brown 71595b482a8SLen Brown case ACPI_RSC_EXIT_LE: 71695b482a8SLen Brown /* 717ba494beeSBob Moore * control - Exit conversion if less than or equal 71895b482a8SLen Brown */ 71995b482a8SLen Brown if (item_count <= info->value) { 72095b482a8SLen Brown goto exit; 72195b482a8SLen Brown } 72295b482a8SLen Brown break; 72395b482a8SLen Brown 72495b482a8SLen Brown case ACPI_RSC_EXIT_NE: 72595b482a8SLen Brown /* 726ba494beeSBob Moore * control - Exit conversion if not equal 72795b482a8SLen Brown */ 72895b482a8SLen Brown switch (COMPARE_OPCODE(info)) { 72995b482a8SLen Brown case ACPI_RSC_COMPARE_VALUE: 73095b482a8SLen Brown 73195b482a8SLen Brown if (*ACPI_ADD_PTR(u8, resource, 73295b482a8SLen Brown COMPARE_TARGET(info)) != 73395b482a8SLen Brown COMPARE_VALUE(info)) { 73495b482a8SLen Brown goto exit; 73595b482a8SLen Brown } 73695b482a8SLen Brown break; 73795b482a8SLen Brown 73895b482a8SLen Brown default: 73995b482a8SLen Brown 74095b482a8SLen Brown ACPI_ERROR((AE_INFO, 74195b482a8SLen Brown "Invalid conversion sub-opcode")); 74295b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 74395b482a8SLen Brown } 74495b482a8SLen Brown break; 74595b482a8SLen Brown 74695b482a8SLen Brown case ACPI_RSC_EXIT_EQ: 74795b482a8SLen Brown /* 748ba494beeSBob Moore * control - Exit conversion if equal 74995b482a8SLen Brown */ 75095b482a8SLen Brown if (*ACPI_ADD_PTR(u8, resource, 75195b482a8SLen Brown COMPARE_TARGET(info)) == 75295b482a8SLen Brown COMPARE_VALUE(info)) { 75395b482a8SLen Brown goto exit; 75495b482a8SLen Brown } 75595b482a8SLen Brown break; 75695b482a8SLen Brown 75795b482a8SLen Brown default: 75895b482a8SLen Brown 75995b482a8SLen Brown ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); 76095b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 76195b482a8SLen Brown } 76295b482a8SLen Brown 76395b482a8SLen Brown count--; 76495b482a8SLen Brown info++; 76595b482a8SLen Brown } 76695b482a8SLen Brown 76795b482a8SLen Brown exit: 76895b482a8SLen Brown return_ACPI_STATUS(AE_OK); 76995b482a8SLen Brown } 77095b482a8SLen Brown 77195b482a8SLen Brown #if 0 77295b482a8SLen Brown /* Previous resource validations */ 77395b482a8SLen Brown 774ba494beeSBob Moore if (aml->ext_address64.revision_ID != AML_RESOURCE_EXTENDED_ADDRESS_REVISION) { 77595b482a8SLen Brown return_ACPI_STATUS(AE_SUPPORT); 77695b482a8SLen Brown } 77795b482a8SLen Brown 77895b482a8SLen Brown if (resource->data.start_dpf.performance_robustness >= 3) { 77995b482a8SLen Brown return_ACPI_STATUS(AE_AML_BAD_RESOURCE_VALUE); 78095b482a8SLen Brown } 78195b482a8SLen Brown 78295b482a8SLen Brown if (((aml->irq.flags & 0x09) == 0x00) || ((aml->irq.flags & 0x09) == 0x09)) { 78395b482a8SLen Brown /* 78495b482a8SLen Brown * Only [active_high, edge_sensitive] or [active_low, level_sensitive] 78595b482a8SLen Brown * polarity/trigger interrupts are allowed (ACPI spec, section 78695b482a8SLen Brown * "IRQ Format"), so 0x00 and 0x09 are illegal. 78795b482a8SLen Brown */ 78895b482a8SLen Brown ACPI_ERROR((AE_INFO, 789f6a22b0bSBob Moore "Invalid interrupt polarity/trigger in resource list, 0x%X", 79095b482a8SLen Brown aml->irq.flags)); 79195b482a8SLen Brown return_ACPI_STATUS(AE_BAD_DATA); 79295b482a8SLen Brown } 79395b482a8SLen Brown 79495b482a8SLen Brown resource->data.extended_irq.interrupt_count = temp8; 79595b482a8SLen Brown if (temp8 < 1) { 79695b482a8SLen Brown 79795b482a8SLen Brown /* Must have at least one IRQ */ 79895b482a8SLen Brown 79995b482a8SLen Brown return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); 80095b482a8SLen Brown } 80195b482a8SLen Brown 80295b482a8SLen Brown if (resource->data.dma.transfer == 0x03) { 80395b482a8SLen Brown ACPI_ERROR((AE_INFO, "Invalid DMA.Transfer preference (3)")); 80495b482a8SLen Brown return_ACPI_STATUS(AE_BAD_DATA); 80595b482a8SLen Brown } 80695b482a8SLen Brown #endif 807