195b482a8SLen Brown /******************************************************************************* 295b482a8SLen Brown * 395b482a8SLen Brown * Module Name: rsmisc - Miscellaneous resource descriptors 495b482a8SLen Brown * 595b482a8SLen Brown ******************************************************************************/ 695b482a8SLen Brown 795b482a8SLen Brown /* 8b4e104eaSBob Moore * Copyright (C) 2000 - 2011, Intel Corp. 995b482a8SLen Brown * All rights reserved. 1095b482a8SLen Brown * 1195b482a8SLen Brown * Redistribution and use in source and binary forms, with or without 1295b482a8SLen Brown * modification, are permitted provided that the following conditions 1395b482a8SLen Brown * are met: 1495b482a8SLen Brown * 1. Redistributions of source code must retain the above copyright 1595b482a8SLen Brown * notice, this list of conditions, and the following disclaimer, 1695b482a8SLen Brown * without modification. 1795b482a8SLen Brown * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1895b482a8SLen Brown * substantially similar to the "NO WARRANTY" disclaimer below 1995b482a8SLen Brown * ("Disclaimer") and any redistribution must be conditioned upon 2095b482a8SLen Brown * including a substantially similar Disclaimer requirement for further 2195b482a8SLen Brown * binary redistribution. 2295b482a8SLen Brown * 3. Neither the names of the above-listed copyright holders nor the names 2395b482a8SLen Brown * of any contributors may be used to endorse or promote products derived 2495b482a8SLen Brown * from this software without specific prior written permission. 2595b482a8SLen Brown * 2695b482a8SLen Brown * Alternatively, this software may be distributed under the terms of the 2795b482a8SLen Brown * GNU General Public License ("GPL") version 2 as published by the Free 2895b482a8SLen Brown * Software Foundation. 2995b482a8SLen Brown * 3095b482a8SLen Brown * NO WARRANTY 3195b482a8SLen Brown * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3295b482a8SLen Brown * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3395b482a8SLen Brown * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3495b482a8SLen Brown * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3595b482a8SLen Brown * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3695b482a8SLen Brown * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3795b482a8SLen Brown * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3895b482a8SLen Brown * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3995b482a8SLen Brown * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4095b482a8SLen Brown * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4195b482a8SLen Brown * POSSIBILITY OF SUCH DAMAGES. 4295b482a8SLen Brown */ 4395b482a8SLen Brown 4495b482a8SLen Brown #include <acpi/acpi.h> 45e2f7a777SLen Brown #include "accommon.h" 46e2f7a777SLen Brown #include "acresrc.h" 4795b482a8SLen Brown 4895b482a8SLen Brown #define _COMPONENT ACPI_RESOURCES 4995b482a8SLen Brown ACPI_MODULE_NAME("rsmisc") 5095b482a8SLen Brown #define INIT_RESOURCE_TYPE(i) i->resource_offset 5195b482a8SLen Brown #define INIT_RESOURCE_LENGTH(i) i->aml_offset 5295b482a8SLen Brown #define INIT_TABLE_LENGTH(i) i->value 5395b482a8SLen Brown #define COMPARE_OPCODE(i) i->resource_offset 5495b482a8SLen Brown #define COMPARE_TARGET(i) i->aml_offset 5595b482a8SLen Brown #define COMPARE_VALUE(i) i->value 5695b482a8SLen Brown /******************************************************************************* 5795b482a8SLen Brown * 5895b482a8SLen Brown * FUNCTION: acpi_rs_convert_aml_to_resource 5995b482a8SLen Brown * 6095b482a8SLen Brown * PARAMETERS: Resource - Pointer to the resource descriptor 6195b482a8SLen Brown * Aml - Where the AML descriptor is returned 6295b482a8SLen Brown * Info - Pointer to appropriate conversion table 6395b482a8SLen Brown * 6495b482a8SLen Brown * RETURN: Status 6595b482a8SLen Brown * 6695b482a8SLen Brown * DESCRIPTION: Convert an external AML resource descriptor to the corresponding 6795b482a8SLen Brown * internal resource descriptor 6895b482a8SLen Brown * 6995b482a8SLen Brown ******************************************************************************/ 7095b482a8SLen Brown acpi_status 7195b482a8SLen Brown acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, 7295b482a8SLen Brown union aml_resource *aml, 7395b482a8SLen Brown struct acpi_rsconvert_info *info) 7495b482a8SLen Brown { 7595b482a8SLen Brown acpi_rs_length aml_resource_length; 7695b482a8SLen Brown void *source; 7795b482a8SLen Brown void *destination; 7895b482a8SLen Brown char *target; 7995b482a8SLen Brown u8 count; 8095b482a8SLen Brown u8 flags_mode = FALSE; 8195b482a8SLen Brown u16 item_count = 0; 8295b482a8SLen Brown u16 temp16 = 0; 8395b482a8SLen Brown 8495b482a8SLen Brown ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource); 8595b482a8SLen Brown 86*e0fe0a8dSLin Ming if (!info) { 87*e0fe0a8dSLin Ming return_ACPI_STATUS(AE_BAD_PARAMETER); 88*e0fe0a8dSLin Ming } 89*e0fe0a8dSLin Ming 9095b482a8SLen Brown if (((acpi_size) resource) & 0x3) { 9195b482a8SLen Brown 9295b482a8SLen Brown /* Each internal resource struct is expected to be 32-bit aligned */ 9395b482a8SLen Brown 9495b482a8SLen Brown ACPI_WARNING((AE_INFO, 95f6a22b0bSBob Moore "Misaligned resource pointer (get): %p Type 0x%2.2X Length %u", 9695b482a8SLen Brown resource, resource->type, resource->length)); 9795b482a8SLen Brown } 9895b482a8SLen Brown 9995b482a8SLen Brown /* Extract the resource Length field (does not include header length) */ 10095b482a8SLen Brown 10195b482a8SLen Brown aml_resource_length = acpi_ut_get_resource_length(aml); 10295b482a8SLen Brown 10395b482a8SLen Brown /* 10495b482a8SLen Brown * First table entry must be ACPI_RSC_INITxxx and must contain the 10595b482a8SLen Brown * table length (# of table entries) 10695b482a8SLen Brown */ 10795b482a8SLen Brown count = INIT_TABLE_LENGTH(info); 10895b482a8SLen Brown while (count) { 10995b482a8SLen Brown /* 11095b482a8SLen Brown * Source is the external AML byte stream buffer, 11195b482a8SLen Brown * destination is the internal resource descriptor 11295b482a8SLen Brown */ 11395b482a8SLen Brown source = ACPI_ADD_PTR(void, aml, info->aml_offset); 11495b482a8SLen Brown destination = 11595b482a8SLen Brown ACPI_ADD_PTR(void, resource, info->resource_offset); 11695b482a8SLen Brown 11795b482a8SLen Brown switch (info->opcode) { 11895b482a8SLen Brown case ACPI_RSC_INITGET: 11995b482a8SLen Brown /* 12095b482a8SLen Brown * Get the resource type and the initial (minimum) length 12195b482a8SLen Brown */ 12295b482a8SLen Brown ACPI_MEMSET(resource, 0, INIT_RESOURCE_LENGTH(info)); 12395b482a8SLen Brown resource->type = INIT_RESOURCE_TYPE(info); 12495b482a8SLen Brown resource->length = INIT_RESOURCE_LENGTH(info); 12595b482a8SLen Brown break; 12695b482a8SLen Brown 12795b482a8SLen Brown case ACPI_RSC_INITSET: 12895b482a8SLen Brown break; 12995b482a8SLen Brown 13095b482a8SLen Brown case ACPI_RSC_FLAGINIT: 13195b482a8SLen Brown 13295b482a8SLen Brown flags_mode = TRUE; 13395b482a8SLen Brown break; 13495b482a8SLen Brown 13595b482a8SLen Brown case ACPI_RSC_1BITFLAG: 13695b482a8SLen Brown /* 13795b482a8SLen Brown * Mask and shift the flag bit 13895b482a8SLen Brown */ 13995b482a8SLen Brown ACPI_SET8(destination) = (u8) 14095b482a8SLen Brown ((ACPI_GET8(source) >> info->value) & 0x01); 14195b482a8SLen Brown break; 14295b482a8SLen Brown 14395b482a8SLen Brown case ACPI_RSC_2BITFLAG: 14495b482a8SLen Brown /* 14595b482a8SLen Brown * Mask and shift the flag bits 14695b482a8SLen Brown */ 14795b482a8SLen Brown ACPI_SET8(destination) = (u8) 14895b482a8SLen Brown ((ACPI_GET8(source) >> info->value) & 0x03); 14995b482a8SLen Brown break; 15095b482a8SLen Brown 151*e0fe0a8dSLin Ming case ACPI_RSC_3BITFLAG: 152*e0fe0a8dSLin Ming /* 153*e0fe0a8dSLin Ming * Mask and shift the flag bits 154*e0fe0a8dSLin Ming */ 155*e0fe0a8dSLin Ming ACPI_SET8(destination) = (u8) 156*e0fe0a8dSLin Ming ((ACPI_GET8(source) >> info->value) & 0x07); 157*e0fe0a8dSLin Ming break; 158*e0fe0a8dSLin Ming 15995b482a8SLen Brown case ACPI_RSC_COUNT: 16095b482a8SLen Brown 16195b482a8SLen Brown item_count = ACPI_GET8(source); 16295b482a8SLen Brown ACPI_SET8(destination) = (u8) item_count; 16395b482a8SLen Brown 16495b482a8SLen Brown resource->length = resource->length + 16595b482a8SLen Brown (info->value * (item_count - 1)); 16695b482a8SLen Brown break; 16795b482a8SLen Brown 16895b482a8SLen Brown case ACPI_RSC_COUNT16: 16995b482a8SLen Brown 17095b482a8SLen Brown item_count = aml_resource_length; 17195b482a8SLen Brown ACPI_SET16(destination) = item_count; 17295b482a8SLen Brown 17395b482a8SLen Brown resource->length = resource->length + 17495b482a8SLen Brown (info->value * (item_count - 1)); 17595b482a8SLen Brown break; 17695b482a8SLen Brown 177*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_PIN: 178*e0fe0a8dSLin Ming 179*e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, info->value); 180*e0fe0a8dSLin Ming item_count = ACPI_GET16(target) - ACPI_GET16(source); 181*e0fe0a8dSLin Ming 182*e0fe0a8dSLin Ming resource->length = resource->length + item_count; 183*e0fe0a8dSLin Ming item_count = item_count / 2; 184*e0fe0a8dSLin Ming ACPI_SET16(destination) = item_count; 185*e0fe0a8dSLin Ming break; 186*e0fe0a8dSLin Ming 187*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_VEN: 188*e0fe0a8dSLin Ming 189*e0fe0a8dSLin Ming item_count = ACPI_GET8(source); 190*e0fe0a8dSLin Ming ACPI_SET8(destination) = (u8)item_count; 191*e0fe0a8dSLin Ming 192*e0fe0a8dSLin Ming resource->length = resource->length + 193*e0fe0a8dSLin Ming (info->value * item_count); 194*e0fe0a8dSLin Ming break; 195*e0fe0a8dSLin Ming 196*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_RES: 197*e0fe0a8dSLin Ming 198*e0fe0a8dSLin Ming /* 199*e0fe0a8dSLin Ming * Vendor data is optional (length/offset may both be zero) 200*e0fe0a8dSLin Ming * Examine vendor data length field first 201*e0fe0a8dSLin Ming */ 202*e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, (info->value + 2)); 203*e0fe0a8dSLin Ming if (ACPI_GET16(target)) { 204*e0fe0a8dSLin Ming 205*e0fe0a8dSLin Ming /* Use vendor offset to get resource source length */ 206*e0fe0a8dSLin Ming 207*e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, info->value); 208*e0fe0a8dSLin Ming item_count = 209*e0fe0a8dSLin Ming ACPI_GET16(target) - ACPI_GET16(source); 210*e0fe0a8dSLin Ming } else { 211*e0fe0a8dSLin Ming /* No vendor data to worry about */ 212*e0fe0a8dSLin Ming 213*e0fe0a8dSLin Ming item_count = aml->large_header.resource_length + 214*e0fe0a8dSLin Ming sizeof(struct aml_resource_large_header) - 215*e0fe0a8dSLin Ming ACPI_GET16(source); 216*e0fe0a8dSLin Ming } 217*e0fe0a8dSLin Ming 218*e0fe0a8dSLin Ming resource->length = resource->length + item_count; 219*e0fe0a8dSLin Ming ACPI_SET16(destination) = item_count; 220*e0fe0a8dSLin Ming break; 221*e0fe0a8dSLin Ming 222*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_SERIAL_VEN: 223*e0fe0a8dSLin Ming 224*e0fe0a8dSLin Ming item_count = ACPI_GET16(source) - info->value; 225*e0fe0a8dSLin Ming 226*e0fe0a8dSLin Ming resource->length = resource->length + item_count; 227*e0fe0a8dSLin Ming ACPI_SET16(destination) = item_count; 228*e0fe0a8dSLin Ming break; 229*e0fe0a8dSLin Ming 230*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_SERIAL_RES: 231*e0fe0a8dSLin Ming 232*e0fe0a8dSLin Ming item_count = (aml_resource_length + 233*e0fe0a8dSLin Ming sizeof(struct aml_resource_large_header)) 234*e0fe0a8dSLin Ming - ACPI_GET16(source) - info->value; 235*e0fe0a8dSLin Ming 236*e0fe0a8dSLin Ming resource->length = resource->length + item_count; 237*e0fe0a8dSLin Ming ACPI_SET16(destination) = item_count; 238*e0fe0a8dSLin Ming break; 239*e0fe0a8dSLin Ming 24095b482a8SLen Brown case ACPI_RSC_LENGTH: 24195b482a8SLen Brown 24295b482a8SLen Brown resource->length = resource->length + info->value; 24395b482a8SLen Brown break; 24495b482a8SLen Brown 24595b482a8SLen Brown case ACPI_RSC_MOVE8: 24695b482a8SLen Brown case ACPI_RSC_MOVE16: 24795b482a8SLen Brown case ACPI_RSC_MOVE32: 24895b482a8SLen Brown case ACPI_RSC_MOVE64: 24995b482a8SLen Brown /* 25095b482a8SLen Brown * Raw data move. Use the Info value field unless item_count has 25195b482a8SLen Brown * been previously initialized via a COUNT opcode 25295b482a8SLen Brown */ 25395b482a8SLen Brown if (info->value) { 25495b482a8SLen Brown item_count = info->value; 25595b482a8SLen Brown } 25695b482a8SLen Brown acpi_rs_move_data(destination, source, item_count, 25795b482a8SLen Brown info->opcode); 25895b482a8SLen Brown break; 25995b482a8SLen Brown 260*e0fe0a8dSLin Ming case ACPI_RSC_MOVE_GPIO_PIN: 261*e0fe0a8dSLin Ming 262*e0fe0a8dSLin Ming /* Generate and set the PIN data pointer */ 263*e0fe0a8dSLin Ming 264*e0fe0a8dSLin Ming target = (char *)ACPI_ADD_PTR(void, resource, 265*e0fe0a8dSLin Ming (resource->length - 266*e0fe0a8dSLin Ming item_count * 2)); 267*e0fe0a8dSLin Ming *(u16 **)destination = ACPI_CAST_PTR(u16, target); 268*e0fe0a8dSLin Ming 269*e0fe0a8dSLin Ming /* Copy the PIN data */ 270*e0fe0a8dSLin Ming 271*e0fe0a8dSLin Ming source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); 272*e0fe0a8dSLin Ming acpi_rs_move_data(target, source, item_count, 273*e0fe0a8dSLin Ming info->opcode); 274*e0fe0a8dSLin Ming break; 275*e0fe0a8dSLin Ming 276*e0fe0a8dSLin Ming case ACPI_RSC_MOVE_GPIO_RES: 277*e0fe0a8dSLin Ming 278*e0fe0a8dSLin Ming /* Generate and set the resource_source string pointer */ 279*e0fe0a8dSLin Ming 280*e0fe0a8dSLin Ming target = (char *)ACPI_ADD_PTR(void, resource, 281*e0fe0a8dSLin Ming (resource->length - 282*e0fe0a8dSLin Ming item_count)); 283*e0fe0a8dSLin Ming *(u8 **)destination = ACPI_CAST_PTR(u8, target); 284*e0fe0a8dSLin Ming 285*e0fe0a8dSLin Ming /* Copy the resource_source string */ 286*e0fe0a8dSLin Ming 287*e0fe0a8dSLin Ming source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); 288*e0fe0a8dSLin Ming acpi_rs_move_data(target, source, item_count, 289*e0fe0a8dSLin Ming info->opcode); 290*e0fe0a8dSLin Ming break; 291*e0fe0a8dSLin Ming 292*e0fe0a8dSLin Ming case ACPI_RSC_MOVE_SERIAL_VEN: 293*e0fe0a8dSLin Ming 294*e0fe0a8dSLin Ming /* Generate and set the Vendor Data pointer */ 295*e0fe0a8dSLin Ming 296*e0fe0a8dSLin Ming target = (char *)ACPI_ADD_PTR(void, resource, 297*e0fe0a8dSLin Ming (resource->length - 298*e0fe0a8dSLin Ming item_count)); 299*e0fe0a8dSLin Ming *(u8 **)destination = ACPI_CAST_PTR(u8, target); 300*e0fe0a8dSLin Ming 301*e0fe0a8dSLin Ming /* Copy the Vendor Data */ 302*e0fe0a8dSLin Ming 303*e0fe0a8dSLin Ming source = ACPI_ADD_PTR(void, aml, info->value); 304*e0fe0a8dSLin Ming acpi_rs_move_data(target, source, item_count, 305*e0fe0a8dSLin Ming info->opcode); 306*e0fe0a8dSLin Ming break; 307*e0fe0a8dSLin Ming 308*e0fe0a8dSLin Ming case ACPI_RSC_MOVE_SERIAL_RES: 309*e0fe0a8dSLin Ming 310*e0fe0a8dSLin Ming /* Generate and set the resource_source string pointer */ 311*e0fe0a8dSLin Ming 312*e0fe0a8dSLin Ming target = (char *)ACPI_ADD_PTR(void, resource, 313*e0fe0a8dSLin Ming (resource->length - 314*e0fe0a8dSLin Ming item_count)); 315*e0fe0a8dSLin Ming *(u8 **)destination = ACPI_CAST_PTR(u8, target); 316*e0fe0a8dSLin Ming 317*e0fe0a8dSLin Ming /* Copy the resource_source string */ 318*e0fe0a8dSLin Ming 319*e0fe0a8dSLin Ming source = 320*e0fe0a8dSLin Ming ACPI_ADD_PTR(void, aml, 321*e0fe0a8dSLin Ming (ACPI_GET16(source) + info->value)); 322*e0fe0a8dSLin Ming acpi_rs_move_data(target, source, item_count, 323*e0fe0a8dSLin Ming info->opcode); 324*e0fe0a8dSLin Ming break; 325*e0fe0a8dSLin Ming 32695b482a8SLen Brown case ACPI_RSC_SET8: 32795b482a8SLen Brown 32895b482a8SLen Brown ACPI_MEMSET(destination, info->aml_offset, info->value); 32995b482a8SLen Brown break; 33095b482a8SLen Brown 33195b482a8SLen Brown case ACPI_RSC_DATA8: 33295b482a8SLen Brown 33395b482a8SLen Brown target = ACPI_ADD_PTR(char, resource, info->value); 33495b482a8SLen Brown ACPI_MEMCPY(destination, source, ACPI_GET16(target)); 33595b482a8SLen Brown break; 33695b482a8SLen Brown 33795b482a8SLen Brown case ACPI_RSC_ADDRESS: 33895b482a8SLen Brown /* 33995b482a8SLen Brown * Common handler for address descriptor flags 34095b482a8SLen Brown */ 34195b482a8SLen Brown if (!acpi_rs_get_address_common(resource, aml)) { 34295b482a8SLen Brown return_ACPI_STATUS 34395b482a8SLen Brown (AE_AML_INVALID_RESOURCE_TYPE); 34495b482a8SLen Brown } 34595b482a8SLen Brown break; 34695b482a8SLen Brown 34795b482a8SLen Brown case ACPI_RSC_SOURCE: 34895b482a8SLen Brown /* 34995b482a8SLen Brown * Optional resource_source (Index and String) 35095b482a8SLen Brown */ 35195b482a8SLen Brown resource->length += 35295b482a8SLen Brown acpi_rs_get_resource_source(aml_resource_length, 35395b482a8SLen Brown info->value, 35495b482a8SLen Brown destination, aml, NULL); 35595b482a8SLen Brown break; 35695b482a8SLen Brown 35795b482a8SLen Brown case ACPI_RSC_SOURCEX: 35895b482a8SLen Brown /* 35995b482a8SLen Brown * Optional resource_source (Index and String). This is the more 36095b482a8SLen Brown * complicated case used by the Interrupt() macro 36195b482a8SLen Brown */ 362*e0fe0a8dSLin Ming target = ACPI_ADD_PTR(char, resource, 363*e0fe0a8dSLin Ming info->aml_offset + 364*e0fe0a8dSLin Ming (item_count * 4)); 36595b482a8SLen Brown 36695b482a8SLen Brown resource->length += 36795b482a8SLen Brown acpi_rs_get_resource_source(aml_resource_length, 368*e0fe0a8dSLin Ming (acpi_rs_length) 369*e0fe0a8dSLin Ming (((item_count - 370*e0fe0a8dSLin Ming 1) * sizeof(u32)) + 371*e0fe0a8dSLin Ming info->value), 372*e0fe0a8dSLin Ming destination, aml, 373*e0fe0a8dSLin Ming target); 37495b482a8SLen Brown break; 37595b482a8SLen Brown 37695b482a8SLen Brown case ACPI_RSC_BITMASK: 37795b482a8SLen Brown /* 37895b482a8SLen Brown * 8-bit encoded bitmask (DMA macro) 37995b482a8SLen Brown */ 38095b482a8SLen Brown item_count = 38195b482a8SLen Brown acpi_rs_decode_bitmask(ACPI_GET8(source), 38295b482a8SLen Brown destination); 38395b482a8SLen Brown if (item_count) { 38495b482a8SLen Brown resource->length += (item_count - 1); 38595b482a8SLen Brown } 38695b482a8SLen Brown 38795b482a8SLen Brown target = ACPI_ADD_PTR(char, resource, info->value); 38895b482a8SLen Brown ACPI_SET8(target) = (u8) item_count; 38995b482a8SLen Brown break; 39095b482a8SLen Brown 39195b482a8SLen Brown case ACPI_RSC_BITMASK16: 39295b482a8SLen Brown /* 39395b482a8SLen Brown * 16-bit encoded bitmask (IRQ macro) 39495b482a8SLen Brown */ 39595b482a8SLen Brown ACPI_MOVE_16_TO_16(&temp16, source); 39695b482a8SLen Brown 39795b482a8SLen Brown item_count = 39895b482a8SLen Brown acpi_rs_decode_bitmask(temp16, destination); 39995b482a8SLen Brown if (item_count) { 40095b482a8SLen Brown resource->length += (item_count - 1); 40195b482a8SLen Brown } 40295b482a8SLen Brown 40395b482a8SLen Brown target = ACPI_ADD_PTR(char, resource, info->value); 40495b482a8SLen Brown ACPI_SET8(target) = (u8) item_count; 40595b482a8SLen Brown break; 40695b482a8SLen Brown 40795b482a8SLen Brown case ACPI_RSC_EXIT_NE: 40895b482a8SLen Brown /* 40995b482a8SLen Brown * Control - Exit conversion if not equal 41095b482a8SLen Brown */ 41195b482a8SLen Brown switch (info->resource_offset) { 41295b482a8SLen Brown case ACPI_RSC_COMPARE_AML_LENGTH: 41395b482a8SLen Brown if (aml_resource_length != info->value) { 41495b482a8SLen Brown goto exit; 41595b482a8SLen Brown } 41695b482a8SLen Brown break; 41795b482a8SLen Brown 41895b482a8SLen Brown case ACPI_RSC_COMPARE_VALUE: 41995b482a8SLen Brown if (ACPI_GET8(source) != info->value) { 42095b482a8SLen Brown goto exit; 42195b482a8SLen Brown } 42295b482a8SLen Brown break; 42395b482a8SLen Brown 42495b482a8SLen Brown default: 42595b482a8SLen Brown 42695b482a8SLen Brown ACPI_ERROR((AE_INFO, 42795b482a8SLen Brown "Invalid conversion sub-opcode")); 42895b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 42995b482a8SLen Brown } 43095b482a8SLen Brown break; 43195b482a8SLen Brown 43295b482a8SLen Brown default: 43395b482a8SLen Brown 43495b482a8SLen Brown ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); 43595b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 43695b482a8SLen Brown } 43795b482a8SLen Brown 43895b482a8SLen Brown count--; 43995b482a8SLen Brown info++; 44095b482a8SLen Brown } 44195b482a8SLen Brown 44295b482a8SLen Brown exit: 44395b482a8SLen Brown if (!flags_mode) { 44495b482a8SLen Brown 44595b482a8SLen Brown /* Round the resource struct length up to the next boundary (32 or 64) */ 44695b482a8SLen Brown 44795b482a8SLen Brown resource->length = 44895b482a8SLen Brown (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); 44995b482a8SLen Brown } 45095b482a8SLen Brown return_ACPI_STATUS(AE_OK); 45195b482a8SLen Brown } 45295b482a8SLen Brown 45395b482a8SLen Brown /******************************************************************************* 45495b482a8SLen Brown * 45595b482a8SLen Brown * FUNCTION: acpi_rs_convert_resource_to_aml 45695b482a8SLen Brown * 45795b482a8SLen Brown * PARAMETERS: Resource - Pointer to the resource descriptor 45895b482a8SLen Brown * Aml - Where the AML descriptor is returned 45995b482a8SLen Brown * Info - Pointer to appropriate conversion table 46095b482a8SLen Brown * 46195b482a8SLen Brown * RETURN: Status 46295b482a8SLen Brown * 46395b482a8SLen Brown * DESCRIPTION: Convert an internal resource descriptor to the corresponding 46495b482a8SLen Brown * external AML resource descriptor. 46595b482a8SLen Brown * 46695b482a8SLen Brown ******************************************************************************/ 46795b482a8SLen Brown 46895b482a8SLen Brown acpi_status 46995b482a8SLen Brown acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, 47095b482a8SLen Brown union aml_resource *aml, 47195b482a8SLen Brown struct acpi_rsconvert_info *info) 47295b482a8SLen Brown { 47395b482a8SLen Brown void *source = NULL; 47495b482a8SLen Brown void *destination; 475*e0fe0a8dSLin Ming char *target; 47695b482a8SLen Brown acpi_rsdesc_size aml_length = 0; 47795b482a8SLen Brown u8 count; 47895b482a8SLen Brown u16 temp16 = 0; 47995b482a8SLen Brown u16 item_count = 0; 48095b482a8SLen Brown 48195b482a8SLen Brown ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml); 48295b482a8SLen Brown 483*e0fe0a8dSLin Ming if (!info) { 484*e0fe0a8dSLin Ming return_ACPI_STATUS(AE_BAD_PARAMETER); 485*e0fe0a8dSLin Ming } 486*e0fe0a8dSLin Ming 48795b482a8SLen Brown /* 48895b482a8SLen Brown * First table entry must be ACPI_RSC_INITxxx and must contain the 48995b482a8SLen Brown * table length (# of table entries) 49095b482a8SLen Brown */ 49195b482a8SLen Brown count = INIT_TABLE_LENGTH(info); 49295b482a8SLen Brown 49395b482a8SLen Brown while (count) { 49495b482a8SLen Brown /* 49595b482a8SLen Brown * Source is the internal resource descriptor, 49695b482a8SLen Brown * destination is the external AML byte stream buffer 49795b482a8SLen Brown */ 49895b482a8SLen Brown source = ACPI_ADD_PTR(void, resource, info->resource_offset); 49995b482a8SLen Brown destination = ACPI_ADD_PTR(void, aml, info->aml_offset); 50095b482a8SLen Brown 50195b482a8SLen Brown switch (info->opcode) { 50295b482a8SLen Brown case ACPI_RSC_INITSET: 50395b482a8SLen Brown 50495b482a8SLen Brown ACPI_MEMSET(aml, 0, INIT_RESOURCE_LENGTH(info)); 50595b482a8SLen Brown aml_length = INIT_RESOURCE_LENGTH(info); 50695b482a8SLen Brown acpi_rs_set_resource_header(INIT_RESOURCE_TYPE(info), 50795b482a8SLen Brown aml_length, aml); 50895b482a8SLen Brown break; 50995b482a8SLen Brown 51095b482a8SLen Brown case ACPI_RSC_INITGET: 51195b482a8SLen Brown break; 51295b482a8SLen Brown 51395b482a8SLen Brown case ACPI_RSC_FLAGINIT: 51495b482a8SLen Brown /* 51595b482a8SLen Brown * Clear the flag byte 51695b482a8SLen Brown */ 51795b482a8SLen Brown ACPI_SET8(destination) = 0; 51895b482a8SLen Brown break; 51995b482a8SLen Brown 52095b482a8SLen Brown case ACPI_RSC_1BITFLAG: 52195b482a8SLen Brown /* 52295b482a8SLen Brown * Mask and shift the flag bit 52395b482a8SLen Brown */ 52495b482a8SLen Brown ACPI_SET8(destination) |= (u8) 52595b482a8SLen Brown ((ACPI_GET8(source) & 0x01) << info->value); 52695b482a8SLen Brown break; 52795b482a8SLen Brown 52895b482a8SLen Brown case ACPI_RSC_2BITFLAG: 52995b482a8SLen Brown /* 53095b482a8SLen Brown * Mask and shift the flag bits 53195b482a8SLen Brown */ 53295b482a8SLen Brown ACPI_SET8(destination) |= (u8) 53395b482a8SLen Brown ((ACPI_GET8(source) & 0x03) << info->value); 53495b482a8SLen Brown break; 53595b482a8SLen Brown 536*e0fe0a8dSLin Ming case ACPI_RSC_3BITFLAG: 537*e0fe0a8dSLin Ming /* 538*e0fe0a8dSLin Ming * Mask and shift the flag bits 539*e0fe0a8dSLin Ming */ 540*e0fe0a8dSLin Ming ACPI_SET8(destination) |= (u8) 541*e0fe0a8dSLin Ming ((ACPI_GET8(source) & 0x07) << info->value); 542*e0fe0a8dSLin Ming break; 543*e0fe0a8dSLin Ming 54495b482a8SLen Brown case ACPI_RSC_COUNT: 54595b482a8SLen Brown 54695b482a8SLen Brown item_count = ACPI_GET8(source); 54795b482a8SLen Brown ACPI_SET8(destination) = (u8) item_count; 54895b482a8SLen Brown 54995b482a8SLen Brown aml_length = 55095b482a8SLen Brown (u16) (aml_length + 55195b482a8SLen Brown (info->value * (item_count - 1))); 55295b482a8SLen Brown break; 55395b482a8SLen Brown 55495b482a8SLen Brown case ACPI_RSC_COUNT16: 55595b482a8SLen Brown 55695b482a8SLen Brown item_count = ACPI_GET16(source); 55795b482a8SLen Brown aml_length = (u16) (aml_length + item_count); 55895b482a8SLen Brown acpi_rs_set_resource_length(aml_length, aml); 55995b482a8SLen Brown break; 56095b482a8SLen Brown 561*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_PIN: 562*e0fe0a8dSLin Ming 563*e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 564*e0fe0a8dSLin Ming ACPI_SET16(destination) = (u16)aml_length; 565*e0fe0a8dSLin Ming 566*e0fe0a8dSLin Ming aml_length = (u16)(aml_length + item_count * 2); 567*e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, info->value); 568*e0fe0a8dSLin Ming ACPI_SET16(target) = (u16)aml_length; 569*e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 570*e0fe0a8dSLin Ming break; 571*e0fe0a8dSLin Ming 572*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_VEN: 573*e0fe0a8dSLin Ming 574*e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 575*e0fe0a8dSLin Ming ACPI_SET16(destination) = (u16)item_count; 576*e0fe0a8dSLin Ming 577*e0fe0a8dSLin Ming aml_length = 578*e0fe0a8dSLin Ming (u16)(aml_length + (info->value * item_count)); 579*e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 580*e0fe0a8dSLin Ming break; 581*e0fe0a8dSLin Ming 582*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_GPIO_RES: 583*e0fe0a8dSLin Ming 584*e0fe0a8dSLin Ming /* Set resource source string length */ 585*e0fe0a8dSLin Ming 586*e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 587*e0fe0a8dSLin Ming ACPI_SET16(destination) = (u16)aml_length; 588*e0fe0a8dSLin Ming 589*e0fe0a8dSLin Ming /* Compute offset for the Vendor Data */ 590*e0fe0a8dSLin Ming 591*e0fe0a8dSLin Ming aml_length = (u16)(aml_length + item_count); 592*e0fe0a8dSLin Ming target = ACPI_ADD_PTR(void, aml, info->value); 593*e0fe0a8dSLin Ming 594*e0fe0a8dSLin Ming /* Set vendor offset only if there is vendor data */ 595*e0fe0a8dSLin Ming 596*e0fe0a8dSLin Ming if (resource->data.gpio.vendor_length) { 597*e0fe0a8dSLin Ming ACPI_SET16(target) = (u16)aml_length; 598*e0fe0a8dSLin Ming } 599*e0fe0a8dSLin Ming 600*e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 601*e0fe0a8dSLin Ming break; 602*e0fe0a8dSLin Ming 603*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_SERIAL_VEN: 604*e0fe0a8dSLin Ming 605*e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 606*e0fe0a8dSLin Ming ACPI_SET16(destination) = item_count + info->value; 607*e0fe0a8dSLin Ming aml_length = (u16)(aml_length + item_count); 608*e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 609*e0fe0a8dSLin Ming break; 610*e0fe0a8dSLin Ming 611*e0fe0a8dSLin Ming case ACPI_RSC_COUNT_SERIAL_RES: 612*e0fe0a8dSLin Ming 613*e0fe0a8dSLin Ming item_count = ACPI_GET16(source); 614*e0fe0a8dSLin Ming aml_length = (u16)(aml_length + item_count); 615*e0fe0a8dSLin Ming acpi_rs_set_resource_length(aml_length, aml); 616*e0fe0a8dSLin Ming break; 617*e0fe0a8dSLin Ming 61895b482a8SLen Brown case ACPI_RSC_LENGTH: 61995b482a8SLen Brown 62095b482a8SLen Brown acpi_rs_set_resource_length(info->value, aml); 62195b482a8SLen Brown break; 62295b482a8SLen Brown 62395b482a8SLen Brown case ACPI_RSC_MOVE8: 62495b482a8SLen Brown case ACPI_RSC_MOVE16: 62595b482a8SLen Brown case ACPI_RSC_MOVE32: 62695b482a8SLen Brown case ACPI_RSC_MOVE64: 62795b482a8SLen Brown 62895b482a8SLen Brown if (info->value) { 62995b482a8SLen Brown item_count = info->value; 63095b482a8SLen Brown } 63195b482a8SLen Brown acpi_rs_move_data(destination, source, item_count, 63295b482a8SLen Brown info->opcode); 63395b482a8SLen Brown break; 63495b482a8SLen Brown 635*e0fe0a8dSLin Ming case ACPI_RSC_MOVE_GPIO_PIN: 636*e0fe0a8dSLin Ming 637*e0fe0a8dSLin Ming destination = (char *)ACPI_ADD_PTR(void, aml, 638*e0fe0a8dSLin Ming ACPI_GET16 639*e0fe0a8dSLin Ming (destination)); 640*e0fe0a8dSLin Ming source = *(u16 **)source; 641*e0fe0a8dSLin Ming acpi_rs_move_data(destination, source, item_count, 642*e0fe0a8dSLin Ming info->opcode); 643*e0fe0a8dSLin Ming break; 644*e0fe0a8dSLin Ming 645*e0fe0a8dSLin Ming case ACPI_RSC_MOVE_GPIO_RES: 646*e0fe0a8dSLin Ming 647*e0fe0a8dSLin Ming /* Used for both resource_source string and vendor_data */ 648*e0fe0a8dSLin Ming 649*e0fe0a8dSLin Ming destination = (char *)ACPI_ADD_PTR(void, aml, 650*e0fe0a8dSLin Ming ACPI_GET16 651*e0fe0a8dSLin Ming (destination)); 652*e0fe0a8dSLin Ming source = *(u8 **)source; 653*e0fe0a8dSLin Ming acpi_rs_move_data(destination, source, item_count, 654*e0fe0a8dSLin Ming info->opcode); 655*e0fe0a8dSLin Ming break; 656*e0fe0a8dSLin Ming 657*e0fe0a8dSLin Ming case ACPI_RSC_MOVE_SERIAL_VEN: 658*e0fe0a8dSLin Ming 659*e0fe0a8dSLin Ming destination = (char *)ACPI_ADD_PTR(void, aml, 660*e0fe0a8dSLin Ming (aml_length - 661*e0fe0a8dSLin Ming item_count)); 662*e0fe0a8dSLin Ming source = *(u8 **)source; 663*e0fe0a8dSLin Ming acpi_rs_move_data(destination, source, item_count, 664*e0fe0a8dSLin Ming info->opcode); 665*e0fe0a8dSLin Ming break; 666*e0fe0a8dSLin Ming 667*e0fe0a8dSLin Ming case ACPI_RSC_MOVE_SERIAL_RES: 668*e0fe0a8dSLin Ming 669*e0fe0a8dSLin Ming destination = (char *)ACPI_ADD_PTR(void, aml, 670*e0fe0a8dSLin Ming (aml_length - 671*e0fe0a8dSLin Ming item_count)); 672*e0fe0a8dSLin Ming source = *(u8 **)source; 673*e0fe0a8dSLin Ming acpi_rs_move_data(destination, source, item_count, 674*e0fe0a8dSLin Ming info->opcode); 675*e0fe0a8dSLin Ming break; 676*e0fe0a8dSLin Ming 67795b482a8SLen Brown case ACPI_RSC_ADDRESS: 67895b482a8SLen Brown 67995b482a8SLen Brown /* Set the Resource Type, General Flags, and Type-Specific Flags */ 68095b482a8SLen Brown 68195b482a8SLen Brown acpi_rs_set_address_common(aml, resource); 68295b482a8SLen Brown break; 68395b482a8SLen Brown 68495b482a8SLen Brown case ACPI_RSC_SOURCEX: 68595b482a8SLen Brown /* 68695b482a8SLen Brown * Optional resource_source (Index and String) 68795b482a8SLen Brown */ 68895b482a8SLen Brown aml_length = 68995b482a8SLen Brown acpi_rs_set_resource_source(aml, (acpi_rs_length) 69095b482a8SLen Brown aml_length, source); 69195b482a8SLen Brown acpi_rs_set_resource_length(aml_length, aml); 69295b482a8SLen Brown break; 69395b482a8SLen Brown 69495b482a8SLen Brown case ACPI_RSC_SOURCE: 69595b482a8SLen Brown /* 69695b482a8SLen Brown * Optional resource_source (Index and String). This is the more 69795b482a8SLen Brown * complicated case used by the Interrupt() macro 69895b482a8SLen Brown */ 69995b482a8SLen Brown aml_length = 70095b482a8SLen Brown acpi_rs_set_resource_source(aml, info->value, 70195b482a8SLen Brown source); 70295b482a8SLen Brown acpi_rs_set_resource_length(aml_length, aml); 70395b482a8SLen Brown break; 70495b482a8SLen Brown 70595b482a8SLen Brown case ACPI_RSC_BITMASK: 70695b482a8SLen Brown /* 70795b482a8SLen Brown * 8-bit encoded bitmask (DMA macro) 70895b482a8SLen Brown */ 70995b482a8SLen Brown ACPI_SET8(destination) = (u8) 71095b482a8SLen Brown acpi_rs_encode_bitmask(source, 71195b482a8SLen Brown *ACPI_ADD_PTR(u8, resource, 71295b482a8SLen Brown info->value)); 71395b482a8SLen Brown break; 71495b482a8SLen Brown 71595b482a8SLen Brown case ACPI_RSC_BITMASK16: 71695b482a8SLen Brown /* 71795b482a8SLen Brown * 16-bit encoded bitmask (IRQ macro) 71895b482a8SLen Brown */ 71995b482a8SLen Brown temp16 = acpi_rs_encode_bitmask(source, 72095b482a8SLen Brown *ACPI_ADD_PTR(u8, 72195b482a8SLen Brown resource, 72295b482a8SLen Brown info-> 72395b482a8SLen Brown value)); 72495b482a8SLen Brown ACPI_MOVE_16_TO_16(destination, &temp16); 72595b482a8SLen Brown break; 72695b482a8SLen Brown 72795b482a8SLen Brown case ACPI_RSC_EXIT_LE: 72895b482a8SLen Brown /* 72995b482a8SLen Brown * Control - Exit conversion if less than or equal 73095b482a8SLen Brown */ 73195b482a8SLen Brown if (item_count <= info->value) { 73295b482a8SLen Brown goto exit; 73395b482a8SLen Brown } 73495b482a8SLen Brown break; 73595b482a8SLen Brown 73695b482a8SLen Brown case ACPI_RSC_EXIT_NE: 73795b482a8SLen Brown /* 73895b482a8SLen Brown * Control - Exit conversion if not equal 73995b482a8SLen Brown */ 74095b482a8SLen Brown switch (COMPARE_OPCODE(info)) { 74195b482a8SLen Brown case ACPI_RSC_COMPARE_VALUE: 74295b482a8SLen Brown 74395b482a8SLen Brown if (*ACPI_ADD_PTR(u8, resource, 74495b482a8SLen Brown COMPARE_TARGET(info)) != 74595b482a8SLen Brown COMPARE_VALUE(info)) { 74695b482a8SLen Brown goto exit; 74795b482a8SLen Brown } 74895b482a8SLen Brown break; 74995b482a8SLen Brown 75095b482a8SLen Brown default: 75195b482a8SLen Brown 75295b482a8SLen Brown ACPI_ERROR((AE_INFO, 75395b482a8SLen Brown "Invalid conversion sub-opcode")); 75495b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 75595b482a8SLen Brown } 75695b482a8SLen Brown break; 75795b482a8SLen Brown 75895b482a8SLen Brown case ACPI_RSC_EXIT_EQ: 75995b482a8SLen Brown /* 76095b482a8SLen Brown * Control - Exit conversion if equal 76195b482a8SLen Brown */ 76295b482a8SLen Brown if (*ACPI_ADD_PTR(u8, resource, 76395b482a8SLen Brown COMPARE_TARGET(info)) == 76495b482a8SLen Brown COMPARE_VALUE(info)) { 76595b482a8SLen Brown goto exit; 76695b482a8SLen Brown } 76795b482a8SLen Brown break; 76895b482a8SLen Brown 76995b482a8SLen Brown default: 77095b482a8SLen Brown 77195b482a8SLen Brown ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); 77295b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 77395b482a8SLen Brown } 77495b482a8SLen Brown 77595b482a8SLen Brown count--; 77695b482a8SLen Brown info++; 77795b482a8SLen Brown } 77895b482a8SLen Brown 77995b482a8SLen Brown exit: 78095b482a8SLen Brown return_ACPI_STATUS(AE_OK); 78195b482a8SLen Brown } 78295b482a8SLen Brown 78395b482a8SLen Brown #if 0 78495b482a8SLen Brown /* Previous resource validations */ 78595b482a8SLen Brown 78695b482a8SLen Brown if (aml->ext_address64.revision_iD != AML_RESOURCE_EXTENDED_ADDRESS_REVISION) { 78795b482a8SLen Brown return_ACPI_STATUS(AE_SUPPORT); 78895b482a8SLen Brown } 78995b482a8SLen Brown 79095b482a8SLen Brown if (resource->data.start_dpf.performance_robustness >= 3) { 79195b482a8SLen Brown return_ACPI_STATUS(AE_AML_BAD_RESOURCE_VALUE); 79295b482a8SLen Brown } 79395b482a8SLen Brown 79495b482a8SLen Brown if (((aml->irq.flags & 0x09) == 0x00) || ((aml->irq.flags & 0x09) == 0x09)) { 79595b482a8SLen Brown /* 79695b482a8SLen Brown * Only [active_high, edge_sensitive] or [active_low, level_sensitive] 79795b482a8SLen Brown * polarity/trigger interrupts are allowed (ACPI spec, section 79895b482a8SLen Brown * "IRQ Format"), so 0x00 and 0x09 are illegal. 79995b482a8SLen Brown */ 80095b482a8SLen Brown ACPI_ERROR((AE_INFO, 801f6a22b0bSBob Moore "Invalid interrupt polarity/trigger in resource list, 0x%X", 80295b482a8SLen Brown aml->irq.flags)); 80395b482a8SLen Brown return_ACPI_STATUS(AE_BAD_DATA); 80495b482a8SLen Brown } 80595b482a8SLen Brown 80695b482a8SLen Brown resource->data.extended_irq.interrupt_count = temp8; 80795b482a8SLen Brown if (temp8 < 1) { 80895b482a8SLen Brown 80995b482a8SLen Brown /* Must have at least one IRQ */ 81095b482a8SLen Brown 81195b482a8SLen Brown return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); 81295b482a8SLen Brown } 81395b482a8SLen Brown 81495b482a8SLen Brown if (resource->data.dma.transfer == 0x03) { 81595b482a8SLen Brown ACPI_ERROR((AE_INFO, "Invalid DMA.Transfer preference (3)")); 81695b482a8SLen Brown return_ACPI_STATUS(AE_BAD_DATA); 81795b482a8SLen Brown } 81895b482a8SLen Brown #endif 819