]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: dsfield - Dispatcher field routines | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
25f044e6 | 8 | * Copyright (C) 2000 - 2013, Intel Corp. |
1da177e4 LT |
9 | * All rights reserved. |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions, and the following disclaimer, | |
16 | * without modification. | |
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | |
18 | * substantially similar to the "NO WARRANTY" disclaimer below | |
19 | * ("Disclaimer") and any redistribution must be conditioned upon | |
20 | * including a substantially similar Disclaimer requirement for further | |
21 | * binary redistribution. | |
22 | * 3. Neither the names of the above-listed copyright holders nor the names | |
23 | * of any contributors may be used to endorse or promote products derived | |
24 | * from this software without specific prior written permission. | |
25 | * | |
26 | * Alternatively, this software may be distributed under the terms of the | |
27 | * GNU General Public License ("GPL") version 2 as published by the Free | |
28 | * Software Foundation. | |
29 | * | |
30 | * NO WARRANTY | |
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | |
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
41 | * POSSIBILITY OF SUCH DAMAGES. | |
42 | */ | |
43 | ||
1da177e4 | 44 | #include <acpi/acpi.h> |
e2f7a777 LB |
45 | #include "accommon.h" |
46 | #include "amlcode.h" | |
47 | #include "acdispat.h" | |
48 | #include "acinterp.h" | |
49 | #include "acnamesp.h" | |
50 | #include "acparser.h" | |
1da177e4 | 51 | |
1da177e4 | 52 | #define _COMPONENT ACPI_DISPATCHER |
4be44fcd | 53 | ACPI_MODULE_NAME("dsfield") |
1da177e4 | 54 | |
44f6c012 | 55 | /* Local prototypes */ |
6ccd7b5a BM |
56 | #ifdef ACPI_ASL_COMPILER |
57 | #include "acdisasm.h" | |
58 | static acpi_status | |
59 | acpi_ds_create_external_region(acpi_status lookup_status, | |
60 | union acpi_parse_object *op, | |
61 | char *path, | |
62 | struct acpi_walk_state *walk_state, | |
63 | struct acpi_namespace_node **node); | |
64 | #endif | |
65 | ||
44f6c012 | 66 | static acpi_status |
4be44fcd LB |
67 | acpi_ds_get_field_names(struct acpi_create_field_info *info, |
68 | struct acpi_walk_state *walk_state, | |
69 | union acpi_parse_object *arg); | |
1da177e4 | 70 | |
6ccd7b5a BM |
71 | #ifdef ACPI_ASL_COMPILER |
72 | /******************************************************************************* | |
73 | * | |
ba494bee | 74 | * FUNCTION: acpi_ds_create_external_region (iASL Disassembler only) |
6ccd7b5a BM |
75 | * |
76 | * PARAMETERS: lookup_status - Status from ns_lookup operation | |
ba494bee BM |
77 | * op - Op containing the Field definition and args |
78 | * path - Pathname of the region | |
6ccd7b5a | 79 | * ` walk_state - Current method state |
ba494bee | 80 | * node - Where the new region node is returned |
6ccd7b5a BM |
81 | * |
82 | * RETURN: Status | |
83 | * | |
84 | * DESCRIPTION: Add region to the external list if NOT_FOUND. Create a new | |
85 | * region node/object. | |
86 | * | |
87 | ******************************************************************************/ | |
88 | ||
89 | static acpi_status | |
90 | acpi_ds_create_external_region(acpi_status lookup_status, | |
91 | union acpi_parse_object *op, | |
92 | char *path, | |
93 | struct acpi_walk_state *walk_state, | |
94 | struct acpi_namespace_node **node) | |
95 | { | |
96 | acpi_status status; | |
97 | union acpi_operand_object *obj_desc; | |
98 | ||
99 | if (lookup_status != AE_NOT_FOUND) { | |
100 | return (lookup_status); | |
101 | } | |
102 | ||
103 | /* | |
104 | * Table disassembly: | |
105 | * operation_region not found. Generate an External for it, and | |
106 | * insert the name into the namespace. | |
107 | */ | |
5af2b635 | 108 | acpi_dm_add_op_to_external_list(op, path, ACPI_TYPE_REGION, 0, 0); |
6ccd7b5a BM |
109 | status = acpi_ns_lookup(walk_state->scope_info, path, ACPI_TYPE_REGION, |
110 | ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, | |
111 | walk_state, node); | |
112 | if (ACPI_FAILURE(status)) { | |
113 | return (status); | |
114 | } | |
115 | ||
116 | /* Must create and install a region object for the new node */ | |
117 | ||
118 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION); | |
119 | if (!obj_desc) { | |
120 | return (AE_NO_MEMORY); | |
121 | } | |
122 | ||
123 | obj_desc->region.node = *node; | |
124 | status = acpi_ns_attach_object(*node, obj_desc, ACPI_TYPE_REGION); | |
125 | return (status); | |
126 | } | |
127 | #endif | |
128 | ||
1da177e4 LT |
129 | /******************************************************************************* |
130 | * | |
131 | * FUNCTION: acpi_ds_create_buffer_field | |
132 | * | |
ba494bee | 133 | * PARAMETERS: op - Current parse op (create_XXField) |
1da177e4 LT |
134 | * walk_state - Current state |
135 | * | |
136 | * RETURN: Status | |
137 | * | |
138 | * DESCRIPTION: Execute the create_field operators: | |
139 | * create_bit_field_op, | |
140 | * create_byte_field_op, | |
141 | * create_word_field_op, | |
142 | * create_dword_field_op, | |
143 | * create_qword_field_op, | |
44f6c012 | 144 | * create_field_op (all of which define a field in a buffer) |
1da177e4 LT |
145 | * |
146 | ******************************************************************************/ | |
147 | ||
148 | acpi_status | |
4be44fcd LB |
149 | acpi_ds_create_buffer_field(union acpi_parse_object *op, |
150 | struct acpi_walk_state *walk_state) | |
1da177e4 | 151 | { |
4be44fcd LB |
152 | union acpi_parse_object *arg; |
153 | struct acpi_namespace_node *node; | |
154 | acpi_status status; | |
155 | union acpi_operand_object *obj_desc; | |
156 | union acpi_operand_object *second_desc = NULL; | |
157 | u32 flags; | |
1da177e4 | 158 | |
b229cf92 | 159 | ACPI_FUNCTION_TRACE(ds_create_buffer_field); |
1da177e4 | 160 | |
cca97b81 BM |
161 | /* |
162 | * Get the name_string argument (name of the new buffer_field) | |
163 | */ | |
1da177e4 | 164 | if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { |
cca97b81 BM |
165 | |
166 | /* For create_field, name is the 4th argument */ | |
167 | ||
4be44fcd LB |
168 | arg = acpi_ps_get_arg(op, 3); |
169 | } else { | |
ba494bee | 170 | /* For all other create_XXXField operators, name is the 3rd argument */ |
1da177e4 | 171 | |
4be44fcd | 172 | arg = acpi_ps_get_arg(op, 2); |
1da177e4 LT |
173 | } |
174 | ||
175 | if (!arg) { | |
4be44fcd | 176 | return_ACPI_STATUS(AE_AML_NO_OPERAND); |
1da177e4 LT |
177 | } |
178 | ||
179 | if (walk_state->deferred_node) { | |
180 | node = walk_state->deferred_node; | |
181 | status = AE_OK; | |
4be44fcd | 182 | } else { |
cca97b81 BM |
183 | /* Execute flag should always be set when this function is entered */ |
184 | ||
185 | if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { | |
186 | return_ACPI_STATUS(AE_AML_INTERNAL); | |
1da177e4 LT |
187 | } |
188 | ||
cca97b81 BM |
189 | /* Creating new namespace node, should not already exist */ |
190 | ||
191 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | | |
192 | ACPI_NS_ERROR_IF_FOUND; | |
193 | ||
7f0c826a LM |
194 | /* |
195 | * Mark node temporary if we are executing a normal control | |
196 | * method. (Don't mark if this is a module-level code method) | |
197 | */ | |
198 | if (walk_state->method_node && | |
199 | !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) { | |
cca97b81 BM |
200 | flags |= ACPI_NS_TEMPORARY; |
201 | } | |
202 | ||
203 | /* Enter the name_string into the namespace */ | |
204 | ||
4be44fcd LB |
205 | status = |
206 | acpi_ns_lookup(walk_state->scope_info, | |
207 | arg->common.value.string, ACPI_TYPE_ANY, | |
208 | ACPI_IMODE_LOAD_PASS1, flags, walk_state, | |
cca97b81 | 209 | &node); |
4be44fcd | 210 | if (ACPI_FAILURE(status)) { |
b8e4d893 | 211 | ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
4be44fcd | 212 | return_ACPI_STATUS(status); |
1da177e4 LT |
213 | } |
214 | } | |
215 | ||
9c52657a BM |
216 | /* |
217 | * We could put the returned object (Node) on the object stack for later, | |
44f6c012 | 218 | * but for now, we will put it in the "op" object that the parser uses, |
cca97b81 | 219 | * so we can get it again at the end of this scope. |
1da177e4 LT |
220 | */ |
221 | op->common.node = node; | |
222 | ||
223 | /* | |
44f6c012 | 224 | * If there is no object attached to the node, this node was just created |
cca97b81 | 225 | * and we need to create the field object. Otherwise, this was a lookup |
44f6c012 | 226 | * of an existing node and we don't want to create the field object again. |
1da177e4 | 227 | */ |
4be44fcd | 228 | obj_desc = acpi_ns_get_attached_object(node); |
1da177e4 | 229 | if (obj_desc) { |
4be44fcd | 230 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
231 | } |
232 | ||
233 | /* | |
234 | * The Field definition is not fully parsed at this time. | |
235 | * (We must save the address of the AML for the buffer and index operands) | |
236 | */ | |
237 | ||
238 | /* Create the buffer field object */ | |
239 | ||
4be44fcd | 240 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER_FIELD); |
1da177e4 LT |
241 | if (!obj_desc) { |
242 | status = AE_NO_MEMORY; | |
243 | goto cleanup; | |
244 | } | |
245 | ||
246 | /* | |
cca97b81 BM |
247 | * Remember location in AML stream of the field unit opcode and operands -- |
248 | * since the buffer and index operands must be evaluated. | |
1da177e4 | 249 | */ |
4be44fcd | 250 | second_desc = obj_desc->common.next_object; |
1da177e4 LT |
251 | second_desc->extra.aml_start = op->named.data; |
252 | second_desc->extra.aml_length = op->named.length; | |
253 | obj_desc->buffer_field.node = node; | |
254 | ||
255 | /* Attach constructed field descriptors to parent node */ | |
256 | ||
4be44fcd LB |
257 | status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_BUFFER_FIELD); |
258 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
259 | goto cleanup; |
260 | } | |
261 | ||
10622bf8 | 262 | cleanup: |
1da177e4 LT |
263 | |
264 | /* Remove local reference to the object */ | |
265 | ||
4be44fcd LB |
266 | acpi_ut_remove_reference(obj_desc); |
267 | return_ACPI_STATUS(status); | |
1da177e4 LT |
268 | } |
269 | ||
1da177e4 LT |
270 | /******************************************************************************* |
271 | * | |
272 | * FUNCTION: acpi_ds_get_field_names | |
273 | * | |
ba494bee | 274 | * PARAMETERS: info - create_field info structure |
1da177e4 | 275 | * ` walk_state - Current method state |
ba494bee | 276 | * arg - First parser arg for the field name list |
1da177e4 LT |
277 | * |
278 | * RETURN: Status | |
279 | * | |
73a3090a | 280 | * DESCRIPTION: Process all named fields in a field declaration. Names are |
1da177e4 LT |
281 | * entered into the namespace. |
282 | * | |
283 | ******************************************************************************/ | |
284 | ||
44f6c012 | 285 | static acpi_status |
4be44fcd LB |
286 | acpi_ds_get_field_names(struct acpi_create_field_info *info, |
287 | struct acpi_walk_state *walk_state, | |
288 | union acpi_parse_object *arg) | |
1da177e4 | 289 | { |
4be44fcd | 290 | acpi_status status; |
5df7e6cb | 291 | u64 position; |
9ce81784 | 292 | union acpi_parse_object *child; |
1da177e4 | 293 | |
b229cf92 | 294 | ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info); |
1da177e4 LT |
295 | |
296 | /* First field starts at bit zero */ | |
297 | ||
298 | info->field_bit_position = 0; | |
299 | ||
300 | /* Process all elements in the field list (of parse nodes) */ | |
301 | ||
302 | while (arg) { | |
303 | /* | |
9ce81784 | 304 | * Four types of field elements are handled: |
ba494bee BM |
305 | * 1) name - Enters a new named field into the namespace |
306 | * 2) offset - specifies a bit offset | |
9ce81784 | 307 | * 3) access_as - changes the access mode/attributes |
ba494bee | 308 | * 4) connection - Associate a resource template with the field |
1da177e4 LT |
309 | */ |
310 | switch (arg->common.aml_opcode) { | |
311 | case AML_INT_RESERVEDFIELD_OP: | |
312 | ||
5df7e6cb BM |
313 | position = (u64) info->field_bit_position |
314 | + (u64) arg->common.value.size; | |
1da177e4 LT |
315 | |
316 | if (position > ACPI_UINT32_MAX) { | |
b8e4d893 BM |
317 | ACPI_ERROR((AE_INFO, |
318 | "Bit offset within field too large (> 0xFFFFFFFF)")); | |
4be44fcd | 319 | return_ACPI_STATUS(AE_SUPPORT); |
1da177e4 LT |
320 | } |
321 | ||
322 | info->field_bit_position = (u32) position; | |
323 | break; | |
324 | ||
1da177e4 | 325 | case AML_INT_ACCESSFIELD_OP: |
9ce81784 | 326 | case AML_INT_EXTACCESSFIELD_OP: |
1da177e4 | 327 | /* |
9ce81784 BM |
328 | * Get new access_type, access_attribute, and access_length fields |
329 | * -- to be used for all field units that follow, until the | |
330 | * end-of-field or another access_as keyword is encountered. | |
331 | * NOTE. These three bytes are encoded in the integer value | |
332 | * of the parseop for convenience. | |
1da177e4 | 333 | * |
44f6c012 | 334 | * In field_flags, preserve the flag bits other than the |
9ce81784 | 335 | * ACCESS_TYPE bits. |
1da177e4 | 336 | */ |
9ce81784 BM |
337 | |
338 | /* access_type (byte_acc, word_acc, etc.) */ | |
339 | ||
44f6c012 | 340 | info->field_flags = (u8) |
4be44fcd LB |
341 | ((info-> |
342 | field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | | |
9ce81784 BM |
343 | ((u8)((u32)(arg->common.value.integer & 0x07)))); |
344 | ||
345 | /* access_attribute (attrib_quick, attrib_byte, etc.) */ | |
346 | ||
347 | info->attribute = | |
348 | (u8)((arg->common.value.integer >> 8) & 0xFF); | |
349 | ||
350 | /* access_length (for serial/buffer protocols) */ | |
351 | ||
352 | info->access_length = | |
353 | (u8)((arg->common.value.integer >> 16) & 0xFF); | |
354 | break; | |
355 | ||
356 | case AML_INT_CONNECTION_OP: | |
357 | /* | |
358 | * Clear any previous connection. New connection is used for all | |
359 | * fields that follow, similar to access_as | |
360 | */ | |
361 | info->resource_buffer = NULL; | |
362 | info->connection_node = NULL; | |
1da177e4 | 363 | |
9ce81784 BM |
364 | /* |
365 | * A Connection() is either an actual resource descriptor (buffer) | |
366 | * or a named reference to a resource template | |
367 | */ | |
368 | child = arg->common.value.arg; | |
369 | if (child->common.aml_opcode == AML_INT_BYTELIST_OP) { | |
370 | info->resource_buffer = child->named.data; | |
371 | info->resource_length = | |
372 | (u16)child->named.value.integer; | |
373 | } else { | |
374 | /* Lookup the Connection() namepath, it should already exist */ | |
375 | ||
376 | status = acpi_ns_lookup(walk_state->scope_info, | |
377 | child->common.value. | |
378 | name, ACPI_TYPE_ANY, | |
379 | ACPI_IMODE_EXECUTE, | |
380 | ACPI_NS_DONT_OPEN_SCOPE, | |
381 | walk_state, | |
382 | &info->connection_node); | |
383 | if (ACPI_FAILURE(status)) { | |
384 | ACPI_ERROR_NAMESPACE(child->common. | |
385 | value.name, | |
386 | status); | |
387 | return_ACPI_STATUS(status); | |
388 | } | |
389 | } | |
1da177e4 LT |
390 | break; |
391 | ||
1da177e4 LT |
392 | case AML_INT_NAMEDFIELD_OP: |
393 | ||
cca97b81 | 394 | /* Lookup the name, it should already exist */ |
1da177e4 | 395 | |
4be44fcd LB |
396 | status = acpi_ns_lookup(walk_state->scope_info, |
397 | (char *)&arg->named.name, | |
398 | info->field_type, | |
399 | ACPI_IMODE_EXECUTE, | |
400 | ACPI_NS_DONT_OPEN_SCOPE, | |
401 | walk_state, &info->field_node); | |
402 | if (ACPI_FAILURE(status)) { | |
b8e4d893 BM |
403 | ACPI_ERROR_NAMESPACE((char *)&arg->named.name, |
404 | status); | |
cca97b81 | 405 | return_ACPI_STATUS(status); |
4be44fcd | 406 | } else { |
1da177e4 LT |
407 | arg->common.node = info->field_node; |
408 | info->field_bit_length = arg->common.value.size; | |
409 | ||
ef805d95 | 410 | /* |
cca97b81 BM |
411 | * If there is no object attached to the node, this node was |
412 | * just created and we need to create the field object. | |
413 | * Otherwise, this was a lookup of an existing node and we | |
414 | * don't want to create the field object again. | |
ef805d95 LM |
415 | */ |
416 | if (!acpi_ns_get_attached_object | |
417 | (info->field_node)) { | |
418 | status = acpi_ex_prep_field_value(info); | |
419 | if (ACPI_FAILURE(status)) { | |
420 | return_ACPI_STATUS(status); | |
421 | } | |
1da177e4 LT |
422 | } |
423 | } | |
424 | ||
425 | /* Keep track of bit position for the next field */ | |
426 | ||
5df7e6cb BM |
427 | position = (u64) info->field_bit_position |
428 | + (u64) arg->common.value.size; | |
1da177e4 LT |
429 | |
430 | if (position > ACPI_UINT32_MAX) { | |
b8e4d893 BM |
431 | ACPI_ERROR((AE_INFO, |
432 | "Field [%4.4s] bit offset too large (> 0xFFFFFFFF)", | |
433 | ACPI_CAST_PTR(char, | |
434 | &info->field_node-> | |
435 | name))); | |
4be44fcd | 436 | return_ACPI_STATUS(AE_SUPPORT); |
1da177e4 LT |
437 | } |
438 | ||
439 | info->field_bit_position += info->field_bit_length; | |
440 | break; | |
441 | ||
1da177e4 LT |
442 | default: |
443 | ||
b8e4d893 | 444 | ACPI_ERROR((AE_INFO, |
f6a22b0b | 445 | "Invalid opcode in field list: 0x%X", |
b8e4d893 | 446 | arg->common.aml_opcode)); |
4be44fcd | 447 | return_ACPI_STATUS(AE_AML_BAD_OPCODE); |
1da177e4 LT |
448 | } |
449 | ||
450 | arg = arg->common.next; | |
451 | } | |
452 | ||
4be44fcd | 453 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
454 | } |
455 | ||
1da177e4 LT |
456 | /******************************************************************************* |
457 | * | |
458 | * FUNCTION: acpi_ds_create_field | |
459 | * | |
ba494bee | 460 | * PARAMETERS: op - Op containing the Field definition and args |
1da177e4 LT |
461 | * region_node - Object for the containing Operation Region |
462 | * ` walk_state - Current method state | |
463 | * | |
464 | * RETURN: Status | |
465 | * | |
466 | * DESCRIPTION: Create a new field in the specified operation region | |
467 | * | |
468 | ******************************************************************************/ | |
469 | ||
470 | acpi_status | |
4be44fcd LB |
471 | acpi_ds_create_field(union acpi_parse_object *op, |
472 | struct acpi_namespace_node *region_node, | |
473 | struct acpi_walk_state *walk_state) | |
1da177e4 | 474 | { |
4be44fcd LB |
475 | acpi_status status; |
476 | union acpi_parse_object *arg; | |
477 | struct acpi_create_field_info info; | |
1da177e4 | 478 | |
b229cf92 | 479 | ACPI_FUNCTION_TRACE_PTR(ds_create_field, op); |
1da177e4 LT |
480 | |
481 | /* First arg is the name of the parent op_region (must already exist) */ | |
482 | ||
483 | arg = op->common.value.arg; | |
6ccd7b5a | 484 | |
1da177e4 | 485 | if (!region_node) { |
4be44fcd LB |
486 | status = |
487 | acpi_ns_lookup(walk_state->scope_info, | |
488 | arg->common.value.name, ACPI_TYPE_REGION, | |
489 | ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, | |
490 | walk_state, ®ion_node); | |
6ccd7b5a BM |
491 | #ifdef ACPI_ASL_COMPILER |
492 | status = acpi_ds_create_external_region(status, arg, | |
493 | arg->common.value.name, | |
494 | walk_state, | |
495 | ®ion_node); | |
496 | #endif | |
4be44fcd | 497 | if (ACPI_FAILURE(status)) { |
b8e4d893 | 498 | ACPI_ERROR_NAMESPACE(arg->common.value.name, status); |
4be44fcd | 499 | return_ACPI_STATUS(status); |
1da177e4 LT |
500 | } |
501 | } | |
502 | ||
9ce81784 BM |
503 | ACPI_MEMSET(&info, 0, sizeof(struct acpi_create_field_info)); |
504 | ||
1da177e4 LT |
505 | /* Second arg is the field flags */ |
506 | ||
507 | arg = arg->common.next; | |
508 | info.field_flags = (u8) arg->common.value.integer; | |
509 | info.attribute = 0; | |
510 | ||
511 | /* Each remaining arg is a Named Field */ | |
512 | ||
513 | info.field_type = ACPI_TYPE_LOCAL_REGION_FIELD; | |
514 | info.region_node = region_node; | |
515 | ||
4be44fcd | 516 | status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); |
4be44fcd | 517 | return_ACPI_STATUS(status); |
1da177e4 LT |
518 | } |
519 | ||
1da177e4 LT |
520 | /******************************************************************************* |
521 | * | |
522 | * FUNCTION: acpi_ds_init_field_objects | |
523 | * | |
ba494bee | 524 | * PARAMETERS: op - Op containing the Field definition and args |
1da177e4 LT |
525 | * ` walk_state - Current method state |
526 | * | |
527 | * RETURN: Status | |
528 | * | |
529 | * DESCRIPTION: For each "Field Unit" name in the argument list that is | |
530 | * part of the field declaration, enter the name into the | |
531 | * namespace. | |
532 | * | |
533 | ******************************************************************************/ | |
534 | ||
535 | acpi_status | |
4be44fcd LB |
536 | acpi_ds_init_field_objects(union acpi_parse_object *op, |
537 | struct acpi_walk_state *walk_state) | |
1da177e4 | 538 | { |
4be44fcd LB |
539 | acpi_status status; |
540 | union acpi_parse_object *arg = NULL; | |
541 | struct acpi_namespace_node *node; | |
542 | u8 type = 0; | |
ef805d95 | 543 | u32 flags; |
1da177e4 | 544 | |
b229cf92 | 545 | ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op); |
1da177e4 | 546 | |
cca97b81 BM |
547 | /* Execute flag should always be set when this function is entered */ |
548 | ||
549 | if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) { | |
550 | if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) { | |
551 | ||
552 | /* bank_field Op is deferred, just return OK */ | |
553 | ||
554 | return_ACPI_STATUS(AE_OK); | |
555 | } | |
556 | ||
557 | return_ACPI_STATUS(AE_AML_INTERNAL); | |
ef805d95 LM |
558 | } |
559 | ||
cca97b81 BM |
560 | /* |
561 | * Get the field_list argument for this opcode. This is the start of the | |
562 | * list of field elements. | |
563 | */ | |
1da177e4 LT |
564 | switch (walk_state->opcode) { |
565 | case AML_FIELD_OP: | |
1d1ea1b7 | 566 | |
4be44fcd | 567 | arg = acpi_ps_get_arg(op, 2); |
1da177e4 LT |
568 | type = ACPI_TYPE_LOCAL_REGION_FIELD; |
569 | break; | |
570 | ||
571 | case AML_BANK_FIELD_OP: | |
1d1ea1b7 | 572 | |
4be44fcd | 573 | arg = acpi_ps_get_arg(op, 4); |
1da177e4 LT |
574 | type = ACPI_TYPE_LOCAL_BANK_FIELD; |
575 | break; | |
576 | ||
577 | case AML_INDEX_FIELD_OP: | |
1d1ea1b7 | 578 | |
4be44fcd | 579 | arg = acpi_ps_get_arg(op, 3); |
1da177e4 LT |
580 | type = ACPI_TYPE_LOCAL_INDEX_FIELD; |
581 | break; | |
582 | ||
583 | default: | |
1d1ea1b7 | 584 | |
4be44fcd | 585 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
1da177e4 LT |
586 | } |
587 | ||
cca97b81 BM |
588 | /* Creating new namespace node(s), should not already exist */ |
589 | ||
590 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | | |
591 | ACPI_NS_ERROR_IF_FOUND; | |
592 | ||
7f0c826a LM |
593 | /* |
594 | * Mark node(s) temporary if we are executing a normal control | |
595 | * method. (Don't mark if this is a module-level code method) | |
596 | */ | |
597 | if (walk_state->method_node && | |
598 | !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) { | |
cca97b81 BM |
599 | flags |= ACPI_NS_TEMPORARY; |
600 | } | |
601 | ||
1da177e4 LT |
602 | /* |
603 | * Walk the list of entries in the field_list | |
7aa7d433 | 604 | * Note: field_list can be of zero length. In this case, Arg will be NULL. |
1da177e4 LT |
605 | */ |
606 | while (arg) { | |
cca97b81 | 607 | /* |
9ce81784 BM |
608 | * Ignore OFFSET/ACCESSAS/CONNECTION terms here; we are only interested |
609 | * in the field names in order to enter them into the namespace. | |
cca97b81 | 610 | */ |
1da177e4 | 611 | if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { |
4be44fcd | 612 | status = acpi_ns_lookup(walk_state->scope_info, |
cca97b81 BM |
613 | (char *)&arg->named.name, type, |
614 | ACPI_IMODE_LOAD_PASS1, flags, | |
615 | walk_state, &node); | |
4be44fcd | 616 | if (ACPI_FAILURE(status)) { |
b8e4d893 BM |
617 | ACPI_ERROR_NAMESPACE((char *)&arg->named.name, |
618 | status); | |
1da177e4 | 619 | if (status != AE_ALREADY_EXISTS) { |
4be44fcd | 620 | return_ACPI_STATUS(status); |
1da177e4 LT |
621 | } |
622 | ||
623 | /* Name already exists, just ignore this error */ | |
624 | ||
625 | status = AE_OK; | |
626 | } | |
627 | ||
628 | arg->common.node = node; | |
629 | } | |
630 | ||
cca97b81 | 631 | /* Get the next field element in the list */ |
1da177e4 LT |
632 | |
633 | arg = arg->common.next; | |
634 | } | |
635 | ||
4be44fcd | 636 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
637 | } |
638 | ||
1da177e4 LT |
639 | /******************************************************************************* |
640 | * | |
641 | * FUNCTION: acpi_ds_create_bank_field | |
642 | * | |
ba494bee | 643 | * PARAMETERS: op - Op containing the Field definition and args |
1da177e4 | 644 | * region_node - Object for the containing Operation Region |
ef805d95 | 645 | * walk_state - Current method state |
1da177e4 LT |
646 | * |
647 | * RETURN: Status | |
648 | * | |
649 | * DESCRIPTION: Create a new bank field in the specified operation region | |
650 | * | |
651 | ******************************************************************************/ | |
652 | ||
653 | acpi_status | |
4be44fcd LB |
654 | acpi_ds_create_bank_field(union acpi_parse_object *op, |
655 | struct acpi_namespace_node *region_node, | |
656 | struct acpi_walk_state *walk_state) | |
1da177e4 | 657 | { |
4be44fcd LB |
658 | acpi_status status; |
659 | union acpi_parse_object *arg; | |
660 | struct acpi_create_field_info info; | |
1da177e4 | 661 | |
b229cf92 | 662 | ACPI_FUNCTION_TRACE_PTR(ds_create_bank_field, op); |
1da177e4 LT |
663 | |
664 | /* First arg is the name of the parent op_region (must already exist) */ | |
665 | ||
666 | arg = op->common.value.arg; | |
667 | if (!region_node) { | |
4be44fcd LB |
668 | status = |
669 | acpi_ns_lookup(walk_state->scope_info, | |
670 | arg->common.value.name, ACPI_TYPE_REGION, | |
671 | ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, | |
672 | walk_state, ®ion_node); | |
6ccd7b5a BM |
673 | #ifdef ACPI_ASL_COMPILER |
674 | status = acpi_ds_create_external_region(status, arg, | |
675 | arg->common.value.name, | |
676 | walk_state, | |
677 | ®ion_node); | |
678 | #endif | |
4be44fcd | 679 | if (ACPI_FAILURE(status)) { |
b8e4d893 | 680 | ACPI_ERROR_NAMESPACE(arg->common.value.name, status); |
4be44fcd | 681 | return_ACPI_STATUS(status); |
1da177e4 LT |
682 | } |
683 | } | |
684 | ||
685 | /* Second arg is the Bank Register (Field) (must already exist) */ | |
686 | ||
687 | arg = arg->common.next; | |
4be44fcd LB |
688 | status = |
689 | acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, | |
690 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | |
691 | ACPI_NS_SEARCH_PARENT, walk_state, | |
692 | &info.register_node); | |
693 | if (ACPI_FAILURE(status)) { | |
b8e4d893 | 694 | ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
4be44fcd | 695 | return_ACPI_STATUS(status); |
1da177e4 LT |
696 | } |
697 | ||
ef805d95 LM |
698 | /* |
699 | * Third arg is the bank_value | |
700 | * This arg is a term_arg, not a constant | |
701 | * It will be evaluated later, by acpi_ds_eval_bank_field_operands | |
702 | */ | |
1da177e4 | 703 | arg = arg->common.next; |
9c52657a | 704 | |
1da177e4 LT |
705 | /* Fourth arg is the field flags */ |
706 | ||
707 | arg = arg->common.next; | |
708 | info.field_flags = (u8) arg->common.value.integer; | |
709 | ||
710 | /* Each remaining arg is a Named Field */ | |
711 | ||
712 | info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD; | |
713 | info.region_node = region_node; | |
714 | ||
ef805d95 LM |
715 | /* |
716 | * Use Info.data_register_node to store bank_field Op | |
717 | * It's safe because data_register_node will never be used when create bank field | |
718 | * We store aml_start and aml_length in the bank_field Op for late evaluation | |
719 | * Used in acpi_ex_prep_field_value(Info) | |
720 | * | |
721 | * TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"? | |
722 | */ | |
723 | info.data_register_node = (struct acpi_namespace_node *)op; | |
1da177e4 | 724 | |
ef805d95 | 725 | status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); |
4be44fcd | 726 | return_ACPI_STATUS(status); |
1da177e4 LT |
727 | } |
728 | ||
1da177e4 LT |
729 | /******************************************************************************* |
730 | * | |
731 | * FUNCTION: acpi_ds_create_index_field | |
732 | * | |
ba494bee | 733 | * PARAMETERS: op - Op containing the Field definition and args |
1da177e4 LT |
734 | * region_node - Object for the containing Operation Region |
735 | * ` walk_state - Current method state | |
736 | * | |
737 | * RETURN: Status | |
738 | * | |
739 | * DESCRIPTION: Create a new index field in the specified operation region | |
740 | * | |
741 | ******************************************************************************/ | |
742 | ||
743 | acpi_status | |
4be44fcd LB |
744 | acpi_ds_create_index_field(union acpi_parse_object *op, |
745 | struct acpi_namespace_node *region_node, | |
746 | struct acpi_walk_state *walk_state) | |
1da177e4 | 747 | { |
4be44fcd LB |
748 | acpi_status status; |
749 | union acpi_parse_object *arg; | |
750 | struct acpi_create_field_info info; | |
1da177e4 | 751 | |
b229cf92 | 752 | ACPI_FUNCTION_TRACE_PTR(ds_create_index_field, op); |
1da177e4 LT |
753 | |
754 | /* First arg is the name of the Index register (must already exist) */ | |
755 | ||
756 | arg = op->common.value.arg; | |
4be44fcd LB |
757 | status = |
758 | acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, | |
759 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | |
760 | ACPI_NS_SEARCH_PARENT, walk_state, | |
761 | &info.register_node); | |
762 | if (ACPI_FAILURE(status)) { | |
b8e4d893 | 763 | ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
4be44fcd | 764 | return_ACPI_STATUS(status); |
1da177e4 LT |
765 | } |
766 | ||
767 | /* Second arg is the data register (must already exist) */ | |
768 | ||
769 | arg = arg->common.next; | |
4be44fcd LB |
770 | status = |
771 | acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, | |
772 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | |
773 | ACPI_NS_SEARCH_PARENT, walk_state, | |
774 | &info.data_register_node); | |
775 | if (ACPI_FAILURE(status)) { | |
b8e4d893 | 776 | ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
4be44fcd | 777 | return_ACPI_STATUS(status); |
1da177e4 LT |
778 | } |
779 | ||
780 | /* Next arg is the field flags */ | |
781 | ||
782 | arg = arg->common.next; | |
783 | info.field_flags = (u8) arg->common.value.integer; | |
784 | ||
785 | /* Each remaining arg is a Named Field */ | |
786 | ||
787 | info.field_type = ACPI_TYPE_LOCAL_INDEX_FIELD; | |
788 | info.region_node = region_node; | |
789 | ||
4be44fcd | 790 | status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); |
4be44fcd | 791 | return_ACPI_STATUS(status); |
1da177e4 | 792 | } |