/*      $NetBSD: aml_parse.c,v 1.6 2022/03/23 13:06:06 andvar Exp $     */

/*-
* Copyright (c) 1999 Doug Rabson
* Copyright (c) 1999, 2000 Mitsuru IWASAKI <[email protected]>
* 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_parse.c,v 1.32 2000/08/12 15:20:45 iwasaki Exp
*      $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_parse.c,v 1.7 2001/10/23 14:54:15 takawata Exp $
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: aml_parse.c,v 1.6 2022/03/23 13:06:06 andvar 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_evalobj.h>
#include <aml/aml_name.h>
#include <aml/aml_obj.h>
#include <aml/aml_parse.h>
#include <aml/aml_status.h>
#include <aml/aml_store.h>

#ifndef _KERNEL
#include <sys/stat.h>
#include <sys/mman.h>

#include <assert.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "debug.h"
#else /* _KERNEL */
#include <sys/systm.h>
#include <sys/bus.h>
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
#ifndef ACPI_NO_OSDFUNC_INLINE
#include <machine/acpica_osd.h>
#endif
#endif /* !_KERNEL */

static int               findsetleftbit(int num);
static int               findsetrightbit(int num);
static int               frombcd(int num);
static int               tobcd(int num);

static u_int32_t         aml_parse_pkglength(struct aml_environ *env);
static u_int8_t          aml_parse_bytedata(struct aml_environ *env);
static u_int16_t         aml_parse_worddata(struct aml_environ *env);
static u_int32_t         aml_parse_dworddata(struct aml_environ *env);
static u_int8_t         *aml_parse_namestring(struct aml_environ *env);
static void              aml_parse_defscope(struct aml_environ *env,
                                           int indent);
static union aml_object *aml_parse_defbuffer(struct aml_environ *env,
                                            int indent);
static struct aml_name  *aml_parse_concat_number(struct aml_environ *env,
                                                int num1, int indent);
static struct aml_name  *aml_parse_concat_buffer(struct aml_environ *env,
                                                union aml_object *obj,
                                                int indent);
static struct aml_name  *aml_parse_concat_string(struct aml_environ *env,
                                                union aml_object *obj,
                                                int indent);
static struct aml_name  *aml_parse_concatop(struct aml_environ *env,
                                           int indent);
static union aml_object *aml_parse_defpackage(struct aml_environ *env,
                                             int indent);
static void              aml_parse_defmethod(struct aml_environ *env,
                                            int indent);
static void              aml_parse_defopregion(struct aml_environ *env,
                                              int indent);
static int               aml_parse_field(struct aml_environ *env,
                                        struct aml_field *template);
static void              aml_parse_fieldlist(struct aml_environ *env,
                                            struct aml_field *template,
                                            int indent);
static void              aml_parse_deffield(struct aml_environ *env,
                                           int indent);
static void              aml_parse_defindexfield(struct aml_environ *env,
                                                int indent);
static void              aml_parse_defbankfield(struct aml_environ *env,
                                               int indent);
static void              aml_parse_defdevice(struct aml_environ *env,
                                            int indent);
static void              aml_parse_defprocessor(struct aml_environ *env,
                                               int indent);
static void              aml_parse_defpowerres(struct aml_environ *env,
                                              int indent);
static void              aml_parse_defthermalzone(struct aml_environ *env,
                                                 int indent);
static struct aml_name  *aml_parse_defelse(struct aml_environ *env,
                                          int indent, int num);
static struct aml_name  *aml_parse_defif(struct aml_environ *env,
                                        int indent);
static struct aml_name  *aml_parse_defwhile(struct aml_environ *env,
                                           int indent);
static void              aml_parse_defmutex(struct aml_environ *env,
                                           int indent);
static void              aml_createfield_generic(struct aml_environ *env,
                                                union aml_object *srcbuf,
                                                int idx, int len,
                                                char *newname);
static void              aml_parse_defcreatefield(struct aml_environ *env,
                                                 int indent);

static int
findsetleftbit(int num)
{
       int     i, filter;

       filter = 0;
       for (i = 0; i < 32; i++) {
               filter = filter >> 1;
               filter |= 1 << 31;
               if (filter & num) {
                       break;
               }
       }
       i = (i == 32) ? 0 : i + 1;
       return (i);
}

static int
findsetrightbit(int num)
{
       int     i, filter;

       filter = 0;
       for (i = 0; i < 32; i++) {
               filter = filter << 1;
               filter |= 1;
               if (filter & num) {
                       break;
               }
       }
       i = (i == 32) ? 0 : i + 1;
       return (i);
}

static int
frombcd(int num)
{
       int     res, factor;

       res = 0;
       factor = 1;
       while (num != 0) {
               res += ((num & 0xf) * factor);
               num = num / 16;
               factor *= 10;
       }
       return (res);
}

static int
tobcd(int num)
{
       int     res, factor;

       res = 0;
       factor = 1;
       while (num != 0) {
               res += ((num % 10) * factor);
               num = num / 10;
               factor *= 16;
       }
       return (res);
}

static u_int32_t
aml_parse_pkglength(struct aml_environ *env)
{
       u_int8_t        *dp;
       u_int32_t       pkglength;

       dp = env->dp;
       pkglength = *dp++;
       switch (pkglength >> 6) {
       case 0:
               break;
       case 1:
               pkglength = (pkglength & 0xf) + (dp[0] << 4);
               dp += 1;
               break;
       case 2:
               pkglength = (pkglength & 0xf) + (dp[0] << 4) + (dp[1] << 12);
               dp += 2;
               break;
       case 3:
               pkglength = (pkglength & 0xf)
                   + (dp[0] << 4) + (dp[1] << 12) + (dp[2] << 20);
               dp += 3;
               break;
       }

       env->dp = dp;
       return (pkglength);
}

static u_int8_t
aml_parse_bytedata(struct aml_environ *env)
{
       u_int8_t        data;

       data = env->dp[0];
       env->dp++;
       return (data);
}

static u_int16_t
aml_parse_worddata(struct aml_environ *env)
{
       u_int16_t       data;

       data = env->dp[0] + (env->dp[1] << 8);
       env->dp += 2;
       return (data);
}

static u_int32_t
aml_parse_dworddata(struct aml_environ *env)
{
       u_int32_t       data;

       data = env->dp[0] + (env->dp[1] << 8) +
           (env->dp[2] << 16) + (env->dp[3] << 24);
       env->dp += 4;
       return (data);
}

static u_int8_t *
aml_parse_namestring(struct aml_environ *env)
{
       u_int8_t        *name;
       int             segcount;

       name = env->dp;
       if (env->dp[0] == '\\')
               env->dp++;
       else if (env->dp[0] == '^')
               while (env->dp[0] == '^')
                       env->dp++;
       if (env->dp[0] == 0x00) /* NullName */
               env->dp++;
       else if (env->dp[0] == 0x2e)    /* DualNamePrefix */
               env->dp += 1 + 4 + 4;   /* NameSeg, NameSeg */
       else if (env->dp[0] == 0x2f) {  /* MultiNamePrefix */
               segcount = env->dp[1];
               env->dp += 1 + 1 + segcount * 4;        /* segcount * NameSeg */
       } else
               env->dp += 4;   /* NameSeg */

       return (name);
}

struct aml_name *
aml_parse_objectlist(struct aml_environ *env, int indent)
{
       union   aml_object *obj;

       obj = NULL;
       while (env->dp < env->end) {
               aml_print_indent(indent);
               obj = aml_eval_name(env, aml_parse_termobj(env, indent));
               AML_DEBUGPRINT("\n");
               if (env->stat == aml_stat_step) {
                       AML_DEBUGGER(env, env);
                       continue;
               }
               if (env->stat != aml_stat_none) {
                       env->tempname.property = obj;
                       return (&env->tempname);
               }
       }
       return (NULL);
}

#define AML_CREATE_NAME(amlname, env, namestr, ret) do {                \
       amlname = aml_create_name(env, namestr);                        \
       if (env->stat == aml_stat_panic)                                \
               return ret;                                             \
} while(0)

#define AML_COPY_OBJECT(dest, env, src, ret) do {                       \
       dest = aml_copy_object(env, src);                               \
       if (dest == NULL) {                                             \
               env->stat = aml_stat_panic;                             \
               return ret;                                             \
       }                                                               \
} while(0)

