scroll mode for very long start menus
[reactos.git] / reactos / drivers / bus / acpi / parser / psargs.c
1 /******************************************************************************
2 *
3 * Module Name: psargs - Parse AML opcode arguments
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 #include "acparser.h"
29 #include "amlcode.h"
30 #include "acnamesp.h"
31
32 #define _COMPONENT ACPI_PARSER
33 MODULE_NAME ("psargs")
34
35
36 /*******************************************************************************
37 *
38 * FUNCTION: Acpi_ps_get_next_package_length
39 *
40 * PARAMETERS: Parser_state - Current parser state object
41 *
42 * RETURN: Decoded package length. On completion, the AML pointer points
43 * past the length byte or bytes.
44 *
45 * DESCRIPTION: Decode and return a package length field
46 *
47 ******************************************************************************/
48
49 u32
50 acpi_ps_get_next_package_length (
51 ACPI_PARSE_STATE *parser_state)
52 {
53 u32 encoded_length;
54 u32 length = 0;
55
56
57 encoded_length = (u32) GET8 (parser_state->aml);
58 parser_state->aml++;
59
60
61 switch (encoded_length >> 6) /* bits 6-7 contain encoding scheme */ {
62 case 0: /* 1-byte encoding (bits 0-5) */
63
64 length = (encoded_length & 0x3F);
65 break;
66
67
68 case 1: /* 2-byte encoding (next byte + bits 0-3) */
69
70 length = ((GET8 (parser_state->aml) << 04) |
71 (encoded_length & 0x0F));
72 parser_state->aml++;
73 break;
74
75
76 case 2: /* 3-byte encoding (next 2 bytes + bits 0-3) */
77
78 length = ((GET8 (parser_state->aml + 1) << 12) |
79 (GET8 (parser_state->aml) << 04) |
80 (encoded_length & 0x0F));
81 parser_state->aml += 2;
82 break;
83
84
85 case 3: /* 4-byte encoding (next 3 bytes + bits 0-3) */
86
87 length = ((GET8 (parser_state->aml + 2) << 20) |
88 (GET8 (parser_state->aml + 1) << 12) |
89 (GET8 (parser_state->aml) << 04) |
90 (encoded_length & 0x0F));
91 parser_state->aml += 3;
92 break;
93 }
94
95 return (length);
96 }
97
98
99 /*******************************************************************************
100 *
101 * FUNCTION: Acpi_ps_get_next_package_end
102 *
103 * PARAMETERS: Parser_state - Current parser state object
104 *
105 * RETURN: Pointer to end-of-package +1
106 *
107 * DESCRIPTION: Get next package length and return a pointer past the end of
108 * the package. Consumes the package length field
109 *
110 ******************************************************************************/
111
112 u8 *
113 acpi_ps_get_next_package_end (
114 ACPI_PARSE_STATE *parser_state)
115 {
116 u8 *start = parser_state->aml;
117 NATIVE_UINT length;
118
119
120 length = (NATIVE_UINT) acpi_ps_get_next_package_length (parser_state);
121
122 return (start + length); /* end of package */
123 }
124
125
126 /*******************************************************************************
127 *
128 * FUNCTION: Acpi_ps_get_next_namestring
129 *
130 * PARAMETERS: Parser_state - Current parser state object
131 *
132 * RETURN: Pointer to the start of the name string (pointer points into
133 * the AML.
134 *
135 * DESCRIPTION: Get next raw namestring within the AML stream. Handles all name
136 * prefix characters. Set parser state to point past the string.
137 * (Name is consumed from the AML.)
138 *
139 ******************************************************************************/
140
141 NATIVE_CHAR *
142 acpi_ps_get_next_namestring (
143 ACPI_PARSE_STATE *parser_state)
144 {
145 u8 *start = parser_state->aml;
146 u8 *end = parser_state->aml;
147 u32 length;
148
149
150 /* Handle multiple prefix characters */
151
152 while (acpi_ps_is_prefix_char (GET8 (end))) {
153 /* include prefix '\\' or '^' */
154
155 end++;
156 }
157
158 /* Decode the path */
159
160 switch (GET8 (end)) {
161 case 0:
162
163 /* Null_name */
164
165 if (end == start) {
166 start = NULL;
167 }
168 end++;
169 break;
170
171
172 case AML_DUAL_NAME_PREFIX:
173
174 /* two name segments */
175
176 end += 9;
177 break;
178
179
180 case AML_MULTI_NAME_PREFIX_OP:
181
182 /* multiple name segments */
183
184 length = (u32) GET8 (end + 1) * 4;
185 end += 2 + length;
186 break;
187
188
189 default:
190
191 /* single name segment */
192 /* assert (Acpi_ps_is_lead (GET8 (End))); */
193
194 end += 4;
195 break;
196 }
197
198 parser_state->aml = (u8*) end;
199
200 return ((NATIVE_CHAR *) start);
201 }
202
203
204 /*******************************************************************************
205 *
206 * FUNCTION: Acpi_ps_get_next_namepath
207 *
208 * PARAMETERS: Parser_state - Current parser state object
209 * Arg - Where the namepath will be stored
210 * Arg_count - If the namepath points to a control method
211 * the method's argument is returned here.
212 * Method_call - Whether the namepath can be the start
213 * of a method call
214 *
215 * RETURN: None
216 *
217 * DESCRIPTION: Get next name (if method call, push appropriate # args). Names
218 * are looked up in either the parsed or internal namespace to
219 * determine if the name represents a control method. If a method
220 * is found, the number of arguments to the method is returned.
221 * This information is critical for parsing to continue correctly.
222 *
223 ******************************************************************************/
224
225
226 #ifdef PARSER_ONLY
227
228 void
229 acpi_ps_get_next_namepath (
230 ACPI_PARSE_STATE *parser_state,
231 ACPI_PARSE_OBJECT *arg,
232 u32 *arg_count,
233 u8 method_call)
234 {
235 NATIVE_CHAR *path;
236 ACPI_PARSE_OBJECT *name_op;
237 ACPI_PARSE_OBJECT *op;
238 ACPI_PARSE_OBJECT *count;
239
240
241 path = acpi_ps_get_next_namestring (parser_state);
242 if (!path || !method_call) {
243 /* Null name case, create a null namepath object */
244
245 acpi_ps_init_op (arg, AML_NAMEPATH_OP);
246 arg->value.name = path;
247 return;
248 }
249
250
251 if (acpi_gbl_parsed_namespace_root) {
252 /*
253 * Lookup the name in the parsed namespace
254 */
255
256 op = NULL;
257 if (method_call) {
258 op = acpi_ps_find (acpi_ps_get_parent_scope (parser_state),
259 path, AML_METHOD_OP, 0);
260 }
261
262 if (op) {
263 if (op->opcode == AML_METHOD_OP) {
264 /*
265 * The name refers to a control method, so this namepath is a
266 * method invocation. We need to 1) Get the number of arguments
267 * associated with this method, and 2) Change the NAMEPATH
268 * object into a METHODCALL object.
269 */
270
271 count = acpi_ps_get_arg (op, 0);
272 if (count && count->opcode == AML_BYTE_OP) {
273 name_op = acpi_ps_alloc_op (AML_NAMEPATH_OP);
274 if (name_op) {
275 /* Change arg into a METHOD CALL and attach the name */
276
277 acpi_ps_init_op (arg, AML_METHODCALL_OP);
278
279 name_op->value.name = path;
280
281 /* Point METHODCALL/NAME to the METHOD Node */
282
283 name_op->node = (ACPI_NAMESPACE_NODE *) op;
284 acpi_ps_append_arg (arg, name_op);
285
286 *arg_count = count->value.integer &
287 METHOD_FLAGS_ARG_COUNT;
288 }
289 }
290
291 return;
292 }
293
294 /*
295 * Else this is normal named object reference.
296 * Just init the NAMEPATH object with the pathname.
297 * (See code below)
298 */
299 }
300 }
301
302
303 /*
304 * Either we didn't find the object in the namespace, or the object is
305 * something other than a control method. Just initialize the Op with the
306 * pathname
307 */
308
309 acpi_ps_init_op (arg, AML_NAMEPATH_OP);
310 arg->value.name = path;
311
312
313 return;
314 }
315
316
317 #else
318
319
320 void
321 acpi_ps_get_next_namepath (
322 ACPI_PARSE_STATE *parser_state,
323 ACPI_PARSE_OBJECT *arg,
324 u32 *arg_count,
325 u8 method_call)
326 {
327 NATIVE_CHAR *path;
328 ACPI_PARSE_OBJECT *name_op;
329 ACPI_STATUS status;
330 ACPI_NAMESPACE_NODE *method_node = NULL;
331 ACPI_NAMESPACE_NODE *node;
332 ACPI_GENERIC_STATE scope_info;
333
334
335 path = acpi_ps_get_next_namestring (parser_state);
336 if (!path || !method_call) {
337 /* Null name case, create a null namepath object */
338
339 acpi_ps_init_op (arg, AML_NAMEPATH_OP);
340 arg->value.name = path;
341 return;
342 }
343
344
345 if (method_call) {
346 /*
347 * Lookup the name in the internal namespace
348 */
349 scope_info.scope.node = NULL;
350 node = parser_state->start_node;
351 if (node) {
352 scope_info.scope.node = node;
353 }
354
355 /*
356 * Lookup object. We don't want to add anything new to the namespace
357 * here, however. So we use MODE_EXECUTE. Allow searching of the
358 * parent tree, but don't open a new scope -- we just want to lookup the
359 * object (MUST BE mode EXECUTE to perform upsearch)
360 */
361
362 status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, IMODE_EXECUTE,
363 NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, NULL,
364 &node);
365 if (ACPI_SUCCESS (status)) {
366 if (node->type == ACPI_TYPE_METHOD) {
367 method_node = node;
368 name_op = acpi_ps_alloc_op (AML_NAMEPATH_OP);
369 if (name_op) {
370 /* Change arg into a METHOD CALL and attach name to it */
371
372 acpi_ps_init_op (arg, AML_METHODCALL_OP);
373
374 name_op->value.name = path;
375
376 /* Point METHODCALL/NAME to the METHOD Node */
377
378 name_op->node = method_node;
379 acpi_ps_append_arg (arg, name_op);
380
381 if (!(ACPI_OPERAND_OBJECT *) method_node->object) {
382 return;
383 }
384
385 *arg_count = ((ACPI_OPERAND_OBJECT *) method_node->object)->method.param_count;
386 }
387
388 return;
389 }
390
391 /*
392 * Else this is normal named object reference.
393 * Just init the NAMEPATH object with the pathname.
394 * (See code below)
395 */
396 }
397 }
398
399 /*
400 * Either we didn't find the object in the namespace, or the object is
401 * something other than a control method. Just initialize the Op with the
402 * pathname.
403 */
404
405 acpi_ps_init_op (arg, AML_NAMEPATH_OP);
406 arg->value.name = path;
407
408
409 return;
410 }
411
412 #endif
413
414 /*******************************************************************************
415 *
416 * FUNCTION: Acpi_ps_get_next_simple_arg
417 *
418 * PARAMETERS: Parser_state - Current parser state object
419 * Arg_type - The argument type (AML_*_ARG)
420 * Arg - Where the argument is returned
421 *
422 * RETURN: None
423 *
424 * DESCRIPTION: Get the next simple argument (constant, string, or namestring)
425 *
426 ******************************************************************************/
427
428 void
429 acpi_ps_get_next_simple_arg (
430 ACPI_PARSE_STATE *parser_state,
431 u32 arg_type,
432 ACPI_PARSE_OBJECT *arg)
433 {
434
435
436 switch (arg_type) {
437
438 case ARGP_BYTEDATA:
439
440 acpi_ps_init_op (arg, AML_BYTE_OP);
441 arg->value.integer = (u32) GET8 (parser_state->aml);
442 parser_state->aml++;
443 break;
444
445
446 case ARGP_WORDDATA:
447
448 acpi_ps_init_op (arg, AML_WORD_OP);
449
450 /* Get 2 bytes from the AML stream */
451
452 MOVE_UNALIGNED16_TO_32 (&arg->value.integer, parser_state->aml);
453 parser_state->aml += 2;
454 break;
455
456
457 case ARGP_DWORDDATA:
458
459 acpi_ps_init_op (arg, AML_DWORD_OP);
460
461 /* Get 4 bytes from the AML stream */
462
463 MOVE_UNALIGNED32_TO_32 (&arg->value.integer, parser_state->aml);
464 parser_state->aml += 4;
465 break;
466
467
468 case ARGP_CHARLIST:
469
470 acpi_ps_init_op (arg, AML_STRING_OP);
471 arg->value.string = (char*) parser_state->aml;
472
473 while (GET8 (parser_state->aml) != '\0') {
474 parser_state->aml++;
475 }
476 parser_state->aml++;
477 break;
478
479
480 case ARGP_NAME:
481 case ARGP_NAMESTRING:
482
483 acpi_ps_init_op (arg, AML_NAMEPATH_OP);
484 arg->value.name = acpi_ps_get_next_namestring (parser_state);
485 break;
486 }
487
488 return;
489 }
490
491
492 /*******************************************************************************
493 *
494 * FUNCTION: Acpi_ps_get_next_field
495 *
496 * PARAMETERS: Parser_state - Current parser state object
497 *
498 * RETURN: A newly allocated FIELD op
499 *
500 * DESCRIPTION: Get next field (Named_field, Reserved_field, or Access_field)
501 *
502 ******************************************************************************/
503
504 ACPI_PARSE_OBJECT *
505 acpi_ps_get_next_field (
506 ACPI_PARSE_STATE *parser_state)
507 {
508 ACPI_PTRDIFF aml_offset = parser_state->aml -
509 parser_state->aml_start;
510 ACPI_PARSE_OBJECT *field;
511 u16 opcode;
512 u32 name;
513
514
515 /* determine field type */
516
517 switch (GET8 (parser_state->aml)) {
518
519 default:
520
521 opcode = AML_NAMEDFIELD_OP;
522 break;
523
524
525 case 0x00:
526
527 opcode = AML_RESERVEDFIELD_OP;
528 parser_state->aml++;
529 break;
530
531
532 case 0x01:
533
534 opcode = AML_ACCESSFIELD_OP;
535 parser_state->aml++;
536 break;
537 }
538
539
540 /* Allocate a new field op */
541
542 field = acpi_ps_alloc_op (opcode);
543 if (field) {
544 field->aml_offset = aml_offset;
545
546 /* Decode the field type */
547
548 switch (opcode) {
549 case AML_NAMEDFIELD_OP:
550
551 /* Get the 4-character name */
552
553 MOVE_UNALIGNED32_TO_32 (&name, parser_state->aml);
554 acpi_ps_set_name (field, name);
555 parser_state->aml += 4;
556
557 /* Get the length which is encoded as a package length */
558
559 field->value.size = acpi_ps_get_next_package_length (parser_state);
560 break;
561
562
563 case AML_RESERVEDFIELD_OP:
564
565 /* Get the length which is encoded as a package length */
566
567 field->value.size = acpi_ps_get_next_package_length (parser_state);
568 break;
569
570
571 case AML_ACCESSFIELD_OP:
572
573 /* Get Access_type and Access_atrib and merge into the field Op */
574
575 field->value.integer = ((GET8 (parser_state->aml) << 8) |
576 GET8 (parser_state->aml));
577 parser_state->aml += 2;
578 break;
579 }
580 }
581
582 return (field);
583 }
584
585
586 /*******************************************************************************
587 *
588 * FUNCTION: Acpi_ps_get_next_arg
589 *
590 * PARAMETERS: Parser_state - Current parser state object
591 * Arg_type - The argument type (AML_*_ARG)
592 * Arg_count - If the argument points to a control method
593 * the method's argument is returned here.
594 *
595 * RETURN: An op object containing the next argument.
596 *
597 * DESCRIPTION: Get next argument (including complex list arguments that require
598 * pushing the parser stack)
599 *
600 ******************************************************************************/
601
602 ACPI_PARSE_OBJECT *
603 acpi_ps_get_next_arg (
604 ACPI_PARSE_STATE *parser_state,
605 u32 arg_type,
606 u32 *arg_count)
607 {
608 ACPI_PARSE_OBJECT *arg = NULL;
609 ACPI_PARSE_OBJECT *prev = NULL;
610 ACPI_PARSE_OBJECT *field;
611 u32 subop;
612
613
614 switch (arg_type) {
615 case ARGP_BYTEDATA:
616 case ARGP_WORDDATA:
617 case ARGP_DWORDDATA:
618 case ARGP_CHARLIST:
619 case ARGP_NAME:
620 case ARGP_NAMESTRING:
621
622 /* constants, strings, and namestrings are all the same size */
623
624 arg = acpi_ps_alloc_op (AML_BYTE_OP);
625 if (arg) {
626 acpi_ps_get_next_simple_arg (parser_state, arg_type, arg);
627 }
628 break;
629
630
631 case ARGP_PKGLENGTH:
632
633 /* package length, nothing returned */
634
635 parser_state->pkg_end = acpi_ps_get_next_package_end (parser_state);
636 break;
637
638
639 case ARGP_FIELDLIST:
640
641 if (parser_state->aml < parser_state->pkg_end) {
642 /* non-empty list */
643
644 while (parser_state->aml < parser_state->pkg_end) {
645 field = acpi_ps_get_next_field (parser_state);
646 if (!field) {
647 break;
648 }
649
650 if (prev) {
651 prev->next = field;
652 }
653
654 else {
655 arg = field;
656 }
657
658 prev = field;
659 }
660
661 /* skip to End of byte data */
662
663 parser_state->aml = parser_state->pkg_end;
664 }
665 break;
666
667
668 case ARGP_BYTELIST:
669
670 if (parser_state->aml < parser_state->pkg_end) {
671 /* non-empty list */
672
673 arg = acpi_ps_alloc_op (AML_BYTELIST_OP);
674 if (arg) {
675 /* fill in bytelist data */
676
677 arg->value.size = (parser_state->pkg_end - parser_state->aml);
678 ((ACPI_PARSE2_OBJECT *) arg)->data = parser_state->aml;
679 }
680
681 /* skip to End of byte data */
682
683 parser_state->aml = parser_state->pkg_end;
684 }
685 break;
686
687
688 case ARGP_TARGET:
689 case ARGP_SUPERNAME: {
690 subop = acpi_ps_peek_opcode (parser_state);
691 if (subop == 0 ||
692 acpi_ps_is_leading_char (subop) ||
693 acpi_ps_is_prefix_char (subop)) {
694 /* Null_name or Name_string */
695
696 arg = acpi_ps_alloc_op (AML_NAMEPATH_OP);
697 if (arg) {
698 acpi_ps_get_next_namepath (parser_state, arg, arg_count, 0);
699 }
700 }
701
702 else {
703 /* single complex argument, nothing returned */
704
705 *arg_count = 1;
706 }
707 }
708 break;
709
710
711 case ARGP_DATAOBJ:
712 case ARGP_TERMARG:
713
714 /* single complex argument, nothing returned */
715
716 *arg_count = 1;
717 break;
718
719
720 case ARGP_DATAOBJLIST:
721 case ARGP_TERMLIST:
722 case ARGP_OBJLIST:
723
724 if (parser_state->aml < parser_state->pkg_end) {
725 /* non-empty list of variable arguments, nothing returned */
726
727 *arg_count = ACPI_VAR_ARGS;
728 }
729 break;
730 }
731
732 return (arg);
733 }