region.c revision 1.1 1 /* $NetBSD: region.c,v 1.1 2007/01/14 04:36:13 christos 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.1 2007/01/14 04:36:13 christos 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_region.h>
45 #include <aml/aml_common.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