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