1 /* $NetBSD: region.c,v 1.3 2009/01/18 09:46:59 lukem 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.3 2009/01/18 09:46:59 lukem 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 56 int aml_debug_prompt_regoutput = 0; 57 int aml_debug_prompt_reginput = 1; 58 59 static void aml_simulation_regload(const char *dumpfile); 60 61 struct ACPIRegionContent { 62 TAILQ_ENTRY(ACPIRegionContent) links; 63 int regtype; 64 u_int32_t addr; 65 u_int8_t value; 66 }; 67 68 TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent); 69 struct ACPIRegionContentList RegionContentList; 70 71 static int aml_simulation_initialized = 0; 72 73 static void 74 aml_simulation_init(void) 75 { 76 77 aml_simulation_initialized = 1; 78 TAILQ_INIT(&RegionContentList); 79 aml_simulation_regload("region.ini"); 80 } 81 82 static int 83 aml_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 99 static int 100 aml_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 117 static int 118 aml_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 135 static u_int32_t 136 aml_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 167 static void 168 aml_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 208 int 209 aml_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; 227 out: 228 return (state); 229 } 230 231 int 232 aml_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 } 250 out: 251 return (state); 252 } 253 254 u_int32_t 255 aml_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 272 u_int32_t 273 aml_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 289 int 290 aml_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 304 out: 305 return (state); 306 } 307 308 static int 309 aml_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 } 352 finish: 353 return (state); 354 } 355 356 static u_int32_t 357 aml_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 369 static int 370 aml_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 381 static int 382 aml_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 394 static int 395 aml_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 406 static int 407 aml_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 432 u_int32_t 433 aml_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 443 int 444 aml_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 455 int 456 aml_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 466 int 467 aml_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 479 int 480 aml_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 493 void 494 aml_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