1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /*******************************************************************************
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Module Name: rsmisc - Miscellaneous resource descriptors
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun ******************************************************************************/
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <acpi/acpi.h>
9*4882a593Smuzhiyun #include "accommon.h"
10*4882a593Smuzhiyun #include "acresrc.h"
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #define _COMPONENT ACPI_RESOURCES
13*4882a593Smuzhiyun ACPI_MODULE_NAME("rsmisc")
14*4882a593Smuzhiyun #define INIT_RESOURCE_TYPE(i) i->resource_offset
15*4882a593Smuzhiyun #define INIT_RESOURCE_LENGTH(i) i->aml_offset
16*4882a593Smuzhiyun #define INIT_TABLE_LENGTH(i) i->value
17*4882a593Smuzhiyun #define COMPARE_OPCODE(i) i->resource_offset
18*4882a593Smuzhiyun #define COMPARE_TARGET(i) i->aml_offset
19*4882a593Smuzhiyun #define COMPARE_VALUE(i) i->value
20*4882a593Smuzhiyun /*******************************************************************************
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * FUNCTION: acpi_rs_convert_aml_to_resource
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * PARAMETERS: resource - Pointer to the resource descriptor
25*4882a593Smuzhiyun * aml - Where the AML descriptor is returned
26*4882a593Smuzhiyun * info - Pointer to appropriate conversion table
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * RETURN: Status
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun * DESCRIPTION: Convert an external AML resource descriptor to the corresponding
31*4882a593Smuzhiyun * internal resource descriptor
32*4882a593Smuzhiyun *
33*4882a593Smuzhiyun ******************************************************************************/
34*4882a593Smuzhiyun acpi_status
acpi_rs_convert_aml_to_resource(struct acpi_resource * resource,union aml_resource * aml,struct acpi_rsconvert_info * info)35*4882a593Smuzhiyun acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
36*4882a593Smuzhiyun union aml_resource *aml,
37*4882a593Smuzhiyun struct acpi_rsconvert_info *info)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun acpi_rs_length aml_resource_length;
40*4882a593Smuzhiyun void *source;
41*4882a593Smuzhiyun void *destination;
42*4882a593Smuzhiyun char *target;
43*4882a593Smuzhiyun u8 count;
44*4882a593Smuzhiyun u8 flags_mode = FALSE;
45*4882a593Smuzhiyun u16 item_count = 0;
46*4882a593Smuzhiyun u16 temp16 = 0;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun if (!info) {
51*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun if (((acpi_size)resource) & 0x3) {
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /* Each internal resource struct is expected to be 32-bit aligned */
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun ACPI_WARNING((AE_INFO,
59*4882a593Smuzhiyun "Misaligned resource pointer (get): %p Type 0x%2.2X Length %u",
60*4882a593Smuzhiyun resource, resource->type, resource->length));
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* Extract the resource Length field (does not include header length) */
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun aml_resource_length = acpi_ut_get_resource_length(aml);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /*
68*4882a593Smuzhiyun * First table entry must be ACPI_RSC_INITxxx and must contain the
69*4882a593Smuzhiyun * table length (# of table entries)
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun count = INIT_TABLE_LENGTH(info);
72*4882a593Smuzhiyun while (count) {
73*4882a593Smuzhiyun /*
74*4882a593Smuzhiyun * Source is the external AML byte stream buffer,
75*4882a593Smuzhiyun * destination is the internal resource descriptor
76*4882a593Smuzhiyun */
77*4882a593Smuzhiyun source = ACPI_ADD_PTR(void, aml, info->aml_offset);
78*4882a593Smuzhiyun destination =
79*4882a593Smuzhiyun ACPI_ADD_PTR(void, resource, info->resource_offset);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun switch (info->opcode) {
82*4882a593Smuzhiyun case ACPI_RSC_INITGET:
83*4882a593Smuzhiyun /*
84*4882a593Smuzhiyun * Get the resource type and the initial (minimum) length
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun memset(resource, 0, INIT_RESOURCE_LENGTH(info));
87*4882a593Smuzhiyun resource->type = INIT_RESOURCE_TYPE(info);
88*4882a593Smuzhiyun resource->length = INIT_RESOURCE_LENGTH(info);
89*4882a593Smuzhiyun break;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun case ACPI_RSC_INITSET:
92*4882a593Smuzhiyun break;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun case ACPI_RSC_FLAGINIT:
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun flags_mode = TRUE;
97*4882a593Smuzhiyun break;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun case ACPI_RSC_1BITFLAG:
100*4882a593Smuzhiyun /*
101*4882a593Smuzhiyun * Mask and shift the flag bit
102*4882a593Smuzhiyun */
103*4882a593Smuzhiyun ACPI_SET8(destination,
104*4882a593Smuzhiyun ((ACPI_GET8(source) >> info->value) & 0x01));
105*4882a593Smuzhiyun break;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun case ACPI_RSC_2BITFLAG:
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun * Mask and shift the flag bits
110*4882a593Smuzhiyun */
111*4882a593Smuzhiyun ACPI_SET8(destination,
112*4882a593Smuzhiyun ((ACPI_GET8(source) >> info->value) & 0x03));
113*4882a593Smuzhiyun break;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun case ACPI_RSC_3BITFLAG:
116*4882a593Smuzhiyun /*
117*4882a593Smuzhiyun * Mask and shift the flag bits
118*4882a593Smuzhiyun */
119*4882a593Smuzhiyun ACPI_SET8(destination,
120*4882a593Smuzhiyun ((ACPI_GET8(source) >> info->value) & 0x07));
121*4882a593Smuzhiyun break;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun case ACPI_RSC_COUNT:
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun item_count = ACPI_GET8(source);
126*4882a593Smuzhiyun ACPI_SET8(destination, item_count);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun resource->length = resource->length +
129*4882a593Smuzhiyun (info->value * (item_count - 1));
130*4882a593Smuzhiyun break;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun case ACPI_RSC_COUNT16:
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun item_count = aml_resource_length;
135*4882a593Smuzhiyun ACPI_SET16(destination, item_count);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun resource->length = resource->length +
138*4882a593Smuzhiyun (info->value * (item_count - 1));
139*4882a593Smuzhiyun break;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun case ACPI_RSC_COUNT_GPIO_PIN:
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun target = ACPI_ADD_PTR(void, aml, info->value);
144*4882a593Smuzhiyun item_count = ACPI_GET16(target) - ACPI_GET16(source);
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun resource->length = resource->length + item_count;
147*4882a593Smuzhiyun item_count = item_count / 2;
148*4882a593Smuzhiyun ACPI_SET16(destination, item_count);
149*4882a593Smuzhiyun break;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun case ACPI_RSC_COUNT_GPIO_VEN:
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun item_count = ACPI_GET8(source);
154*4882a593Smuzhiyun ACPI_SET8(destination, item_count);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun resource->length =
157*4882a593Smuzhiyun resource->length + (info->value * item_count);
158*4882a593Smuzhiyun break;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun case ACPI_RSC_COUNT_GPIO_RES:
161*4882a593Smuzhiyun /*
162*4882a593Smuzhiyun * Vendor data is optional (length/offset may both be zero)
163*4882a593Smuzhiyun * Examine vendor data length field first
164*4882a593Smuzhiyun */
165*4882a593Smuzhiyun target = ACPI_ADD_PTR(void, aml, (info->value + 2));
166*4882a593Smuzhiyun if (ACPI_GET16(target)) {
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /* Use vendor offset to get resource source length */
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun target = ACPI_ADD_PTR(void, aml, info->value);
171*4882a593Smuzhiyun item_count =
172*4882a593Smuzhiyun ACPI_GET16(target) - ACPI_GET16(source);
173*4882a593Smuzhiyun } else {
174*4882a593Smuzhiyun /* No vendor data to worry about */
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun item_count = aml->large_header.resource_length +
177*4882a593Smuzhiyun sizeof(struct aml_resource_large_header) -
178*4882a593Smuzhiyun ACPI_GET16(source);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun resource->length = resource->length + item_count;
182*4882a593Smuzhiyun ACPI_SET16(destination, item_count);
183*4882a593Smuzhiyun break;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun case ACPI_RSC_COUNT_SERIAL_VEN:
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun item_count = ACPI_GET16(source) - info->value;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun resource->length = resource->length + item_count;
190*4882a593Smuzhiyun ACPI_SET16(destination, item_count);
191*4882a593Smuzhiyun break;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun case ACPI_RSC_COUNT_SERIAL_RES:
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun item_count = (aml_resource_length +
196*4882a593Smuzhiyun sizeof(struct aml_resource_large_header))
197*4882a593Smuzhiyun - ACPI_GET16(source) - info->value;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun resource->length = resource->length + item_count;
200*4882a593Smuzhiyun ACPI_SET16(destination, item_count);
201*4882a593Smuzhiyun break;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun case ACPI_RSC_LENGTH:
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun resource->length = resource->length + info->value;
206*4882a593Smuzhiyun break;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun case ACPI_RSC_MOVE8:
209*4882a593Smuzhiyun case ACPI_RSC_MOVE16:
210*4882a593Smuzhiyun case ACPI_RSC_MOVE32:
211*4882a593Smuzhiyun case ACPI_RSC_MOVE64:
212*4882a593Smuzhiyun /*
213*4882a593Smuzhiyun * Raw data move. Use the Info value field unless item_count has
214*4882a593Smuzhiyun * been previously initialized via a COUNT opcode
215*4882a593Smuzhiyun */
216*4882a593Smuzhiyun if (info->value) {
217*4882a593Smuzhiyun item_count = info->value;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun acpi_rs_move_data(destination, source, item_count,
220*4882a593Smuzhiyun info->opcode);
221*4882a593Smuzhiyun break;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun case ACPI_RSC_MOVE_GPIO_PIN:
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /* Generate and set the PIN data pointer */
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun target = (char *)ACPI_ADD_PTR(void, resource,
228*4882a593Smuzhiyun (resource->length -
229*4882a593Smuzhiyun item_count * 2));
230*4882a593Smuzhiyun *(u16 **)destination = ACPI_CAST_PTR(u16, target);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /* Copy the PIN data */
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source));
235*4882a593Smuzhiyun acpi_rs_move_data(target, source, item_count,
236*4882a593Smuzhiyun info->opcode);
237*4882a593Smuzhiyun break;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun case ACPI_RSC_MOVE_GPIO_RES:
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun /* Generate and set the resource_source string pointer */
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun target = (char *)ACPI_ADD_PTR(void, resource,
244*4882a593Smuzhiyun (resource->length -
245*4882a593Smuzhiyun item_count));
246*4882a593Smuzhiyun *(u8 **)destination = ACPI_CAST_PTR(u8, target);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun /* Copy the resource_source string */
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source));
251*4882a593Smuzhiyun acpi_rs_move_data(target, source, item_count,
252*4882a593Smuzhiyun info->opcode);
253*4882a593Smuzhiyun break;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun case ACPI_RSC_MOVE_SERIAL_VEN:
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* Generate and set the Vendor Data pointer */
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun target = (char *)ACPI_ADD_PTR(void, resource,
260*4882a593Smuzhiyun (resource->length -
261*4882a593Smuzhiyun item_count));
262*4882a593Smuzhiyun *(u8 **)destination = ACPI_CAST_PTR(u8, target);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /* Copy the Vendor Data */
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun source = ACPI_ADD_PTR(void, aml, info->value);
267*4882a593Smuzhiyun acpi_rs_move_data(target, source, item_count,
268*4882a593Smuzhiyun info->opcode);
269*4882a593Smuzhiyun break;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun case ACPI_RSC_MOVE_SERIAL_RES:
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* Generate and set the resource_source string pointer */
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun target = (char *)ACPI_ADD_PTR(void, resource,
276*4882a593Smuzhiyun (resource->length -
277*4882a593Smuzhiyun item_count));
278*4882a593Smuzhiyun *(u8 **)destination = ACPI_CAST_PTR(u8, target);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /* Copy the resource_source string */
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun source =
283*4882a593Smuzhiyun ACPI_ADD_PTR(void, aml,
284*4882a593Smuzhiyun (ACPI_GET16(source) + info->value));
285*4882a593Smuzhiyun acpi_rs_move_data(target, source, item_count,
286*4882a593Smuzhiyun info->opcode);
287*4882a593Smuzhiyun break;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun case ACPI_RSC_SET8:
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun memset(destination, info->aml_offset, info->value);
292*4882a593Smuzhiyun break;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun case ACPI_RSC_DATA8:
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun target = ACPI_ADD_PTR(char, resource, info->value);
297*4882a593Smuzhiyun memcpy(destination, source, ACPI_GET16(target));
298*4882a593Smuzhiyun break;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun case ACPI_RSC_ADDRESS:
301*4882a593Smuzhiyun /*
302*4882a593Smuzhiyun * Common handler for address descriptor flags
303*4882a593Smuzhiyun */
304*4882a593Smuzhiyun if (!acpi_rs_get_address_common(resource, aml)) {
305*4882a593Smuzhiyun return_ACPI_STATUS
306*4882a593Smuzhiyun (AE_AML_INVALID_RESOURCE_TYPE);
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun break;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun case ACPI_RSC_SOURCE:
311*4882a593Smuzhiyun /*
312*4882a593Smuzhiyun * Optional resource_source (Index and String)
313*4882a593Smuzhiyun */
314*4882a593Smuzhiyun resource->length +=
315*4882a593Smuzhiyun acpi_rs_get_resource_source(aml_resource_length,
316*4882a593Smuzhiyun info->value,
317*4882a593Smuzhiyun destination, aml, NULL);
318*4882a593Smuzhiyun break;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun case ACPI_RSC_SOURCEX:
321*4882a593Smuzhiyun /*
322*4882a593Smuzhiyun * Optional resource_source (Index and String). This is the more
323*4882a593Smuzhiyun * complicated case used by the Interrupt() macro
324*4882a593Smuzhiyun */
325*4882a593Smuzhiyun target = ACPI_ADD_PTR(char, resource,
326*4882a593Smuzhiyun info->aml_offset +
327*4882a593Smuzhiyun (item_count * 4));
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun resource->length +=
330*4882a593Smuzhiyun acpi_rs_get_resource_source(aml_resource_length,
331*4882a593Smuzhiyun (acpi_rs_length)
332*4882a593Smuzhiyun (((item_count -
333*4882a593Smuzhiyun 1) * sizeof(u32)) +
334*4882a593Smuzhiyun info->value),
335*4882a593Smuzhiyun destination, aml,
336*4882a593Smuzhiyun target);
337*4882a593Smuzhiyun break;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun case ACPI_RSC_BITMASK:
340*4882a593Smuzhiyun /*
341*4882a593Smuzhiyun * 8-bit encoded bitmask (DMA macro)
342*4882a593Smuzhiyun */
343*4882a593Smuzhiyun item_count =
344*4882a593Smuzhiyun acpi_rs_decode_bitmask(ACPI_GET8(source),
345*4882a593Smuzhiyun destination);
346*4882a593Smuzhiyun if (item_count) {
347*4882a593Smuzhiyun resource->length += (item_count - 1);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun target = ACPI_ADD_PTR(char, resource, info->value);
351*4882a593Smuzhiyun ACPI_SET8(target, item_count);
352*4882a593Smuzhiyun break;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun case ACPI_RSC_BITMASK16:
355*4882a593Smuzhiyun /*
356*4882a593Smuzhiyun * 16-bit encoded bitmask (IRQ macro)
357*4882a593Smuzhiyun */
358*4882a593Smuzhiyun ACPI_MOVE_16_TO_16(&temp16, source);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun item_count =
361*4882a593Smuzhiyun acpi_rs_decode_bitmask(temp16, destination);
362*4882a593Smuzhiyun if (item_count) {
363*4882a593Smuzhiyun resource->length += (item_count - 1);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun target = ACPI_ADD_PTR(char, resource, info->value);
367*4882a593Smuzhiyun ACPI_SET8(target, item_count);
368*4882a593Smuzhiyun break;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun case ACPI_RSC_EXIT_NE:
371*4882a593Smuzhiyun /*
372*4882a593Smuzhiyun * control - Exit conversion if not equal
373*4882a593Smuzhiyun */
374*4882a593Smuzhiyun switch (info->resource_offset) {
375*4882a593Smuzhiyun case ACPI_RSC_COMPARE_AML_LENGTH:
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun if (aml_resource_length != info->value) {
378*4882a593Smuzhiyun goto exit;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun break;
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun case ACPI_RSC_COMPARE_VALUE:
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun if (ACPI_GET8(source) != info->value) {
385*4882a593Smuzhiyun goto exit;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun break;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun default:
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun ACPI_ERROR((AE_INFO,
392*4882a593Smuzhiyun "Invalid conversion sub-opcode"));
393*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun break;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun default:
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun ACPI_ERROR((AE_INFO, "Invalid conversion opcode"));
400*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun count--;
404*4882a593Smuzhiyun info++;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun exit:
408*4882a593Smuzhiyun if (!flags_mode) {
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun /* Round the resource struct length up to the next boundary (32 or 64) */
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun resource->length = (u32)
413*4882a593Smuzhiyun ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length);
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun return_ACPI_STATUS(AE_OK);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun /*******************************************************************************
419*4882a593Smuzhiyun *
420*4882a593Smuzhiyun * FUNCTION: acpi_rs_convert_resource_to_aml
421*4882a593Smuzhiyun *
422*4882a593Smuzhiyun * PARAMETERS: resource - Pointer to the resource descriptor
423*4882a593Smuzhiyun * aml - Where the AML descriptor is returned
424*4882a593Smuzhiyun * info - Pointer to appropriate conversion table
425*4882a593Smuzhiyun *
426*4882a593Smuzhiyun * RETURN: Status
427*4882a593Smuzhiyun *
428*4882a593Smuzhiyun * DESCRIPTION: Convert an internal resource descriptor to the corresponding
429*4882a593Smuzhiyun * external AML resource descriptor.
430*4882a593Smuzhiyun *
431*4882a593Smuzhiyun ******************************************************************************/
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun acpi_status
acpi_rs_convert_resource_to_aml(struct acpi_resource * resource,union aml_resource * aml,struct acpi_rsconvert_info * info)434*4882a593Smuzhiyun acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
435*4882a593Smuzhiyun union aml_resource *aml,
436*4882a593Smuzhiyun struct acpi_rsconvert_info *info)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun void *source = NULL;
439*4882a593Smuzhiyun void *destination;
440*4882a593Smuzhiyun char *target;
441*4882a593Smuzhiyun acpi_rsdesc_size aml_length = 0;
442*4882a593Smuzhiyun u8 count;
443*4882a593Smuzhiyun u16 temp16 = 0;
444*4882a593Smuzhiyun u16 item_count = 0;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (!info) {
449*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /*
453*4882a593Smuzhiyun * First table entry must be ACPI_RSC_INITxxx and must contain the
454*4882a593Smuzhiyun * table length (# of table entries)
455*4882a593Smuzhiyun */
456*4882a593Smuzhiyun count = INIT_TABLE_LENGTH(info);
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun while (count) {
459*4882a593Smuzhiyun /*
460*4882a593Smuzhiyun * Source is the internal resource descriptor,
461*4882a593Smuzhiyun * destination is the external AML byte stream buffer
462*4882a593Smuzhiyun */
463*4882a593Smuzhiyun source = ACPI_ADD_PTR(void, resource, info->resource_offset);
464*4882a593Smuzhiyun destination = ACPI_ADD_PTR(void, aml, info->aml_offset);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun switch (info->opcode) {
467*4882a593Smuzhiyun case ACPI_RSC_INITSET:
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun memset(aml, 0, INIT_RESOURCE_LENGTH(info));
470*4882a593Smuzhiyun aml_length = INIT_RESOURCE_LENGTH(info);
471*4882a593Smuzhiyun acpi_rs_set_resource_header(INIT_RESOURCE_TYPE(info),
472*4882a593Smuzhiyun aml_length, aml);
473*4882a593Smuzhiyun break;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun case ACPI_RSC_INITGET:
476*4882a593Smuzhiyun break;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun case ACPI_RSC_FLAGINIT:
479*4882a593Smuzhiyun /*
480*4882a593Smuzhiyun * Clear the flag byte
481*4882a593Smuzhiyun */
482*4882a593Smuzhiyun ACPI_SET8(destination, 0);
483*4882a593Smuzhiyun break;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun case ACPI_RSC_1BITFLAG:
486*4882a593Smuzhiyun /*
487*4882a593Smuzhiyun * Mask and shift the flag bit
488*4882a593Smuzhiyun */
489*4882a593Smuzhiyun ACPI_SET_BIT(*ACPI_CAST8(destination), (u8)
490*4882a593Smuzhiyun ((ACPI_GET8(source) & 0x01) << info->
491*4882a593Smuzhiyun value));
492*4882a593Smuzhiyun break;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun case ACPI_RSC_2BITFLAG:
495*4882a593Smuzhiyun /*
496*4882a593Smuzhiyun * Mask and shift the flag bits
497*4882a593Smuzhiyun */
498*4882a593Smuzhiyun ACPI_SET_BIT(*ACPI_CAST8(destination), (u8)
499*4882a593Smuzhiyun ((ACPI_GET8(source) & 0x03) << info->
500*4882a593Smuzhiyun value));
501*4882a593Smuzhiyun break;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun case ACPI_RSC_3BITFLAG:
504*4882a593Smuzhiyun /*
505*4882a593Smuzhiyun * Mask and shift the flag bits
506*4882a593Smuzhiyun */
507*4882a593Smuzhiyun ACPI_SET_BIT(*ACPI_CAST8(destination), (u8)
508*4882a593Smuzhiyun ((ACPI_GET8(source) & 0x07) << info->
509*4882a593Smuzhiyun value));
510*4882a593Smuzhiyun break;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun case ACPI_RSC_COUNT:
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun item_count = ACPI_GET8(source);
515*4882a593Smuzhiyun ACPI_SET8(destination, item_count);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun aml_length = (u16)
518*4882a593Smuzhiyun (aml_length + (info->value * (item_count - 1)));
519*4882a593Smuzhiyun break;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun case ACPI_RSC_COUNT16:
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun item_count = ACPI_GET16(source);
524*4882a593Smuzhiyun aml_length = (u16) (aml_length + item_count);
525*4882a593Smuzhiyun acpi_rs_set_resource_length(aml_length, aml);
526*4882a593Smuzhiyun break;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun case ACPI_RSC_COUNT_GPIO_PIN:
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun item_count = ACPI_GET16(source);
531*4882a593Smuzhiyun ACPI_SET16(destination, aml_length);
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun aml_length = (u16)(aml_length + item_count * 2);
534*4882a593Smuzhiyun target = ACPI_ADD_PTR(void, aml, info->value);
535*4882a593Smuzhiyun ACPI_SET16(target, aml_length);
536*4882a593Smuzhiyun acpi_rs_set_resource_length(aml_length, aml);
537*4882a593Smuzhiyun break;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun case ACPI_RSC_COUNT_GPIO_VEN:
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun item_count = ACPI_GET16(source);
542*4882a593Smuzhiyun ACPI_SET16(destination, item_count);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun aml_length =
545*4882a593Smuzhiyun (u16)(aml_length + (info->value * item_count));
546*4882a593Smuzhiyun acpi_rs_set_resource_length(aml_length, aml);
547*4882a593Smuzhiyun break;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun case ACPI_RSC_COUNT_GPIO_RES:
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun /* Set resource source string length */
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun item_count = ACPI_GET16(source);
554*4882a593Smuzhiyun ACPI_SET16(destination, aml_length);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /* Compute offset for the Vendor Data */
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun aml_length = (u16)(aml_length + item_count);
559*4882a593Smuzhiyun target = ACPI_ADD_PTR(void, aml, info->value);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun /* Set vendor offset only if there is vendor data */
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun ACPI_SET16(target, aml_length);
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun acpi_rs_set_resource_length(aml_length, aml);
566*4882a593Smuzhiyun break;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun case ACPI_RSC_COUNT_SERIAL_VEN:
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun item_count = ACPI_GET16(source);
571*4882a593Smuzhiyun ACPI_SET16(destination, item_count + info->value);
572*4882a593Smuzhiyun aml_length = (u16)(aml_length + item_count);
573*4882a593Smuzhiyun acpi_rs_set_resource_length(aml_length, aml);
574*4882a593Smuzhiyun break;
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun case ACPI_RSC_COUNT_SERIAL_RES:
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun item_count = ACPI_GET16(source);
579*4882a593Smuzhiyun aml_length = (u16)(aml_length + item_count);
580*4882a593Smuzhiyun acpi_rs_set_resource_length(aml_length, aml);
581*4882a593Smuzhiyun break;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun case ACPI_RSC_LENGTH:
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun acpi_rs_set_resource_length(info->value, aml);
586*4882a593Smuzhiyun break;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun case ACPI_RSC_MOVE8:
589*4882a593Smuzhiyun case ACPI_RSC_MOVE16:
590*4882a593Smuzhiyun case ACPI_RSC_MOVE32:
591*4882a593Smuzhiyun case ACPI_RSC_MOVE64:
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (info->value) {
594*4882a593Smuzhiyun item_count = info->value;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun acpi_rs_move_data(destination, source, item_count,
597*4882a593Smuzhiyun info->opcode);
598*4882a593Smuzhiyun break;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun case ACPI_RSC_MOVE_GPIO_PIN:
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun destination = (char *)ACPI_ADD_PTR(void, aml,
603*4882a593Smuzhiyun ACPI_GET16
604*4882a593Smuzhiyun (destination));
605*4882a593Smuzhiyun source = *(u16 **)source;
606*4882a593Smuzhiyun acpi_rs_move_data(destination, source, item_count,
607*4882a593Smuzhiyun info->opcode);
608*4882a593Smuzhiyun break;
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun case ACPI_RSC_MOVE_GPIO_RES:
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun /* Used for both resource_source string and vendor_data */
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun destination = (char *)ACPI_ADD_PTR(void, aml,
615*4882a593Smuzhiyun ACPI_GET16
616*4882a593Smuzhiyun (destination));
617*4882a593Smuzhiyun source = *(u8 **)source;
618*4882a593Smuzhiyun acpi_rs_move_data(destination, source, item_count,
619*4882a593Smuzhiyun info->opcode);
620*4882a593Smuzhiyun break;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun case ACPI_RSC_MOVE_SERIAL_VEN:
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun destination = (char *)ACPI_ADD_PTR(void, aml,
625*4882a593Smuzhiyun (aml_length -
626*4882a593Smuzhiyun item_count));
627*4882a593Smuzhiyun source = *(u8 **)source;
628*4882a593Smuzhiyun acpi_rs_move_data(destination, source, item_count,
629*4882a593Smuzhiyun info->opcode);
630*4882a593Smuzhiyun break;
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun case ACPI_RSC_MOVE_SERIAL_RES:
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun destination = (char *)ACPI_ADD_PTR(void, aml,
635*4882a593Smuzhiyun (aml_length -
636*4882a593Smuzhiyun item_count));
637*4882a593Smuzhiyun source = *(u8 **)source;
638*4882a593Smuzhiyun acpi_rs_move_data(destination, source, item_count,
639*4882a593Smuzhiyun info->opcode);
640*4882a593Smuzhiyun break;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun case ACPI_RSC_ADDRESS:
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun /* Set the Resource Type, General Flags, and Type-Specific Flags */
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun acpi_rs_set_address_common(aml, resource);
647*4882a593Smuzhiyun break;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun case ACPI_RSC_SOURCEX:
650*4882a593Smuzhiyun /*
651*4882a593Smuzhiyun * Optional resource_source (Index and String)
652*4882a593Smuzhiyun */
653*4882a593Smuzhiyun aml_length =
654*4882a593Smuzhiyun acpi_rs_set_resource_source(aml,
655*4882a593Smuzhiyun (acpi_rs_length)
656*4882a593Smuzhiyun aml_length, source);
657*4882a593Smuzhiyun acpi_rs_set_resource_length(aml_length, aml);
658*4882a593Smuzhiyun break;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun case ACPI_RSC_SOURCE:
661*4882a593Smuzhiyun /*
662*4882a593Smuzhiyun * Optional resource_source (Index and String). This is the more
663*4882a593Smuzhiyun * complicated case used by the Interrupt() macro
664*4882a593Smuzhiyun */
665*4882a593Smuzhiyun aml_length =
666*4882a593Smuzhiyun acpi_rs_set_resource_source(aml, info->value,
667*4882a593Smuzhiyun source);
668*4882a593Smuzhiyun acpi_rs_set_resource_length(aml_length, aml);
669*4882a593Smuzhiyun break;
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun case ACPI_RSC_BITMASK:
672*4882a593Smuzhiyun /*
673*4882a593Smuzhiyun * 8-bit encoded bitmask (DMA macro)
674*4882a593Smuzhiyun */
675*4882a593Smuzhiyun ACPI_SET8(destination,
676*4882a593Smuzhiyun acpi_rs_encode_bitmask(source,
677*4882a593Smuzhiyun *ACPI_ADD_PTR(u8,
678*4882a593Smuzhiyun resource,
679*4882a593Smuzhiyun info->
680*4882a593Smuzhiyun value)));
681*4882a593Smuzhiyun break;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun case ACPI_RSC_BITMASK16:
684*4882a593Smuzhiyun /*
685*4882a593Smuzhiyun * 16-bit encoded bitmask (IRQ macro)
686*4882a593Smuzhiyun */
687*4882a593Smuzhiyun temp16 =
688*4882a593Smuzhiyun acpi_rs_encode_bitmask(source,
689*4882a593Smuzhiyun *ACPI_ADD_PTR(u8, resource,
690*4882a593Smuzhiyun info->value));
691*4882a593Smuzhiyun ACPI_MOVE_16_TO_16(destination, &temp16);
692*4882a593Smuzhiyun break;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun case ACPI_RSC_EXIT_LE:
695*4882a593Smuzhiyun /*
696*4882a593Smuzhiyun * control - Exit conversion if less than or equal
697*4882a593Smuzhiyun */
698*4882a593Smuzhiyun if (item_count <= info->value) {
699*4882a593Smuzhiyun goto exit;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun break;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun case ACPI_RSC_EXIT_NE:
704*4882a593Smuzhiyun /*
705*4882a593Smuzhiyun * control - Exit conversion if not equal
706*4882a593Smuzhiyun */
707*4882a593Smuzhiyun switch (COMPARE_OPCODE(info)) {
708*4882a593Smuzhiyun case ACPI_RSC_COMPARE_VALUE:
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun if (*ACPI_ADD_PTR(u8, resource,
711*4882a593Smuzhiyun COMPARE_TARGET(info)) !=
712*4882a593Smuzhiyun COMPARE_VALUE(info)) {
713*4882a593Smuzhiyun goto exit;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun break;
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun default:
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun ACPI_ERROR((AE_INFO,
720*4882a593Smuzhiyun "Invalid conversion sub-opcode"));
721*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun break;
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun case ACPI_RSC_EXIT_EQ:
726*4882a593Smuzhiyun /*
727*4882a593Smuzhiyun * control - Exit conversion if equal
728*4882a593Smuzhiyun */
729*4882a593Smuzhiyun if (*ACPI_ADD_PTR(u8, resource,
730*4882a593Smuzhiyun COMPARE_TARGET(info)) ==
731*4882a593Smuzhiyun COMPARE_VALUE(info)) {
732*4882a593Smuzhiyun goto exit;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun break;
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun default:
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun ACPI_ERROR((AE_INFO, "Invalid conversion opcode"));
739*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun count--;
743*4882a593Smuzhiyun info++;
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun exit:
747*4882a593Smuzhiyun return_ACPI_STATUS(AE_OK);
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun #if 0
751*4882a593Smuzhiyun /* Previous resource validations */
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun if (aml->ext_address64.revision_ID != AML_RESOURCE_EXTENDED_ADDRESS_REVISION) {
754*4882a593Smuzhiyun return_ACPI_STATUS(AE_SUPPORT);
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun if (resource->data.start_dpf.performance_robustness >= 3) {
758*4882a593Smuzhiyun return_ACPI_STATUS(AE_AML_BAD_RESOURCE_VALUE);
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun if (((aml->irq.flags & 0x09) == 0x00) || ((aml->irq.flags & 0x09) == 0x09)) {
762*4882a593Smuzhiyun /*
763*4882a593Smuzhiyun * Only [active_high, edge_sensitive] or [active_low, level_sensitive]
764*4882a593Smuzhiyun * polarity/trigger interrupts are allowed (ACPI spec, section
765*4882a593Smuzhiyun * "IRQ Format"), so 0x00 and 0x09 are illegal.
766*4882a593Smuzhiyun */
767*4882a593Smuzhiyun ACPI_ERROR((AE_INFO,
768*4882a593Smuzhiyun "Invalid interrupt polarity/trigger in resource list, 0x%X",
769*4882a593Smuzhiyun aml->irq.flags));
770*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_DATA);
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun resource->data.extended_irq.interrupt_count = temp8;
774*4882a593Smuzhiyun if (temp8 < 1) {
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun /* Must have at least one IRQ */
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun if (resource->data.dma.transfer == 0x03) {
782*4882a593Smuzhiyun ACPI_ERROR((AE_INFO, "Invalid DMA.Transfer preference (3)"));
783*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_DATA);
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun #endif
786