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