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
aml_simulation_init(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
aml_simulate_regcontent_add(int regtype,u_int32_t addr,u_int8_t value)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
aml_simulate_regcontent_read(int regtype,u_int32_t addr,u_int8_t * valuep)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
aml_simulate_regcontent_write(int regtype,u_int32_t addr,u_int8_t * valuep)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
aml_simulate_prompt(char * msg,u_int32_t def_val)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
aml_simulation_regload(const char * dumpfile)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
aml_region_read_simple(struct aml_region_handle * h,vm_offset_t offset,u_int32_t * valuep)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
aml_region_write_simple(struct aml_region_handle * h,vm_offset_t offset,u_int32_t value)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
aml_region_prompt_read(struct aml_region_handle * h,u_int32_t value)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
aml_region_prompt_write(struct aml_region_handle * h,u_int32_t value)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
aml_region_prompt_update_value(u_int32_t orgval,u_int32_t value,struct aml_region_handle * h)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
aml_simulate_region_io_buffer(int io,int regtype,u_int32_t flags,u_int8_t * buffer,u_int32_t baseaddr,u_int32_t bitoffset,u_int32_t bitlen)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
aml_simulate_region_read(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)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
aml_simulate_region_read_into_buffer(int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int8_t * buffer)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
aml_simulate_region_write(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t value,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)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
aml_simulate_region_write_from_buffer(int regtype,u_int32_t flags,u_int8_t * buffer,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)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
aml_simulate_region_bcopy(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int32_t dflags,u_int32_t daddr,u_int32_t dbitoffset,u_int32_t dbitlen)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
aml_region_read(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)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
aml_region_read_into_buffer(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int8_t * buffer)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
aml_region_write(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t value,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)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
aml_region_write_from_buffer(struct aml_environ * env,int regtype,u_int32_t flags,u_int8_t * buffer,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)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
aml_region_bcopy(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int32_t dflags,u_int32_t daddr,u_int32_t dbitoffset,u_int32_t dbitlen)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
aml_simulation_regdump(const char * dumpfile)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