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