Home | History | Annotate | Line # | Download | only in aml
      1 /*	$NetBSD: aml_common.c,v 1.5 2021/12/12 08:49:58 andvar Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1999 Takanori Watanabe
      5  * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki (at) FreeBSD.org>
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  *
     29  *	Id: aml_common.c,v 1.9 2000/08/09 14:47:43 iwasaki Exp
     30  *	$FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_common.c,v 1.6 2000/11/09 06:24:45 iwasaki Exp $
     31  */
     32 #include <sys/cdefs.h>
     33 __RCSID("$NetBSD: aml_common.c,v 1.5 2021/12/12 08:49:58 andvar Exp $");
     34 
     35 #include <sys/param.h>
     36 
     37 #ifndef _KERNEL
     38 #include <assert.h>
     39 #include <err.h>
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <unistd.h>
     44 #else /* _KERNEL */
     45 #include "opt_acpi.h"
     46 #include <sys/kernel.h>
     47 #include <sys/sysctl.h>
     48 #include <sys/systm.h>
     49 #include <sys/bus.h>
     50 #include <dev/acpi/acpireg.h>
     51 #include <dev/acpi/acpivar.h>
     52 #ifndef ACPI_NO_OSDFUNC_INLINE
     53 #include <machine/acpica_osd.h>
     54 #endif /* !ACPI_NO_OSDFUNC_INLINE */
     55 #endif /* !_KERNEL */
     56 
     57 #include <acpi_common.h>
     58 #include <aml/aml_common.h>
     59 #include <aml/aml_env.h>
     60 #include <aml/aml_evalobj.h>
     61 #include <aml/aml_name.h>
     62 #include <aml/aml_obj.h>
     63 #include <aml/aml_parse.h>
     64 #include <aml/aml_status.h>
     65 #include <aml/aml_store.h>
     66 
     67 /* for debugging */
     68 #ifdef AML_DEBUG
     69 int	aml_debug = 1;
     70 #else	/* !AML_DEBUG */
     71 int	aml_debug = 0;
     72 #endif	/* AML_DEBUG */
     73 #ifdef _KERNEL
     74 SYSCTL_INT(_debug, OID_AUTO, aml_debug, CTLFLAG_RW, &aml_debug, 1, "");
     75 #endif /* _KERNEL */
     76 
     77 static void	 aml_print_nameseg(u_int8_t *dp);
     78 
     79 static void
     80 aml_print_nameseg(u_int8_t *dp)
     81 {
     82 
     83 	if (dp[3] != '_') {
     84 		AML_DEBUGPRINT("%c%c%c%c", dp[0], dp[1], dp[2], dp[3]);
     85 	} else if (dp[2] != '_') {
     86 		AML_DEBUGPRINT("%c%c%c_", dp[0], dp[1], dp[2]);
     87 	} else if (dp[1] != '_') {
     88 		AML_DEBUGPRINT("%c%c__", dp[0], dp[1]);
     89 	} else if (dp[0] != '_') {
     90 		AML_DEBUGPRINT("%c___", dp[0]);
     91 	}
     92 }
     93 
     94 void
     95 aml_print_namestring(u_int8_t *dp)
     96 {
     97 	int	segcount;
     98 	int	i;
     99 
    100 	if (dp[0] == '\\') {
    101 		AML_DEBUGPRINT("%c", dp[0]);
    102 		dp++;
    103 	} else if (dp[0] == '^') {
    104 		while (dp[0] == '^') {
    105 			AML_DEBUGPRINT("%c", dp[0]);
    106 			dp++;
    107 		}
    108 	}
    109 	if (dp[0] == 0x00) {	/* NullName */
    110 		/* AML_DEBUGPRINT("<null>"); */
    111 		dp++;
    112 	} else if (dp[0] == 0x2e) {	/* DualNamePrefix */
    113 		aml_print_nameseg(dp + 1);
    114 		AML_DEBUGPRINT("%c", '.');
    115 		aml_print_nameseg(dp + 5);
    116 	} else if (dp[0] == 0x2f) {	/* MultiNamePrefix */
    117 		segcount = dp[1];
    118 		for (i = 0, dp += 2; i < segcount; i++, dp += 4) {
    119 			if (i > 0) {
    120 				AML_DEBUGPRINT("%c", '.');
    121 			}
    122 			aml_print_nameseg(dp);
    123 		}
    124 	} else			/* NameSeg */
    125 		aml_print_nameseg(dp);
    126 }
    127 
    128 int
    129 aml_print_curname(struct aml_name *name)
    130 {
    131 	struct	aml_name *root;
    132 
    133 	root = aml_get_rootname();
    134 	if (name == root) {
    135 		AML_DEBUGPRINT("\\");
    136 		return (0);
    137 	} else {
    138 		aml_print_curname(name->parent);
    139 	}
    140 	aml_print_nameseg((unsigned char *)name->name);
    141 	AML_DEBUGPRINT(".");
    142 	return (0);
    143 }
    144 
    145 void
    146 aml_print_indent(int indent)
    147 {
    148 	int	i;
    149 
    150 	for (i = 0; i < indent; i++)
    151 		AML_DEBUGPRINT("    ");
    152 }
    153 
    154 void
    155 aml_showobject(union aml_object * obj)
    156 {
    157 	int	debug;
    158 	int	i;
    159 
    160 	if (obj == NULL) {
    161 		printf("NO object\n");
    162 		return;
    163 	}
    164 	debug = aml_debug;
    165 	aml_debug = 1;
    166 	switch (obj->type) {
    167 	case aml_t_num:
    168 		printf("Num:0x%x\n", obj->num.number);
    169 		break;
    170 	case aml_t_processor:
    171 		printf("Processor:No %d,Port 0x%x length 0x%x\n",
    172 		    obj->proc.id, obj->proc.addr, obj->proc.len);
    173 		break;
    174 	case aml_t_mutex:
    175 		printf("Mutex:Level %d\n", obj->mutex.level);
    176 		break;
    177 	case aml_t_powerres:
    178 		printf("PowerResource:Level %d Order %d\n",
    179 		    obj->pres.level, obj->pres.order);
    180 		break;
    181 	case aml_t_opregion:
    182 		printf("OperationRegion:Busspace%d, Offset 0x%x Length 0x%x\n",
    183 		    obj->opregion.space, obj->opregion.offset,
    184 		    obj->opregion.length);
    185 		break;
    186 	case aml_t_field:
    187 		printf("Fieldelement:flag 0x%x offset 0x%x len 0x%x {",
    188 		    obj->field.flags, obj->field.bitoffset,
    189 		    obj->field.bitlen);
    190 		switch (obj->field.f.ftype) {
    191 		case f_t_field:
    192 			aml_print_namestring(obj->field.f.fld.regname);
    193 			break;
    194 		case f_t_index:
    195 			aml_print_namestring(obj->field.f.ifld.indexname);
    196 			printf(" ");
    197 			aml_print_namestring(obj->field.f.ifld.dataname);
    198 			break;
    199 		case f_t_bank:
    200 			aml_print_namestring(obj->field.f.bfld.regname);
    201 			printf(" ");
    202 			aml_print_namestring(obj->field.f.bfld.bankname);
    203 			printf("0x%x", obj->field.f.bfld.bankvalue);
    204 			break;
    205 		}
    206 		printf("}\n");
    207 		break;
    208 	case aml_t_method:
    209 		printf("Method: Arg %d From %p To %p\n", obj->meth.argnum,
    210 		    obj->meth.from, obj->meth.to);
    211 		break;
    212 	case aml_t_buffer:
    213 		printf("Buffer: size:0x%x Data %p\n", obj->buffer.size,
    214 		    obj->buffer.data);
    215 		break;
    216 	case aml_t_device:
    217 		printf("Device\n");
    218 		break;
    219 	case aml_t_bufferfield:
    220 		printf("Bufferfield:offset 0x%x len 0x%x Origin %p\n",
    221 		    obj->bfld.bitoffset, obj->bfld.bitlen, obj->bfld.origin);
    222 		break;
    223 	case aml_t_string:
    224 		printf("String:%s\n", obj->str.string);
    225 		break;
    226 	case aml_t_package:
    227 		printf("Package:elements %d \n", obj->package.elements);
    228 		for (i = 0; i < obj->package.elements; i++) {
    229 			if (obj->package.objects[i] == NULL) {
    230 				break;
    231 			}
    232 			if (obj->package.objects[i]->type < 0) {
    233 				continue;
    234 			}
    235 			printf("        ");
    236 			aml_showobject(obj->package.objects[i]);
    237 		}
    238 		break;
    239 	case aml_t_therm:
    240 		printf("Thermalzone\n");
    241 		break;
    242 	case aml_t_event:
    243 		printf("Event\n");
    244 		break;
    245 	case aml_t_ddbhandle:
    246 		printf("DDBHANDLE\n");
    247 		break;
    248 	case aml_t_objref:
    249 		if (obj->objref.alias == 1) {
    250 			printf("Alias");
    251 		} else {
    252 			printf("Object reference");
    253 			if (obj->objref.offset >= 0) {
    254 				printf(" (offset 0x%x)", obj->objref.offset);
    255 			}
    256 		}
    257 		printf(" of ");
    258 		aml_showobject(obj->objref.ref);
    259 		break;
    260 	default:
    261 		printf("UNK ID=%d\n", obj->type);
    262 	}
    263 
    264 	aml_debug = debug;
    265 }
    266 
    267 void
    268 aml_showtree(struct aml_name * aname, int lev)
    269 {
    270 	int	i;
    271 	struct	aml_name *ptr;
    272 	char	name[5];
    273 
    274 	for (i = 0; i < lev; i++) {
    275 		printf("  ");
    276 	}
    277 	strncpy(name, aname->name, 4);
    278 	name[4] = 0;
    279 	printf("%s  ", name);
    280 	if (aname->property != NULL) {
    281 		aml_showobject(aname->property);
    282 	} else {
    283 		printf("\n");
    284 	}
    285 	for (ptr = aname->child; ptr; ptr = ptr->brother)
    286 		aml_showtree(ptr, lev + 1);
    287 }
    288 
    289 /*
    290  * Common Region I/O Stuff
    291  */
    292 
    293 static __inline u_int64_t
    294 aml_adjust_bitmask(u_int32_t flags, u_int32_t bitlen)
    295 {
    296 	u_int64_t	bitmask;
    297 
    298 	switch (AML_FIELDFLAGS_ACCESSTYPE(flags)) {
    299 	case AML_FIELDFLAGS_ACCESS_ANYACC:
    300 		if (bitlen <= 8) {
    301 			bitmask = 0x000000ff;
    302 			break;
    303 		}
    304 		if (bitlen <= 16) {
    305 			bitmask = 0x0000ffff;
    306 			break;
    307 		}
    308 		bitmask = 0xffffffff;
    309 		break;
    310 	case AML_FIELDFLAGS_ACCESS_BYTEACC:
    311 		bitmask = 0x000000ff;
    312 		break;
    313 	case AML_FIELDFLAGS_ACCESS_WORDACC:
    314 		bitmask = 0x0000ffff;
    315 		break;
    316 	case AML_FIELDFLAGS_ACCESS_DWORDACC:
    317 	default:
    318 		bitmask = 0xffffffff;
    319 		break;
    320 	}
    321 
    322 	switch (bitlen) {
    323 	case 16:
    324 		bitmask |= 0x0000ffff;
    325 		break;
    326 	case 32:
    327 		bitmask |= 0xffffffff;
    328 		break;
    329 	}
    330 
    331 	return (bitmask);
    332 }
    333 
    334 u_int32_t
    335 aml_adjust_readvalue(u_int32_t flags, u_int32_t bitoffset, u_int32_t bitlen,
    336     u_int32_t orgval)
    337 {
    338 	u_int32_t	offset, retval;
    339 	u_int64_t	bitmask;
    340 
    341 	offset = bitoffset;	/* XXX bitoffset may change in this function! */
    342 	bitmask = aml_adjust_bitmask(flags, bitlen);
    343 	retval = (orgval >> offset) & (~(bitmask << bitlen)) & bitmask;
    344 
    345 	return (retval);
    346 }
    347 
    348 u_int32_t
    349 aml_adjust_updatevalue(u_int32_t flags, u_int32_t bitoffset, u_int32_t bitlen,
    350     u_int32_t orgval, u_int32_t value)
    351 {
    352 	u_int32_t	offset, retval;
    353 	u_int64_t	bitmask;
    354 
    355 	offset = bitoffset;	/* XXX bitoffset may change in this function! */
    356 	bitmask = aml_adjust_bitmask(flags, bitlen);
    357 	retval = orgval;
    358 	switch (AML_FIELDFLAGS_UPDATERULE(flags)) {
    359 	case AML_FIELDFLAGS_UPDATE_PRESERVE:
    360 		retval &= (~(((u_int64_t)1 << bitlen) - 1) << offset) |
    361 			  (~(bitmask << offset));
    362 		break;
    363 	case AML_FIELDFLAGS_UPDATE_WRITEASONES:
    364 		retval =  (~(((u_int64_t)1 << bitlen) - 1) << offset) |
    365 			  (~(bitmask << offset));
    366 		retval &= bitmask;	/* trim the upper bits */
    367 		break;
    368 	case AML_FIELDFLAGS_UPDATE_WRITEASZEROS:
    369 		retval = 0;
    370 		break;
    371 	default:
    372 		printf("illegal update rule: %d\n", flags);
    373 		return (orgval);
    374 	}
    375 
    376 	retval |= (value << (offset & bitmask));
    377 	return (retval);
    378 }
    379 
    380 /*
    381  * BufferField I/O
    382  */
    383 
    384 #define AML_BUFFER_INPUT	0
    385 #define AML_BUFFER_OUTPUT	1
    386 
    387 static int	 aml_bufferfield_io(int io, u_int32_t *valuep,
    388 				    u_int8_t *origin, u_int32_t bitoffset,
    389 				    u_int32_t bitlen);
    390 
    391 static int
    392 aml_bufferfield_io(int io, u_int32_t *valuep, u_int8_t *origin,
    393     u_int32_t bitoffset, u_int32_t bitlen)
    394 {
    395 	u_int8_t	val, tmp, masklow, maskhigh;
    396 	u_int8_t	offsetlow, offsethigh;
    397 	u_int8_t	*addr;
    398 	u_int32_t	value, readval;
    399 	u_int32_t	byteoffset, bytelen, i;
    400 
    401 	masklow = maskhigh = 0xff;
    402 	val = readval = 0;
    403 	value = *valuep;
    404 
    405 	byteoffset = bitoffset / 8;
    406 	bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0);
    407 	addr = origin + byteoffset;
    408 
    409 	/* simple I/O ? */
    410 	if (bitlen <= 8 || bitlen == 16 || bitlen == 32) {
    411 		bcopy(addr, &readval, bytelen);
    412 		AML_DEBUGPRINT("\n\t[bufferfield:0x%x@%p:%d,%d]",
    413 		    readval, addr, bitoffset % 8, bitlen);
    414 		switch (io) {
    415 		case AML_BUFFER_INPUT:
    416 			value = aml_adjust_readvalue(AML_FIELDFLAGS_ACCESS_BYTEACC,
    417 			    bitoffset % 8, bitlen, readval);
    418 			*valuep = value;
    419 			AML_DEBUGPRINT("\n[read(bufferfield, %p)&mask:0x%x]\n",
    420 			    addr, value);
    421 			break;
    422 		case AML_BUFFER_OUTPUT:
    423 			value = aml_adjust_updatevalue(AML_FIELDFLAGS_ACCESS_BYTEACC,
    424 			    bitoffset % 8, bitlen, readval, value);
    425 			bcopy(&value, addr, bytelen);
    426 			AML_DEBUGPRINT("->[bufferfield:0x%x@%p:%d,%d]",
    427 			    value, addr, bitoffset % 8, bitlen);
    428 			break;
    429 		}
    430 		goto out;
    431 	}
    432 
    433 	offsetlow = bitoffset % 8;
    434 	if (bytelen > 1) {
    435 		offsethigh = (bitlen - (8 - offsetlow)) % 8;
    436 	} else {
    437 		offsethigh = 0;
    438 	}
    439 
    440 	if (offsetlow) {
    441 		masklow = (~((1 << bitlen) - 1) << offsetlow) | ~(0xff << offsetlow);
    442 		AML_DEBUGPRINT("\t[offsetlow = 0x%x, masklow = 0x%x, ~masklow = 0x%x]\n",
    443 		    offsetlow, masklow, ~masklow & 0xff);
    444 	}
    445 	if (offsethigh) {
    446 		maskhigh = 0xff << offsethigh;
    447 		AML_DEBUGPRINT("\t[offsethigh = 0x%x, maskhigh = 0x%x, ~maskhigh = 0x%x]\n",
    448 		    offsethigh, maskhigh, ~maskhigh & 0xff);
    449 	}
    450 	for (i = bytelen; i > 0; i--, addr++) {
    451 		val = *addr;
    452 
    453 		AML_DEBUGPRINT("\t[bufferfield:0x%02x@%p]", val, addr);
    454 
    455 		switch (io) {
    456 		case AML_BUFFER_INPUT:
    457 			tmp = val;
    458 			/* the lowest byte? */
    459 			if (i == bytelen) {
    460 				if (offsetlow) {
    461 					readval = tmp & ~masklow;
    462 				} else {
    463 					readval = tmp;
    464 				}
    465 			} else {
    466 				if (i == 1 && offsethigh) {
    467 					tmp = tmp & ~maskhigh;
    468 				}
    469 				readval = (tmp << (8 * (bytelen - i))) | readval;
    470 			}
    471 
    472 			AML_DEBUGPRINT("\n");
    473 			/* goto to next byte... */
    474 			if (i > 1) {
    475 				continue;
    476 			}
    477 			/* final adjustment before finishing region access */
    478 			if (offsetlow) {
    479 				readval = readval >> offsetlow;
    480 			}
    481 			AML_DEBUGPRINT("[read(bufferfield, %p)&mask:0x%x]\n",
    482 			    addr, readval);
    483 			*valuep = readval;
    484 
    485 			break;
    486 
    487 		case AML_BUFFER_OUTPUT:
    488 			tmp = value & 0xff;
    489 			/* the lowest byte? */
    490 			if (i == bytelen) {
    491 				if (offsetlow) {
    492 					tmp = (val & masklow) | tmp << offsetlow;
    493 				}
    494 				value = value >> (8 - offsetlow);
    495 			} else {
    496 				if (i == 1 && offsethigh) {
    497 					tmp = (val & maskhigh) | tmp;
    498 				}
    499 				value = value >> 8;
    500 			}
    501 
    502 			AML_DEBUGPRINT("->[bufferfield:0x%02x@%p]\n",
    503 			    tmp, addr);
    504 			*addr = tmp;
    505 		}
    506 	}
    507 out:
    508 	return (0);
    509 }
    510 
    511 u_int32_t
    512 aml_bufferfield_read(u_int8_t *origin, u_int32_t bitoffset,
    513     u_int32_t bitlen)
    514 {
    515 	int	value;
    516 
    517 	value = 0;
    518 	aml_bufferfield_io(AML_BUFFER_INPUT, (u_int32_t *)&value, origin,
    519 	    bitoffset, bitlen);
    520 	return (value);
    521 }
    522 
    523 int
    524 aml_bufferfield_write(u_int32_t value, u_int8_t *origin,
    525     u_int32_t bitoffset, u_int32_t bitlen)
    526 {
    527 	int	status;
    528 
    529 	status = aml_bufferfield_io(AML_BUFFER_OUTPUT, &value,
    530 	    origin, bitoffset, bitlen);
    531 	return (status);
    532 }
    533 
    534 int
    535 aml_region_handle_alloc(struct aml_environ *env, int regtype, u_int32_t flags,
    536     u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen,
    537     struct aml_region_handle *h)
    538 {
    539 	int	state;
    540 
    541 	state = 0;
    542 	bzero(h, sizeof(struct aml_region_handle));
    543 
    544 	h->env = env;
    545 	h->regtype = regtype;
    546 	h->flags = flags;
    547 	h->baseaddr = baseaddr;
    548 	h->bitoffset = bitoffset;
    549 	h->bitlen = bitlen;
    550 
    551 	switch (AML_FIELDFLAGS_ACCESSTYPE(flags)) {
    552 	case AML_FIELDFLAGS_ACCESS_ANYACC:
    553 		if (bitlen <= 8) {
    554 			h->unit = 1;
    555 			break;
    556 		}
    557 		if (bitlen <= 16) {
    558 			h->unit = 2;
    559 			break;
    560 		}
    561 		h->unit = 4;
    562 		break;
    563 	case AML_FIELDFLAGS_ACCESS_BYTEACC:
    564 		h->unit = 1;
    565 		break;
    566 	case AML_FIELDFLAGS_ACCESS_WORDACC:
    567 		h->unit = 2;
    568 		break;
    569 	case AML_FIELDFLAGS_ACCESS_DWORDACC:
    570 		h->unit = 4;
    571 		break;
    572 	default:
    573 		h->unit = 1;
    574 		break;
    575 	}
    576 
    577 	h->addr = baseaddr + h->unit * ((bitoffset / 8) / h->unit);
    578 	h->bytelen = baseaddr + ((bitoffset + bitlen) / 8) - h->addr +
    579 		     ((bitlen % 8) ? 1 : 0);
    580 
    581 #ifdef _KERNEL
    582 	switch (h->regtype) {
    583 	case AML_REGION_SYSMEM:
    584 		OsdMapMemory((void *)h->addr, h->bytelen, (void **)&h->vaddr);
    585 		break;
    586 
    587 	case AML_REGION_PCICFG:
    588 		/* Obtain PCI bus number */
    589 		pci_info = aml_search_name(env, "_BBN");
    590 		if (pci_info == NULL || pci_info->property->type != aml_t_num) {
    591 			AML_DEBUGPRINT("Cannot locate _BBN. Using default 0\n");
    592 			h->pci_bus = 0;
    593 		} else {
    594 			AML_DEBUGPRINT("found _BBN: %d\n",
    595 			    pci_info->property->num.number);
    596 			h->pci_bus = pci_info->property->num.number & 0xff;
    597 		}
    598 
    599 		/* Obtain device & function number */
    600 		pci_info = aml_search_name(env, "_ADR");
    601 		if (pci_info == NULL || pci_info->property->type != aml_t_num) {
    602 			printf("Cannot locate: _ADR\n");
    603 			state = -1;
    604 			goto out;
    605 		}
    606 		h->pci_devfunc = pci_info->property->num.number;
    607 
    608 		AML_DEBUGPRINT("[pci%d.%d]", h->pci_bus, h->pci_devfunc);
    609 		break;
    610 
    611 	default:
    612 		break;
    613 	}
    614 
    615 out:
    616 #endif	/* _KERNEL */
    617 	return (state);
    618 }
    619 
    620 void
    621 aml_region_handle_free(struct aml_region_handle *h)
    622 {
    623 #ifdef _KERNEL
    624 	switch (h->regtype) {
    625 	case AML_REGION_SYSMEM:
    626 		OsdUnMapMemory((void *)h->vaddr, h->bytelen);
    627 		break;
    628 
    629 	default:
    630 		break;
    631 	}
    632 #endif	/* _KERNEL */
    633 }
    634 
    635 static int
    636 aml_region_io_simple(struct aml_environ *env, int io, int regtype,
    637     u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr,
    638     u_int32_t bitoffset, u_int32_t bitlen)
    639 {
    640 	int		state;
    641 	u_int32_t	readval, value, offset, bytelen, i;
    642 	struct		aml_region_handle handle;
    643 
    644 	state = aml_region_handle_alloc(env, regtype, flags,
    645             baseaddr, bitoffset, bitlen, &handle);
    646 	if (state == -1) {
    647 		goto out;
    648 	}
    649 
    650 	readval = 0;
    651 	offset = bitoffset % (handle.unit * 8);
    652 	/* limitation of 32 bits alignment */
    653 	bytelen = (handle.bytelen > 4) ? 4 : handle.bytelen;
    654 
    655 	if (io == AML_REGION_INPUT ||
    656 	    AML_FIELDFLAGS_UPDATERULE(flags) == AML_FIELDFLAGS_UPDATE_PRESERVE) {
    657 		for (i = 0; i < bytelen; i += handle.unit) {
    658 			state = aml_region_read_simple(&handle, i, &value);
    659 			if (state == -1) {
    660 				goto out;
    661 			}
    662 			readval |= (value << (i * 8));
    663 		}
    664 		AML_DEBUGPRINT("\t[%d:0x%x@0x%lx:%d,%d]",
    665 		    regtype, readval, handle.addr, offset, bitlen);
    666 	}
    667 
    668 	switch (io) {
    669 	case AML_REGION_INPUT:
    670 		AML_DEBUGPRINT("\n");
    671 		readval = aml_adjust_readvalue(flags, offset, bitlen, readval);
    672 		value = readval;
    673 		value = aml_region_prompt_read(&handle, value);
    674 		state = aml_region_prompt_update_value(readval, value, &handle);
    675 		if (state == -1) {
    676 			goto out;
    677 		}
    678 
    679 		*valuep = value;
    680 		break;
    681 	case AML_REGION_OUTPUT:
    682 		value = *valuep;
    683 		value = aml_adjust_updatevalue(flags, offset,
    684 		    bitlen, readval, value);
    685 		value = aml_region_prompt_write(&handle, value);
    686 		AML_DEBUGPRINT("\t->[%d:0x%x@0x%lx:%d,%d]\n", regtype, value,
    687 		    handle.addr, offset, bitlen);
    688 		for (i = 0; i < bytelen; i += handle.unit) {
    689 			state = aml_region_write_simple(&handle, i, value);
    690 			if (state == -1) {
    691 				goto out;
    692 			}
    693 			value = value >> (handle.unit * 8);
    694 		}
    695 		break;
    696 	}
    697 
    698 	aml_region_handle_free(&handle);
    699 out:
    700 	return (state);
    701 }
    702 
    703 int
    704 aml_region_io(struct aml_environ *env, int io, int regtype,
    705     u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr,
    706     u_int32_t bitoffset, u_int32_t bitlen)
    707 {
    708 	u_int32_t	unit, offset;
    709 	u_int32_t	offadj, bitadj;
    710 	u_int32_t	value, readval, i;
    711 	int		state;
    712 
    713 	readval = 0;
    714 	state = 0;
    715 	unit = 4;	/* limitation of 32 bits alignment */
    716 	offset = bitoffset % (unit * 8);
    717 	offadj = 0;
    718 	bitadj = 0;
    719 	if (offset + bitlen > unit * 8) {
    720 		bitadj = bitlen  - (unit * 8 - offset);
    721 	}
    722 	for (i = 0; i < offset + bitlen; i += unit * 8) {
    723 		value = (*valuep) >> offadj;
    724 		state = aml_region_io_simple(env, io, regtype, flags,
    725 		    &value, baseaddr, bitoffset + offadj, bitlen - bitadj);
    726 		if (state == -1) {
    727 			goto out;
    728 		}
    729 		readval |= value << offadj;
    730 		bitadj = offadj = bitlen - bitadj;
    731 	}
    732 	*valuep = readval;
    733 
    734 out:
    735 	return (state);
    736 }
    737