xref: /netbsd-src/usr.sbin/acpitools/amldb/region.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
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