summaryrefslogtreecommitdiff
path: root/usr.sbin/acpidump/aml/aml_name.c
diff options
context:
space:
mode:
authorThorsten Lockert <tholo@cvs.openbsd.org>2005-06-02 20:09:40 +0000
committerThorsten Lockert <tholo@cvs.openbsd.org>2005-06-02 20:09:40 +0000
commitc2b861c0e32dd295ee7538db6b2aac4dd7c87de2 (patch)
tree7da2e9ae4792b3d3765f32971ba6c6c0ad4de685 /usr.sbin/acpidump/aml/aml_name.c
parent204533b59784a2ed890ea3c6aad96531b3989704 (diff)
Start on a basic ACPI framework -- does not do much more than read out the
ACPI tables into kernel memory and attach ACPI and HPET timers currently. In order to test this code, enabling the devices in GENERIC as well as the ACPI_ENABLE option is needed. This code does not do any thermal control yet, so this should be done with care depending on the platform. In the tree so more people can contribute to making this more fully featured. Ok niklas@ grange@ tedu@
Diffstat (limited to 'usr.sbin/acpidump/aml/aml_name.c')
-rw-r--r--usr.sbin/acpidump/aml/aml_name.c481
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);
+}