#define AML_ALLOC_OBJECT(dest, env, type, ret) do {                     \
       dest = aml_alloc_object(type, NULL);                            \
       if (dest == NULL) {                                             \
               env->stat= aml_stat_panic;                              \
               return ret;                                             \
       }                                                               \
} while(0)

static void
aml_parse_defscope(struct aml_environ *env, int indent)
{
       u_int8_t        *start, *end, *oend;
       u_int8_t        *name;
       u_int32_t       pkglength;
       struct  aml_name *oname;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);

       AML_DEBUGPRINT("Scope(");
       name = aml_parse_namestring(env);
       aml_print_namestring(name);
       AML_DEBUGPRINT(") {\n");
       oname = env->curname;
       AML_CREATE_NAME(env->curname, env, name,);
       oend = env->end;
       env->end = end = start + pkglength;
       aml_parse_objectlist(env, indent + 1);
       aml_print_indent(indent);
       AML_DEBUGPRINT("}");
       AML_SYSASSERT(env->dp == env->end);
       env->dp = end;
       env->end = oend;
       env->curname = oname;
       env->stat = aml_stat_none;
}

static union aml_object *
aml_parse_defbuffer(struct aml_environ *env, int indent)
{
       u_int8_t        *start;
       u_int8_t        *end;
       u_int8_t        *buffer;
       u_int32_t       pkglength;
       int     size1, size2, size;
       union   aml_object *obj;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       end = start + pkglength;

       AML_DEBUGPRINT("Buffer(");
       obj = aml_eval_name(env, aml_parse_termobj(env, indent));
       size1 = aml_objtonum(env, obj);
       size2 = end - env->dp;
       size = (size1 < size2) ? size1 : size2;
       if (size1 > 0) {
               buffer = memman_alloc_flexsize(aml_memman, size1);
               if (buffer == NULL) {
                       AML_DEBUGPRINT("NO MEMORY\n");
                       env->stat = aml_stat_panic;
                       return (NULL);
               }
               bzero(buffer, size1);
               bcopy(env->dp, buffer, size);
       } else {
               buffer = NULL;
       }

       obj = &env->tempobject;
       obj->type = aml_t_buffer;
       obj->buffer.size = size1;
       obj->buffer.data = buffer;
       AML_DEBUGPRINT(") ");
       env->dp = end;

       return (obj);
}

static struct aml_name *
aml_parse_concat_number(struct aml_environ *env, int num1, int indent)
{
       int     num2;
       struct  aml_name *destname;
       union   aml_object *obj;

       num2 = aml_objtonum(env, aml_eval_name(env,
               aml_parse_termobj(env, indent)));
       AML_DEBUGPRINT(", ");
       destname = aml_parse_termobj(env, indent);
       AML_DEBUGPRINT(")");
       obj = &env->tempobject;
       obj->type = aml_t_buffer;
       obj->buffer.size = 2;
       obj->buffer.data = memman_alloc_flexsize(aml_memman, 2);
       if (obj->buffer.data == NULL) {
               env->stat = aml_stat_panic;
               return (NULL);
       }
       obj->buffer.data[0] = num1 & 0xff;
       obj->buffer.data[1] = num2 & 0xff;
       aml_store_to_name(env, obj, destname);
       return (&env->tempname);
}

static struct aml_name *
aml_parse_concat_buffer(struct aml_environ *env, union aml_object *obj,
   int indent)
{
       union   aml_object *tmpobj, *tmpobj2, *resobj;
       struct  aml_name *destname;

       tmpobj = aml_eval_name(env, aml_parse_termobj(env, indent));
       AML_DEBUGPRINT(", ");
       if (tmpobj->type != aml_t_buffer) {
               env->stat = aml_stat_panic;
               return (NULL);
       }
       AML_COPY_OBJECT(tmpobj2, env, tmpobj, NULL);
       destname = aml_parse_termobj(env, indent);
       AML_DEBUGPRINT(")");
       resobj = &env->tempobject;
       env->tempname.property = resobj;
       resobj->buffer.type = aml_t_buffer;
       resobj->buffer.size = tmpobj2->buffer.size + obj->buffer.size;
       if (resobj->buffer.size > 0) {
               resobj->buffer.data = memman_alloc_flexsize(aml_memman,
                   resobj->buffer.size);
               if (resobj->buffer.data == NULL) {
                       env->stat = aml_stat_panic;
                       return (NULL);
               }
               bcopy(obj->buffer.data, resobj->buffer.data, obj->buffer.size);
               bcopy(tmpobj2->buffer.data,
                   resobj->buffer.data + obj->buffer.size,
                   tmpobj2->buffer.size);
       } else {
               resobj->buffer.data = NULL;
       }
       aml_free_object(&tmpobj2);
       aml_store_to_name(env, resobj, destname);
       return (&env->tempname);
}

static struct aml_name *
aml_parse_concat_string(struct aml_environ *env, union aml_object *obj,
   int indent)
{
       int     len;
       union   aml_object *tmpobj, *tmpobj2, *resobj;
       struct  aml_name *destname;

       tmpobj = aml_eval_name(env, aml_parse_termobj(env, indent));
       AML_DEBUGPRINT(", ");
       if (tmpobj->type != aml_t_string) {
               env->stat = aml_stat_panic;
               return (NULL);
       }
       AML_COPY_OBJECT(tmpobj2, env, tmpobj, NULL);
       destname = aml_parse_termobj(env, indent);
       AML_DEBUGPRINT(")");
       resobj = &env->tempobject;
       env->tempname.property = resobj;
       resobj->type = aml_t_buffer;
       resobj->str.needfree = 1;
       len = strlen((const char *)obj->str.string) +
           strlen((const char *)tmpobj2->str.string) + 1;
       if (len > 0) {
               resobj->str.string = memman_alloc_flexsize(aml_memman, len);
               if (resobj->str.string == NULL) {
                       env->stat = aml_stat_panic;
                       return (NULL);
               }
               strlcpy((char *)resobj->str.string, (const char *)obj->str.string, len);
               strlcat((char *)resobj->str.string, (const char *)tmpobj->str.string, len);
       } else {
               resobj->str.string = NULL;
       }
       aml_free_object(&tmpobj2);
       aml_store_to_name(env, resobj, destname);
       return (&env->tempname);
}

static struct aml_name *
aml_parse_concatop(struct aml_environ *env, int indent)
{
       union   aml_object *obj, *tmpobj;
       struct  aml_name *aname;

       AML_DEBUGPRINT("Concat(");
       obj = aml_eval_name(env, aml_parse_termobj(env, indent));
       AML_DEBUGPRINT(", ");
       switch (obj->type) {
       case aml_t_num:
               aname = aml_parse_concat_number(env, aml_objtonum(env, obj), indent);
               break;

       case aml_t_buffer:
               /* obj may be temporal object */
               AML_COPY_OBJECT(tmpobj, env, obj, NULL);
               aname = aml_parse_concat_buffer(env, obj, indent);
               aml_free_object(&tmpobj);
               break;

       case aml_t_string:
               /* obj may be temporal object */
               AML_COPY_OBJECT(tmpobj, env, obj, NULL);
               aname = aml_parse_concat_string(env, obj, indent);
               aml_free_object(&tmpobj);
               break;

       default:
               env->stat = aml_stat_panic;
               aname = NULL;
               break;
       }

       AML_DEBUGPRINT("\n");
       return (aname);
}

static union aml_object *
aml_parse_defpackage(struct aml_environ *env, int indent)
{
       u_int8_t        numelements;
       u_int8_t        *start;
       u_int32_t       pkglength;
       int             i;
       struct  aml_environ *copy;
       struct  aml_name *tmpname;
       union   aml_object *obj, **objects;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       numelements = aml_parse_bytedata(env);
       copy = memman_alloc(aml_memman, memid_aml_environ);
       if (copy == NULL) {
               env->stat = aml_stat_panic;
               return (NULL);
       }
       if (numelements > 0) {
               objects = memman_alloc_flexsize(aml_memman,
                   numelements * sizeof(union aml_object *));
               if (objects == NULL) {
                       env->stat = aml_stat_panic;
                       return (NULL);
               } else {
                       bzero(objects, numelements * sizeof(union aml_object *));
               }
       } else {
               objects = NULL;
       }

       *copy = *env;
       env->dp = copy->end = start + pkglength;
       AML_DEBUGPRINT("Package() {\n");
       i = 0;
       while ((copy->dp < copy->end) && (i < numelements)) {
               aml_print_indent(indent + 1);
               tmpname = aml_parse_termobj(copy, indent + 1);

               if (tmpname != NULL) {
                       objects[i] = aml_copy_object(copy, tmpname->property);
               }
               AML_DEBUGPRINT(",\n");
               i++;
       }
       aml_free_objectcontent(&copy->tempobject);

       aml_print_indent(indent);
       AML_DEBUGPRINT("}");
       obj = &env->tempobject;
       obj->type = aml_t_package;
       obj->package.elements = numelements;
       obj->package.objects = objects;

       memman_free(aml_memman, memid_aml_environ, copy);
       return (obj);
}

