xref: /netbsd/usr.sbin/acpitools/aml/aml_common.c (revision e0efbec3)
1*e0efbec3Sandvar /*	$NetBSD: aml_common.c,v 1.5 2021/12/12 08:49:58 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_common.c,v 1.9 2000/08/09 14:47:43 iwasaki Exp
3053e202c1Schristos  *	$FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_common.c,v 1.6 2000/11/09 06:24:45 iwasaki Exp $
3153e202c1Schristos  */
3253e202c1Schristos #include <sys/cdefs.h>
33*e0efbec3Sandvar __RCSID("$NetBSD: aml_common.c,v 1.5 2021/12/12 08:49:58 andvar Exp $");
3453e202c1Schristos 
3553e202c1Schristos #include <sys/param.h>
3653e202c1Schristos 
3753e202c1Schristos #ifndef _KERNEL
3853e202c1Schristos #include <assert.h>
3953e202c1Schristos #include <err.h>
4053e202c1Schristos #include <stdio.h>
4153e202c1Schristos #include <stdlib.h>
4253e202c1Schristos #include <string.h>
4353e202c1Schristos #include <unistd.h>
4453e202c1Schristos #else /* _KERNEL */
4553e202c1Schristos #include "opt_acpi.h"
4653e202c1Schristos #include <sys/kernel.h>
4753e202c1Schristos #include <sys/sysctl.h>
4853e202c1Schristos #include <sys/systm.h>
4953e202c1Schristos #include <sys/bus.h>
5053e202c1Schristos #include <dev/acpi/acpireg.h>
5153e202c1Schristos #include <dev/acpi/acpivar.h>
5253e202c1Schristos #ifndef ACPI_NO_OSDFUNC_INLINE
5353e202c1Schristos #include <machine/acpica_osd.h>
5453e202c1Schristos #endif /* !ACPI_NO_OSDFUNC_INLINE */
5553e202c1Schristos #endif /* !_KERNEL */
5653e202c1Schristos 
5753e202c1Schristos #include <acpi_common.h>
5853e202c1Schristos #include <aml/aml_common.h>
5953e202c1Schristos #include <aml/aml_env.h>
6053e202c1Schristos #include <aml/aml_evalobj.h>
6153e202c1Schristos #include <aml/aml_name.h>
6253e202c1Schristos #include <aml/aml_obj.h>
6353e202c1Schristos #include <aml/aml_parse.h>
6453e202c1Schristos #include <aml/aml_status.h>
6553e202c1Schristos #include <aml/aml_store.h>
6653e202c1Schristos 
6753e202c1Schristos /* for debugging */
6853e202c1Schristos #ifdef AML_DEBUG
6953e202c1Schristos int	aml_debug = 1;
7053e202c1Schristos #else	/* !AML_DEBUG */
7153e202c1Schristos int	aml_debug = 0;
7253e202c1Schristos #endif	/* AML_DEBUG */
7353e202c1Schristos #ifdef _KERNEL
7453e202c1Schristos SYSCTL_INT(_debug, OID_AUTO, aml_debug, CTLFLAG_RW, &aml_debug, 1, "");
7553e202c1Schristos #endif /* _KERNEL */
7653e202c1Schristos 
7753e202c1Schristos static void	 aml_print_nameseg(u_int8_t *dp);
7853e202c1Schristos 
7953e202c1Schristos static void
aml_print_nameseg(u_int8_t * dp)8053e202c1Schristos aml_print_nameseg(u_int8_t *dp)
8153e202c1Schristos {
8253e202c1Schristos 
8353e202c1Schristos 	if (dp[3] != '_') {
8453e202c1Schristos 		AML_DEBUGPRINT("%c%c%c%c", dp[0], dp[1], dp[2], dp[3]);
8553e202c1Schristos 	} else if (dp[2] != '_') {
8653e202c1Schristos 		AML_DEBUGPRINT("%c%c%c_", dp[0], dp[1], dp[2]);
8753e202c1Schristos 	} else if (dp[1] != '_') {
8853e202c1Schristos 		AML_DEBUGPRINT("%c%c__", dp[0], dp[1]);
8953e202c1Schristos 	} else if (dp[0] != '_') {
9053e202c1Schristos 		AML_DEBUGPRINT("%c___", dp[0]);
9153e202c1Schristos 	}
9253e202c1Schristos }
9353e202c1Schristos 
9453e202c1Schristos void
aml_print_namestring(u_int8_t * dp)9553e202c1Schristos aml_print_namestring(u_int8_t *dp)
9653e202c1Schristos {
9753e202c1Schristos 	int	segcount;
9853e202c1Schristos 	int	i;
9953e202c1Schristos 
10053e202c1Schristos 	if (dp[0] == '\\') {
10153e202c1Schristos 		AML_DEBUGPRINT("%c", dp[0]);
10253e202c1Schristos 		dp++;
10353e202c1Schristos 	} else if (dp[0] == '^') {
10453e202c1Schristos 		while (dp[0] == '^') {
10553e202c1Schristos 			AML_DEBUGPRINT("%c", dp[0]);
10653e202c1Schristos 			dp++;
10753e202c1Schristos 		}
10853e202c1Schristos 	}
10953e202c1Schristos 	if (dp[0] == 0x00) {	/* NullName */
11053e202c1Schristos 		/* AML_DEBUGPRINT("<null>"); */
11153e202c1Schristos 		dp++;
11253e202c1Schristos 	} else if (dp[0] == 0x2e) {	/* DualNamePrefix */
11353e202c1Schristos 		aml_print_nameseg(dp + 1);
11453e202c1Schristos 		AML_DEBUGPRINT("%c", '.');
11553e202c1Schristos 		aml_print_nameseg(dp + 5);
11653e202c1Schristos 	} else if (dp[0] == 0x2f) {	/* MultiNamePrefix */
11753e202c1Schristos 		segcount = dp[1];
11853e202c1Schristos 		for (i = 0, dp += 2; i < segcount; i++, dp += 4) {
11953e202c1Schristos 			if (i > 0) {
12053e202c1Schristos 				AML_DEBUGPRINT("%c", '.');
12153e202c1Schristos 			}
12253e202c1Schristos 			aml_print_nameseg(dp);
12353e202c1Schristos 		}
12453e202c1Schristos 	} else			/* NameSeg */
12553e202c1Schristos 		aml_print_nameseg(dp);
12653e202c1Schristos }
12753e202c1Schristos 
12853e202c1Schristos int
aml_print_curname(struct aml_name * name)12953e202c1Schristos aml_print_curname(struct aml_name *name)
13053e202c1Schristos {
13153e202c1Schristos 	struct	aml_name *root;
13253e202c1Schristos 
13353e202c1Schristos 	root = aml_get_rootname();
13453e202c1Schristos 	if (name == root) {
13553e202c1Schristos 		AML_DEBUGPRINT("\\");
13653e202c1Schristos 		return (0);
13753e202c1Schristos 	} else {
13853e202c1Schristos 		aml_print_curname(name->parent);
13953e202c1Schristos 	}
14053e202c1Schristos 	aml_print_nameseg((unsigned char *)name->name);
14153e202c1Schristos 	AML_DEBUGPRINT(".");
14253e202c1Schristos 	return (0);
14353e202c1Schristos }
14453e202c1Schristos 
14553e202c1Schristos void
aml_print_indent(int indent)14653e202c1Schristos aml_print_indent(int indent)
14753e202c1Schristos {
14853e202c1Schristos 	int	i;
14953e202c1Schristos 
15053e202c1Schristos 	for (i = 0; i < indent; i++)
15153e202c1Schristos 		AML_DEBUGPRINT("    ");
15253e202c1Schristos }
15353e202c1Schristos 
15453e202c1Schristos void
aml_showobject(union aml_object * obj)15553e202c1Schristos aml_showobject(union aml_object * obj)
15653e202c1Schristos {
15753e202c1Schristos 	int	debug;
15853e202c1Schristos 	int	i;
15953e202c1Schristos 
16053e202c1Schristos 	if (obj == NULL) {
16153e202c1Schristos 		printf("NO object\n");
16253e202c1Schristos 		return;
16353e202c1Schristos 	}
16453e202c1Schristos 	debug = aml_debug;
16553e202c1Schristos 	aml_debug = 1;
16653e202c1Schristos 	switch (obj->type) {
16753e202c1Schristos 	case aml_t_num:
16853e202c1Schristos 		printf("Num:0x%x\n", obj->num.number);
16953e202c1Schristos 		break;
17053e202c1Schristos 	case aml_t_processor:
17153e202c1Schristos 		printf("Processor:No %d,Port 0x%x length 0x%x\n",
17253e202c1Schristos 		    obj->proc.id, obj->proc.addr, obj->proc.len);
17353e202c1Schristos 		break;
17453e202c1Schristos 	case aml_t_mutex:
17553e202c1Schristos 		printf("Mutex:Level %d\n", obj->mutex.level);
17653e202c1Schristos 		break;
17753e202c1Schristos 	case aml_t_powerres:
17853e202c1Schristos 		printf("PowerResource:Level %d Order %d\n",
17953e202c1Schristos 		    obj->pres.level, obj->pres.order);
18053e202c1Schristos 		break;
18153e202c1Schristos 	case aml_t_opregion:
182*e0efbec3Sandvar 		printf("OperationRegion:Busspace%d, Offset 0x%x Length 0x%x\n",
18353e202c1Schristos 		    obj->opregion.space, obj->opregion.offset,
18453e202c1Schristos 		    obj->opregion.length);
18553e202c1Schristos 		break;
18653e202c1Schristos 	case aml_t_field:
18753e202c1Schristos 		printf("Fieldelement:flag 0x%x offset 0x%x len 0x%x {",
18853e202c1Schristos 		    obj->field.flags, obj->field.bitoffset,
18953e202c1Schristos 		    obj->field.bitlen);
19053e202c1Schristos 		switch (obj->field.f.ftype) {
19153e202c1Schristos 		case f_t_field:
19253e202c1Schristos 			aml_print_namestring(obj->field.f.fld.regname);
19353e202c1Schristos 			break;
19453e202c1Schristos 		case f_t_index:
19553e202c1Schristos 			aml_print_namestring(obj->field.f.ifld.indexname);
19653e202c1Schristos 			printf(" ");
19753e202c1Schristos 			aml_print_namestring(obj->field.f.ifld.dataname);
19853e202c1Schristos 			break;
19953e202c1Schristos 		case f_t_bank:
20053e202c1Schristos 			aml_print_namestring(obj->field.f.bfld.regname);
20153e202c1Schristos 			printf(" ");
20253e202c1Schristos 			aml_print_namestring(obj->field.f.bfld.bankname);
20353e202c1Schristos 			printf("0x%x", obj->field.f.bfld.bankvalue);
20453e202c1Schristos 			break;
20553e202c1Schristos 		}
20653e202c1Schristos 		printf("}\n");
20753e202c1Schristos 		break;
20853e202c1Schristos 	case aml_t_method:
20953e202c1Schristos 		printf("Method: Arg %d From %p To %p\n", obj->meth.argnum,
21053e202c1Schristos 		    obj->meth.from, obj->meth.to);
21153e202c1Schristos 		break;
21253e202c1Schristos 	case aml_t_buffer:
21353e202c1Schristos 		printf("Buffer: size:0x%x Data %p\n", obj->buffer.size,
21453e202c1Schristos 		    obj->buffer.data);
21553e202c1Schristos 		break;
21653e202c1Schristos 	case aml_t_device:
21753e202c1Schristos 		printf("Device\n");
21853e202c1Schristos 		break;
21953e202c1Schristos 	case aml_t_bufferfield:
22053e202c1Schristos 		printf("Bufferfield:offset 0x%x len 0x%x Origin %p\n",
22153e202c1Schristos 		    obj->bfld.bitoffset, obj->bfld.bitlen, obj->bfld.origin);
22253e202c1Schristos 		break;
22353e202c1Schristos 	case aml_t_string:
22453e202c1Schristos 		printf("String:%s\n", obj->str.string);
22553e202c1Schristos 		break;
22653e202c1Schristos 	case aml_t_package:
22753e202c1Schristos 		printf("Package:elements %d \n", obj->package.elements);
22853e202c1Schristos 		for (i = 0; i < obj->package.elements; i++) {
22953e202c1Schristos 			if (obj->package.objects[i] == NULL) {
23053e202c1Schristos 				break;
23153e202c1Schristos 			}
23253e202c1Schristos 			if (obj->package.objects[i]->type < 0) {
23353e202c1Schristos 				continue;
23453e202c1Schristos 			}
23553e202c1Schristos 			printf("        ");
23653e202c1Schristos 			aml_showobject(obj->package.objects[i]);
23753e202c1Schristos 		}
23853e202c1Schristos 		break;
23953e202c1Schristos 	case aml_t_therm:
24053e202c1Schristos 		printf("Thermalzone\n");
24153e202c1Schristos 		break;
24253e202c1Schristos 	case aml_t_event:
24353e202c1Schristos 		printf("Event\n");
24453e202c1Schristos 		break;
24553e202c1Schristos 	case aml_t_ddbhandle:
24653e202c1Schristos 		printf("DDBHANDLE\n");
24753e202c1Schristos 		break;
24853e202c1Schristos 	case aml_t_objref:
24953e202c1Schristos 		if (obj->objref.alias == 1) {
25053e202c1Schristos 			printf("Alias");
25153e202c1Schristos 		} else {
25253e202c1Schristos 			printf("Object reference");
25353e202c1Schristos 			if (obj->objref.offset >= 0) {
25453e202c1Schristos 				printf(" (offset 0x%x)", obj->objref.offset);
25553e202c1Schristos 			}
25653e202c1Schristos 		}
25753e202c1Schristos 		printf(" of ");
25853e202c1Schristos 		aml_showobject(obj->objref.ref);
25953e202c1Schristos 		break;
26053e202c1Schristos 	default:
26153e202c1Schristos 		printf("UNK ID=%d\n", obj->type);
26253e202c1Schristos 	}
26353e202c1Schristos 
26453e202c1Schristos 	aml_debug = debug;
26553e202c1Schristos }
26653e202c1Schristos 
26753e202c1Schristos void
aml_showtree(struct aml_name * aname,int lev)26853e202c1Schristos aml_showtree(struct aml_name * aname, int lev)
26953e202c1Schristos {
27053e202c1Schristos 	int	i;
27153e202c1Schristos 	struct	aml_name *ptr;
27253e202c1Schristos 	char	name[5];
27353e202c1Schristos 
27453e202c1Schristos 	for (i = 0; i < lev; i++) {
27553e202c1Schristos 		printf("  ");
27653e202c1Schristos 	}
27753e202c1Schristos 	strncpy(name, aname->name, 4);
27853e202c1Schristos 	name[4] = 0;
27953e202c1Schristos 	printf("%s  ", name);
28053e202c1Schristos 	if (aname->property != NULL) {
28153e202c1Schristos 		aml_showobject(aname->property);
28253e202c1Schristos 	} else {
28353e202c1Schristos 		printf("\n");
28453e202c1Schristos 	}
28553e202c1Schristos 	for (ptr = aname->child; ptr; ptr = ptr->brother)
28653e202c1Schristos 		aml_showtree(ptr, lev + 1);
28753e202c1Schristos }
28853e202c1Schristos 
28953e202c1Schristos /*
29053e202c1Schristos  * Common Region I/O Stuff
29153e202c1Schristos  */
29253e202c1Schristos 
29353e202c1Schristos static __inline u_int64_t
aml_adjust_bitmask(u_int32_t flags,u_int32_t bitlen)29453e202c1Schristos aml_adjust_bitmask(u_int32_t flags, u_int32_t bitlen)
29553e202c1Schristos {
29653e202c1Schristos 	u_int64_t	bitmask;
29753e202c1Schristos 
29853e202c1Schristos 	switch (AML_FIELDFLAGS_ACCESSTYPE(flags)) {
29953e202c1Schristos 	case AML_FIELDFLAGS_ACCESS_ANYACC:
30053e202c1Schristos 		if (bitlen <= 8) {
30153e202c1Schristos 			bitmask = 0x000000ff;
30253e202c1Schristos 			break;
30353e202c1Schristos 		}
30453e202c1Schristos 		if (bitlen <= 16) {
30553e202c1Schristos 			bitmask = 0x0000ffff;
30653e202c1Schristos 			break;
30753e202c1Schristos 		}
30853e202c1Schristos 		bitmask = 0xffffffff;
30953e202c1Schristos 		break;
31053e202c1Schristos 	case AML_FIELDFLAGS_ACCESS_BYTEACC:
31153e202c1Schristos 		bitmask = 0x000000ff;
31253e202c1Schristos 		break;
31353e202c1Schristos 	case AML_FIELDFLAGS_ACCESS_WORDACC:
31453e202c1Schristos 		bitmask = 0x0000ffff;
31553e202c1Schristos 		break;
31653e202c1Schristos 	case AML_FIELDFLAGS_ACCESS_DWORDACC:
31753e202c1Schristos 	default:
31853e202c1Schristos 		bitmask = 0xffffffff;
31953e202c1Schristos 		break;
32053e202c1Schristos 	}
32153e202c1Schristos 
32253e202c1Schristos 	switch (bitlen) {
32353e202c1Schristos 	case 16:
32453e202c1Schristos 		bitmask |= 0x0000ffff;
32553e202c1Schristos 		break;
32653e202c1Schristos 	case 32:
32753e202c1Schristos 		bitmask |= 0xffffffff;
32853e202c1Schristos 		break;
32953e202c1Schristos 	}
33053e202c1Schristos 
33153e202c1Schristos 	return (bitmask);
33253e202c1Schristos }
33353e202c1Schristos 
33453e202c1Schristos u_int32_t
aml_adjust_readvalue(u_int32_t flags,u_int32_t bitoffset,u_int32_t bitlen,u_int32_t orgval)33553e202c1Schristos aml_adjust_readvalue(u_int32_t flags, u_int32_t bitoffset, u_int32_t bitlen,
33653e202c1Schristos     u_int32_t orgval)
33753e202c1Schristos {
33853e202c1Schristos 	u_int32_t	offset, retval;
33953e202c1Schristos 	u_int64_t	bitmask;
34053e202c1Schristos 
34153e202c1Schristos 	offset = bitoffset;	/* XXX bitoffset may change in this function! */
34253e202c1Schristos 	bitmask = aml_adjust_bitmask(flags, bitlen);
34353e202c1Schristos 	retval = (orgval >> offset) & (~(bitmask << bitlen)) & bitmask;
34453e202c1Schristos 
34553e202c1Schristos 	return (retval);
34653e202c1Schristos }
34753e202c1Schristos 
34853e202c1Schristos u_int32_t
aml_adjust_updatevalue(u_int32_t flags,u_int32_t bitoffset,u_int32_t bitlen,u_int32_t orgval,u_int32_t value)34953e202c1Schristos aml_adjust_updatevalue(u_int32_t flags, u_int32_t bitoffset, u_int32_t bitlen,
35053e202c1Schristos     u_int32_t orgval, u_int32_t value)
35153e202c1Schristos {
35253e202c1Schristos 	u_int32_t	offset, retval;
35353e202c1Schristos 	u_int64_t	bitmask;
35453e202c1Schristos 
35553e202c1Schristos 	offset = bitoffset;	/* XXX bitoffset may change in this function! */
35653e202c1Schristos 	bitmask = aml_adjust_bitmask(flags, bitlen);
35753e202c1Schristos 	retval = orgval;
35853e202c1Schristos 	switch (AML_FIELDFLAGS_UPDATERULE(flags)) {
35953e202c1Schristos 	case AML_FIELDFLAGS_UPDATE_PRESERVE:
36053e202c1Schristos 		retval &= (~(((u_int64_t)1 << bitlen) - 1) << offset) |
36153e202c1Schristos 			  (~(bitmask << offset));
36253e202c1Schristos 		break;
36353e202c1Schristos 	case AML_FIELDFLAGS_UPDATE_WRITEASONES:
36453e202c1Schristos 		retval =  (~(((u_int64_t)1 << bitlen) - 1) << offset) |
36553e202c1Schristos 			  (~(bitmask << offset));
36653e202c1Schristos 		retval &= bitmask;	/* trim the upper bits */
36753e202c1Schristos 		break;
36853e202c1Schristos 	case AML_FIELDFLAGS_UPDATE_WRITEASZEROS:
36953e202c1Schristos 		retval = 0;
37053e202c1Schristos 		break;
37153e202c1Schristos 	default:
37253e202c1Schristos 		printf("illegal update rule: %d\n", flags);
37353e202c1Schristos 		return (orgval);
37453e202c1Schristos 	}
37553e202c1Schristos 
37653e202c1Schristos 	retval |= (value << (offset & bitmask));
37753e202c1Schristos 	return (retval);
37853e202c1Schristos }
37953e202c1Schristos 
38053e202c1Schristos /*
38153e202c1Schristos  * BufferField I/O
38253e202c1Schristos  */
38353e202c1Schristos 
38453e202c1Schristos #define AML_BUFFER_INPUT	0
38553e202c1Schristos #define AML_BUFFER_OUTPUT	1
38653e202c1Schristos 
38753e202c1Schristos static int	 aml_bufferfield_io(int io, u_int32_t *valuep,
38853e202c1Schristos 				    u_int8_t *origin, u_int32_t bitoffset,
38953e202c1Schristos 				    u_int32_t bitlen);
39053e202c1Schristos 
39153e202c1Schristos static int
aml_bufferfield_io(int io,u_int32_t * valuep,u_int8_t * origin,u_int32_t bitoffset,u_int32_t bitlen)39253e202c1Schristos aml_bufferfield_io(int io, u_int32_t *valuep, u_int8_t *origin,
39353e202c1Schristos     u_int32_t bitoffset, u_int32_t bitlen)
39453e202c1Schristos {
39553e202c1Schristos 	u_int8_t	val, tmp, masklow, maskhigh;
39653e202c1Schristos 	u_int8_t	offsetlow, offsethigh;
39753e202c1Schristos 	u_int8_t	*addr;
39853e202c1Schristos 	u_int32_t	value, readval;
399e7dd2c75Slukem 	u_int32_t	byteoffset, bytelen, i;
40053e202c1Schristos 
40153e202c1Schristos 	masklow = maskhigh = 0xff;
40253e202c1Schristos 	val = readval = 0;
40353e202c1Schristos 	value = *valuep;
40453e202c1Schristos 
40553e202c1Schristos 	byteoffset = bitoffset / 8;
40653e202c1Schristos 	bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0);
40753e202c1Schristos 	addr = origin + byteoffset;
40853e202c1Schristos 
40953e202c1Schristos 	/* simple I/O ? */
41053e202c1Schristos 	if (bitlen <= 8 || bitlen == 16 || bitlen == 32) {
41153e202c1Schristos 		bcopy(addr, &readval, bytelen);
41253e202c1Schristos 		AML_DEBUGPRINT("\n\t[bufferfield:0x%x@%p:%d,%d]",
41353e202c1Schristos 		    readval, addr, bitoffset % 8, bitlen);
41453e202c1Schristos 		switch (io) {
41553e202c1Schristos 		case AML_BUFFER_INPUT:
41653e202c1Schristos 			value = aml_adjust_readvalue(AML_FIELDFLAGS_ACCESS_BYTEACC,
41753e202c1Schristos 			    bitoffset % 8, bitlen, readval);
41853e202c1Schristos 			*valuep = value;
41953e202c1Schristos 			AML_DEBUGPRINT("\n[read(bufferfield, %p)&mask:0x%x]\n",
42053e202c1Schristos 			    addr, value);
42153e202c1Schristos 			break;
42253e202c1Schristos 		case AML_BUFFER_OUTPUT:
42353e202c1Schristos 			value = aml_adjust_updatevalue(AML_FIELDFLAGS_ACCESS_BYTEACC,
42453e202c1Schristos 			    bitoffset % 8, bitlen, readval, value);
42553e202c1Schristos 			bcopy(&value, addr, bytelen);
42653e202c1Schristos 			AML_DEBUGPRINT("->[bufferfield:0x%x@%p:%d,%d]",
42753e202c1Schristos 			    value, addr, bitoffset % 8, bitlen);
42853e202c1Schristos 			break;
42953e202c1Schristos 		}
43053e202c1Schristos 		goto out;
43153e202c1Schristos 	}
43253e202c1Schristos 
43353e202c1Schristos 	offsetlow = bitoffset % 8;
43453e202c1Schristos 	if (bytelen > 1) {
43553e202c1Schristos 		offsethigh = (bitlen - (8 - offsetlow)) % 8;
43653e202c1Schristos 	} else {
43753e202c1Schristos 		offsethigh = 0;
43853e202c1Schristos 	}
43953e202c1Schristos 
44053e202c1Schristos 	if (offsetlow) {
44153e202c1Schristos 		masklow = (~((1 << bitlen) - 1) << offsetlow) | ~(0xff << offsetlow);
44253e202c1Schristos 		AML_DEBUGPRINT("\t[offsetlow = 0x%x, masklow = 0x%x, ~masklow = 0x%x]\n",
44353e202c1Schristos 		    offsetlow, masklow, ~masklow & 0xff);
44453e202c1Schristos 	}
44553e202c1Schristos 	if (offsethigh) {
44653e202c1Schristos 		maskhigh = 0xff << offsethigh;
44753e202c1Schristos 		AML_DEBUGPRINT("\t[offsethigh = 0x%x, maskhigh = 0x%x, ~maskhigh = 0x%x]\n",
44853e202c1Schristos 		    offsethigh, maskhigh, ~maskhigh & 0xff);
44953e202c1Schristos 	}
45053e202c1Schristos 	for (i = bytelen; i > 0; i--, addr++) {
45153e202c1Schristos 		val = *addr;
45253e202c1Schristos 
45353e202c1Schristos 		AML_DEBUGPRINT("\t[bufferfield:0x%02x@%p]", val, addr);
45453e202c1Schristos 
45553e202c1Schristos 		switch (io) {
45653e202c1Schristos 		case AML_BUFFER_INPUT:
45753e202c1Schristos 			tmp = val;
45853e202c1Schristos 			/* the lowest byte? */
45953e202c1Schristos 			if (i == bytelen) {
46053e202c1Schristos 				if (offsetlow) {
46153e202c1Schristos 					readval = tmp & ~masklow;
46253e202c1Schristos 				} else {
46353e202c1Schristos 					readval = tmp;
46453e202c1Schristos 				}
46553e202c1Schristos 			} else {
46653e202c1Schristos 				if (i == 1 && offsethigh) {
46753e202c1Schristos 					tmp = tmp & ~maskhigh;
46853e202c1Schristos 				}
46953e202c1Schristos 				readval = (tmp << (8 * (bytelen - i))) | readval;
47053e202c1Schristos 			}
47153e202c1Schristos 
47253e202c1Schristos 			AML_DEBUGPRINT("\n");
47353e202c1Schristos 			/* goto to next byte... */
47453e202c1Schristos 			if (i > 1) {
47553e202c1Schristos 				continue;
47653e202c1Schristos 			}
47753e202c1Schristos 			/* final adjustment before finishing region access */
47853e202c1Schristos 			if (offsetlow) {
47953e202c1Schristos 				readval = readval >> offsetlow;
48053e202c1Schristos 			}
48153e202c1Schristos 			AML_DEBUGPRINT("[read(bufferfield, %p)&mask:0x%x]\n",
48253e202c1Schristos 			    addr, readval);
48353e202c1Schristos 			*valuep = readval;
48453e202c1Schristos 
48553e202c1Schristos 			break;
48653e202c1Schristos 
48753e202c1Schristos 		case AML_BUFFER_OUTPUT:
48853e202c1Schristos 			tmp = value & 0xff;
48953e202c1Schristos 			/* the lowest byte? */
49053e202c1Schristos 			if (i == bytelen) {
49153e202c1Schristos 				if (offsetlow) {
49253e202c1Schristos 					tmp = (val & masklow) | tmp << offsetlow;
49353e202c1Schristos 				}
49453e202c1Schristos 				value = value >> (8 - offsetlow);
49553e202c1Schristos 			} else {
49653e202c1Schristos 				if (i == 1 && offsethigh) {
49753e202c1Schristos 					tmp = (val & maskhigh) | tmp;
49853e202c1Schristos 				}
49953e202c1Schristos 				value = value >> 8;
50053e202c1Schristos 			}
50153e202c1Schristos 
50253e202c1Schristos 			AML_DEBUGPRINT("->[bufferfield:0x%02x@%p]\n",
50353e202c1Schristos 			    tmp, addr);
50453e202c1Schristos 			*addr = tmp;
50553e202c1Schristos 		}
50653e202c1Schristos 	}
50753e202c1Schristos out:
50853e202c1Schristos 	return (0);
50953e202c1Schristos }
51053e202c1Schristos 
51153e202c1Schristos u_int32_t
aml_bufferfield_read(u_int8_t * origin,u_int32_t bitoffset,u_int32_t bitlen)51253e202c1Schristos aml_bufferfield_read(u_int8_t *origin, u_int32_t bitoffset,
51353e202c1Schristos     u_int32_t bitlen)
51453e202c1Schristos {
51553e202c1Schristos 	int	value;
51653e202c1Schristos 
51753e202c1Schristos 	value = 0;
51853e202c1Schristos 	aml_bufferfield_io(AML_BUFFER_INPUT, (u_int32_t *)&value, origin,
51953e202c1Schristos 	    bitoffset, bitlen);
52053e202c1Schristos 	return (value);
52153e202c1Schristos }
52253e202c1Schristos 
52353e202c1Schristos int
aml_bufferfield_write(u_int32_t value,u_int8_t * origin,u_int32_t bitoffset,u_int32_t bitlen)52453e202c1Schristos aml_bufferfield_write(u_int32_t value, u_int8_t *origin,
52553e202c1Schristos     u_int32_t bitoffset, u_int32_t bitlen)
52653e202c1Schristos {
52753e202c1Schristos 	int	status;
52853e202c1Schristos 
52953e202c1Schristos 	status = aml_bufferfield_io(AML_BUFFER_OUTPUT, &value,
53053e202c1Schristos 	    origin, bitoffset, bitlen);
53153e202c1Schristos 	return (status);
53253e202c1Schristos }
53353e202c1Schristos 
53453e202c1Schristos int
aml_region_handle_alloc(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t baseaddr,u_int32_t bitoffset,u_int32_t bitlen,struct aml_region_handle * h)53553e202c1Schristos aml_region_handle_alloc(struct aml_environ *env, int regtype, u_int32_t flags,
53653e202c1Schristos     u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen,
53753e202c1Schristos     struct aml_region_handle *h)
53853e202c1Schristos {
53953e202c1Schristos 	int	state;
54053e202c1Schristos 
54153e202c1Schristos 	state = 0;
54253e202c1Schristos 	bzero(h, sizeof(struct aml_region_handle));
54353e202c1Schristos 
54453e202c1Schristos 	h->env = env;
54553e202c1Schristos 	h->regtype = regtype;
54653e202c1Schristos 	h->flags = flags;
54753e202c1Schristos 	h->baseaddr = baseaddr;
54853e202c1Schristos 	h->bitoffset = bitoffset;
54953e202c1Schristos 	h->bitlen = bitlen;
55053e202c1Schristos 
55153e202c1Schristos 	switch (AML_FIELDFLAGS_ACCESSTYPE(flags)) {
55253e202c1Schristos 	case AML_FIELDFLAGS_ACCESS_ANYACC:
55353e202c1Schristos 		if (bitlen <= 8) {
55453e202c1Schristos 			h->unit = 1;
55553e202c1Schristos 			break;
55653e202c1Schristos 		}
55753e202c1Schristos 		if (bitlen <= 16) {
55853e202c1Schristos 			h->unit = 2;
55953e202c1Schristos 			break;
56053e202c1Schristos 		}
56153e202c1Schristos 		h->unit = 4;
56253e202c1Schristos 		break;
56353e202c1Schristos 	case AML_FIELDFLAGS_ACCESS_BYTEACC:
56453e202c1Schristos 		h->unit = 1;
56553e202c1Schristos 		break;
56653e202c1Schristos 	case AML_FIELDFLAGS_ACCESS_WORDACC:
56753e202c1Schristos 		h->unit = 2;
56853e202c1Schristos 		break;
56953e202c1Schristos 	case AML_FIELDFLAGS_ACCESS_DWORDACC:
57053e202c1Schristos 		h->unit = 4;
57153e202c1Schristos 		break;
57253e202c1Schristos 	default:
57353e202c1Schristos 		h->unit = 1;
57453e202c1Schristos 		break;
57553e202c1Schristos 	}
57653e202c1Schristos 
57753e202c1Schristos 	h->addr = baseaddr + h->unit * ((bitoffset / 8) / h->unit);
57853e202c1Schristos 	h->bytelen = baseaddr + ((bitoffset + bitlen) / 8) - h->addr +
57953e202c1Schristos 		     ((bitlen % 8) ? 1 : 0);
58053e202c1Schristos 
58153e202c1Schristos #ifdef _KERNEL
58253e202c1Schristos 	switch (h->regtype) {
58353e202c1Schristos 	case AML_REGION_SYSMEM:
58453e202c1Schristos 		OsdMapMemory((void *)h->addr, h->bytelen, (void **)&h->vaddr);
58553e202c1Schristos 		break;
58653e202c1Schristos 
58753e202c1Schristos 	case AML_REGION_PCICFG:
58853e202c1Schristos 		/* Obtain PCI bus number */
58953e202c1Schristos 		pci_info = aml_search_name(env, "_BBN");
59053e202c1Schristos 		if (pci_info == NULL || pci_info->property->type != aml_t_num) {
59153e202c1Schristos 			AML_DEBUGPRINT("Cannot locate _BBN. Using default 0\n");
59253e202c1Schristos 			h->pci_bus = 0;
59353e202c1Schristos 		} else {
59453e202c1Schristos 			AML_DEBUGPRINT("found _BBN: %d\n",
59553e202c1Schristos 			    pci_info->property->num.number);
59653e202c1Schristos 			h->pci_bus = pci_info->property->num.number & 0xff;
59753e202c1Schristos 		}
59853e202c1Schristos 
59953e202c1Schristos 		/* Obtain device & function number */
60053e202c1Schristos 		pci_info = aml_search_name(env, "_ADR");
60153e202c1Schristos 		if (pci_info == NULL || pci_info->property->type != aml_t_num) {
60253e202c1Schristos 			printf("Cannot locate: _ADR\n");
60353e202c1Schristos 			state = -1;
60453e202c1Schristos 			goto out;
60553e202c1Schristos 		}
60653e202c1Schristos 		h->pci_devfunc = pci_info->property->num.number;
60753e202c1Schristos 
60853e202c1Schristos 		AML_DEBUGPRINT("[pci%d.%d]", h->pci_bus, h->pci_devfunc);
60953e202c1Schristos 		break;
61053e202c1Schristos 
61153e202c1Schristos 	default:
61253e202c1Schristos 		break;
61353e202c1Schristos 	}
61453e202c1Schristos 
61553e202c1Schristos out:
61653e202c1Schristos #endif	/* _KERNEL */
61753e202c1Schristos 	return (state);
61853e202c1Schristos }
61953e202c1Schristos 
62053e202c1Schristos void
aml_region_handle_free(struct aml_region_handle * h)62153e202c1Schristos aml_region_handle_free(struct aml_region_handle *h)
62253e202c1Schristos {
62353e202c1Schristos #ifdef _KERNEL
62453e202c1Schristos 	switch (h->regtype) {
62553e202c1Schristos 	case AML_REGION_SYSMEM:
62653e202c1Schristos 		OsdUnMapMemory((void *)h->vaddr, h->bytelen);
62753e202c1Schristos 		break;
62853e202c1Schristos 
62953e202c1Schristos 	default:
63053e202c1Schristos 		break;
63153e202c1Schristos 	}
63253e202c1Schristos #endif	/* _KERNEL */
63353e202c1Schristos }
63453e202c1Schristos 
63553e202c1Schristos static int
aml_region_io_simple(struct aml_environ * env,int io,int regtype,u_int32_t flags,u_int32_t * valuep,u_int32_t baseaddr,u_int32_t bitoffset,u_int32_t bitlen)63653e202c1Schristos aml_region_io_simple(struct aml_environ *env, int io, int regtype,
63753e202c1Schristos     u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr,
63853e202c1Schristos     u_int32_t bitoffset, u_int32_t bitlen)
63953e202c1Schristos {
640e7dd2c75Slukem 	int		state;
641e7dd2c75Slukem 	u_int32_t	readval, value, offset, bytelen, i;
64253e202c1Schristos 	struct		aml_region_handle handle;
64353e202c1Schristos 
64453e202c1Schristos 	state = aml_region_handle_alloc(env, regtype, flags,
64553e202c1Schristos             baseaddr, bitoffset, bitlen, &handle);
64653e202c1Schristos 	if (state == -1) {
64753e202c1Schristos 		goto out;
64853e202c1Schristos 	}
64953e202c1Schristos 
65053e202c1Schristos 	readval = 0;
65153e202c1Schristos 	offset = bitoffset % (handle.unit * 8);
65253e202c1Schristos 	/* limitation of 32 bits alignment */
65353e202c1Schristos 	bytelen = (handle.bytelen > 4) ? 4 : handle.bytelen;
65453e202c1Schristos 
65553e202c1Schristos 	if (io == AML_REGION_INPUT ||
65653e202c1Schristos 	    AML_FIELDFLAGS_UPDATERULE(flags) == AML_FIELDFLAGS_UPDATE_PRESERVE) {
65753e202c1Schristos 		for (i = 0; i < bytelen; i += handle.unit) {
65853e202c1Schristos 			state = aml_region_read_simple(&handle, i, &value);
65953e202c1Schristos 			if (state == -1) {
66053e202c1Schristos 				goto out;
66153e202c1Schristos 			}
66253e202c1Schristos 			readval |= (value << (i * 8));
66353e202c1Schristos 		}
66453e202c1Schristos 		AML_DEBUGPRINT("\t[%d:0x%x@0x%lx:%d,%d]",
66553e202c1Schristos 		    regtype, readval, handle.addr, offset, bitlen);
66653e202c1Schristos 	}
66753e202c1Schristos 
66853e202c1Schristos 	switch (io) {
66953e202c1Schristos 	case AML_REGION_INPUT:
67053e202c1Schristos 		AML_DEBUGPRINT("\n");
67153e202c1Schristos 		readval = aml_adjust_readvalue(flags, offset, bitlen, readval);
67253e202c1Schristos 		value = readval;
67353e202c1Schristos 		value = aml_region_prompt_read(&handle, value);
67453e202c1Schristos 		state = aml_region_prompt_update_value(readval, value, &handle);
67553e202c1Schristos 		if (state == -1) {
67653e202c1Schristos 			goto out;
67753e202c1Schristos 		}
67853e202c1Schristos 
67953e202c1Schristos 		*valuep = value;
68053e202c1Schristos 		break;
68153e202c1Schristos 	case AML_REGION_OUTPUT:
68253e202c1Schristos 		value = *valuep;
68353e202c1Schristos 		value = aml_adjust_updatevalue(flags, offset,
68453e202c1Schristos 		    bitlen, readval, value);
68553e202c1Schristos 		value = aml_region_prompt_write(&handle, value);
68653e202c1Schristos 		AML_DEBUGPRINT("\t->[%d:0x%x@0x%lx:%d,%d]\n", regtype, value,
68753e202c1Schristos 		    handle.addr, offset, bitlen);
68853e202c1Schristos 		for (i = 0; i < bytelen; i += handle.unit) {
68953e202c1Schristos 			state = aml_region_write_simple(&handle, i, value);
69053e202c1Schristos 			if (state == -1) {
69153e202c1Schristos 				goto out;
69253e202c1Schristos 			}
69353e202c1Schristos 			value = value >> (handle.unit * 8);
69453e202c1Schristos 		}
69553e202c1Schristos 		break;
69653e202c1Schristos 	}
69753e202c1Schristos 
69853e202c1Schristos 	aml_region_handle_free(&handle);
69953e202c1Schristos out:
70053e202c1Schristos 	return (state);
70153e202c1Schristos }
70253e202c1Schristos 
70353e202c1Schristos int
aml_region_io(struct aml_environ * env,int io,int regtype,u_int32_t flags,u_int32_t * valuep,u_int32_t baseaddr,u_int32_t bitoffset,u_int32_t bitlen)70453e202c1Schristos aml_region_io(struct aml_environ *env, int io, int regtype,
70553e202c1Schristos     u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr,
70653e202c1Schristos     u_int32_t bitoffset, u_int32_t bitlen)
70753e202c1Schristos {
70853e202c1Schristos 	u_int32_t	unit, offset;
70953e202c1Schristos 	u_int32_t	offadj, bitadj;
710e7dd2c75Slukem 	u_int32_t	value, readval, i;
711e7dd2c75Slukem 	int		state;
71253e202c1Schristos 
71353e202c1Schristos 	readval = 0;
71453e202c1Schristos 	state = 0;
71553e202c1Schristos 	unit = 4;	/* limitation of 32 bits alignment */
71653e202c1Schristos 	offset = bitoffset % (unit * 8);
71753e202c1Schristos 	offadj = 0;
71853e202c1Schristos 	bitadj = 0;
71953e202c1Schristos 	if (offset + bitlen > unit * 8) {
72053e202c1Schristos 		bitadj = bitlen  - (unit * 8 - offset);
72153e202c1Schristos 	}
72253e202c1Schristos 	for (i = 0; i < offset + bitlen; i += unit * 8) {
72353e202c1Schristos 		value = (*valuep) >> offadj;
72453e202c1Schristos 		state = aml_region_io_simple(env, io, regtype, flags,
72553e202c1Schristos 		    &value, baseaddr, bitoffset + offadj, bitlen - bitadj);
72653e202c1Schristos 		if (state == -1) {
72753e202c1Schristos 			goto out;
72853e202c1Schristos 		}
72953e202c1Schristos 		readval |= value << offadj;
73053e202c1Schristos 		bitadj = offadj = bitlen - bitadj;
73153e202c1Schristos 	}
73253e202c1Schristos 	*valuep = readval;
73353e202c1Schristos 
73453e202c1Schristos out:
73553e202c1Schristos 	return (state);
73653e202c1Schristos }
737