]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: dsfield - Dispatcher field routines | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
77848130 | 8 | * Copyright (C) 2000 - 2012, 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 | * | |
74 | * FUNCTION: acpi_ds_create_external_region (i_aSL Disassembler only) | |
75 | * | |
76 | * PARAMETERS: lookup_status - Status from ns_lookup operation | |
77 | * Op - Op containing the Field definition and args | |
78 | * Path - Pathname of the region | |
79 | * ` walk_state - Current method state | |
80 | * Node - Where the new region node is returned | |
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 | */ | |
108 | acpi_dm_add_to_external_list(op, path, ACPI_TYPE_REGION, 0); | |
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 | * | |
44f6c012 | 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 { | |
cca97b81 | 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 | ||
4be44fcd | 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 | * | |
274 | * PARAMETERS: Info - create_field info structure | |
275 | * ` walk_state - Current method state | |
276 | * Arg - First parser arg for the field name list | |
277 | * | |
278 | * RETURN: Status | |
279 | * | |
280 | * DESCRIPTION: Process all named fields in a field declaration. Names are | |
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 BM |
304 | * Four types of field elements are handled: |
305 | * 1) Name - Enters a new named field into the namespace | |
306 | * 2) Offset - specifies a bit offset | |
307 | * 3) access_as - changes the access mode/attributes | |
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 | * | |
460 | * PARAMETERS: Op - Op containing the Field definition and args | |
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 | * | |
524 | * PARAMETERS: Op - Op containing the Field definition and args | |
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: | |
4be44fcd | 566 | arg = acpi_ps_get_arg(op, 2); |
1da177e4 LT |
567 | type = ACPI_TYPE_LOCAL_REGION_FIELD; |
568 | break; | |
569 | ||
570 | case AML_BANK_FIELD_OP: | |
4be44fcd | 571 | arg = acpi_ps_get_arg(op, 4); |
1da177e4 LT |
572 | type = ACPI_TYPE_LOCAL_BANK_FIELD; |
573 | break; | |
574 | ||
575 | case AML_INDEX_FIELD_OP: | |
4be44fcd | 576 | arg = acpi_ps_get_arg(op, 3); |
1da177e4 LT |
577 | type = ACPI_TYPE_LOCAL_INDEX_FIELD; |
578 | break; | |
579 | ||
580 | default: | |
4be44fcd | 581 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
1da177e4 LT |
582 | } |
583 | ||
cca97b81 BM |
584 | /* Creating new namespace node(s), should not already exist */ |
585 | ||
586 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | | |
587 | ACPI_NS_ERROR_IF_FOUND; | |
588 | ||
7f0c826a LM |
589 | /* |
590 | * Mark node(s) temporary if we are executing a normal control | |
591 | * method. (Don't mark if this is a module-level code method) | |
592 | */ | |
593 | if (walk_state->method_node && | |
594 | !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) { | |
cca97b81 BM |
595 | flags |= ACPI_NS_TEMPORARY; |
596 | } | |
597 | ||
1da177e4 LT |
598 | /* |
599 | * Walk the list of entries in the field_list | |
7aa7d433 | 600 | * Note: field_list can be of zero length. In this case, Arg will be NULL. |
1da177e4 LT |
601 | */ |
602 | while (arg) { | |
cca97b81 | 603 | /* |
9ce81784 BM |
604 | * Ignore OFFSET/ACCESSAS/CONNECTION terms here; we are only interested |
605 | * in the field names in order to enter them into the namespace. | |
cca97b81 | 606 | */ |
1da177e4 | 607 | if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { |
4be44fcd | 608 | status = acpi_ns_lookup(walk_state->scope_info, |
cca97b81 BM |
609 | (char *)&arg->named.name, type, |
610 | ACPI_IMODE_LOAD_PASS1, flags, | |
611 | walk_state, &node); | |
4be44fcd | 612 | if (ACPI_FAILURE(status)) { |
b8e4d893 BM |
613 | ACPI_ERROR_NAMESPACE((char *)&arg->named.name, |
614 | status); | |
1da177e4 | 615 | if (status != AE_ALREADY_EXISTS) { |
4be44fcd | 616 | return_ACPI_STATUS(status); |
1da177e4 LT |
617 | } |
618 | ||
619 | /* Name already exists, just ignore this error */ | |
620 | ||
621 | status = AE_OK; | |
622 | } | |
623 | ||
624 | arg->common.node = node; | |
625 | } | |
626 | ||
cca97b81 | 627 | /* Get the next field element in the list */ |
1da177e4 LT |
628 | |
629 | arg = arg->common.next; | |
630 | } | |
631 | ||
4be44fcd | 632 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
633 | } |
634 | ||
1da177e4 LT |
635 | /******************************************************************************* |
636 | * | |
637 | * FUNCTION: acpi_ds_create_bank_field | |
638 | * | |
639 | * PARAMETERS: Op - Op containing the Field definition and args | |
640 | * region_node - Object for the containing Operation Region | |
ef805d95 | 641 | * walk_state - Current method state |
1da177e4 LT |
642 | * |
643 | * RETURN: Status | |
644 | * | |
645 | * DESCRIPTION: Create a new bank field in the specified operation region | |
646 | * | |
647 | ******************************************************************************/ | |
648 | ||
649 | acpi_status | |
4be44fcd LB |
650 | acpi_ds_create_bank_field(union acpi_parse_object *op, |
651 | struct acpi_namespace_node *region_node, | |
652 | struct acpi_walk_state *walk_state) | |
1da177e4 | 653 | { |
4be44fcd LB |
654 | acpi_status status; |
655 | union acpi_parse_object *arg; | |
656 | struct acpi_create_field_info info; | |
1da177e4 | 657 | |
b229cf92 | 658 | ACPI_FUNCTION_TRACE_PTR(ds_create_bank_field, op); |
1da177e4 LT |
659 | |
660 | /* First arg is the name of the parent op_region (must already exist) */ | |
661 | ||
662 | arg = op->common.value.arg; | |
663 | if (!region_node) { | |
4be44fcd LB |
664 | status = |
665 | acpi_ns_lookup(walk_state->scope_info, | |
666 | arg->common.value.name, ACPI_TYPE_REGION, | |
667 | ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, | |
668 | walk_state, ®ion_node); | |
6ccd7b5a BM |
669 | #ifdef ACPI_ASL_COMPILER |
670 | status = acpi_ds_create_external_region(status, arg, | |
671 | arg->common.value.name, | |
672 | walk_state, | |
673 | ®ion_node); | |
674 | #endif | |
4be44fcd | 675 | if (ACPI_FAILURE(status)) { |
b8e4d893 | 676 | ACPI_ERROR_NAMESPACE(arg->common.value.name, status); |
4be44fcd | 677 | return_ACPI_STATUS(status); |
1da177e4 LT |
678 | } |
679 | } | |
680 | ||
681 | /* Second arg is the Bank Register (Field) (must already exist) */ | |
682 | ||
683 | arg = arg->common.next; | |
4be44fcd LB |
684 | status = |
685 | acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, | |
686 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | |
687 | ACPI_NS_SEARCH_PARENT, walk_state, | |
688 | &info.register_node); | |
689 | if (ACPI_FAILURE(status)) { | |
b8e4d893 | 690 | ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
4be44fcd | 691 | return_ACPI_STATUS(status); |
1da177e4 LT |
692 | } |
693 | ||
ef805d95 LM |
694 | /* |
695 | * Third arg is the bank_value | |
696 | * This arg is a term_arg, not a constant | |
697 | * It will be evaluated later, by acpi_ds_eval_bank_field_operands | |
698 | */ | |
1da177e4 | 699 | arg = arg->common.next; |
9c52657a | 700 | |
1da177e4 LT |
701 | /* Fourth arg is the field flags */ |
702 | ||
703 | arg = arg->common.next; | |
704 | info.field_flags = (u8) arg->common.value.integer; | |
705 | ||
706 | /* Each remaining arg is a Named Field */ | |
707 | ||
708 | info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD; | |
709 | info.region_node = region_node; | |
710 | ||
ef805d95 LM |
711 | /* |
712 | * Use Info.data_register_node to store bank_field Op | |
713 | * It's safe because data_register_node will never be used when create bank field | |
714 | * We store aml_start and aml_length in the bank_field Op for late evaluation | |
715 | * Used in acpi_ex_prep_field_value(Info) | |
716 | * | |
717 | * TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"? | |
718 | */ | |
719 | info.data_register_node = (struct acpi_namespace_node *)op; | |
1da177e4 | 720 | |
ef805d95 | 721 | status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); |
4be44fcd | 722 | return_ACPI_STATUS(status); |
1da177e4 LT |
723 | } |
724 | ||
1da177e4 LT |
725 | /******************************************************************************* |
726 | * | |
727 | * FUNCTION: acpi_ds_create_index_field | |
728 | * | |
729 | * PARAMETERS: Op - Op containing the Field definition and args | |
730 | * region_node - Object for the containing Operation Region | |
731 | * ` walk_state - Current method state | |
732 | * | |
733 | * RETURN: Status | |
734 | * | |
735 | * DESCRIPTION: Create a new index field in the specified operation region | |
736 | * | |
737 | ******************************************************************************/ | |
738 | ||
739 | acpi_status | |
4be44fcd LB |
740 | acpi_ds_create_index_field(union acpi_parse_object *op, |
741 | struct acpi_namespace_node *region_node, | |
742 | struct acpi_walk_state *walk_state) | |
1da177e4 | 743 | { |
4be44fcd LB |
744 | acpi_status status; |
745 | union acpi_parse_object *arg; | |
746 | struct acpi_create_field_info info; | |
1da177e4 | 747 | |
b229cf92 | 748 | ACPI_FUNCTION_TRACE_PTR(ds_create_index_field, op); |
1da177e4 LT |
749 | |
750 | /* First arg is the name of the Index register (must already exist) */ | |
751 | ||
752 | arg = op->common.value.arg; | |
4be44fcd LB |
753 | status = |
754 | acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, | |
755 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | |
756 | ACPI_NS_SEARCH_PARENT, walk_state, | |
757 | &info.register_node); | |
758 | if (ACPI_FAILURE(status)) { | |
b8e4d893 | 759 | ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
4be44fcd | 760 | return_ACPI_STATUS(status); |
1da177e4 LT |
761 | } |
762 | ||
763 | /* Second arg is the data register (must already exist) */ | |
764 | ||
765 | arg = arg->common.next; | |
4be44fcd LB |
766 | status = |
767 | acpi_ns_lookup(walk_state->scope_info, arg->common.value.string, | |
768 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | |
769 | ACPI_NS_SEARCH_PARENT, walk_state, | |
770 | &info.data_register_node); | |
771 | if (ACPI_FAILURE(status)) { | |
b8e4d893 | 772 | ACPI_ERROR_NAMESPACE(arg->common.value.string, status); |
4be44fcd | 773 | return_ACPI_STATUS(status); |
1da177e4 LT |
774 | } |
775 | ||
776 | /* Next arg is the field flags */ | |
777 | ||
778 | arg = arg->common.next; | |
779 | info.field_flags = (u8) arg->common.value.integer; | |
780 | ||
781 | /* Each remaining arg is a Named Field */ | |
782 | ||
783 | info.field_type = ACPI_TYPE_LOCAL_INDEX_FIELD; | |
784 | info.region_node = region_node; | |
785 | ||
4be44fcd | 786 | status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); |
4be44fcd | 787 | return_ACPI_STATUS(status); |
1da177e4 | 788 | } |