static void
aml_parse_defmethod(struct aml_environ *env, int indent)
{
       u_int8_t        flags;
       u_int8_t        *start;
       u_int32_t       pkglength;
       char    *name;
       struct  aml_environ *copy;
       struct  aml_method *meth;
       struct  aml_name *aname;
       union   aml_object *aobj;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       copy = memman_alloc(aml_memman, memid_aml_environ);
       if (copy == NULL) {
               env->stat = aml_stat_panic;
               return;
       }
       AML_DEBUGPRINT("Method(");
       name = (char *)aml_parse_namestring(env);
       aml_print_namestring((unsigned char *)name);
       AML_CREATE_NAME(aname, env, (unsigned char *)name,);
       if (aname->property != NULL) {
               env->stat = aml_stat_panic;
               AML_DEBUGPRINT("Already Defined \n");
               goto out;
       }
       AML_ALLOC_OBJECT(aobj, env, aml_t_method,);
       meth = &aobj->meth;
       aname->property = aobj;
       flags = *env->dp++;

       if (flags) {
               AML_DEBUGPRINT(", %d", flags);
       }
       AML_DEBUGPRINT(") {\n");
       *copy = *env;
       meth->argnum = flags;
       meth->from = env->dp;
       meth->to = env->dp = copy->end = start + pkglength;
       aml_print_indent(indent);
       AML_DEBUGPRINT("}");
out:
       memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defopregion(struct aml_environ *env, int indent)
{
       u_int8_t        *name;
       struct  aml_name *aname;
       struct  aml_opregion *opregion;
       union   aml_object *obj;
       const char      *regions[] = {
               "SystemMemory",
               "SystemIO",
               "PCI_Config",
               "EmbeddedControl",
               "SMBus",
       };

       AML_DEBUGPRINT("OperationRegion(");
       /* Name */
       name = aml_parse_namestring(env);
       aml_print_namestring(name);
       AML_CREATE_NAME(aname, env, name,);
       if (aname->property != NULL) {
               env->stat = aml_stat_panic;
               AML_DEBUGPRINT("Already Defined \n");
               return;
       }
       AML_ALLOC_OBJECT(aname->property, env, aml_t_opregion,);
       opregion = &aname->property->opregion;
       opregion->space = *env->dp;
       AML_DEBUGPRINT(", %s, ", regions[*env->dp]);    /* Space */
       env->dp++;
       obj = aml_eval_name(env, aml_parse_termobj(env, indent));       /* Offset */
       opregion->offset = aml_objtonum(env, obj);
       AML_DEBUGPRINT(", ");
       obj = aml_eval_name(env, aml_parse_termobj(env, indent));       /* Length */
       opregion->length = aml_objtonum(env, obj);
       AML_DEBUGPRINT(")");
}

static const char       *accessnames[] = {
       "AnyAcc",
       "ByteAcc",
       "WordAcc",
       "DWordAcc",
       "BlockAcc",
       "SMBSendRecvAcc",
       "SMBQuickAcc"
};

static int
aml_parse_field(struct aml_environ *env, struct aml_field *template)
{
       u_int8_t        *name;
       u_int8_t        acc, attribute;
       u_int32_t       width;
       struct  aml_name *aname;
       struct  aml_field *prop;

       switch (*env->dp) {
       case '\\':
       case '^':
       case 'A'...'Z':
       case '_':
       case '.':
       case '/':
               name = aml_parse_namestring(env);
               width = aml_parse_pkglength(env);
               template->bitlen = width;
               aml_print_namestring(name);
               AML_CREATE_NAME(aname, env, name, 0);
               /* Alignment */
               if (width == 16) {
                       template->bitoffset += 15;
                       template->bitoffset &= (~15);
               }
               if (width == 32) {
                       template->bitoffset += 31;
                       template->bitoffset &= (~31);
               } else if ((width & 7) == 0) {
                       template->bitoffset += 7;
                       template->bitoffset &= (~7);
               } else if ((width > 32) && (width & 7) != 0) {
                       AML_DEBUGPRINT("??? Can I treat it?\n");
               }
               if (aname->property != NULL) {
                       env->stat = aml_stat_panic;
                       AML_DEBUGPRINT("Already Defined \n");
                       return (0);
               }
               AML_ALLOC_OBJECT(aname->property, env, aml_t_field, 0);
               prop = &aname->property->field;
               *prop = *template;
               template->bitoffset += width;
               AML_DEBUGPRINT(",\t%d", width);
               break;
       case 0x00:
               env->dp++;
               width = aml_parse_pkglength(env);
               template->bitoffset += width;
               AML_DEBUGPRINT("Offset(0x%x)", template->bitoffset);
               break;
       case 0x01:
               acc = env->dp[1];
               attribute = env->dp[2];
               env->dp += 3;
               AML_DEBUGPRINT("AccessAs(%s, %d)", accessnames[acc], attribute);
               template->bitoffset = attribute;
               template->flags = (template->flags | 0xf0) | acc;
               break;
       }
       return (template->bitoffset);
}

static void
aml_parse_fieldlist(struct aml_environ *env, struct aml_field *template,
   int indent)
{

       while (env->dp < env->end) {
               aml_print_indent(indent);
               (void)aml_parse_field(env, template);
               if (env->dp < env->end) {
                       AML_DEBUGPRINT(",\n");
               } else {
                       AML_DEBUGPRINT("\n");
               }
       }
}

static void
aml_parse_deffield(struct aml_environ *env, int indent)
{
       u_int8_t        flags;
       u_int8_t        *start, *name;
       u_int32_t       pkglength;
       struct  aml_environ *copy;
       struct  aml_field fieldtemplate;
       static  const char *lockrules[] = {"NoLock", "Lock"};
       static  const char *updaterules[] = {"Preserve", "WriteAsOnes",
                                            "WriteAsZeros", "*Error*"};

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       copy = memman_alloc(aml_memman, memid_aml_environ);
       if (copy == NULL) {
               env->stat = aml_stat_panic;
               return;
       }
       AML_DEBUGPRINT("Field(");
       aml_print_namestring(name = aml_parse_namestring(env));
       fieldtemplate.type = aml_t_field;
       flags = aml_parse_bytedata(env);
       fieldtemplate.flags = flags;

       *copy = *env;
       env->dp = copy->end = start + pkglength;
       fieldtemplate.bitoffset = 0;
       fieldtemplate.bitlen = 0;
       fieldtemplate.f.ftype = f_t_field;
       fieldtemplate.f.fld.regname = name;
       AML_DEBUGPRINT(", %s, %s, %s) {\n",
           accessnames[flags & 0xf],
           lockrules[(flags >> 4) & 1],
           updaterules[(flags >> 5) & 3]);
       aml_parse_fieldlist(copy, &fieldtemplate, indent + 1);
       aml_print_indent(indent);
       AML_DEBUGPRINT("}");
       aml_free_objectcontent(&copy->tempobject);

       AML_SYSASSERT(copy->dp == copy->end);
       memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defindexfield(struct aml_environ *env, int indent)
{
       u_int8_t        flags;
       u_int8_t        *start, *iname, *dname;
       u_int32_t       pkglength;
       struct  aml_environ *copy;
       struct  aml_field template;
       static  const char *lockrules[] = {"NoLock", "Lock"};
       static  const char *updaterules[] = {"Preserve", "WriteAsOnes",
                                            "WriteAsZeros", "*Error*"};

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       copy = memman_alloc(aml_memman, memid_aml_environ);
       if (copy == NULL) {
               env->stat = aml_stat_panic;
               return;
       }
       AML_DEBUGPRINT("IndexField(");
       aml_print_namestring(iname = aml_parse_namestring(env));        /* Name1 */
       AML_DEBUGPRINT(", ");
       aml_print_namestring(dname = aml_parse_namestring(env));        /* Name2 */
       template.type = aml_t_field;
       template.flags = flags = aml_parse_bytedata(env);
       template.bitoffset = 0;
       template.bitlen = 0;
       template.f.ftype = f_t_index;
       template.f.ifld.indexname = iname;
       template.f.ifld.dataname = dname;
       AML_DEBUGPRINT(", %s, %s, %s) {\n",
           accessnames[flags & 0xf],
           lockrules[(flags >> 4) & 1],
           updaterules[(flags >> 5) & 3]);
       *copy = *env;
       env->dp = copy->end = start + pkglength;
       aml_parse_fieldlist(copy, &template, indent + 1);
       aml_print_indent(indent);
       AML_DEBUGPRINT("}");
       aml_free_objectcontent(&copy->tempobject);

       AML_SYSASSERT(copy->dp == copy->end);
       memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defbankfield(struct aml_environ *env, int indent)
{
       u_int8_t        flags;
       u_int8_t        *start, *rname, *bname;
       u_int32_t       pkglength, bankvalue;
       struct  aml_environ *copy;
       struct  aml_field template;
       union   aml_object *obj;
       static  const char *lockrules[] = {"NoLock", "Lock"};
       static  const char *updaterules[] = {"Preserve", "WriteAsOnes",
                                            "WriteAsZeros", "*Error*"};

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       copy = memman_alloc(aml_memman, memid_aml_environ);
       if (copy == NULL) {
               env->stat = aml_stat_panic;
               return;
       }
       AML_DEBUGPRINT("BankField(");
       aml_print_namestring(rname = aml_parse_namestring(env));        /* Name1 */
       AML_DEBUGPRINT(", ");
       aml_print_namestring(bname = aml_parse_namestring(env));        /* Name2 */
       AML_DEBUGPRINT(", ");
       obj = aml_eval_name(env, aml_parse_termobj(env, indent));       /* BankValue */
       bankvalue = aml_objtonum(env, obj);
       template.type = aml_t_field;
       template.flags = flags = aml_parse_bytedata(env);
       template.bitoffset = 0;
       template.bitlen = 0;
       template.f.ftype = f_t_bank;
       template.f.bfld.regname = rname;
       template.f.bfld.bankname = bname;
       template.f.bfld.bankvalue = bankvalue;
       *copy = *env;
       env->dp = copy->end = start + pkglength;
       AML_DEBUGPRINT(", %s, %s, %s) {\n",
           accessnames[flags & 0xf],
           lockrules[(flags >> 4) & 1],
           updaterules[(flags >> 5) & 3]);
       aml_parse_fieldlist(copy, &template, indent + 1);
       aml_print_indent(indent);
       AML_DEBUGPRINT("}");

       aml_free_objectcontent(&copy->tempobject);
       AML_SYSASSERT(copy->dp == copy->end);
       memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defdevice(struct aml_environ *env, int indent)
{
       u_int8_t        *start;
       u_int8_t        *name;
       u_int32_t       pkglength;
       struct  aml_environ *copy;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       copy = memman_alloc(aml_memman, memid_aml_environ);
       if (copy == NULL) {
               env->stat = aml_stat_panic;
               return;
       }
       AML_DEBUGPRINT("Device(");
       name = aml_parse_namestring(env);
       aml_print_namestring(name);
       AML_DEBUGPRINT(") {\n");
       *copy = *env;
       AML_CREATE_NAME(copy->curname, env, name,);
       if (copy->curname->property != NULL) {
               env->stat = aml_stat_panic;
               AML_DEBUGPRINT("Already Defined \n");
               goto out;
       }
       AML_ALLOC_OBJECT(copy->curname->property, env, aml_t_device,);
       env->dp = copy->end = start + pkglength;
       aml_parse_objectlist(copy, indent + 1);
       aml_print_indent(indent);
       AML_DEBUGPRINT("}");
       aml_free_objectcontent(&copy->tempobject);

       AML_SYSASSERT(copy->dp == copy->end);
out:
       memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defprocessor(struct aml_environ *env, int indent)
{
       u_int8_t        *start;
       u_int8_t        *name;
       u_int32_t       pkglength;
       struct  aml_environ *copy;
       struct  aml_processor *proc;
       union   aml_object *obj;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       copy = memman_alloc(aml_memman, memid_aml_environ);
       if (copy == NULL) {
               env->stat = aml_stat_panic;
               return;
       }
       AML_ALLOC_OBJECT(obj, env, aml_t_processor,);
       proc = &obj->proc;
       AML_DEBUGPRINT("Processor(");
       name = aml_parse_namestring(env);
       aml_print_namestring(name);
       proc->id = aml_parse_bytedata(env);
       proc->addr = aml_parse_dworddata(env);
       proc->len = aml_parse_bytedata(env);
       AML_DEBUGPRINT(", %d, 0x%x, 0x%x) {\n", proc->id, proc->addr, proc->len);
       *copy = *env;
       AML_CREATE_NAME(copy->curname, env, name,);
       if (copy->curname->property != NULL) {
               env->stat = aml_stat_panic;
               AML_DEBUGPRINT("Already Defined \n");
               goto out;
       }
       copy->curname->property = obj;
       env->dp = copy->end = start + pkglength;
       aml_parse_objectlist(copy, indent + 1);
       aml_print_indent(indent);
       AML_DEBUGPRINT("}");
       aml_free_objectcontent(&copy->tempobject);

       AML_SYSASSERT(copy->dp == copy->end);
out:
       memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defpowerres(struct aml_environ *env, int indent)
{
       u_int8_t        *start;
       u_int8_t        *name;
       u_int32_t       pkglength;
       struct  aml_environ *copy;
       struct  aml_powerres *pres;
       union   aml_object *obj;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       copy = memman_alloc(aml_memman, memid_aml_environ);
       if (copy == NULL) {
               env->stat = aml_stat_panic;
               return;
       }
       AML_DEBUGPRINT("PowerResource(");
       AML_ALLOC_OBJECT(obj, env, aml_t_powerres,);
       name = aml_parse_namestring(env);
       aml_print_namestring(name);
       pres = &obj->pres;
       pres->level = aml_parse_bytedata(env);
       pres->order = aml_parse_worddata(env);
       AML_DEBUGPRINT(", %d, %d) {\n", pres->level, pres->order);
       *copy = *env;
       AML_CREATE_NAME(copy->curname, env, name,);
       if (copy->curname->property != NULL) {
               env->stat = aml_stat_panic;
               AML_DEBUGPRINT("Already Defined \n");
               goto out;
       }
       copy->curname->property = obj;
       env->dp = copy->end = start + pkglength;

       aml_parse_objectlist(copy, indent + 1);
       aml_print_indent(indent);
       AML_DEBUGPRINT("}");
       aml_free_objectcontent(&copy->tempobject);

       AML_SYSASSERT(copy->dp == copy->end);
out:
       memman_free(aml_memman, memid_aml_environ, copy);
}

static void
aml_parse_defthermalzone(struct aml_environ *env, int indent)
{
       u_int8_t        *start;
       u_int8_t        *name;
       u_int32_t       pkglength;
       struct  aml_environ *copy;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       copy = memman_alloc(aml_memman, memid_aml_environ);
       if (copy == NULL) {
               env->stat = aml_stat_panic;
               return;
       }
       AML_DEBUGPRINT("ThermalZone(");
       name = aml_parse_namestring(env);
       aml_print_namestring(name);
       AML_DEBUGPRINT(") {\n");
       *copy = *env;
       AML_CREATE_NAME(copy->curname, env, name,);
       if (copy->curname->property != NULL) {
               env->stat = aml_stat_panic;
               AML_DEBUGPRINT("Already Defined \n");
               goto out;
       }
       AML_ALLOC_OBJECT(copy->curname->property, env, aml_t_therm,);
       env->dp = copy->end = start + pkglength;
       aml_parse_objectlist(copy, indent + 1);
       aml_print_indent(indent);
       AML_DEBUGPRINT("}");
       aml_free_objectcontent(&copy->tempobject);
       AML_SYSASSERT(copy->dp == copy->end);
out:
       memman_free(aml_memman, memid_aml_environ, copy);
}

static struct aml_name *
aml_parse_defelse(struct aml_environ *env, int indent, int num)
{
       u_int8_t        *start, *end, *oend;
       u_int32_t       pkglength;
       struct  aml_name *aname;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       oend = env->end;
       env->end = end = start + pkglength;
       aname = NULL;

       AML_DEBUGPRINT("Else {\n");
       if (num == 0) {
               aname = aml_parse_objectlist(env, indent + 1);
               aml_print_indent(indent);
       }
       AML_DEBUGPRINT("}");

       env->dp = end;
       env->end = oend;
       return (aname);
}

static struct aml_name *
aml_parse_defif(struct aml_environ *env, int indent)
{
       u_int8_t        *start, *end, *oend;
       u_int32_t       pkglength;
       int     num;
       struct  aml_name *aname, *aname1;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       aname = NULL;

       AML_DEBUGPRINT("If(");
       num = aml_objtonum(env, aml_eval_name
           (env, aml_parse_termobj(env, indent)));
       oend = env->end;
       end = start + pkglength;
       AML_DEBUGPRINT(")");
       if (num) {
               AML_DEBUGPRINT("{\n");
               env->end = end;
               aname = aml_parse_objectlist(env, indent + 1);
               aml_print_indent(indent);
               AML_DEBUGPRINT("}");
       }
       env->dp = end;
       env->end = oend;
       if ((end < oend) && *(env->dp) == 0xa1) {
               env->dp++;
               aname1 = aml_parse_defelse(env, indent, num);
               aname = (num == 0) ? aname1 : aname;
       }
       return (aname);
}

static struct aml_name *
aml_parse_defwhile(struct aml_environ *env, int indent)
{
       u_int8_t        *start, *end, *oend;
       u_int32_t       pkglength;
       int     num;
       struct  aml_name *aname;

       start = env->dp;
       pkglength = aml_parse_pkglength(env);
       oend = env->end;
       end = start + pkglength;
       aname = NULL;
       for (;;) {
               env->dp = start;
               aml_parse_pkglength(env);
               AML_DEBUGPRINT("While(");
               num = aml_objtonum(env, aml_eval_name
                   (env, aml_parse_termobj(env, indent)));
               AML_DEBUGPRINT(")");
               if (num == 0) {
                       break;
               }
               AML_DEBUGPRINT(" {\n");
               env->end = end;
               aname = aml_parse_objectlist(env, indent + 1);
               if (env->stat == aml_stat_step) {
                       AML_DEBUGGER(env, env);
                       continue;
               }
               if (env->stat != aml_stat_none)
                       break;
               aml_print_indent(indent);
               AML_DEBUGPRINT("}");
       }
       AML_DEBUGPRINT("\n");
       env->dp = end;
       env->end = oend;
       if (env->stat == aml_stat_break) {
               env->stat = aml_stat_none;
               aname = NULL;
       }
       return (aname);
}

static void
aml_parse_defmutex(struct aml_environ *env, int indent)
{
       char    *name;
       struct  aml_name *aname;
       struct  aml_mutex *mut;

       /* MutexOp */
       AML_DEBUGPRINT("Mutex(");
       name = (char *)aml_parse_namestring(env);
       aml_print_namestring((unsigned char *)name);
       AML_CREATE_NAME(aname, env, (unsigned char *)name,);
       if (aname->property != NULL) {
               env->stat = aml_stat_panic;
               AML_DEBUGPRINT("Already Defined \n");
               return;
       }
       AML_ALLOC_OBJECT(aname->property, env, aml_t_mutex,);
       mut = &aname->property->mutex;
       mut->level = *env->dp++;
       STAILQ_INIT(&mut->queue);
       AML_DEBUGPRINT(", %d)", mut->level);
}

static void
aml_createfield_generic(struct aml_environ *env,
   union aml_object *srcbuf, int idx,
   int len, char *newname)
{
       struct  aml_bufferfield *field;
       struct  aml_name *aname;

       if (srcbuf == NULL || srcbuf->type != aml_t_buffer) {
               AML_DEBUGPRINT("Not Buffer assigned,");
               env->stat = aml_stat_panic;
               return;
       }
       AML_CREATE_NAME(aname, env, (unsigned char *)newname,);
       if (aname->property != NULL) {
               env->stat = aml_stat_panic;
               AML_DEBUGPRINT("Already Defined \n");
               return;
       }
       AML_ALLOC_OBJECT(aname->property, env, aml_t_bufferfield,);
       field = &aname->property->bfld;
       field->bitoffset = idx;
       field->bitlen = len;
       field->origin = srcbuf->buffer.data;
}

static void
aml_parse_defcreatefield(struct aml_environ *env, int indent)
{
       int     idx, len;
       char    *newname;
       union   aml_object *obj, *srcbuf;

       /* CreateFieldOp */
       AML_DEBUGPRINT("CreateField(");
       srcbuf = aml_eval_name(env, aml_parse_termobj(env, indent));
       if (srcbuf == &env->tempobject) {
               AML_DEBUGPRINT("NONAMED BUFFER\n");
               env->stat = aml_stat_panic;
               return;
       }
       AML_DEBUGPRINT(", ");
       obj = aml_eval_name(env, aml_parse_termobj(env, indent));
       idx = aml_objtonum(env, obj);
       AML_DEBUGPRINT(", ");
       obj = aml_eval_name(env, aml_parse_termobj(env, indent));
       len = aml_objtonum(env, obj);
       AML_DEBUGPRINT(", ");
       newname = (char *)aml_parse_namestring(env);
       aml_print_namestring((unsigned char *)newname);
       aml_createfield_generic(env, srcbuf, idx, len, newname);
       AML_DEBUGPRINT(") ");
}

/*
* Returns Named object or parser buffer. The object need not be free because
* it returns preallocated buffer in env or Contain of named object.  If You
* need to preserve object, create a copy and then store.  And The object
* returned from this function is not valid after another call is
* shared, tempolary buffer may be shared.
*/
struct aml_name *
aml_parse_termobj(struct aml_environ *env, int indent)
{
       u_int8_t        opcode;
       u_int8_t        *name;
       int     value;
       int     num1, num2;
       int     len;
       int     match1, match2, i, pkgval, start;
       int     widthindex, idx;
       char    *newname;
       struct  aml_name *aname;
       struct  aml_name *destname1, *destname2;
       struct  aml_name *tmpname, *srcname;
       struct  aml_name *src;
       union   aml_object *ret;
       union   aml_object *tmpobj;
       union   aml_object anum;
       union   aml_object *objref;
       union   aml_object *srcobj;
       union   aml_object *obj;
       union   aml_object *srcbuf;
       static int      widthtbl[4] = {32, 16, 8, 1};
       const char      *opname[4] = {"CreateDWordField", "CreateWordField",
                                     "CreateByteField", "CreateBitField"};

       aname = &env->tempname;
       ret = &env->tempobject;
       anum.type = aml_t_num;
       aname->property = ret;
       aml_free_objectcontent(ret);
       if (env->stat == aml_stat_panic) {
               /*
                * If previously parser panic , parsing next instruction is
                * prohibited.
                */
               return (NULL);
       }
       aname = NULL;
       opcode = *env->dp++;
       switch (opcode) {
       case '\\':
       case '^':
       case 'A' ... 'Z':
       case '_':
       case '.':
       case '/':
               env->dp--;
               ret->type = aml_t_namestr;
               ret->nstr.dp = aml_parse_namestring(env);
               aml_print_namestring(ret->nstr.dp);
               aname = &env->tempname;
               break;
       case 0x0a:              /* BytePrefix */
               ret->type = aml_t_num;
               value = aml_parse_bytedata(env);
               ret->num.number = value;
               AML_DEBUGPRINT("0x%x", value);
               aname = &env->tempname;
               break;
       case 0x0b:              /* WordPrefix */
               ret->type = aml_t_num;
               value = aml_parse_worddata(env);
               ret->num.number = value;
               AML_DEBUGPRINT("0x%x", value);
               aname = &env->tempname;
               break;
       case 0x0c:              /* DWordPrefix */
               ret->type = aml_t_num;
               value = aml_parse_dworddata(env);
               ret->num.number = value;
               AML_DEBUGPRINT("0x%x", value);
               aname = &env->tempname;
               break;
       case 0x0d:              /* StringPrefix */
               ret->type = aml_t_string;
               ret->str.string = env->dp;
               len = strlen((const char *)env->dp);
               ret->str.needfree = 0;
               AML_DEBUGPRINT("\"%s\"", (const char *)ret->str.string);
               env->dp += (len + 1);
               aname = &env->tempname;
               break;
       case 0x00:              /* ZeroOp */
               ret->type = aml_t_num;
               ret->num.number = 0;
               ret->num.constant = 1;
               AML_DEBUGPRINT("Zero");
               aname = &env->tempname;
               break;
       case 0x01:              /* OneOp */
               ret->type = aml_t_num;
               ret->num.number = 1;
               ret->num.constant = 1;
               AML_DEBUGPRINT("One");
               aname = &env->tempname;
               break;
       case 0xff:              /* OnesOp */
               ret->type = aml_t_num;
               ret->num.number = 0xffffffff;
               ret->num.constant = 1;
               AML_DEBUGPRINT("Ones");
               aname = &env->tempname;
               break;
       case 0x06:              /* AliasOp */
               AML_DEBUGPRINT("Alias(");
               tmpname = aml_parse_termobj(env, indent);
               if (env->stat == aml_stat_panic) {
                       return (NULL);
               }
               if (tmpname->property == NULL ||
                   tmpname->property->type != aml_t_namestr) {
                       env->stat = aml_stat_panic;
                       return (NULL);
               }
               /*
                * XXX if srcname is deleted after this object, what
                * shall I do?
                */
               srcname = aml_search_name(env, tmpname->property->nstr.dp);
               AML_DEBUGPRINT(", ");
               name = aml_parse_namestring(env);
               aml_print_namestring(name);
               AML_CREATE_NAME(aname, env, name, 0);
               if (aname->property != NULL) {
                       env->stat = aml_stat_panic;
                       AML_DEBUGPRINT("Already Defined \n");
                       aml_print_curname(aname);
                       return (NULL);
               }
               AML_ALLOC_OBJECT(aname->property, env, aml_t_objref, NULL);
               objref = aname->property;
               objref->objref.nameref = srcname;
               objref->objref.ref = srcname->property;
               objref->objref.offset = -1;
               objref->objref.alias = 1;       /* Yes, this is an alias */
               AML_DEBUGPRINT(")");
               /* shut the interpreter up during the namespace initializing */
               return (NULL);
       case 0x08:              /* NameOp */
               AML_DEBUGPRINT("Name(");
               name = aml_parse_namestring(env);
               aml_print_namestring(name);
               AML_CREATE_NAME(aname, env, name, 0);
               if (env->stat == aml_stat_panic) {
                       AML_DEBUGPRINT("Already Defined \n");
                       aml_print_curname(aname);
                       return (NULL);
               }
               AML_DEBUGPRINT(", ");
               AML_COPY_OBJECT(aname->property, env,
                   aml_eval_name(env,
                       aml_parse_termobj(env, indent)),
                   NULL);
               AML_DEBUGPRINT(")");
               break;
       case 0x10:              /* ScopeOp */
               aml_parse_defscope(env, indent);
               break;
       case 0x11:              /* BufferOp */
               aname = &env->tempname;
               aname->property = aml_parse_defbuffer(env, indent);
               break;
       case 0x12:              /* PackageOp */
               aname = &env->tempname;
               aname->property = aml_parse_defpackage(env, indent);
               break;
       case 0x14:              /* MethodOp */
               aml_parse_defmethod(env, indent);
               break;
       case 0x5b:              /* ExtOpPrefix */
               opcode = *env->dp++;
               switch (opcode) {
               case 0x01:
                       aml_parse_defmutex(env, indent);
                       break;
               case 0x02:      /* EventOp */
                       AML_DEBUGPRINT("Event(");
                       name = aml_parse_namestring(env);
                       aml_print_namestring(name);
                       AML_CREATE_NAME(aname, env, name, 0);
                       if (aname->property != NULL) {
                               env->stat = aml_stat_panic;
                               AML_DEBUGPRINT("Already Defined \n");
                               return (NULL);
                       }
                       AML_ALLOC_OBJECT(aname->property, env, aml_t_event, NULL);
                       AML_DEBUGPRINT(")");
                       return (NULL);
                       break;
               case 0x12:      /* CondRefOfOp */
                       AML_DEBUGPRINT("CondRefOf(");
                       src = aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(", ");
                       if (src == &env->tempname || src == NULL) {
                               aml_parse_termobj(env, indent);
                               AML_DEBUGPRINT(")");
                               anum.num.number = 0xffffffff;
                               env->tempobject.num = anum.num;
                               aname = &env->tempname;
                               break;
                       }
                       AML_ALLOC_OBJECT(objref, env, aml_t_objref, NULL);
                       if (src->property == NULL ||
                           src->property->type != aml_t_namestr) {
                               objref->objref.nameref = src;
                       } else {
                               objref->objref.nameref = aml_create_local_object();
                       }
                       objref->objref.ref = src->property;
                       objref->objref.offset = -1;     /* different from IndexOp */

                       destname1 = aml_parse_termobj(env, indent);
                       aml_store_to_name(env, objref, destname1);
                       anum.num.number = 0;
                       env->tempobject.num = anum.num;
                       aname = &env->tempname;
                       AML_DEBUGPRINT(")");
                       break;
               case 0x13:
                       aml_parse_defcreatefield(env, indent);
                       break;
               case 0x20:      /* LoadOp *//* XXX Not Impremented */
                       AML_DEBUGPRINT("Load(");
                       aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(", ");
                       aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(")");
                       break;
               case 0x21:      /* StallOp */
                       AML_DEBUGPRINT("Stall(");
                       num1 = aml_objtonum(env, aml_eval_name(env,
                           aml_parse_termobj(env, indent)));
                       AML_DEBUGPRINT(")");
                       AML_STALL(num1);
                       break;
               case 0x22:      /* SleepOp */
                       AML_DEBUGPRINT("Sleep(");
                       num1 = aml_objtonum(env, aml_eval_name(env,
                           aml_parse_termobj(env, indent)));
                       AML_SLEEP(0, num1);
                       AML_DEBUGPRINT(")");
                       break;
               case 0x23:      /* AcquireOp *//* XXX Not yet */
                       AML_DEBUGPRINT("Acquire(");
                       aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(", 0x%x)", aml_parse_worddata(env));
                       break;
               case 0x24:      /* SignalOp *//* XXX Not yet */
                       AML_DEBUGPRINT("Signal(");
                       aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(")");
                       break;
               case 0x25:      /* WaitOp *//* XXX Not yet impremented */
                       AML_DEBUGPRINT("Wait(");
                       aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(", ");
                       aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(")");
                       break;
               case 0x26:      /* ResetOp *//* XXX Not yet impremented */
                       AML_DEBUGPRINT("Reset(");
                       aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(")");
                       break;
               case 0x27:      /* ReleaseOp *//* XXX Not yet impremented */
                       AML_DEBUGPRINT("Release(");
                       aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(")");
                       break;
#define NUMOP2(opname, operation) do {                                  \
       AML_DEBUGPRINT(opname);                                         \
       AML_DEBUGPRINT("(");                                            \
       num1 = aml_objtonum(env, aml_eval_name(env,                     \
           aml_parse_termobj(env, indent)));                           \
       AML_DEBUGPRINT(", ");                                           \
       anum.num.number = operation (num1);                             \
       destname1 = aml_parse_termobj(env, indent);                     \
       AML_DEBUGPRINT(")");                                            \
       aml_store_to_name(env, &anum, destname1);                       \
       env->tempobject.num = anum.num;                                 \
       env->tempname.property = &env->tempobject;                      \
       aname = &env->tempname;                                         \
} while(0)

               case 0x28:      /* FromBCDOp */
                       NUMOP2("FromBCD", frombcd);
                       break;
               case 0x29:      /* ToBCDOp */
                       NUMOP2("ToBCD", tobcd);
                       break;
               case 0x2a:      /* UnloadOp *//* XXX Not yet impremented */
                       AML_DEBUGPRINT("Unload(");
                       aml_parse_termobj(env, indent);
                       AML_DEBUGPRINT(")");
                       break;
               case 0x30:
                       env->tempobject.type = aml_t_num;
                       env->tempobject.num.number = 0;
                       env->tempobject.num.constant = 1;
                       AML_DEBUGPRINT("Revision");
                       break;
               case 0x31:
                       env->tempobject.type = aml_t_debug;
                       aname = &env->tempname;
                       AML_DEBUGPRINT("Debug");
                       break;
               case 0x32:      /* FatalOp */
                       AML_DEBUGPRINT("Fatal(");
                       AML_DEBUGPRINT("0x%x, ", aml_parse_bytedata(env));
                       AML_DEBUGPRINT("0x%x, ", aml_parse_dworddata(env));
                       aml_parse_termobj(env, indent);
                       env->stat = aml_stat_panic;
                       AML_DEBUGPRINT(")");
                       break;
               case 0x80:      /* OpRegionOp */
                       aml_parse_defopregion(env, indent);
                       break;
               case 0x81:      /* FieldOp */
                       aml_parse_deffield(env, indent);
                       break;
               case 0x82:      /* DeviceOp */
                       aml_parse_defdevice(env, indent);
                       break;
               case 0x83:      /* ProcessorOp */
                       aml_parse_defprocessor(env, indent);
                       break;
               case 0x84:      /* PowerResOp */
                       aml_parse_defpowerres(env, indent);
                       break;
               case 0x85:      /* ThermalZoneOp */
                       aml_parse_defthermalzone(env, indent);
                       break;
               case 0x86:      /* IndexFieldOp */
                       aml_parse_defindexfield(env, indent);
                       break;
               case 0x87:      /* BankFieldOp */
                       aml_parse_defbankfield(env, indent);
                       break;
               default:
                       AML_SYSERRX(1, "strange opcode 0x5b, 0x%x\n", opcode);
                       AML_SYSABORT();
               }
               break;
       case 0x68 ... 0x6e:     /* ArgN */
               AML_DEBUGPRINT("Arg%d", opcode - 0x68);
               return (aml_local_stack_getArgX(NULL, opcode - 0x68));
               break;
       case 0x60 ... 0x67:
               AML_DEBUGPRINT("Local%d", opcode - 0x60);
               return (aml_local_stack_getLocalX(opcode - 0x60));
               break;
       case 0x70:              /* StoreOp */
               AML_DEBUGPRINT("Store(");
               aname = aml_create_local_object();
               AML_COPY_OBJECT(tmpobj, env,
                   aml_eval_name(env,  aml_parse_termobj(env, indent)), NULL);
               aname->property = tmpobj;
               AML_DEBUGPRINT(", ");
               destname1 = aml_parse_termobj(env, indent);
               AML_DEBUGPRINT(")");
               /* XXX
                * temporary object may change during aml_store_to_name()
                * operation, so we make a copy of it on stack.
                */
               if (destname1 == &env->tempname &&
                   destname1->property == &env->tempobject) {
                       destname1 = aml_create_local_object();
                       AML_COPY_OBJECT(destname1->property, env,
                           &env->tempobject, NULL);
               }
               aml_store_to_name(env, tmpobj, destname1);
               if (env->stat == aml_stat_panic) {
                       AML_DEBUGPRINT("StoreOp failed");
                       return (NULL);
               }
               aname = aml_create_local_object();
               AML_COPY_OBJECT(tmpobj, env, destname1->property, NULL);
               aname->property = tmpobj;
               if (tmpobj == NULL) {
                       printf("???");
                       break;
               }
               break;
       case 0x71:              /* RefOfOp */
               AML_DEBUGPRINT("RefOf(");
               src = aml_parse_termobj(env, indent);
               AML_DEBUGPRINT(")");

               aname = aml_create_local_object();
               AML_ALLOC_OBJECT(aname->property, env, aml_t_objref, NULL);
               objref = aname->property;
               if (src->property == NULL ||
                   src->property->type != aml_t_namestr) {
                       objref->objref.nameref = src;
               } else {
                       objref->objref.nameref = aml_create_local_object();
               }
               objref->objref.ref = src->property;
               objref->objref.offset = -1;     /* different from IndexOp */
               break;

#define NUMOP3_2(opname, oparation, ope2) do {                          \
       AML_DEBUGPRINT(opname);                                         \
       AML_DEBUGPRINT("(");                                            \
       num1 = aml_objtonum(env, aml_eval_name(env,                     \
           aml_parse_termobj(env, indent)));                           \
       AML_DEBUGPRINT(", ");                                           \
       num2 = aml_objtonum(env, aml_eval_name(env,                     \
           aml_parse_termobj(env, indent)));                           \
       AML_DEBUGPRINT(", ");                                           \
       anum.num.number = ope2(num1 oparation num2);                    \
       destname1 = aml_parse_termobj(env, indent);                     \
       AML_DEBUGPRINT(")");                                            \
       aml_store_to_name(env, &anum, destname1);                       \
       env->tempobject.num = anum.num;                                 \
       env->tempname.property = &env->tempobject;                      \
       aname = &env->tempname;                                         \
} while(0)

#define NUMOP3(opname, operation)       NUMOP3_2(opname, operation, )
#define NUMOPN3(opname, operation)      NUMOP3_2(opname, operation, ~)

       case 0x72:              /* AddOp */
               NUMOP3("Add", +);
               break;
       case 0x73:              /* ConcatOp  */
               aname = aml_parse_concatop(env, indent);
               break;
       case 0x74:              /* SubtractOp */
               NUMOP3("Subtract", -);
               break;
       case 0x75:              /* IncrementOp */
               AML_DEBUGPRINT("Increment(");
               aname = aml_parse_termobj(env, indent);
               num1 = aml_objtonum(env, aml_eval_name(env, aname));
               num1++;
               anum.num.number = num1;
               AML_DEBUGPRINT(")");
               aml_store_to_name(env, &anum, aname);
               aname = &env->tempname;
               env->tempobject.num = anum.num;
               break;
       case 0x76:              /* DecrementOp */
               AML_DEBUGPRINT("Decrement(");
               aname = aml_parse_termobj(env, indent);
               num1 = aml_objtonum(env, aml_eval_name(env, aname));
               num1--;
               anum.num.number = num1;
               AML_DEBUGPRINT(")");
               aml_store_to_name(env, &anum, aname);
               aname = &env->tempname;
               env->tempobject.num = anum.num;
               break;
       case 0x77:              /* MultiplyOp */
               NUMOP3("Multiply", *);
               break;
       case 0x78:              /* DivideOp */
               AML_DEBUGPRINT("Divide(");
               num1 = aml_objtonum(env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)));
               AML_DEBUGPRINT(", ");
               num2 = aml_objtonum(env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)));
               AML_DEBUGPRINT(", ");
               anum.num.number = num1 % num2;
               destname1 = aml_parse_termobj(env, indent);
               aml_store_to_name(env, &anum, destname1);
               AML_DEBUGPRINT(", ");
               anum.num.number = num1 / num2;
               destname2 = aml_parse_termobj(env, indent);
               AML_DEBUGPRINT(")");
               aml_store_to_name(env, &anum, destname2);
               env->tempobject.num = anum.num;
               aname = &env->tempname;
               break;
       case 0x79:              /* ShiftLeftOp */
               NUMOP3("ShiftLeft", <<);
               break;
       case 0x7a:              /* ShiftRightOp */
               NUMOP3("ShiftRight", >>);
               break;
       case 0x7b:              /* AndOp */
               NUMOP3("And", &);
               break;
       case 0x7c:              /* NAndOp */
               NUMOPN3("NAnd", &);
               break;
       case 0x7d:              /* OrOp */
               NUMOP3("Or", |);
               break;
       case 0x7e:              /* NOrOp */
               NUMOPN3("NOr", |);
               break;
       case 0x7f:              /* XOrOp */
               NUMOP3("XOr", ^);
               break;
       case 0x80:              /* NotOp */
               NUMOP2("Not", ~);
               break;
       case 0x81:              /* FindSetLeftBitOp */
               NUMOP2("FindSetLeftBit", findsetleftbit);
               break;
       case 0x82:              /* FindSetRightBitOp */
               NUMOP2("FindSetRightBit", findsetrightbit);
               break;
       case 0x83:              /* DerefOp */
               AML_DEBUGPRINT("DerefOf(");
               objref = aml_eval_name(env, aml_parse_termobj(env, indent));
               AML_DEBUGPRINT(")");

               if (objref->objref.ref == NULL) {
                       env->tempname.property = objref->objref.ref;
                       aname = &env->tempname;
                       break;
               }
               switch (objref->objref.ref->type) {
               case aml_t_package:
               case aml_t_buffer:
                       if (objref->objref.offset < 0) {
                               env->tempname.property = objref->objref.ref;
                       } else {
                               objref->objref.deref = 1;
                               env->tempname.property = objref;
                       }
                       break;
               default:
                       env->tempname.property = objref->objref.ref;
                       break;
               }

               aname = &env->tempname;
               break;
       case 0x86:              /* NotifyOp *//* XXX Not yet impremented */
               AML_DEBUGPRINT("Notify(");
               aml_parse_termobj(env, indent);
               AML_DEBUGPRINT(", ");
               aml_parse_termobj(env, indent);
               AML_DEBUGPRINT(")");
               break;
       case 0x87:              /* SizeOfOp */
               AML_DEBUGPRINT("SizeOf(");
               aname = aml_parse_termobj(env, indent);
               tmpobj = aml_eval_name(env, aname);

               AML_DEBUGPRINT(")");
               num1 = 0;
               switch (tmpobj->type) {
               case aml_t_buffer:
                       num1 = tmpobj->buffer.size;
                       break;
               case aml_t_string:
                       num1 = strlen((const char *)tmpobj->str.string);
                       break;
               case aml_t_package:
                       num1 = tmpobj->package.elements;
                       break;
               default:
                       AML_DEBUGPRINT("Args of SizeOf should be "
                                      "buffer/string/package only\n");
                       break;
               }

               anum.num.number = num1;
               env->tempobject.num = anum.num;
               aname = &env->tempname;
               break;
       case 0x88:              /* IndexOp */
               AML_DEBUGPRINT("Index(");
               srcobj = aml_eval_name(env, aml_parse_termobj(env, indent));
               AML_DEBUGPRINT(", ");
               num1 = aml_objtonum(env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)));
               AML_DEBUGPRINT(", ");
               destname1 = aml_parse_termobj(env, indent);
               AML_DEBUGPRINT(")");
               aname = aml_create_local_object();
               switch (srcobj->type) {
               case aml_t_package:
               case aml_t_buffer:
                       AML_ALLOC_OBJECT(objref, env, aml_t_objref, NULL);
                       aname->property = objref;
                       objref->objref.ref = srcobj;
                       objref->objref.offset = num1;
                       objref->objref.deref = 0;
                       break;
               default:
                       AML_DEBUGPRINT("Arg0 of Index should be either "
                                      "buffer or package\n");
                       return (aname);
               }

               aml_store_to_name(env, objref, destname1);
               break;
       case 0x89:              /* MatchOp *//* XXX Not yet Impremented */
               AML_DEBUGPRINT("Match(");
               AML_COPY_OBJECT(obj, env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)), NULL);
               if (obj->type != aml_t_package) {
                       env->stat = aml_stat_panic;
                       return (NULL);
               }
               anum.num.number = 0xffffffff;
               match1 = *env->dp;
               AML_DEBUGPRINT(", %d", *env->dp);
               env->dp++;
               num1 = aml_objtonum(env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)));
               match2 = *env->dp;
               AML_DEBUGPRINT(", %d", *env->dp);
               env->dp++;
               num2 = aml_objtonum(env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)));
               AML_DEBUGPRINT(", ");
               start = aml_objtonum(env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)));

