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