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 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 i, state; 213 u_int8_t val; 214 u_int32_t value; 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 i, state; 236 u_int8_t val; 237 238 state = 0; 239 val = 0; 240 for (i = 0; i < h->unit; i++) { 241 val = value & 0xff; 242 state = aml_simulate_regcontent_write(h->regtype, 243 h->addr + offset + i, &val); 244 if (state == -1) { 245 goto out; 246 } 247 value = value >> 8; 248 } 249 out: 250 return (state); 251 } 252 253 u_int32_t 254 aml_region_prompt_read(struct aml_region_handle *h, u_int32_t value) 255 { 256 u_int32_t retval; 257 char buf[64]; 258 259 retval = value; 260 sprintf(buf, "[read(%d, 0x%lx)&mask:0x%x]", 261 h->regtype, h->addr, value); 262 if (aml_debug_prompt_reginput) { 263 retval = aml_simulate_prompt(buf, value); 264 } else { 265 printf("\t%s\n", buf); 266 } 267 268 return (retval); 269 } 270 271 u_int32_t 272 aml_region_prompt_write(struct aml_region_handle *h, u_int32_t value) 273 { 274 u_int32_t retval; 275 char buf[64]; 276 277 retval = value; 278 if (aml_debug_prompt_regoutput) { 279 printf("\n"); 280 sprintf(buf, "[write(%d, 0x%x, 0x%lx)]", 281 h->regtype, value, h->addr); 282 retval = aml_simulate_prompt(buf, value); 283 } 284 285 return (retval); 286 } 287 288 int 289 aml_region_prompt_update_value(u_int32_t orgval, u_int32_t value, 290 struct aml_region_handle *h) 291 { 292 int state; 293 294 state = 0; 295 if (orgval != value) { 296 state = aml_region_io(h->env, AML_REGION_OUTPUT, h->regtype, 297 h->flags, &value, h->baseaddr, h->bitoffset, h->bitlen); 298 if (state == -1) { 299 goto out; 300 } 301 } 302 303 out: 304 return (state); 305 } 306 307 static int 308 aml_simulate_region_io_buffer(int io, int regtype, u_int32_t flags, 309 u_int8_t *buffer, u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen) 310 { 311 u_int8_t val; 312 u_int8_t offsetlow, offsethigh; 313 u_int32_t addr, byteoffset, bytelen; 314 int state, i; 315 316 val = 0; 317 offsetlow = offsethigh = 0; 318 state = 0; 319 320 byteoffset = bitoffset / 8; 321 bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0); 322 addr = baseaddr + byteoffset; 323 offsetlow = bitoffset % 8; 324 assert(offsetlow == 0); 325 326 if (bytelen > 1) { 327 offsethigh = (bitlen - (8 - offsetlow)) % 8; 328 } 329 assert(offsethigh == 0); 330 331 for (i = bytelen; i > 0; i--, addr++) { 332 switch (io) { 333 case AML_REGION_INPUT: 334 val = 0; 335 state = aml_simulate_regcontent_read(regtype, addr, &val); 336 if (state == -1) { 337 goto finish; 338 } 339 buffer[bytelen - i] = val; 340 break; 341 case AML_REGION_OUTPUT: 342 val = buffer[bytelen - i]; 343 state = aml_simulate_regcontent_write(regtype, 344 addr, &val); 345 if (state == -1) { 346 goto finish; 347 } 348 break; 349 } 350 } 351 finish: 352 return (state); 353 } 354 355 static u_int32_t 356 aml_simulate_region_read(struct aml_environ *env, int regtype, 357 u_int32_t flags, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 358 { 359 u_int32_t value; 360 int state; 361 362 state = aml_region_io(env, AML_REGION_INPUT, regtype, flags, &value, 363 addr, bitoffset, bitlen); 364 assert(state != -1); 365 return (value); 366 } 367 368 static int 369 aml_simulate_region_read_into_buffer(int regtype, u_int32_t flags, 370 u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen, u_int8_t *buffer) 371 { 372 int state; 373 374 state = aml_simulate_region_io_buffer(AML_REGION_INPUT, regtype, flags, 375 buffer, addr, bitoffset, bitlen); 376 assert(state != -1); 377 return (state); 378 } 379 380 static int 381 aml_simulate_region_write(struct aml_environ *env, int regtype, 382 u_int32_t flags, u_int32_t value, u_int32_t addr, u_int32_t bitoffset, 383 u_int32_t bitlen) 384 { 385 int state; 386 387 state = aml_region_io(env, AML_REGION_OUTPUT, regtype, flags, 388 &value, addr, bitoffset, bitlen); 389 assert(state != -1); 390 return (state); 391 } 392 393 static int 394 aml_simulate_region_write_from_buffer(int regtype, u_int32_t flags, 395 u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 396 { 397 int state; 398 399 state = aml_simulate_region_io_buffer(AML_REGION_OUTPUT, regtype, 400 flags, buffer, addr, bitoffset, bitlen); 401 assert(state != -1); 402 return (state); 403 } 404 405 static int 406 aml_simulate_region_bcopy(struct aml_environ *env, int regtype, 407 u_int32_t flags, u_int32_t addr, 408 u_int32_t bitoffset, u_int32_t bitlen, 409 u_int32_t dflags, u_int32_t daddr, 410 u_int32_t dbitoffset, u_int32_t dbitlen) 411 { 412 u_int32_t len, i; 413 u_int32_t value; 414 int state; 415 416 len = (bitlen > dbitlen) ? dbitlen : bitlen; 417 len = len / 8 + ((len % 8) ? 1 : 0); 418 419 for (i = 0; i < len; i++) { 420 state = aml_region_io(env, AML_REGION_INPUT, regtype, 421 flags, &value, addr, bitoffset + i * 8, 8); 422 assert(state != -1); 423 state = aml_region_io(env, AML_REGION_OUTPUT, regtype, 424 dflags, &value, daddr, dbitoffset + i * 8, 8); 425 assert(state != -1); 426 } 427 428 return (0); 429 } 430 431 u_int32_t 432 aml_region_read(struct aml_environ *env, int regtype, u_int32_t flags, 433 u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 434 { 435 436 AML_REGION_READ_DEBUG(regtype, flags, addr, bitoffset, bitlen); 437 438 return (aml_simulate_region_read(env, regtype, flags, addr, 439 bitoffset, bitlen)); 440 } 441 442 int 443 aml_region_read_into_buffer(struct aml_environ *env, int regtype, 444 u_int32_t flags, u_int32_t addr, u_int32_t bitoffset, 445 u_int32_t bitlen, u_int8_t *buffer) 446 { 447 448 AML_REGION_READ_INTO_BUFFER_DEBUG(regtype, flags, addr, bitoffset, bitlen); 449 450 return (aml_simulate_region_read_into_buffer(regtype, flags, addr, 451 bitoffset, bitlen, buffer)); 452 } 453 454 int 455 aml_region_write(struct aml_environ *env, int regtype, u_int32_t flags, 456 u_int32_t value, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) 457 { 458 459 AML_REGION_WRITE_DEBUG(regtype, flags, value, addr, bitoffset, bitlen); 460 461 return (aml_simulate_region_write(env, regtype, flags, value, addr, 462 bitoffset, bitlen)); 463 } 464 465 int 466 aml_region_write_from_buffer(struct aml_environ *env, int regtype, 467 u_int32_t flags, u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset, 468 u_int32_t bitlen) 469 { 470 471 AML_REGION_WRITE_FROM_BUFFER_DEBUG(regtype, flags, 472 addr, bitoffset, bitlen); 473 474 return (aml_simulate_region_write_from_buffer(regtype, flags, buffer, 475 addr, bitoffset, bitlen)); 476 } 477 478 int 479 aml_region_bcopy(struct aml_environ *env, int regtype, u_int32_t flags, 480 u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen, 481 u_int32_t dflags, u_int32_t daddr, 482 u_int32_t dbitoffset, u_int32_t dbitlen) 483 { 484 485 AML_REGION_BCOPY_DEBUG(regtype, flags, addr, bitoffset, bitlen, 486 dflags, daddr, dbitoffset, dbitlen); 487 488 return (aml_simulate_region_bcopy(env, regtype, flags, addr, bitoffset, 489 bitlen, dflags, daddr, dbitoffset, dbitlen)); 490 } 491 492 void 493 aml_simulation_regdump(const char *dumpfile) 494 { 495 struct ACPIRegionContent *rc; 496 FILE *fp; 497 498 if (!aml_simulation_initialized) { 499 return; 500 } 501 if ((fp = fopen(dumpfile, "w")) == NULL) { 502 warn("%s", dumpfile); 503 return; 504 } 505 while (!TAILQ_EMPTY(&RegionContentList)) { 506 rc = TAILQ_FIRST(&RegionContentList); 507 fprintf(fp, "%d 0x%x 0x%x\n", 508 rc->regtype, rc->addr, rc->value); 509 TAILQ_REMOVE(&RegionContentList, rc, links); 510 free(rc); 511 } 512 513 fclose(fp); 514 TAILQ_INIT(&RegionContentList); 515 } 516