#define MATCHOP(opnum, arg1, arg2)      ((opnum == 0) ? (1) :           \
   (opnum == 1) ? ((arg1) == (arg2))   :                               \
   (opnum == 2) ? ((arg1) <= (arg2))   :                               \
   (opnum == 3) ? ((arg1) <  (arg2))   :                               \
   (opnum == 4) ? ((arg1) >= (arg2))   :                               \
   (opnum == 5) ? ((arg1) >  (arg2))   : 0 )

               for (i = start; i < obj->package.elements; i++) {
                       pkgval = aml_objtonum(env, obj->package.objects[i]);
                       if (MATCHOP(match1, pkgval, num1) &&
                           MATCHOP(match2, pkgval, num2)) {
                               anum.num.number = i;
                               break;
                       }
               }
               AML_DEBUGPRINT(")");
               aml_free_object(&obj);
               aname = &env->tempname;
               env->tempname.property = &env->tempobject;
               env->tempobject.num = anum.num;
               break;
#undef MATCHOP
       case 0x8a ... 0x8d:     /* CreateDWordFieldOp */
               widthindex = *(env->dp - 1) - 0x8a;
               AML_DEBUGPRINT("%s(", opname[widthindex]);
               srcbuf = aml_eval_name(env, aml_parse_termobj(env, indent));
               if (srcbuf == &env->tempobject) {
                       AML_DEBUGPRINT("NOT NAMEDBUF\n");
                       env->stat = aml_stat_panic;
                       return (NULL);
               }
               AML_DEBUGPRINT(", ");
               idx = aml_objtonum(env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)));
               if (widthindex != 3) {
                       idx *= 8;
               }
               AML_DEBUGPRINT(", ");
               newname = (char *)aml_parse_namestring(env);
               aml_print_namestring((unsigned char *)newname);
               aml_createfield_generic(env, srcbuf, idx,
                   widthtbl[widthindex], newname);
               AML_DEBUGPRINT(")");
               break;
       case 0x8e:              /* ObjectTypeOp */
               AML_DEBUGPRINT("ObjectType(");
               aname = aml_parse_termobj(env, indent);
               if (aname == NULL) {
                       env->tempobject.type = aml_t_num;
                       env->tempobject.num.number = aml_t_null;
               } else {
                       env->tempobject.type = aml_t_num;
                       env->tempobject.num.number = aname->property->type;
               }
               aname = &env->tempname;
               AML_DEBUGPRINT(")");
               break;

