diff options
Diffstat (limited to 'usr.sbin/acpidump/aml/aml_name.c')
-rw-r--r-- | usr.sbin/acpidump/aml/aml_name.c | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/usr.sbin/acpidump/aml/aml_name.c b/usr.sbin/acpidump/aml/aml_name.c new file mode 100644 index 00000000000..b41698d7e2c --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_name.c @@ -0,0 +1,481 @@ +/* $OpenBSD: aml_name.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Yasuo Yokoyama + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_name.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $ + */ +#include <sys/types.h> + +#include <aml/aml_amlmem.h> +#include <aml/aml_common.h> +#include <aml/aml_env.h> +#include <aml/aml_name.h> + +#ifndef _KERNEL +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "debug.h" +#else /* _KERNEL */ +#include <sys/systm.h> +#endif /* !_KERNEL */ + +static struct aml_name *aml_find_name(struct aml_name *, char *); +static struct aml_name *aml_new_name(struct aml_name *, char *); +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, char *name) +{ + struct aml_name *result; + + if (!parent) + parent = &rootname; + for (result = parent->child; result; result = result->brother) + if (!strncmp(result->name, 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, char *name) +{ + 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(int 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, char *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, name, 4); + newname->parent = parent; + newname->child = NULL; + newname->property = NULL; + if (parent->child) + newname->brother = parent->child; + else + newname->brother = NULL; + 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 *, u_int8_t *, int); + +struct aml_name * +aml_search_name(struct aml_environ *env, u_int8_t *dp) +{ + + return (aml_nameman(env, dp, AML_SEARCH_NAME)); +} + +struct aml_name * +aml_create_name(struct aml_environ *env, u_int8_t *dp) +{ + + return (aml_nameman(env, dp, AML_CREATE_NAME)); +} + +static struct aml_name * +aml_nameman(struct aml_environ *env, u_int8_t *dp, int flag) +{ + int segcount; + int i; + struct aml_name *newname, *curname; + struct aml_name *(*searchfunc) (struct aml_name *, char *); + +#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) + 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 index) +{ + + if (stack_top == NULL) + return (NULL); + return (&stack_top->localvalue[index]); +} + +struct aml_name * +aml_local_stack_getArgX(struct aml_local_stack *stack, int index) +{ + + if (!stack) + stack = stack_top; + if (stack == NULL) + return (NULL); + return (&stack->argumentvalue[index]); +} + +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); +} |