Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / usr.sbin / acpitools / aml / aml_name.c
blob4ce8c43e175162357a1907427da21e7573e565c8
1 /* $NetBSD: aml_name.c,v 1.3 2008/01/15 19:08:00 jmcneill Exp $ */
3 /*-
4 * Copyright (c) 1999 Takanori Watanabe
5 * Copyright (c) 1999, 2000 Yasuo Yokoyama
6 * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
30 * Id: aml_name.c,v 1.15 2000/08/16 18:14:53 iwasaki Exp
31 * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_name.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $
33 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: aml_name.c,v 1.3 2008/01/15 19:08:00 jmcneill Exp $");
36 #include <sys/param.h>
38 #include <acpi_common.h>
39 #include <aml/aml_amlmem.h>
40 #include <aml/aml_common.h>
41 #include <aml/aml_env.h>
42 #include <aml/aml_name.h>
44 #ifndef _KERNEL
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
49 #include "debug.h"
50 #else /* _KERNEL */
51 #include <sys/systm.h>
52 #endif /* !_KERNEL */
54 static struct aml_name *aml_find_name(struct aml_name *, const u_int8_t *);
55 static struct aml_name *aml_new_name(struct aml_name *, const u_int8_t *);
56 static void aml_delete_name(struct aml_name *);
58 static struct aml_name rootname = {"\\", NULL, NULL, NULL, NULL, NULL};
60 static struct aml_name_group root_group = {
61 AML_NAME_GROUP_ROOT,
62 &rootname,
63 NULL
66 struct aml_name_group *name_group_list = &root_group;
67 struct aml_local_stack *stack_top = NULL;
69 struct aml_name *
70 aml_get_rootname()
73 return (&rootname);
76 static struct aml_name *
77 aml_find_name(struct aml_name *parent, const u_int8_t *name)
79 struct aml_name *result;
81 if (!parent)
82 parent = &rootname;
83 for (result = parent->child; result; result = result->brother)
84 if (!strncmp(result->name, (const char *)name, 4))
85 break;
86 return (result);
90 * Parse given namesppace expression and find a first matched object
91 * under given level of the tree by depth first search.
94 struct aml_name *
95 aml_find_from_namespace(struct aml_name *parent, const char *name)
97 const char *ptr;
98 int len;
99 struct aml_name *result;
101 ptr = name;
102 if (!parent)
103 parent = &rootname;
105 if (ptr[0] == '\\') {
106 ptr++;
107 parent = &rootname;
109 for (len = 0; ptr[len] != '.' && ptr[len] != '\0'; len++)
112 for (result = parent->child; result; result = result->brother) {
113 if (!strncmp(result->name, ptr, len)) {
114 if (ptr[len] == '\0' || ptr[len + 1] == '\0') {
115 return (result);
117 ptr += len;
118 if (ptr[0] != '.') {
119 return (NULL);
121 ptr++;
122 return (aml_find_from_namespace(result, ptr));
126 return (NULL);
129 static void
130 _aml_apply_foreach_found_objects(struct aml_name *parent, char *name,
131 int len, int shallow, int (*func)(struct aml_name *, va_list), va_list ap)
133 struct aml_name *child, *ptr;
135 child = ptr = NULL;
137 /* function to apply must be specified */
138 if (func == NULL) {
139 return;
142 for (child = parent->child; child; child = child->brother) {
143 if (!strncmp(child->name, name, len)) {
144 /* if function call was failed, stop searching */
145 if (func(child, ap) != 0) {
146 return;
151 if (shallow == 1) {
152 return;
155 for (ptr = parent->child; ptr; ptr = ptr->brother) {
156 /* do more searching */
157 _aml_apply_foreach_found_objects(ptr, name, len, 0, func, ap);
162 * Find named objects as many as possible under given level of
163 * namespace, and apply given callback function for each
164 * named objects found. If the callback function returns non-zero
165 * value, then the search terminates immediately.
166 * Note that object name expression is used as forward substring match,
167 * not exact match. The name expression "_L" will match for objects
168 * which have name starting with "_L" such as "\_SB_.LID_._LID" and
169 * "\_GPE._L00" and so on. The name expression can include parent object
170 * name in it like "\_GPE._L". In this case, GPE X level wake handlers
171 * will be found under "\_GPE" in shallow level.
174 void
175 aml_apply_foreach_found_objects(struct aml_name *start, char *name,
176 int (*func)(struct aml_name *, va_list), ...)
178 int i, len, has_dot, last_is_dot, shallow;
179 struct aml_name *child, *parent;
180 va_list ap;
182 shallow = 0;
183 if (start == NULL) {
184 parent = &rootname;
185 } else {
186 parent = start;
188 if (name[0] == '\\') {
189 name++;
190 parent = &rootname;
191 shallow = 1;
194 len = strlen(name);
195 last_is_dot = 0;
196 /* the last dot should be ignored */
197 if (len > 0 && name[len - 1] == '.') {
198 len--;
199 last_is_dot = 1;
202 has_dot = 0;
203 for (i = 0; i < len - 1; i++) {
204 if (name[i] == '.') {
205 has_dot = 1;
206 break;
210 /* try to parse expression and find any matched object. */
211 if (has_dot == 1) {
212 child = aml_find_from_namespace(parent, name);
213 if (child == NULL) {
214 return;
218 * we have at least one object matched, search all objects
219 * under upper level of the found object.
221 parent = child->parent;
223 /* find the last `.' */
224 for (name = name + len - 1; *name != '.'; name--)
226 name++;
227 len = strlen(name) - last_is_dot;
228 shallow = 1;
231 if (len > 4) {
232 return;
235 va_start(ap, func);
236 _aml_apply_foreach_found_objects(parent, name, len, shallow, func, ap);
237 va_end(ap);
240 struct aml_name_group *
241 aml_new_name_group(void *id)
243 struct aml_name_group *result;
245 result = memman_alloc(aml_memman, memid_aml_name_group);
246 result->id = id;
247 result->head = NULL;
248 result->next = name_group_list;
249 name_group_list = result;
250 return (result);
253 void
254 aml_delete_name_group(struct aml_name_group *target)
256 struct aml_name_group *previous;
258 previous = name_group_list;
259 if (previous == target)
260 name_group_list = target->next;
261 else {
262 while (previous && previous->next != target)
263 previous = previous->next;
264 if (previous)
265 previous->next = target->next;
267 target->next = NULL;
268 if (target->head)
269 aml_delete_name(target->head);
270 memman_free(aml_memman, memid_aml_name_group, target);
273 static struct aml_name *
274 aml_new_name(struct aml_name *parent, const u_int8_t *name)
276 struct aml_name *newname;
278 if ((newname = aml_find_name(parent, name)) != NULL)
279 return (newname);
281 newname = memman_alloc(aml_memman, memid_aml_name);
282 strncpy(newname->name, (const char *)name, 4);
283 newname->parent = parent;
284 newname->child = NULL;
285 newname->property = NULL;
286 if (parent && parent->child)
287 newname->brother = parent->child;
288 else
289 newname->brother = NULL;
290 if (parent)
291 parent->child = newname;
293 newname->chain = name_group_list->head;
294 name_group_list->head = newname;
296 return (newname);
300 * NOTE:
301 * aml_delete_name() doesn't maintain aml_name_group::{head,tail}.
303 static void
304 aml_delete_name(struct aml_name *target)
306 struct aml_name *next;
307 struct aml_name *ptr;
309 for (; target; target = next) {
310 next = target->chain;
311 if (target->child) {
312 target->chain = NULL;
313 continue;
315 if (target->brother) {
316 if (target->parent) {
317 if (target->parent->child == target) {
318 target->parent->child = target->brother;
319 } else {
320 ptr = target->parent->child;
321 while (ptr && ptr->brother != target)
322 ptr = ptr->brother;
323 if (ptr)
324 ptr->brother = target->brother;
326 target->brother = NULL;
328 } else if (target->parent) {
329 target->parent->child = NULL;
331 aml_free_object(&target->property);
332 memman_free(aml_memman, memid_aml_name, target);
336 #define AML_SEARCH_NAME 0
337 #define AML_CREATE_NAME 1
338 static struct aml_name *aml_nameman(struct aml_environ *, const u_int8_t *, int);
340 struct aml_name *
341 aml_search_name(struct aml_environ *env, const u_int8_t *dp)
344 return (aml_nameman(env, dp, AML_SEARCH_NAME));
347 struct aml_name *
348 aml_create_name(struct aml_environ *env, const u_int8_t *dp)
351 return (aml_nameman(env, dp, AML_CREATE_NAME));
354 static struct aml_name *
355 aml_nameman(struct aml_environ *env, const u_int8_t *dp, int flag)
357 int segcount;
358 int i;
359 struct aml_name *newname, *curname;
360 struct aml_name *(*searchfunc) (struct aml_name *, const u_int8_t *);
362 #define CREATECHECK() do { \
363 if (newname == NULL) { \
364 AML_DEBUGPRINT("ERROR CANNOT FIND NAME\n"); \
365 env->stat = aml_stat_panic; \
366 return (NULL); \
368 } while(0)
370 searchfunc = (flag == AML_CREATE_NAME) ? aml_new_name : aml_find_name;
371 newname = env->curname;
372 if (dp[0] == '\\') {
373 newname = &rootname;
374 dp++;
375 } else if (dp[0] == '^') {
376 while (dp[0] == '^') {
377 newname = newname->parent;
378 CREATECHECK();
379 dp++;
382 if (dp[0] == 0x00) { /* NullName */
383 dp++;
384 } else if (dp[0] == 0x2e) { /* DualNamePrefix */
385 newname = (*searchfunc) (newname, dp + 1);
386 CREATECHECK();
387 newname = (*searchfunc) (newname, dp + 5);
388 CREATECHECK();
389 } else if (dp[0] == 0x2f) { /* MultiNamePrefix */
390 segcount = dp[1];
391 for (i = 0, dp += 2; i < segcount; i++, dp += 4) {
392 newname = (*searchfunc) (newname, dp);
393 CREATECHECK();
395 } else if (flag == AML_CREATE_NAME) { /* NameSeg */
396 newname = aml_new_name(newname, dp);
397 CREATECHECK();
398 } else {
399 curname = newname;
400 for (;;) {
401 newname = aml_find_name(curname, dp);
402 if (newname != NULL)
403 break;
404 if (curname == &rootname || curname == NULL)
405 break;
406 curname = curname->parent;
409 return (newname);
412 #undef CREATECHECK
414 struct aml_local_stack *
415 aml_local_stack_create()
417 struct aml_local_stack *result;
419 result = memman_alloc(aml_memman, memid_aml_local_stack);
420 memset(result, 0, sizeof(struct aml_local_stack));
421 return (result);
424 void
425 aml_local_stack_push(struct aml_local_stack *stack)
428 stack->next = stack_top;
429 stack_top = stack;
432 struct aml_local_stack *
433 aml_local_stack_pop()
435 struct aml_local_stack *result;
437 result = stack_top;
438 stack_top = result->next;
439 result->next = NULL;
440 return (result);
443 void
444 aml_local_stack_delete(struct aml_local_stack *stack)
446 int i;
448 for (i = 0; i < 8; i++)
449 aml_free_object(&stack->localvalue[i].property);
450 for (i = 0; i < 7; i++)
451 aml_free_object(&stack->argumentvalue[i].property);
452 aml_delete_name(stack->temporary);
453 memman_free(aml_memman, memid_aml_local_stack, stack);
456 struct aml_name *
457 aml_local_stack_getLocalX(int idx)
460 if (stack_top == NULL)
461 return (NULL);
462 return (&stack_top->localvalue[idx]);
465 struct aml_name *
466 aml_local_stack_getArgX(struct aml_local_stack *stack, int idx)
469 if (!stack)
470 stack = stack_top;
471 if (stack == NULL)
472 return (NULL);
473 return (&stack->argumentvalue[idx]);
476 struct aml_name *
477 aml_create_local_object()
479 struct aml_name *result;
481 result = memman_alloc(aml_memman, memid_aml_name);
482 result->child = result->brother = result->parent = NULL;
483 result->property = NULL;
484 result->chain = stack_top->temporary;
485 stack_top->temporary = result;
486 return (result);