#define CMPOP(opname,operation) do {                                    \
       AML_DEBUGPRINT(opname);                                         \
       AML_DEBUGPRINT("(");                                            \
       num1 = aml_objtonum(env, aml_eval_name(env,                     \
           aml_parse_termobj(env, indent)));                           \
       AML_DEBUGPRINT(", ");                                           \
       num2 = aml_objtonum(env, aml_eval_name(env,                     \
           aml_parse_termobj(env, indent)));                           \
       aname = &env->tempname;                                         \
       env->tempobject.type = aml_t_num;                               \
       env->tempobject.num.number = (num1 operation num2) ? 0xffffffff : 0;    \
       aname->property = &env->tempobject;                             \
       AML_DEBUGPRINT(")");                                            \
} while(0)

       case 0x90:
               CMPOP("LAnd", &&);
               break;
       case 0x91:
               CMPOP("LOr", ||);
               break;
       case 0x92:
               AML_DEBUGPRINT("LNot(");
               num1 = aml_objtonum(env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)));
               aname = &env->tempname;
               env->tempobject.type = aml_t_num;
               env->tempobject.num.number = (!num1) ? 0xffffffff : 0;
               aname->property = &env->tempobject;
               AML_DEBUGPRINT(")");
               break;
       case 0x93:
               CMPOP("LEqual", ==);
               break;
       case 0x94:
               CMPOP("LGreater", >);
               break;
       case 0x95:
               CMPOP("LLess", <);
               break;
       case 0xa0:              /* IfOp */
               aname = aml_parse_defif(env, indent);
               break;
#if 0

       case 0xa1:              /* ElseOp should not be treated in Main parser
                                * But If Op */
               aml_parse_defelse(env, indent);
               break;
#endif
       case 0xa2:              /* WhileOp */
               aname = aml_parse_defwhile(env, indent);
               break;
       case 0xa3:              /* NoopOp */
               AML_DEBUGPRINT("Noop");
               break;
       case 0xa5:              /* BreakOp */
               AML_DEBUGPRINT("Break");
               env->stat = aml_stat_break;
               break;
       case 0xa4:              /* ReturnOp */
               AML_DEBUGPRINT("Return(");
               AML_COPY_OBJECT(env->tempname.property, env, aml_eval_name(env,
                   aml_parse_termobj(env, indent)), NULL);
               aname = &env->tempname;
               env->stat = aml_stat_return;
               AML_DEBUGPRINT(")");
               break;
       case 0xcc:              /* BreakPointOp */
               /* XXX Not Yet Impremented (Not need?) */
               AML_DEBUGPRINT("BreakPoint");
               break;
       default:
               AML_SYSERRX(1, "strange opcode 0x%x\n", opcode);
               AML_SYSABORT();
       }

       return (aname);
}