1/* $NetBSD: region.c,v 1.2 2008/08/29 00:50:01 gmcgarry Exp $ */ 2 3/*- 4 * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * Id: region.c,v 1.14 2000/08/08 14:12:25 iwasaki Exp 29 * $FreeBSD: src/usr.sbin/acpi/amldb/region.c,v 1.4 2000/11/19 13:29:43 kris Exp $ 30 */ 31#include <sys/cdefs.h> 32__RCSID("$NetBSD: region.c,v 1.2 2008/08/29 00:50:01 gmcgarry Exp $"); 33 34/* 35 * Region I/O subroutine 36 */ 37 38#include <sys/param.h> 39#include <sys/queue.h> 40 41#include <acpi_common.h> 42#include <aml/aml_amlmem.h> 43#include <aml/aml_name.h> 44#include <aml/aml_common.h> 45#include <aml/aml_region.h> 46 47#include <assert.h> 48#include <err.h> 49#include <stdlib.h> 50#include <stdio.h> 51#include <string.h> 52#include <unistd.h> 53 54#include "debug.h" 55 56int aml_debug_prompt_regoutput = 0; 57int aml_debug_prompt_reginput = 1; 58 59static void aml_simulation_regload(const char *dumpfile); 60 61struct ACPIRegionContent { 62 TAILQ_ENTRY(ACPIRegionContent) links; 63 int regtype; 64 u_int32_t addr; 65 u_int8_t value; 66}; 67 68TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent); 69struct ACPIRegionContentList RegionContentList; 70 71static int aml_simulation_initialized = 0; 72 73static void 74aml_simulation_init(void) 75{ 76 77 aml_simulation_initialized = 1; 78 TAILQ_INIT(&RegionContentList); 79 aml_simulation_regload("region.ini"); 80} 81 82static int 83aml_simulate_regcontent_add(int regtype, u_int32_t addr, u_int8_t value) 84{ 85 struct ACPIRegionContent *rc; 86 87 rc = malloc(sizeof(struct ACPIRegionContent)); 88 if (rc == NULL) { 89 return (-1); /* malloc fail */ 90 } 91 rc->regtype = regtype; 92 rc->addr = addr; 93 rc->value = value; 94 95 TAILQ_INSERT_TAIL(&RegionContentList, rc, links); 96 return (0); 97} 98 99static int 100aml_simulate_regcontent_read(int regtype, u_int32_t addr, u_int8_t *valuep) 101{ 102 struct ACPIRegionContent *rc; 103 104 if (!aml_simulation_initialized) { 105 aml_simulation_init(); 106 } 107 TAILQ_FOREACH(rc, &RegionContentList, links) { 108 if (rc->regtype == regtype && rc->addr == addr) { 109 *valuep = rc->value; 110 return (1); /* found */ 111 } 112 } 113 114 return (aml_simulate_regcontent_add(regtype, addr, 0)); 115} 116 117static int 118aml_simulate_regcontent_write(int regtype, u_int32_t addr, u_int8_t *valuep) 119{ 120 struct ACPIRegionContent *rc; 121 122 if (!aml_simulation_initialized) { 123 aml_simulation_init(); 124 } 125 TAILQ_FOREACH(rc, &RegionContentList, links) { 126 if (rc->regtype == regtype && rc->addr == addr) { 127 rc->value = *valuep; 128 return (1); /* exists */ 129 } 130 } 131 132 return (aml_simulate_regcontent_add(regtype, addr, *valuep)); 133} 134 135static u_int32_t 136aml_simulate_prompt(char *msg, u_int32_t def_val) 137{ 138 char buf[16], *ep; 139 u_int32_t val; 140 141 val = def_val; 142 printf("DEBUG"); 143 if (msg != NULL) { 144 printf("%s", msg); 145 } 146 printf("(default: 0x%x / %u) >>", val, val); 147 fflush(stdout); 148 149 bzero(buf, sizeof buf); 150 while (1) { 151 if (read(0, buf, sizeof buf) == 0) { 152 continue; 153 } 154 if (buf[0] == '\n') { 155 break; /* use default value */ 156 } 157 if (buf[0] == '0' && buf[1] == 'x') { 158 val = strtoq(buf, &ep, 16); 159 } else { 160 val = strtoq(buf, &ep, 10); 161 } 162 break; 163 } 164 return (val); 165} 166 167static void 168aml_simulation_regload(const char *dumpfile) 169{ 170 char buf[256], *np, *ep; 171 struct ACPIRegionContent rc; 172 FILE *fp; 173 174 if (!aml_simulation_initialized) { 175 return; 176 } 177 if ((fp = fopen(dumpfile, "r")) == NULL) { 178 warn("%s", dumpfile); 179 return; 180 } 181 while (fgets(buf, sizeof buf, fp) != NULL) { 182 np = buf; 183 /* reading region type */ 184 rc.regtype = strtoq(np, &ep, 10); 185 if (np == ep) { 186 continue; 187 } 188 np = ep; 189 190 /* reading address */ 191 rc.addr = strtoq(np, &ep, 16); 192 if (np == ep) { 193 continue; 194 } 195 np = ep; 196 197 /* reading value */ 198 rc.value = strtoq(np, &ep, 16); 199 if (np == ep) { 200 continue; 201 } 202 aml_simulate_regcontent_write(rc.regtype, rc.addr, &rc.value); 203 } 204 205 fclose(fp); 206} 207 208int 209aml_region_read_simple(struct aml_region_handle *h, vm_offset_t offset, 210 u_int32_t *valuep) 211{ 212 int state; 213 u_int8_t val; 214 u_int32_t value, i; 215 216 state = 0; 217 value = val = 0; 218 for (i = 0; i < h->unit; i++) { 219 state = aml_simulate_regcontent_read(h->regtype, 220 h->addr + offset + i, &val); 221 if (state == -1) { 222 goto out; 223 } 224 value |= val << (i * 8); 225 } 226 *valuep = value; 227out: 228 return (state); 229} 230 231int 232aml_region_write_simple(struct aml_region_handle *h, vm_offset_t offset, 233 u_int32_t value) 234{ 235 int state; 236 u_int8_t val; 237 u_int32_t i; 238 239 state = 0; 240 val = 0; 241 for (i = 0; i < h->unit; i++) { 242 val = value & 0xff; 243 state = aml_simulate_regcontent_write(h->regtype, 244 h->addr + offset + i, &val); 245 if (state == -1) { 246 goto out; 247 } 248 value = value >> 8; 249 } 250out: 251 return (state); 252} 253 254u_int32_t 255aml_region_prompt_read(struct aml_region_handle *h, u_int32_t value) 256{ 257 u_int32_t retval; 258 char buf[64]; 259 260 retval = value; 261 sprintf(buf, "[read(%d, 0x%lx)&mask:0x%x]", 262 h->regtype, h->addr, value); 263 if (aml_debug_prompt_reginput) { 264 retval = aml_simulate_prompt(buf, value); 265 } else { 266 printf("\t%s\n", buf); 267 } 268 269 return (retval); 270} 271 272u_int32_t 273aml_region_prompt_write(struct aml_region_handle *h, u_int32_t value) 274{ 275 u_int32_t retval; 276 char buf[64]; 277 278 retval = value; 279 if (aml_debug_prompt_regoutput) { 280 printf("\n"); 281 sprintf(buf, "[write(%d, 0x%x, 0x%lx)]", 282 h->regtype, value, h->addr); 283 retval = aml_simulate_prompt(buf, value); 284 } 285 286 return (retval); 287} 288 289int 290aml_region_prompt_update_value(u_int32_t orgval, u_int32_t value, 291 struct aml_region_handle *h) 292{ 293 int state; 294 295 state = 0; 296 if (orgval != value) { 297 state = aml_region_io(h->env, AML_REGION_OUTPUT, h->regtype, 298 h->flags, &value, h->baseaddr, h->bitoffset, h->bitlen); 299 if (state == -1) { 300 goto out; 301 } 302 } 303 304out: 305 return (state); 306} 307 308static int 309aml_simulate_region_io_buffer(int io, int regtype, u_int32_t flags, 310 u_int8_t *buffer, u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen) 311{ 312 u_int8_t val; 313 u_int8_t offsetlow, offsethigh; 314 u_int32_t addr, byteoffset, bytelen; 315 int state, i; 316 317 val = 0; 318 offsetlow = offsethigh = 0; 319 state = 0; 320 321 byteoffset = bitoffset / 8; 322 bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0); 323 addr = baseaddr + byteoffset; 324 offsetlow = bitoffset % 8; 325 assert(offsetlow == 0); 326 327 if (bytelen > 1) { 328 offsethigh = (bitlen - (8 - offsetlow)) % 8; 329 } 330 assert(offsethigh == 0); 331 332 for (i = bytelen; i > 0; i--, addr++) { 333 switch (io) { 334 case AML_REGION_INPUT: 335 val = 0; 336 state = aml_simulate_regcontent_read(regtype, addr, &val); 337 if (state == -1) { 338 goto finish; 339 } 340 buffer[bytelen - i] = val; 341 break; 342 case AML_REGION_OUTPUT: 343 val = buffer[bytelen - i]; 344 state = aml_simulate_regcontent_write(regtype, 345 addr, &val); 346 if (state == -1) { 347 goto finish; 348 } 349 break; 350 } 351 } 352finish: 353 return (state); 354} 355 356static u_int32_t 357aml_simulate_region_read(struct aml_environ *env, int regtype, 358 u_int32_t flags, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 359{ 360 u_int32_t value; 361 int state; 362 363 state = aml_region_io(env, AML_REGION_INPUT, regtype, flags, &value, 364 addr, bitoffset, bitlen); 365 assert(state != -1); 366 return (value); 367} 368 369static int 370aml_simulate_region_read_into_buffer(int regtype, u_int32_t flags, 371 u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen, u_int8_t *buffer) 372{ 373 int state; 374 375 state = aml_simulate_region_io_buffer(AML_REGION_INPUT, regtype, flags, 376 buffer, addr, bitoffset, bitlen); 377 assert(state != -1); 378 return (state); 379} 380 381static int 382aml_simulate_region_write(struct aml_environ *env, int regtype, 383 u_int32_t flags, u_int32_t value, u_int32_t addr, u_int32_t bitoffset, 384 u_int32_t bitlen) 385{ 386 int state; 387 388 state = aml_region_io(env, AML_REGION_OUTPUT, regtype, flags, 389 &value, addr, bitoffset, bitlen); 390 assert(state != -1); 391 return (state); 392} 393 394static int 395aml_simulate_region_write_from_buffer(int regtype, u_int32_t flags, 396 u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 397{ 398 int state; 399 400 state = aml_simulate_region_io_buffer(AML_REGION_OUTPUT, regtype, 401 flags, buffer, addr, bitoffset, bitlen); 402 assert(state != -1); 403 return (state); 404} 405 406static int 407aml_simulate_region_bcopy(struct aml_environ *env, int regtype, 408 u_int32_t flags, u_int32_t addr, 409 u_int32_t bitoffset, u_int32_t bitlen, 410 u_int32_t dflags, u_int32_t daddr, 411 u_int32_t dbitoffset, u_int32_t dbitlen) 412{ 413 u_int32_t len, i; 414 u_int32_t value; 415 int state; 416 417 len = (bitlen > dbitlen) ? dbitlen : bitlen; 418 len = len / 8 + ((len % 8) ? 1 : 0); 419 420 for (i = 0; i < len; i++) { 421 state = aml_region_io(env, AML_REGION_INPUT, regtype, 422 flags, &value, addr, bitoffset + i * 8, 8); 423 assert(state != -1); 424 state = aml_region_io(env, AML_REGION_OUTPUT, regtype, 425 dflags, &value, daddr, dbitoffset + i * 8, 8); 426 assert(state != -1); 427 } 428 429 return (0); 430} 431 432u_int32_t 433aml_region_read(struct aml_environ *env, int regtype, u_int32_t flags, 434 u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 435{ 436 437 AML_REGION_READ_DEBUG(regtype, flags, addr, bitoffset, bitlen); 438 439 return (aml_simulate_region_read(env, regtype, flags, addr, 440 bitoffset, bitlen)); 441} 442 443int 444aml_region_read_into_buffer(struct aml_environ *env, int regtype, 445 u_int32_t flags, u_int32_t addr, u_int32_t bitoffset, 446 u_int32_t bitlen, u_int8_t *buffer) 447{ 448 449 AML_REGION_READ_INTO_BUFFER_DEBUG(regtype, flags, addr, bitoffset, bitlen); 450 451 return (aml_simulate_region_read_into_buffer(regtype, flags, addr, 452 bitoffset, bitlen, buffer)); 453} 454 455int 456aml_region_write(struct aml_environ *env, int regtype, u_int32_t flags, 457 u_int32_t value, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 458{ 459 460 AML_REGION_WRITE_DEBUG(regtype, flags, value, addr, bitoffset, bitlen); 461 462 return (aml_simulate_region_write(env, regtype, flags, value, addr, 463 bitoffset, bitlen)); 464} 465 466int 467aml_region_write_from_buffer(struct aml_environ *env, int regtype, 468 u_int32_t flags, u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset, 469 u_int32_t bitlen) 470{ 471 472 AML_REGION_WRITE_FROM_BUFFER_DEBUG(regtype, flags, 473 addr, bitoffset, bitlen); 474 475 return (aml_simulate_region_write_from_buffer(regtype, flags, buffer, 476 addr, bitoffset, bitlen)); 477} 478 479int 480aml_region_bcopy(struct aml_environ *env, int regtype, u_int32_t flags, 481 u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen, 482 u_int32_t dflags, u_int32_t daddr, 483 u_int32_t dbitoffset, u_int32_t dbitlen) 484{ 485 486 AML_REGION_BCOPY_DEBUG(regtype, flags, addr, bitoffset, bitlen, 487 dflags, daddr, dbitoffset, dbitlen); 488 489 return (aml_simulate_region_bcopy(env, regtype, flags, addr, bitoffset, 490 bitlen, dflags, daddr, dbitoffset, dbitlen)); 491} 492 493void 494aml_simulation_regdump(const char *dumpfile) 495{ 496 struct ACPIRegionContent *rc; 497 FILE *fp; 498 499 if (!aml_simulation_initialized) { 500 return; 501 } 502 if ((fp = fopen(dumpfile, "w")) == NULL) { 503 warn("%s", dumpfile); 504 return; 505 } 506 while (!TAILQ_EMPTY(&RegionContentList)) { 507 rc = TAILQ_FIRST(&RegionContentList); 508 fprintf(fp, "%d 0x%x 0x%x\n", 509 rc->regtype, rc->addr, rc->value); 510 TAILQ_REMOVE(&RegionContentList, rc, links); 511 free(rc); 512 } 513 514 fclose(fp); 515 TAILQ_INIT(&RegionContentList); 516} 517