1*74b6b0adSandvar /* $NetBSD: aml_store.c,v 1.5 2024/07/31 20:20:11 andvar Exp $ */ 253e202c1Schristos 353e202c1Schristos /*- 453e202c1Schristos * Copyright (c) 1999 Takanori Watanabe 553e202c1Schristos * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 653e202c1Schristos * All rights reserved. 753e202c1Schristos * 853e202c1Schristos * Redistribution and use in source and binary forms, with or without 953e202c1Schristos * modification, are permitted provided that the following conditions 1053e202c1Schristos * are met: 1153e202c1Schristos * 1. Redistributions of source code must retain the above copyright 1253e202c1Schristos * notice, this list of conditions and the following disclaimer. 1353e202c1Schristos * 2. Redistributions in binary form must reproduce the above copyright 1453e202c1Schristos * notice, this list of conditions and the following disclaimer in the 1553e202c1Schristos * documentation and/or other materials provided with the distribution. 1653e202c1Schristos * 1753e202c1Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1853e202c1Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1953e202c1Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2053e202c1Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2153e202c1Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2253e202c1Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2353e202c1Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2453e202c1Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2553e202c1Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2653e202c1Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2753e202c1Schristos * SUCH DAMAGE. 2853e202c1Schristos * 2953e202c1Schristos * Id: aml_store.c,v 1.22 2000/08/09 14:47:44 iwasaki Exp 3053e202c1Schristos * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_store.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $ 3153e202c1Schristos */ 3253e202c1Schristos #include <sys/cdefs.h> 33*74b6b0adSandvar __RCSID("$NetBSD: aml_store.c,v 1.5 2024/07/31 20:20:11 andvar Exp $"); 3453e202c1Schristos 3553e202c1Schristos #include <sys/param.h> 3653e202c1Schristos 3753e202c1Schristos #include <acpi_common.h> 3853e202c1Schristos #include <aml/aml_amlmem.h> 3953e202c1Schristos #include <aml/aml_common.h> 4053e202c1Schristos #include <aml/aml_env.h> 4153e202c1Schristos #include <aml/aml_evalobj.h> 4253e202c1Schristos #include <aml/aml_name.h> 4353e202c1Schristos #include <aml/aml_obj.h> 4453e202c1Schristos #include <aml/aml_region.h> 4553e202c1Schristos #include <aml/aml_status.h> 4653e202c1Schristos #include <aml/aml_store.h> 4753e202c1Schristos 4853e202c1Schristos #ifndef _KERNEL 4953e202c1Schristos #include <assert.h> 5053e202c1Schristos #include <stdio.h> 5153e202c1Schristos #include <string.h> 5253e202c1Schristos 5353e202c1Schristos #include "debug.h" 5453e202c1Schristos #else /* _KERNEL */ 5553e202c1Schristos #include <sys/systm.h> 5653e202c1Schristos #endif /* !_KERNEL */ 5753e202c1Schristos 5853e202c1Schristos static void 5953e202c1Schristos aml_store_to_fieldname(struct aml_environ *env, union aml_object *obj, 6053e202c1Schristos struct aml_name *name) 6153e202c1Schristos { 6253e202c1Schristos u_int8_t *buffer; 6353e202c1Schristos struct aml_name *wname, *oname, *iname; 6453e202c1Schristos struct aml_field *field; 6553e202c1Schristos struct aml_opregion *or; 6653e202c1Schristos union aml_object tobj, iobj, *tmpobj; 6753e202c1Schristos 6853e202c1Schristos field = &name->property->field; 6953e202c1Schristos oname = env->curname; 7053e202c1Schristos iname = NULL; 7153e202c1Schristos env->curname = name->parent; 7253e202c1Schristos if (field->f.ftype == f_t_field) { 7353e202c1Schristos wname = aml_search_name(env, field->f.fld.regname); 7453e202c1Schristos if (wname == NULL || 7553e202c1Schristos wname->property == NULL || 7653e202c1Schristos wname->property->type != aml_t_opregion) { 77016d86eeSandvar AML_DEBUGPRINT("Inappropriate Type\n"); 7853e202c1Schristos env->stat = aml_stat_panic; 7953e202c1Schristos env->curname = oname; 8053e202c1Schristos return; 8153e202c1Schristos } 8253e202c1Schristos or = &wname->property->opregion; 8353e202c1Schristos switch (obj->type) { 8453e202c1Schristos case aml_t_num: 8553e202c1Schristos aml_region_write(env, or->space, field->flags, 8653e202c1Schristos obj->num.number, or->offset, 8753e202c1Schristos field->bitoffset, field->bitlen); 8853e202c1Schristos AML_DEBUGPRINT("[write(%d, 0x%x, 0x%x)]", 8953e202c1Schristos or->space, obj->num.number, 9053e202c1Schristos or->offset + field->bitoffset / 8); 9153e202c1Schristos break; 9253e202c1Schristos case aml_t_buffer: 9353e202c1Schristos case aml_t_bufferfield: 9453e202c1Schristos if (obj->type == aml_t_buffer) { 9553e202c1Schristos buffer = obj->buffer.data; 9653e202c1Schristos } else { 9753e202c1Schristos buffer = obj->bfld.origin; 9853e202c1Schristos buffer += obj->bfld.bitoffset / 8; 9953e202c1Schristos } 10053e202c1Schristos aml_region_write_from_buffer(env, or->space, 10153e202c1Schristos field->flags, buffer, or->offset, field->bitoffset, 10253e202c1Schristos field->bitlen); 10353e202c1Schristos break; 10453e202c1Schristos case aml_t_regfield: 10553e202c1Schristos if (or->space != obj->regfield.space) { 10653e202c1Schristos AML_DEBUGPRINT("aml_store_to_fieldname: " 10753e202c1Schristos "Different type of space\n"); 10853e202c1Schristos break; 10953e202c1Schristos } 11053e202c1Schristos aml_region_bcopy(env, obj->regfield.space, 11153e202c1Schristos obj->regfield.flags, obj->regfield.offset, 11253e202c1Schristos obj->regfield.bitoffset, obj->regfield.bitlen, 11353e202c1Schristos field->flags, or->offset, field->bitoffset, 11453e202c1Schristos field->bitlen); 11553e202c1Schristos break; 11653e202c1Schristos default: 11753e202c1Schristos AML_DEBUGPRINT("aml_store_to_fieldname: " 118*74b6b0adSandvar "Inappropriate Type of src object\n"); 11953e202c1Schristos break; 12053e202c1Schristos } 12153e202c1Schristos } else if (field->f.ftype == f_t_index) { 12253e202c1Schristos iname = aml_search_name(env, field->f.ifld.indexname); 12353e202c1Schristos wname = aml_search_name(env, field->f.ifld.dataname); 12453e202c1Schristos iobj.type = aml_t_num; 12553e202c1Schristos iobj.num.number = field->bitoffset / 8; /* AccessType Boundary */ 12653e202c1Schristos 12753e202c1Schristos /* read whole values of IndexField */ 12853e202c1Schristos aml_store_to_name(env, &iobj, iname); 12953e202c1Schristos tmpobj = aml_eval_name(env, wname); 13053e202c1Schristos 13153e202c1Schristos /* make the values to be written */ 13253e202c1Schristos tobj.num = obj->num; 13353e202c1Schristos tobj.num.number = aml_adjust_updatevalue(field->flags, 13453e202c1Schristos field->bitoffset & 7, field->bitlen, 13553e202c1Schristos tmpobj->num.number, obj->num.number); 13653e202c1Schristos 13753e202c1Schristos /* write the values to IndexField */ 13853e202c1Schristos aml_store_to_name(env, &iobj, iname); 13953e202c1Schristos aml_store_to_name(env, &tobj, wname); 14053e202c1Schristos } 14153e202c1Schristos env->curname = oname; 14253e202c1Schristos } 14353e202c1Schristos 14453e202c1Schristos static void 14553e202c1Schristos aml_store_to_buffer(struct aml_environ *env, union aml_object *obj, 14653e202c1Schristos union aml_object *buf, int offset) 14753e202c1Schristos { 14853e202c1Schristos int size; 14953e202c1Schristos int bitlen; 15053e202c1Schristos 15153e202c1Schristos switch (obj->type) { 15253e202c1Schristos case aml_t_num: 15353e202c1Schristos if (offset > buf->buffer.size) { 15453e202c1Schristos aml_realloc_object(buf, offset); 15553e202c1Schristos } 15653e202c1Schristos buf->buffer.data[offset] = obj->num.number & 0xff; 15753e202c1Schristos AML_DEBUGPRINT("[Store number 0x%x to buffer]", 15853e202c1Schristos obj->num.number & 0xff); 15953e202c1Schristos break; 16053e202c1Schristos case aml_t_string: 16153e202c1Schristos size = strlen((const char *)obj->str.string); 16253e202c1Schristos if (buf->buffer.size - offset < size) { 16353e202c1Schristos aml_realloc_object(buf, offset + size + 1); 16453e202c1Schristos } 16553e202c1Schristos strcpy((char *)&buf->buffer.data[offset], 16653e202c1Schristos (const char *)obj->str.string); 16753e202c1Schristos AML_DEBUGPRINT("[Store string to buffer]"); 16853e202c1Schristos break; 16953e202c1Schristos case aml_t_buffer: 17053e202c1Schristos bzero(buf->buffer.data, buf->buffer.size); 17153e202c1Schristos if (obj->buffer.size > buf->buffer.size) { 17253e202c1Schristos size = buf->buffer.size; 17353e202c1Schristos } else { 17453e202c1Schristos size = obj->buffer.size; 17553e202c1Schristos } 17653e202c1Schristos bcopy(obj->buffer.data, buf->buffer.data, size); 17753e202c1Schristos break; 17853e202c1Schristos case aml_t_regfield: 17953e202c1Schristos bitlen = (buf->buffer.size - offset) * 8; 18053e202c1Schristos if (bitlen > obj->regfield.bitlen) { 18153e202c1Schristos bitlen = obj->regfield.bitlen; 18253e202c1Schristos } 18353e202c1Schristos aml_region_read_into_buffer(env, obj->regfield.space, 18453e202c1Schristos obj->regfield.flags, obj->regfield.offset, 18553e202c1Schristos obj->regfield.bitoffset, bitlen, 18653e202c1Schristos buf->buffer.data + offset); 18753e202c1Schristos break; 18853e202c1Schristos default: 18953e202c1Schristos goto not_yet; 19053e202c1Schristos } 19153e202c1Schristos return; 19253e202c1Schristos not_yet: 19353e202c1Schristos AML_DEBUGPRINT("[XXX not supported yet]"); 19453e202c1Schristos } 19553e202c1Schristos 19653e202c1Schristos 19753e202c1Schristos void 19853e202c1Schristos aml_store_to_object(struct aml_environ *env, union aml_object *src, 19953e202c1Schristos union aml_object * dest) 20053e202c1Schristos { 20153e202c1Schristos u_int8_t *buffer, *srcbuf; 20253e202c1Schristos int offset, bitlen; 20353e202c1Schristos 20453e202c1Schristos switch (dest->type) { 20553e202c1Schristos case aml_t_num: 20653e202c1Schristos if (src->type == aml_t_num) { 20753e202c1Schristos dest->num = src->num; 20853e202c1Schristos AML_DEBUGPRINT("[Store number 0x%x]", src->num.number); 20953e202c1Schristos } else { 21053e202c1Schristos env->stat = aml_stat_panic; 21153e202c1Schristos } 21253e202c1Schristos break; 21353e202c1Schristos case aml_t_string: 21453e202c1Schristos case aml_t_package: 21553e202c1Schristos break; 21653e202c1Schristos case aml_t_buffer: 21753e202c1Schristos aml_store_to_buffer(env, src, dest, 0); 21853e202c1Schristos break; 21953e202c1Schristos case aml_t_bufferfield: 22053e202c1Schristos buffer = dest->bfld.origin; 22153e202c1Schristos offset = dest->bfld.bitoffset; 22253e202c1Schristos bitlen = dest->bfld.bitlen; 22353e202c1Schristos 22453e202c1Schristos switch (src->type) { 22553e202c1Schristos case aml_t_num: 22653e202c1Schristos if (aml_bufferfield_write(src->num.number, buffer, offset, bitlen)) { 22753e202c1Schristos AML_DEBUGPRINT("aml_bufferfield_write() failed\n"); 22853e202c1Schristos } 22953e202c1Schristos break; 23053e202c1Schristos case aml_t_buffer: 23153e202c1Schristos case aml_t_bufferfield: 23253e202c1Schristos if (src->type == aml_t_buffer) { 23353e202c1Schristos srcbuf = src->buffer.data; 23453e202c1Schristos } else { 23553e202c1Schristos srcbuf = src->bfld.origin; 23653e202c1Schristos srcbuf += src->bfld.bitoffset / 8; 23753e202c1Schristos } 23853e202c1Schristos bcopy(srcbuf, buffer, bitlen / 8); 23953e202c1Schristos break; 24053e202c1Schristos case aml_t_regfield: 24153e202c1Schristos aml_region_read_into_buffer(env, src->regfield.space, 24253e202c1Schristos src->regfield.flags, src->regfield.offset, 24353e202c1Schristos src->regfield.bitoffset, src->regfield.bitlen, 24453e202c1Schristos buffer); 24553e202c1Schristos break; 24653e202c1Schristos default: 24753e202c1Schristos AML_DEBUGPRINT("not implemented yet"); 24853e202c1Schristos break; 24953e202c1Schristos } 25053e202c1Schristos break; 25153e202c1Schristos case aml_t_debug: 25253e202c1Schristos aml_showobject(src); 25353e202c1Schristos break; 25453e202c1Schristos default: 25553e202c1Schristos AML_DEBUGPRINT("[Unimplemented %d]", dest->type); 25653e202c1Schristos break; 25753e202c1Schristos } 25853e202c1Schristos } 25953e202c1Schristos 26053e202c1Schristos static void 26153e202c1Schristos aml_store_to_objref(struct aml_environ *env, union aml_object *obj, 26253e202c1Schristos union aml_object *r) 26353e202c1Schristos { 26453e202c1Schristos int offset; 26553e202c1Schristos union aml_object *ref; 26653e202c1Schristos 26753e202c1Schristos if (r->objref.ref == NULL) { 26853e202c1Schristos r->objref.ref = aml_alloc_object(obj->type, NULL); /* XXX */ 26953e202c1Schristos r->objref.nameref->property = r->objref.ref; 27053e202c1Schristos } 27153e202c1Schristos ref = r->objref.ref; 27253e202c1Schristos 27353e202c1Schristos switch (ref->type) { 27453e202c1Schristos case aml_t_buffer: 27553e202c1Schristos offset = r->objref.offset; 27653e202c1Schristos aml_store_to_buffer(env, obj, ref, r->objref.offset); 27753e202c1Schristos break; 27853e202c1Schristos case aml_t_package: 27953e202c1Schristos offset = r->objref.offset; 28053e202c1Schristos if (r->objref.ref->package.elements < offset) { 28153e202c1Schristos aml_realloc_object(ref, offset); 28253e202c1Schristos } 28353e202c1Schristos if (ref->package.objects[offset] == NULL) { 28453e202c1Schristos ref->package.objects[offset] = aml_copy_object(env, obj); 28553e202c1Schristos } else { 28653e202c1Schristos aml_store_to_object(env, obj, ref->package.objects[offset]); 28753e202c1Schristos } 28853e202c1Schristos break; 28953e202c1Schristos default: 29053e202c1Schristos aml_store_to_object(env, obj, ref); 29153e202c1Schristos break; 29253e202c1Schristos } 29353e202c1Schristos } 29453e202c1Schristos 29553e202c1Schristos /* 29653e202c1Schristos * Store to Named object 29753e202c1Schristos */ 29853e202c1Schristos void 29953e202c1Schristos aml_store_to_name(struct aml_environ *env, union aml_object *obj, 30053e202c1Schristos struct aml_name *name) 30153e202c1Schristos { 30253e202c1Schristos struct aml_name *wname; 30353e202c1Schristos 30453e202c1Schristos if (env->stat == aml_stat_panic) { 30553e202c1Schristos return; 30653e202c1Schristos } 30753e202c1Schristos if (name == NULL || obj == NULL) { 30811850c9eSandvar AML_DEBUGPRINT("[Try to store non-existent name]"); 30953e202c1Schristos return; 31053e202c1Schristos } 31153e202c1Schristos if (name->property == NULL) { 31253e202c1Schristos name->property = aml_copy_object(env, obj); 31353e202c1Schristos AML_DEBUGPRINT("[Copy number 0x%x]", obj->num.number); 31453e202c1Schristos return; 31553e202c1Schristos } 31653e202c1Schristos if (name->property->type == aml_t_namestr) { 31753e202c1Schristos wname = aml_search_name(env, name->property->nstr.dp); 31853e202c1Schristos name = wname; 31953e202c1Schristos } 32053e202c1Schristos if (name == NULL) { 32153e202c1Schristos env->stat = aml_stat_panic; 32253e202c1Schristos return; 32353e202c1Schristos } 32453e202c1Schristos if (name->property == NULL || name->property->type == aml_t_null) { 32553e202c1Schristos name->property = aml_copy_object(env, obj); 32653e202c1Schristos AML_DEBUGPRINT("[Copy number 0x%x]", obj->num.number); 32753e202c1Schristos return; 32853e202c1Schristos } 32953e202c1Schristos /* Writes to constant object are not allowed */ 33053e202c1Schristos if (name->property != NULL && name->property->type == aml_t_num && 33153e202c1Schristos name->property->num.constant == 1) { 33253e202c1Schristos return; 33353e202c1Schristos } 33453e202c1Schristos /* try to dereference */ 33553e202c1Schristos if (obj->type == aml_t_objref && obj->objref.deref == 0) { 33653e202c1Schristos AML_DEBUGPRINT("Source object isn't dereferenced yet, " 33753e202c1Schristos "try to dereference anyway\n"); 33853e202c1Schristos obj->objref.deref = 1; 33953e202c1Schristos obj = aml_eval_objref(env, obj); 34053e202c1Schristos } 34153e202c1Schristos switch (name->property->type) { 34253e202c1Schristos case aml_t_field: 34353e202c1Schristos aml_store_to_fieldname(env, obj, name); 34453e202c1Schristos break; 34553e202c1Schristos case aml_t_objref: 34653e202c1Schristos aml_store_to_objref(env, obj, name->property); 34753e202c1Schristos break; 34853e202c1Schristos case aml_t_num: 34953e202c1Schristos if (name == &env->tempname) 35053e202c1Schristos break; 351fbffadb9Smrg /* FALLTHROUGH */ 35253e202c1Schristos default: 35353e202c1Schristos aml_store_to_object(env, obj, name->property); 35453e202c1Schristos break; 35553e202c1Schristos } 35653e202c1Schristos } 357