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
acpi_rs_convert_aml_to_resource(struct acpi_resource * resource,union aml_resource * aml,struct acpi_rsconvert_info * info)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
acpi_rs_convert_resource_to_aml(struct acpi_resource * resource,union aml_resource * aml,struct acpi_rsconvert_info * info)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