/* $NetBSD: aml_name.c,v 1.4 2009/10/08 13:16:13 cegger Exp $ */ /*- * Copyright (c) 1999 Takanori Watanabe * Copyright (c) 1999, 2000 Yasuo Yokoyama * Copyright (c) 1999, 2000 Mitsuru IWASAKI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Id: aml_name.c,v 1.15 2000/08/16 18:14:53 iwasaki Exp * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_name.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $ */ #include __RCSID("$NetBSD: aml_name.c,v 1.4 2009/10/08 13:16:13 cegger Exp $"); #include #include #include #include #include #include #ifndef _KERNEL #include #include #include #include "debug.h" #else /* _KERNEL */ #include #endif /* !_KERNEL */ static struct aml_name *aml_find_name(struct aml_name *, const u_int8_t *); static struct aml_name *aml_new_name(struct aml_name *, const u_int8_t *); static void aml_delete_name(struct aml_name *); static struct aml_name rootname = {"\\", NULL, NULL, NULL, NULL, NULL}; static struct aml_name_group root_group = { AML_NAME_GROUP_ROOT, &rootname, NULL }; struct aml_name_group *name_group_list = &root_group; struct aml_local_stack *stack_top = NULL; struct aml_name * aml_get_rootname() { return (&rootname); } static struct aml_name * aml_find_name(struct aml_name *parent, const u_int8_t *name) { struct aml_name *result; if (!parent) parent = &rootname; for (result = parent->child; result; result = result->brother) if (!strncmp(result->name, (const char *)name, 4)) break; return (result); } /* * Parse given namesppace expression and find a first matched object * under given level of the tree by depth first search. */ struct aml_name * aml_find_from_namespace(struct aml_name *parent, const char *name) { const char *ptr; int len; struct aml_name *result; ptr = name; if (!parent) parent = &rootname; if (ptr[0] == '\\') { ptr++; parent = &rootname; } for (len = 0; ptr[len] != '.' && ptr[len] != '\0'; len++) ; for (result = parent->child; result; result = result->brother) { if (!strncmp(result->name, ptr, len)) { if (ptr[len] == '\0' || ptr[len + 1] == '\0') { return (result); } ptr += len; if (ptr[0] != '.') { return (NULL); } ptr++; return (aml_find_from_namespace(result, ptr)); } } return (NULL); } static void _aml_apply_foreach_found_objects(struct aml_name *parent, char *name, int len, int shallow, int (*func)(struct aml_name *, va_list), va_list ap) { struct aml_name *child, *ptr; child = ptr = NULL; /* function to apply must be specified */ if (func == NULL) { return; } for (child = parent->child; child; child = child->brother) { if (!strncmp(child->name, name, len)) { /* if function call was failed, stop searching */ if (func(child, ap) != 0) { return; } } } if (shallow == 1) { return; } for (ptr = parent->child; ptr; ptr = ptr->brother) { /* do more searching */ _aml_apply_foreach_found_objects(ptr, name, len, 0, func, ap); } } /* * Find named objects as many as possible under given level of * namespace, and apply given callback function for each * named objects found. If the callback function returns non-zero * value, then the search terminates immediately. * Note that object name expression is used as forward substring match, * not exact match. The name expression "_L" will match for objects * which have name starting with "_L" such as "\_SB_.LID_._LID" and * "\_GPE._L00" and so on. The name expression can include parent object * name in it like "\_GPE._L". In this case, GPE X level wake handlers * will be found under "\_GPE" in shallow level. */ void aml_apply_foreach_found_objects(struct aml_name *start, char *name, int (*func)(struct aml_name *, va_list), ...) { int i, len, has_dot, last_is_dot, shallow; struct aml_name *child, *parent; va_list ap; shallow = 0; if (start == NULL) { parent = &rootname; } else { parent = start; } if (name[0] == '\\') { name++; parent = &rootname; shallow = 1; } len = strlen(name); last_is_dot = 0; /* the last dot should be ignored */ if (len > 0 && name[len - 1] == '.') { len--; last_is_dot = 1; } has_dot = 0; for (i = 0; i < len - 1; i++) { if (name[i] == '.') { has_dot = 1; break; } } /* try to parse expression and find any matched object. */ if (has_dot == 1) { child = aml_find_from_namespace(parent, name); if (child == NULL) { return; } /* * we have at least one object matched, search all objects * under upper level of the found object. */ parent = child->parent; /* find the last `.' */ for (name = name + len - 1; *name != '.'; name--) ; name++; len = strlen(name) - last_is_dot; shallow = 1; } if (len > 4) { return; } va_start(ap, func); _aml_apply_foreach_found_objects(parent, name, len, shallow, func, ap); va_end(ap); } struct aml_name_group * aml_new_name_group(void *id) { struct aml_name_group *result; result = memman_alloc(aml_memman, memid_aml_name_group); result->id = id; result->head = NULL; result->next = name_group_list; name_group_list = result; return (result); } void aml_delete_name_group(struct aml_name_group *target) { struct aml_name_group *previous; previous = name_group_list; if (previous == target) name_group_list = target->next; else { while (previous && previous->next != target) previous = previous->next; if (previous) previous->next = target->next; } target->next = NULL; if (target->head) aml_delete_name(target->head); memman_free(aml_memman, memid_aml_name_group, target); } static struct aml_name * aml_new_name(struct aml_name *parent, const u_int8_t *name) { struct aml_name *newname; if ((newname = aml_find_name(parent, name)) != NULL) return (newname); newname = memman_alloc(aml_memman, memid_aml_name); strncpy(newname->name, (const char *)name, 4); newname->parent = parent; newname->child = NULL; newname->property = NULL; if (parent && parent->child) newname->brother = parent->child; else newname->brother = NULL; if (parent) parent->child = newname; newname->chain = name_group_list->head; name_group_list->head = newname; return (newname); } /* * NOTE: * aml_delete_name() doesn't maintain aml_name_group::{head,tail}. */ static void aml_delete_name(struct aml_name *target) { struct aml_name *next; struct aml_name *ptr; for (; target; target = next) { next = target->chain; if (target->child) { target->chain = NULL; continue; } if (target->brother) { if (target->parent) { if (target->parent->child == target) { target->parent->child = target->brother; } else { ptr = target->parent->child; while (ptr && ptr->brother != target) ptr = ptr->brother; if (ptr) ptr->brother = target->brother; } target->brother = NULL; } } else if (target->parent) { target->parent->child = NULL; } aml_free_object(&target->property); memman_free(aml_memman, memid_aml_name, target); } } #define AML_SEARCH_NAME 0 #define AML_CREATE_NAME 1 static struct aml_name *aml_nameman(struct aml_environ *, const u_int8_t *, int); struct aml_name * aml_search_name(struct aml_environ *env, const u_int8_t *dp) { return (aml_nameman(env, dp, AML_SEARCH_NAME)); } struct aml_name * aml_create_name(struct aml_environ *env, const u_int8_t *dp) { return (aml_nameman(env, dp, AML_CREATE_NAME)); } static struct aml_name * aml_nameman(struct aml_environ *env, const u_int8_t *dp, int flag) { int segcount; int i; struct aml_name *newname, *curname; struct aml_name *(*searchfunc) (struct aml_name *, const u_int8_t *); #define CREATECHECK() do { \ if (newname == NULL) { \ AML_DEBUGPRINT("ERROR CANNOT FIND NAME\n"); \ env->stat = aml_stat_panic; \ return (NULL); \ } \ } while(0) searchfunc = (flag == AML_CREATE_NAME) ? aml_new_name : aml_find_name; newname = env->curname; if (dp[0] == '\\') { newname = &rootname; dp++; } else if (dp[0] == '^') { while (dp[0] == '^') { newname = newname->parent; CREATECHECK(); dp++; } } if (dp[0] == 0x00) { /* NullName */ dp++; } else if (dp[0] == 0x2e) { /* DualNamePrefix */ newname = (*searchfunc) (newname, dp + 1); CREATECHECK(); newname = (*searchfunc) (newname, dp + 5); CREATECHECK(); } else if (dp[0] == 0x2f) { /* MultiNamePrefix */ segcount = dp[1]; for (i = 0, dp += 2; i < segcount; i++, dp += 4) { newname = (*searchfunc) (newname, dp); CREATECHECK(); } } else if (flag == AML_CREATE_NAME) { /* NameSeg */ newname = aml_new_name(newname, dp); CREATECHECK(); } else { curname = newname; for (;;) { newname = aml_find_name(curname, dp); if (newname != NULL) break; if (curname == &rootname || curname == NULL) break; curname = curname->parent; } } return (newname); } #undef CREATECHECK struct aml_local_stack * aml_local_stack_create() { struct aml_local_stack *result; result = memman_alloc(aml_memman, memid_aml_local_stack); memset(result, 0, sizeof(struct aml_local_stack)); return (result); } void aml_local_stack_push(struct aml_local_stack *stack) { stack->next = stack_top; stack_top = stack; } struct aml_local_stack * aml_local_stack_pop() { struct aml_local_stack *result; result = stack_top; stack_top = result->next; result->next = NULL; return (result); } void aml_local_stack_delete(struct aml_local_stack *stack) { int i; for (i = 0; i < 8; i++) aml_free_object(&stack->localvalue[i].property); for (i = 0; i < 7; i++) aml_free_object(&stack->argumentvalue[i].property); aml_delete_name(stack->temporary); memman_free(aml_memman, memid_aml_local_stack, stack); } struct aml_name * aml_local_stack_getLocalX(int idx) { if (stack_top == NULL) return (NULL); return (&stack_top->localvalue[idx]); } struct aml_name * aml_local_stack_getArgX(struct aml_local_stack *stack, int idx) { if (!stack) stack = stack_top; if (stack == NULL) return (NULL); return (&stack->argumentvalue[idx]); } struct aml_name * aml_create_local_object() { struct aml_name *result; result = memman_alloc(aml_memman, memid_aml_name); result->child = result->brother = result->parent = NULL; result->property = NULL; result->chain = stack_top->temporary; stack_top->temporary = result; return (result); }