Merge trunk HEAD (46152)
[reactos.git] / drivers / bus / acpi / dispatcher / dsobject.c
1 /******************************************************************************
2 *
3 * Module Name: dsobject - Dispatcher object management routines
4 * $Revision: 1.1 $
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 R. Byron Moore
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include <acpi.h>
28
29 #define _COMPONENT ACPI_DISPATCHER
30 MODULE_NAME ("dsobject")
31
32
33 /*******************************************************************************
34 *
35 * FUNCTION: Acpi_ds_init_one_object
36 *
37 * PARAMETERS: Obj_handle - Node
38 * Level - Current nesting level
39 * Context - Points to a init info struct
40 * Return_value - Not used
41 *
42 * RETURN: Status
43 *
44 * DESCRIPTION: Callback from Acpi_walk_namespace. Invoked for every object
45 * within the namespace.
46 *
47 * Currently, the only objects that require initialization are:
48 * 1) Methods
49 * 2) Op Regions
50 *
51 ******************************************************************************/
52
53 ACPI_STATUS
54 acpi_ds_init_one_object (
55 ACPI_HANDLE obj_handle,
56 u32 level,
57 void *context,
58 void **return_value)
59 {
60 OBJECT_TYPE_INTERNAL type;
61 ACPI_STATUS status;
62 ACPI_INIT_WALK_INFO *info = (ACPI_INIT_WALK_INFO *) context;
63 u8 table_revision;
64
65
66 info->object_count++;
67 table_revision = info->table_desc->pointer->revision;
68
69 /*
70 * We are only interested in objects owned by the table that
71 * was just loaded
72 */
73
74 if (((ACPI_NAMESPACE_NODE *) obj_handle)->owner_id !=
75 info->table_desc->table_id) {
76 return (AE_OK);
77 }
78
79
80 /* And even then, we are only interested in a few object types */
81
82 type = acpi_ns_get_type (obj_handle);
83
84 switch (type) {
85
86 case ACPI_TYPE_REGION:
87
88 acpi_ds_initialize_region (obj_handle);
89
90 info->op_region_count++;
91 break;
92
93
94 case ACPI_TYPE_METHOD:
95
96 info->method_count++;
97
98
99 /*
100 * Set the execution data width (32 or 64) based upon the
101 * revision number of the parent ACPI table.
102 */
103
104 if (table_revision == 1) {
105 ((ACPI_NAMESPACE_NODE *)obj_handle)->flags |= ANOBJ_DATA_WIDTH_32;
106 }
107
108 /*
109 * Always parse methods to detect errors, we may delete
110 * the parse tree below
111 */
112
113 status = acpi_ds_parse_method (obj_handle);
114
115 /* TBD: [Errors] what do we do with an error? */
116
117 if (ACPI_FAILURE (status)) {
118 break;
119 }
120
121 /*
122 * Delete the parse tree. We simple re-parse the method
123 * for every execution since there isn't much overhead
124 */
125 acpi_ns_delete_namespace_subtree (obj_handle);
126 break;
127
128 default:
129 break;
130 }
131
132 /*
133 * We ignore errors from above, and always return OK, since
134 * we don't want to abort the walk on a single error.
135 */
136 return (AE_OK);
137 }
138
139
140 /*******************************************************************************
141 *
142 * FUNCTION: Acpi_ds_initialize_objects
143 *
144 * PARAMETERS: None
145 *
146 * RETURN: Status
147 *
148 * DESCRIPTION: Walk the entire namespace and perform any necessary
149 * initialization on the objects found therein
150 *
151 ******************************************************************************/
152
153 ACPI_STATUS
154 acpi_ds_initialize_objects (
155 ACPI_TABLE_DESC *table_desc,
156 ACPI_NAMESPACE_NODE *start_node)
157 {
158 ACPI_STATUS status;
159 ACPI_INIT_WALK_INFO info;
160
161
162 info.method_count = 0;
163 info.op_region_count = 0;
164 info.object_count = 0;
165 info.table_desc = table_desc;
166
167
168 /* Walk entire namespace from the supplied root */
169
170 status = acpi_walk_namespace (ACPI_TYPE_ANY, start_node,
171 ACPI_UINT32_MAX, acpi_ds_init_one_object,
172 &info, NULL);
173
174 return (AE_OK);
175 }
176
177
178 /*****************************************************************************
179 *
180 * FUNCTION: Acpi_ds_init_object_from_op
181 *
182 * PARAMETERS: Op - Parser op used to init the internal object
183 * Opcode - AML opcode associated with the object
184 * Obj_desc - Namespace object to be initialized
185 *
186 * RETURN: Status
187 *
188 * DESCRIPTION: Initialize a namespace object from a parser Op and its
189 * associated arguments. The namespace object is a more compact
190 * representation of the Op and its arguments.
191 *
192 ****************************************************************************/
193
194 ACPI_STATUS
195 acpi_ds_init_object_from_op (
196 ACPI_WALK_STATE *walk_state,
197 ACPI_PARSE_OBJECT *op,
198 u16 opcode,
199 ACPI_OPERAND_OBJECT **obj_desc)
200 {
201 ACPI_STATUS status;
202 ACPI_PARSE_OBJECT *arg;
203 ACPI_PARSE2_OBJECT *byte_list;
204 ACPI_OPERAND_OBJECT *arg_desc;
205 ACPI_OPCODE_INFO *op_info;
206
207
208 op_info = acpi_ps_get_opcode_info (opcode);
209 if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) {
210 /* Unknown opcode */
211
212 return (AE_TYPE);
213 }
214
215
216 /* Get and prepare the first argument */
217
218 switch ((*obj_desc)->common.type) {
219 case ACPI_TYPE_BUFFER:
220
221 /* First arg is a number */
222
223 acpi_ds_create_operand (walk_state, op->value.arg, 0);
224 arg_desc = walk_state->operands [walk_state->num_operands - 1];
225 acpi_ds_obj_stack_pop (1, walk_state);
226
227 /* Resolve the object (could be an arg or local) */
228
229 status = acpi_aml_resolve_to_value (&arg_desc, walk_state);
230 if (ACPI_FAILURE (status)) {
231 acpi_cm_remove_reference (arg_desc);
232 return (status);
233 }
234
235 /* We are expecting a number */
236
237 if (arg_desc->common.type != ACPI_TYPE_INTEGER) {
238 acpi_cm_remove_reference (arg_desc);
239 return (AE_TYPE);
240 }
241
242 /* Get the value, delete the internal object */
243
244 (*obj_desc)->buffer.length = (u32) arg_desc->integer.value;
245 acpi_cm_remove_reference (arg_desc);
246
247 /* Allocate the buffer */
248
249 if ((*obj_desc)->buffer.length == 0) {
250 (*obj_desc)->buffer.pointer = NULL;
251 REPORT_WARNING (("Buffer created with zero length in AML\n"));
252 break;
253 }
254
255 else {
256 (*obj_desc)->buffer.pointer =
257 acpi_cm_callocate ((*obj_desc)->buffer.length);
258
259 if (!(*obj_desc)->buffer.pointer) {
260 return (AE_NO_MEMORY);
261 }
262 }
263
264 /*
265 * Second arg is the buffer data (optional)
266 * Byte_list can be either individual bytes or a
267 * string initializer!
268 */
269
270 /* skip first arg */
271 arg = op->value.arg;
272 byte_list = (ACPI_PARSE2_OBJECT *) arg->next;
273 if (byte_list) {
274 if (byte_list->opcode != AML_BYTELIST_OP) {
275 return (AE_TYPE);
276 }
277
278 MEMCPY ((*obj_desc)->buffer.pointer, byte_list->data,
279 (*obj_desc)->buffer.length);
280 }
281
282 break;
283
284
285 case ACPI_TYPE_PACKAGE:
286
287 /*
288 * When called, an internal package object has already
289 * been built and is pointed to by *Obj_desc.
290 * Acpi_ds_build_internal_object build another internal
291 * package object, so remove reference to the original
292 * so that it is deleted. Error checking is done
293 * within the remove reference function.
294 */
295 acpi_cm_remove_reference(*obj_desc);
296
297 status = acpi_ds_build_internal_object (walk_state, op, obj_desc);
298 break;
299
300 case ACPI_TYPE_INTEGER:
301 (*obj_desc)->integer.value = op->value.integer;
302 break;
303
304
305 case ACPI_TYPE_STRING:
306 (*obj_desc)->string.pointer = op->value.string;
307 (*obj_desc)->string.length = STRLEN (op->value.string);
308 break;
309
310
311 case ACPI_TYPE_METHOD:
312 break;
313
314
315 case INTERNAL_TYPE_REFERENCE:
316
317 switch (ACPI_GET_OP_CLASS (op_info)) {
318 case OPTYPE_LOCAL_VARIABLE:
319
320 /* Split the opcode into a base opcode + offset */
321
322 (*obj_desc)->reference.opcode = AML_LOCAL_OP;
323 (*obj_desc)->reference.offset = opcode - AML_LOCAL_OP;
324 break;
325
326 case OPTYPE_METHOD_ARGUMENT:
327
328 /* Split the opcode into a base opcode + offset */
329
330 (*obj_desc)->reference.opcode = AML_ARG_OP;
331 (*obj_desc)->reference.offset = opcode - AML_ARG_OP;
332 break;
333
334 default: /* Constants, Literals, etc.. */
335
336 if (op->opcode == AML_NAMEPATH_OP) {
337 /* Node was saved in Op */
338
339 (*obj_desc)->reference.node = op->node;
340 }
341
342 (*obj_desc)->reference.opcode = opcode;
343 break;
344 }
345
346 break;
347
348
349 default:
350
351 break;
352 }
353
354 return (AE_OK);
355 }
356
357
358 /*****************************************************************************
359 *
360 * FUNCTION: Acpi_ds_build_internal_simple_obj
361 *
362 * PARAMETERS: Op - Parser object to be translated
363 * Obj_desc_ptr - Where the ACPI internal object is returned
364 *
365 * RETURN: Status
366 *
367 * DESCRIPTION: Translate a parser Op object to the equivalent namespace object
368 * Simple objects are any objects other than a package object!
369 *
370 ****************************************************************************/
371
372 static ACPI_STATUS
373 acpi_ds_build_internal_simple_obj (
374 ACPI_WALK_STATE *walk_state,
375 ACPI_PARSE_OBJECT *op,
376 ACPI_OPERAND_OBJECT **obj_desc_ptr)
377 {
378 ACPI_OPERAND_OBJECT *obj_desc;
379 OBJECT_TYPE_INTERNAL type;
380 ACPI_STATUS status;
381 u32 length;
382 char *name;
383
384
385 if (op->opcode == AML_NAMEPATH_OP) {
386 /*
387 * This is an object reference. If The name was
388 * previously looked up in the NS, it is stored in this op.
389 * Otherwise, go ahead and look it up now
390 */
391
392 if (!op->node) {
393 status = acpi_ns_lookup (walk_state->scope_info,
394 op->value.string, ACPI_TYPE_ANY,
395 IMODE_EXECUTE,
396 NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE,
397 NULL,
398 (ACPI_NAMESPACE_NODE **)&(op->node));
399
400 if (ACPI_FAILURE (status)) {
401 if (status == AE_NOT_FOUND) {
402 name = NULL;
403 acpi_ns_externalize_name (ACPI_UINT32_MAX, op->value.string, &length, &name);
404
405 if (name) {
406 REPORT_WARNING (("Reference %s at AML %X not found\n",
407 name, op->aml_offset));
408 acpi_cm_free (name);
409 }
410 else {
411 REPORT_WARNING (("Reference %s at AML %X not found\n",
412 op->value.string, op->aml_offset));
413 }
414 *obj_desc_ptr = NULL;
415 }
416
417 else {
418 return (status);
419 }
420 }
421 }
422
423 /*
424 * The reference will be a Reference
425 * TBD: [Restructure] unless we really need a separate
426 * type of INTERNAL_TYPE_REFERENCE change
427 * Acpi_ds_map_opcode_to_data_type to handle this case
428 */
429 type = INTERNAL_TYPE_REFERENCE;
430 }
431 else {
432 type = acpi_ds_map_opcode_to_data_type (op->opcode, NULL);
433 }
434
435
436 /* Create and init the internal ACPI object */
437
438 obj_desc = acpi_cm_create_internal_object (type);
439 if (!obj_desc) {
440 return (AE_NO_MEMORY);
441 }
442
443 status = acpi_ds_init_object_from_op (walk_state, op,
444 op->opcode, &obj_desc);
445
446 if (ACPI_FAILURE (status)) {
447 acpi_cm_remove_reference (obj_desc);
448 return (status);
449 }
450
451 *obj_desc_ptr = obj_desc;
452
453 return (AE_OK);
454 }
455
456
457 /*****************************************************************************
458 *
459 * FUNCTION: Acpi_ds_build_internal_package_obj
460 *
461 * PARAMETERS: Op - Parser object to be translated
462 * Obj_desc_ptr - Where the ACPI internal object is returned
463 *
464 * RETURN: Status
465 *
466 * DESCRIPTION: Translate a parser Op package object to the equivalent
467 * namespace object
468 *
469 ****************************************************************************/
470
471 ACPI_STATUS
472 acpi_ds_build_internal_package_obj (
473 ACPI_WALK_STATE *walk_state,
474 ACPI_PARSE_OBJECT *op,
475 ACPI_OPERAND_OBJECT **obj_desc_ptr)
476 {
477 ACPI_PARSE_OBJECT *arg;
478 ACPI_OPERAND_OBJECT *obj_desc;
479 ACPI_STATUS status = AE_OK;
480
481
482 obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_PACKAGE);
483 if (!obj_desc) {
484 return (AE_NO_MEMORY);
485 }
486
487 /* The first argument must be the package length */
488
489 arg = op->value.arg;
490 obj_desc->package.count = arg->value.integer;
491
492 /*
493 * Allocate the array of pointers (ptrs to the
494 * individual objects) Add an extra pointer slot so
495 * that the list is always null terminated.
496 */
497
498 obj_desc->package.elements =
499 acpi_cm_callocate ((obj_desc->package.count + 1) *
500 sizeof (void *));
501
502 if (!obj_desc->package.elements) {
503 /* Package vector allocation failure */
504
505 REPORT_ERROR (("Ds_build_internal_package_obj: Package vector allocation failure\n"));
506
507 acpi_cm_delete_object_desc (obj_desc);
508 return (AE_NO_MEMORY);
509 }
510
511 obj_desc->package.next_element = obj_desc->package.elements;
512
513 /*
514 * Now init the elements of the package
515 */
516
517 arg = arg->next;
518 while (arg) {
519 if (arg->opcode == AML_PACKAGE_OP) {
520 status = acpi_ds_build_internal_package_obj (walk_state, arg,
521 obj_desc->package.next_element);
522 }
523
524 else {
525 status = acpi_ds_build_internal_simple_obj (walk_state, arg,
526 obj_desc->package.next_element);
527 }
528
529 obj_desc->package.next_element++;
530 arg = arg->next;
531 }
532
533 *obj_desc_ptr = obj_desc;
534 return (status);
535 }
536
537
538 /*****************************************************************************
539 *
540 * FUNCTION: Acpi_ds_build_internal_object
541 *
542 * PARAMETERS: Op - Parser object to be translated
543 * Obj_desc_ptr - Where the ACPI internal object is returned
544 *
545 * RETURN: Status
546 *
547 * DESCRIPTION: Translate a parser Op object to the equivalent namespace
548 * object
549 *
550 ****************************************************************************/
551
552 ACPI_STATUS
553 acpi_ds_build_internal_object (
554 ACPI_WALK_STATE *walk_state,
555 ACPI_PARSE_OBJECT *op,
556 ACPI_OPERAND_OBJECT **obj_desc_ptr)
557 {
558 ACPI_STATUS status;
559
560
561 if (op->opcode == AML_PACKAGE_OP) {
562 status = acpi_ds_build_internal_package_obj (walk_state, op,
563 obj_desc_ptr);
564 }
565
566 else {
567 status = acpi_ds_build_internal_simple_obj (walk_state, op,
568 obj_desc_ptr);
569 }
570
571 return (status);
572 }
573
574
575 /*****************************************************************************
576 *
577 * FUNCTION: Acpi_ds_create_node
578 *
579 * PARAMETERS: Op - Parser object to be translated
580 * Obj_desc_ptr - Where the ACPI internal object is returned
581 *
582 * RETURN: Status
583 *
584 * DESCRIPTION:
585 *
586 ****************************************************************************/
587
588 ACPI_STATUS
589 acpi_ds_create_node (
590 ACPI_WALK_STATE *walk_state,
591 ACPI_NAMESPACE_NODE *node,
592 ACPI_PARSE_OBJECT *op)
593 {
594 ACPI_STATUS status;
595 ACPI_OPERAND_OBJECT *obj_desc;
596
597
598 if (!op->value.arg) {
599 /* No arguments, there is nothing to do */
600
601 return (AE_OK);
602 }
603
604
605 /* Build an internal object for the argument(s) */
606
607 status = acpi_ds_build_internal_object (walk_state,
608 op->value.arg, &obj_desc);
609 if (ACPI_FAILURE (status)) {
610 return (status);
611 }
612
613
614 /* Re-type the object according to it's argument */
615
616 node->type = obj_desc->common.type;
617
618 /* Init obj */
619
620 status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc,
621 (u8) node->type);
622 if (ACPI_FAILURE (status)) {
623 goto cleanup;
624 }
625
626 return (status);
627
628
629 cleanup:
630
631 acpi_cm_remove_reference (obj_desc);
632
633 return (status);
634 }
635
636