aml_common.c revision 1.1
1/* $NetBSD: aml_common.c,v 1.1 2007/01/14 04:36:13 christos 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.1 2007/01/14 04:36:13 christos 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 70int aml_debug = 1; 71#else /* !AML_DEBUG */ 72int aml_debug = 0; 73#endif /* AML_DEBUG */ 74#ifdef _KERNEL 75SYSCTL_INT(_debug, OID_AUTO, aml_debug, CTLFLAG_RW, &aml_debug, 1, ""); 76#endif /* _KERNEL */ 77 78static void aml_print_nameseg(u_int8_t *dp); 79 80static void 81aml_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 95void 96aml_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 129int 130aml_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 146void 147aml_print_indent(int indent) 148{ 149 int i; 150 151 for (i = 0; i < indent; i++) 152 AML_DEBUGPRINT(" "); 153} 154 155void 156aml_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 268void 269aml_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 294static __inline u_int64_t 295aml_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 335u_int32_t 336aml_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 349u_int32_t 350aml_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 388static 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 392static int 393aml_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 int i; 400 u_int32_t value, readval; 401 u_int32_t byteoffset, bytelen; 402 403 masklow = maskhigh = 0xff; 404 val = readval = 0; 405 value = *valuep; 406 407 byteoffset = bitoffset / 8; 408 bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0); 409 addr = origin + byteoffset; 410 411 /* simple I/O ? */ 412 if (bitlen <= 8 || bitlen == 16 || bitlen == 32) { 413 bcopy(addr, &readval, bytelen); 414 AML_DEBUGPRINT("\n\t[bufferfield:0x%x@%p:%d,%d]", 415 readval, addr, bitoffset % 8, bitlen); 416 switch (io) { 417 case AML_BUFFER_INPUT: 418 value = aml_adjust_readvalue(AML_FIELDFLAGS_ACCESS_BYTEACC, 419 bitoffset % 8, bitlen, readval); 420 *valuep = value; 421 AML_DEBUGPRINT("\n[read(bufferfield, %p)&mask:0x%x]\n", 422 addr, value); 423 break; 424 case AML_BUFFER_OUTPUT: 425 value = aml_adjust_updatevalue(AML_FIELDFLAGS_ACCESS_BYTEACC, 426 bitoffset % 8, bitlen, readval, value); 427 bcopy(&value, addr, bytelen); 428 AML_DEBUGPRINT("->[bufferfield:0x%x@%p:%d,%d]", 429 value, addr, bitoffset % 8, bitlen); 430 break; 431 } 432 goto out; 433 } 434 435 offsetlow = bitoffset % 8; 436 if (bytelen > 1) { 437 offsethigh = (bitlen - (8 - offsetlow)) % 8; 438 } else { 439 offsethigh = 0; 440 } 441 442 if (offsetlow) { 443 masklow = (~((1 << bitlen) - 1) << offsetlow) | ~(0xff << offsetlow); 444 AML_DEBUGPRINT("\t[offsetlow = 0x%x, masklow = 0x%x, ~masklow = 0x%x]\n", 445 offsetlow, masklow, ~masklow & 0xff); 446 } 447 if (offsethigh) { 448 maskhigh = 0xff << offsethigh; 449 AML_DEBUGPRINT("\t[offsethigh = 0x%x, maskhigh = 0x%x, ~maskhigh = 0x%x]\n", 450 offsethigh, maskhigh, ~maskhigh & 0xff); 451 } 452 for (i = bytelen; i > 0; i--, addr++) { 453 val = *addr; 454 455 AML_DEBUGPRINT("\t[bufferfield:0x%02x@%p]", val, addr); 456 457 switch (io) { 458 case AML_BUFFER_INPUT: 459 tmp = val; 460 /* the lowest byte? */ 461 if (i == bytelen) { 462 if (offsetlow) { 463 readval = tmp & ~masklow; 464 } else { 465 readval = tmp; 466 } 467 } else { 468 if (i == 1 && offsethigh) { 469 tmp = tmp & ~maskhigh; 470 } 471 readval = (tmp << (8 * (bytelen - i))) | readval; 472 } 473 474 AML_DEBUGPRINT("\n"); 475 /* goto to next byte... */ 476 if (i > 1) { 477 continue; 478 } 479 /* final adjustment before finishing region access */ 480 if (offsetlow) { 481 readval = readval >> offsetlow; 482 } 483 AML_DEBUGPRINT("[read(bufferfield, %p)&mask:0x%x]\n", 484 addr, readval); 485 *valuep = readval; 486 487 break; 488 489 case AML_BUFFER_OUTPUT: 490 tmp = value & 0xff; 491 /* the lowest byte? */ 492 if (i == bytelen) { 493 if (offsetlow) { 494 tmp = (val & masklow) | tmp << offsetlow; 495 } 496 value = value >> (8 - offsetlow); 497 } else { 498 if (i == 1 && offsethigh) { 499 tmp = (val & maskhigh) | tmp; 500 } 501 value = value >> 8; 502 } 503 504 AML_DEBUGPRINT("->[bufferfield:0x%02x@%p]\n", 505 tmp, addr); 506 *addr = tmp; 507 } 508 } 509out: 510 return (0); 511} 512 513u_int32_t 514aml_bufferfield_read(u_int8_t *origin, u_int32_t bitoffset, 515 u_int32_t bitlen) 516{ 517 int value; 518 519 value = 0; 520 aml_bufferfield_io(AML_BUFFER_INPUT, (u_int32_t *)&value, origin, 521 bitoffset, bitlen); 522 return (value); 523} 524 525int 526aml_bufferfield_write(u_int32_t value, u_int8_t *origin, 527 u_int32_t bitoffset, u_int32_t bitlen) 528{ 529 int status; 530 531 status = aml_bufferfield_io(AML_BUFFER_OUTPUT, &value, 532 origin, bitoffset, bitlen); 533 return (status); 534} 535 536int 537aml_region_handle_alloc(struct aml_environ *env, int regtype, u_int32_t flags, 538 u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen, 539 struct aml_region_handle *h) 540{ 541 int state; 542 struct aml_name *pci_info; 543 544 state = 0; 545 pci_info = NULL; 546 bzero(h, sizeof(struct aml_region_handle)); 547 548 h->env = env; 549 h->regtype = regtype; 550 h->flags = flags; 551 h->baseaddr = baseaddr; 552 h->bitoffset = bitoffset; 553 h->bitlen = bitlen; 554 555 switch (AML_FIELDFLAGS_ACCESSTYPE(flags)) { 556 case AML_FIELDFLAGS_ACCESS_ANYACC: 557 if (bitlen <= 8) { 558 h->unit = 1; 559 break; 560 } 561 if (bitlen <= 16) { 562 h->unit = 2; 563 break; 564 } 565 h->unit = 4; 566 break; 567 case AML_FIELDFLAGS_ACCESS_BYTEACC: 568 h->unit = 1; 569 break; 570 case AML_FIELDFLAGS_ACCESS_WORDACC: 571 h->unit = 2; 572 break; 573 case AML_FIELDFLAGS_ACCESS_DWORDACC: 574 h->unit = 4; 575 break; 576 default: 577 h->unit = 1; 578 break; 579 } 580 581 h->addr = baseaddr + h->unit * ((bitoffset / 8) / h->unit); 582 h->bytelen = baseaddr + ((bitoffset + bitlen) / 8) - h->addr + 583 ((bitlen % 8) ? 1 : 0); 584 585#ifdef _KERNEL 586 switch (h->regtype) { 587 case AML_REGION_SYSMEM: 588 OsdMapMemory((void *)h->addr, h->bytelen, (void **)&h->vaddr); 589 break; 590 591 case AML_REGION_PCICFG: 592 /* Obtain PCI bus number */ 593 pci_info = aml_search_name(env, "_BBN"); 594 if (pci_info == NULL || pci_info->property->type != aml_t_num) { 595 AML_DEBUGPRINT("Cannot locate _BBN. Using default 0\n"); 596 h->pci_bus = 0; 597 } else { 598 AML_DEBUGPRINT("found _BBN: %d\n", 599 pci_info->property->num.number); 600 h->pci_bus = pci_info->property->num.number & 0xff; 601 } 602 603 /* Obtain device & function number */ 604 pci_info = aml_search_name(env, "_ADR"); 605 if (pci_info == NULL || pci_info->property->type != aml_t_num) { 606 printf("Cannot locate: _ADR\n"); 607 state = -1; 608 goto out; 609 } 610 h->pci_devfunc = pci_info->property->num.number; 611 612 AML_DEBUGPRINT("[pci%d.%d]", h->pci_bus, h->pci_devfunc); 613 break; 614 615 default: 616 break; 617 } 618 619out: 620#endif /* _KERNEL */ 621 return (state); 622} 623 624void 625aml_region_handle_free(struct aml_region_handle *h) 626{ 627#ifdef _KERNEL 628 switch (h->regtype) { 629 case AML_REGION_SYSMEM: 630 OsdUnMapMemory((void *)h->vaddr, h->bytelen); 631 break; 632 633 default: 634 break; 635 } 636#endif /* _KERNEL */ 637} 638 639static int 640aml_region_io_simple(struct aml_environ *env, int io, int regtype, 641 u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr, 642 u_int32_t bitoffset, u_int32_t bitlen) 643{ 644 int i, state; 645 u_int32_t readval, value, offset, bytelen; 646 struct aml_region_handle handle; 647 648 state = aml_region_handle_alloc(env, regtype, flags, 649 baseaddr, bitoffset, bitlen, &handle); 650 if (state == -1) { 651 goto out; 652 } 653 654 readval = 0; 655 offset = bitoffset % (handle.unit * 8); 656 /* limitation of 32 bits alignment */ 657 bytelen = (handle.bytelen > 4) ? 4 : handle.bytelen; 658 659 if (io == AML_REGION_INPUT || 660 AML_FIELDFLAGS_UPDATERULE(flags) == AML_FIELDFLAGS_UPDATE_PRESERVE) { 661 for (i = 0; i < bytelen; i += handle.unit) { 662 state = aml_region_read_simple(&handle, i, &value); 663 if (state == -1) { 664 goto out; 665 } 666 readval |= (value << (i * 8)); 667 } 668 AML_DEBUGPRINT("\t[%d:0x%x@0x%lx:%d,%d]", 669 regtype, readval, handle.addr, offset, bitlen); 670 } 671 672 switch (io) { 673 case AML_REGION_INPUT: 674 AML_DEBUGPRINT("\n"); 675 readval = aml_adjust_readvalue(flags, offset, bitlen, readval); 676 value = readval; 677 value = aml_region_prompt_read(&handle, value); 678 state = aml_region_prompt_update_value(readval, value, &handle); 679 if (state == -1) { 680 goto out; 681 } 682 683 *valuep = value; 684 break; 685 case AML_REGION_OUTPUT: 686 value = *valuep; 687 value = aml_adjust_updatevalue(flags, offset, 688 bitlen, readval, value); 689 value = aml_region_prompt_write(&handle, value); 690 AML_DEBUGPRINT("\t->[%d:0x%x@0x%lx:%d,%d]\n", regtype, value, 691 handle.addr, offset, bitlen); 692 for (i = 0; i < bytelen; i += handle.unit) { 693 state = aml_region_write_simple(&handle, i, value); 694 if (state == -1) { 695 goto out; 696 } 697 value = value >> (handle.unit * 8); 698 } 699 break; 700 } 701 702 aml_region_handle_free(&handle); 703out: 704 return (state); 705} 706 707int 708aml_region_io(struct aml_environ *env, int io, int regtype, 709 u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr, 710 u_int32_t bitoffset, u_int32_t bitlen) 711{ 712 u_int32_t unit, offset; 713 u_int32_t offadj, bitadj; 714 u_int32_t value, readval; 715 int state, i; 716 717 readval = 0; 718 state = 0; 719 unit = 4; /* limitation of 32 bits alignment */ 720 offset = bitoffset % (unit * 8); 721 offadj = 0; 722 bitadj = 0; 723 if (offset + bitlen > unit * 8) { 724 bitadj = bitlen - (unit * 8 - offset); 725 } 726 for (i = 0; i < offset + bitlen; i += unit * 8) { 727 value = (*valuep) >> offadj; 728 state = aml_region_io_simple(env, io, regtype, flags, 729 &value, baseaddr, bitoffset + offadj, bitlen - bitadj); 730 if (state == -1) { 731 goto out; 732 } 733 readval |= value << offadj; 734 bitadj = offadj = bitlen - bitadj; 735 } 736 *valuep = readval; 737 738out: 739 return (state); 740} 741