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