Home | History | Annotate | Line # | Download | only in amldb
      1 /*	$NetBSD: region.c,v 1.3 2009/01/18 09:46:59 lukem Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki (at) 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