#include <sys/cdefs.h>
__RCSID("$NetBSD: aml_name.c,v 1.4 2009/10/08 13:16:13 cegger Exp $");
#include <sys/param.h>
#include <acpi_common.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
#include <sys/systm.h>
#endif
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);
}
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;
if (func == NULL) {
return;
}
for (child = parent->child; child; child = child->brother) {
if (!strncmp(child->name, name, len)) {
if (func(child, ap) != 0) {
return;
}
}
}
if (shallow == 1) {
return;
}
for (ptr = parent->child; ptr; ptr = ptr->brother) {
_aml_apply_foreach_found_objects(ptr, name, len, 0, func, ap);
}
}
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;
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;
}
}
if (has_dot == 1) {
child = aml_find_from_namespace(parent, name);
if (child == NULL) {
return;
}
parent = child->parent;
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);
}
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) {
dp++;
} else if (dp[0] == 0x2e) {
newname = (*searchfunc) (newname, dp + 1);
CREATECHECK();
newname = (*searchfunc) (newname, dp + 5);
CREATECHECK();
} else if (dp[0] == 0x2f) {
segcount = dp[1];
for (i = 0, dp += 2; i < segcount; i++, dp += 4) {
newname = (*searchfunc) (newname, dp);
CREATECHECK();
}
} else if (flag == AML_CREATE_NAME) {
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);
}