aml_common.c revision 1.2 1 1.2 lukem /* $NetBSD: aml_common.c,v 1.2 2009/01/18 09:46:59 lukem Exp $ */
2 1.1 christos
3 1.1 christos /*-
4 1.1 christos * Copyright (c) 1999 Takanori Watanabe
5 1.1 christos * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki (at) FreeBSD.org>
6 1.1 christos * All rights reserved.
7 1.1 christos *
8 1.1 christos * Redistribution and use in source and binary forms, with or without
9 1.1 christos * modification, are permitted provided that the following conditions
10 1.1 christos * are met:
11 1.1 christos * 1. Redistributions of source code must retain the above copyright
12 1.1 christos * notice, this list of conditions and the following disclaimer.
13 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 christos * notice, this list of conditions and the following disclaimer in the
15 1.1 christos * documentation and/or other materials provided with the distribution.
16 1.1 christos *
17 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 1.1 christos * SUCH DAMAGE.
28 1.1 christos *
29 1.1 christos * Id: aml_common.c,v 1.9 2000/08/09 14:47:43 iwasaki Exp
30 1.1 christos * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_common.c,v 1.6 2000/11/09 06:24:45 iwasaki Exp $
31 1.1 christos */
32 1.1 christos #include <sys/cdefs.h>
33 1.2 lukem __RCSID("$NetBSD: aml_common.c,v 1.2 2009/01/18 09:46:59 lukem Exp $");
34 1.1 christos
35 1.1 christos #include <sys/param.h>
36 1.1 christos
37 1.1 christos #ifndef _KERNEL
38 1.1 christos #include <assert.h>
39 1.1 christos #include <err.h>
40 1.1 christos #include <stdio.h>
41 1.1 christos #include <stdlib.h>
42 1.1 christos #include <string.h>
43 1.1 christos #include <unistd.h>
44 1.1 christos #else /* _KERNEL */
45 1.1 christos #include "opt_acpi.h"
46 1.1 christos #include <sys/kernel.h>
47 1.1 christos #include <sys/sysctl.h>
48 1.1 christos #include <sys/systm.h>
49 1.1 christos #include <sys/bus.h>
50 1.1 christos #include <machine/bus.h>
51 1.1 christos #include <dev/acpi/acpireg.h>
52 1.1 christos #include <dev/acpi/acpivar.h>
53 1.1 christos #ifndef ACPI_NO_OSDFUNC_INLINE
54 1.1 christos #include <machine/acpica_osd.h>
55 1.1 christos #endif /* !ACPI_NO_OSDFUNC_INLINE */
56 1.1 christos #endif /* !_KERNEL */
57 1.1 christos
58 1.1 christos #include <acpi_common.h>
59 1.1 christos #include <aml/aml_common.h>
60 1.1 christos #include <aml/aml_env.h>
61 1.1 christos #include <aml/aml_evalobj.h>
62 1.1 christos #include <aml/aml_name.h>
63 1.1 christos #include <aml/aml_obj.h>
64 1.1 christos #include <aml/aml_parse.h>
65 1.1 christos #include <aml/aml_status.h>
66 1.1 christos #include <aml/aml_store.h>
67 1.1 christos
68 1.1 christos /* for debugging */
69 1.1 christos #ifdef AML_DEBUG
70 1.1 christos int aml_debug = 1;
71 1.1 christos #else /* !AML_DEBUG */
72 1.1 christos int aml_debug = 0;
73 1.1 christos #endif /* AML_DEBUG */
74 1.1 christos #ifdef _KERNEL
75 1.1 christos SYSCTL_INT(_debug, OID_AUTO, aml_debug, CTLFLAG_RW, &aml_debug, 1, "");
76 1.1 christos #endif /* _KERNEL */
77 1.1 christos
78 1.1 christos static void aml_print_nameseg(u_int8_t *dp);
79 1.1 christos
80 1.1 christos static void
81 1.1 christos aml_print_nameseg(u_int8_t *dp)
82 1.1 christos {
83 1.1 christos
84 1.1 christos if (dp[3] != '_') {
85 1.1 christos AML_DEBUGPRINT("%c%c%c%c", dp[0], dp[1], dp[2], dp[3]);
86 1.1 christos } else if (dp[2] != '_') {
87 1.1 christos AML_DEBUGPRINT("%c%c%c_", dp[0], dp[1], dp[2]);
88 1.1 christos } else if (dp[1] != '_') {
89 1.1 christos AML_DEBUGPRINT("%c%c__", dp[0], dp[1]);
90 1.1 christos } else if (dp[0] != '_') {
91 1.1 christos AML_DEBUGPRINT("%c___", dp[0]);
92 1.1 christos }
93 1.1 christos }
94 1.1 christos
95 1.1 christos void
96 1.1 christos aml_print_namestring(u_int8_t *dp)
97 1.1 christos {
98 1.1 christos int segcount;
99 1.1 christos int i;
100 1.1 christos
101 1.1 christos if (dp[0] == '\\') {
102 1.1 christos AML_DEBUGPRINT("%c", dp[0]);
103 1.1 christos dp++;
104 1.1 christos } else if (dp[0] == '^') {
105 1.1 christos while (dp[0] == '^') {
106 1.1 christos AML_DEBUGPRINT("%c", dp[0]);
107 1.1 christos dp++;
108 1.1 christos }
109 1.1 christos }
110 1.1 christos if (dp[0] == 0x00) { /* NullName */
111 1.1 christos /* AML_DEBUGPRINT("<null>"); */
112 1.1 christos dp++;
113 1.1 christos } else if (dp[0] == 0x2e) { /* DualNamePrefix */
114 1.1 christos aml_print_nameseg(dp + 1);
115 1.1 christos AML_DEBUGPRINT("%c", '.');
116 1.1 christos aml_print_nameseg(dp + 5);
117 1.1 christos } else if (dp[0] == 0x2f) { /* MultiNamePrefix */
118 1.1 christos segcount = dp[1];
119 1.1 christos for (i = 0, dp += 2; i < segcount; i++, dp += 4) {
120 1.1 christos if (i > 0) {
121 1.1 christos AML_DEBUGPRINT("%c", '.');
122 1.1 christos }
123 1.1 christos aml_print_nameseg(dp);
124 1.1 christos }
125 1.1 christos } else /* NameSeg */
126 1.1 christos aml_print_nameseg(dp);
127 1.1 christos }
128 1.1 christos
129 1.1 christos int
130 1.1 christos aml_print_curname(struct aml_name *name)
131 1.1 christos {
132 1.1 christos struct aml_name *root;
133 1.1 christos
134 1.1 christos root = aml_get_rootname();
135 1.1 christos if (name == root) {
136 1.1 christos AML_DEBUGPRINT("\\");
137 1.1 christos return (0);
138 1.1 christos } else {
139 1.1 christos aml_print_curname(name->parent);
140 1.1 christos }
141 1.1 christos aml_print_nameseg((unsigned char *)name->name);
142 1.1 christos AML_DEBUGPRINT(".");
143 1.1 christos return (0);
144 1.1 christos }
145 1.1 christos
146 1.1 christos void
147 1.1 christos aml_print_indent(int indent)
148 1.1 christos {
149 1.1 christos int i;
150 1.1 christos
151 1.1 christos for (i = 0; i < indent; i++)
152 1.1 christos AML_DEBUGPRINT(" ");
153 1.1 christos }
154 1.1 christos
155 1.1 christos void
156 1.1 christos aml_showobject(union aml_object * obj)
157 1.1 christos {
158 1.1 christos int debug;
159 1.1 christos int i;
160 1.1 christos
161 1.1 christos if (obj == NULL) {
162 1.1 christos printf("NO object\n");
163 1.1 christos return;
164 1.1 christos }
165 1.1 christos debug = aml_debug;
166 1.1 christos aml_debug = 1;
167 1.1 christos switch (obj->type) {
168 1.1 christos case aml_t_num:
169 1.1 christos printf("Num:0x%x\n", obj->num.number);
170 1.1 christos break;
171 1.1 christos case aml_t_processor:
172 1.1 christos printf("Processor:No %d,Port 0x%x length 0x%x\n",
173 1.1 christos obj->proc.id, obj->proc.addr, obj->proc.len);
174 1.1 christos break;
175 1.1 christos case aml_t_mutex:
176 1.1 christos printf("Mutex:Level %d\n", obj->mutex.level);
177 1.1 christos break;
178 1.1 christos case aml_t_powerres:
179 1.1 christos printf("PowerResource:Level %d Order %d\n",
180 1.1 christos obj->pres.level, obj->pres.order);
181 1.1 christos break;
182 1.1 christos case aml_t_opregion:
183 1.1 christos printf("OprationRegion:Busspace%d, Offset 0x%x Length 0x%x\n",
184 1.1 christos obj->opregion.space, obj->opregion.offset,
185 1.1 christos obj->opregion.length);
186 1.1 christos break;
187 1.1 christos case aml_t_field:
188 1.1 christos printf("Fieldelement:flag 0x%x offset 0x%x len 0x%x {",
189 1.1 christos obj->field.flags, obj->field.bitoffset,
190 1.1 christos obj->field.bitlen);
191 1.1 christos switch (obj->field.f.ftype) {
192 1.1 christos case f_t_field:
193 1.1 christos aml_print_namestring(obj->field.f.fld.regname);
194 1.1 christos break;
195 1.1 christos case f_t_index:
196 1.1 christos aml_print_namestring(obj->field.f.ifld.indexname);
197 1.1 christos printf(" ");
198 1.1 christos aml_print_namestring(obj->field.f.ifld.dataname);
199 1.1 christos break;
200 1.1 christos case f_t_bank:
201 1.1 christos aml_print_namestring(obj->field.f.bfld.regname);
202 1.1 christos printf(" ");
203 1.1 christos aml_print_namestring(obj->field.f.bfld.bankname);
204 1.1 christos printf("0x%x", obj->field.f.bfld.bankvalue);
205 1.1 christos break;
206 1.1 christos }
207 1.1 christos printf("}\n");
208 1.1 christos break;
209 1.1 christos case aml_t_method:
210 1.1 christos printf("Method: Arg %d From %p To %p\n", obj->meth.argnum,
211 1.1 christos obj->meth.from, obj->meth.to);
212 1.1 christos break;
213 1.1 christos case aml_t_buffer:
214 1.1 christos printf("Buffer: size:0x%x Data %p\n", obj->buffer.size,
215 1.1 christos obj->buffer.data);
216 1.1 christos break;
217 1.1 christos case aml_t_device:
218 1.1 christos printf("Device\n");
219 1.1 christos break;
220 1.1 christos case aml_t_bufferfield:
221 1.1 christos printf("Bufferfield:offset 0x%x len 0x%x Origin %p\n",
222 1.1 christos obj->bfld.bitoffset, obj->bfld.bitlen, obj->bfld.origin);
223 1.1 christos break;
224 1.1 christos case aml_t_string:
225 1.1 christos printf("String:%s\n", obj->str.string);
226 1.1 christos break;
227 1.1 christos case aml_t_package:
228 1.1 christos printf("Package:elements %d \n", obj->package.elements);
229 1.1 christos for (i = 0; i < obj->package.elements; i++) {
230 1.1 christos if (obj->package.objects[i] == NULL) {
231 1.1 christos break;
232 1.1 christos }
233 1.1 christos if (obj->package.objects[i]->type < 0) {
234 1.1 christos continue;
235 1.1 christos }
236 1.1 christos printf(" ");
237 1.1 christos aml_showobject(obj->package.objects[i]);
238 1.1 christos }
239 1.1 christos break;
240 1.1 christos case aml_t_therm:
241 1.1 christos printf("Thermalzone\n");
242 1.1 christos break;
243 1.1 christos case aml_t_event:
244 1.1 christos printf("Event\n");
245 1.1 christos break;
246 1.1 christos case aml_t_ddbhandle:
247 1.1 christos printf("DDBHANDLE\n");
248 1.1 christos break;
249 1.1 christos case aml_t_objref:
250 1.1 christos if (obj->objref.alias == 1) {
251 1.1 christos printf("Alias");
252 1.1 christos } else {
253 1.1 christos printf("Object reference");
254 1.1 christos if (obj->objref.offset >= 0) {
255 1.1 christos printf(" (offset 0x%x)", obj->objref.offset);
256 1.1 christos }
257 1.1 christos }
258 1.1 christos printf(" of ");
259 1.1 christos aml_showobject(obj->objref.ref);
260 1.1 christos break;
261 1.1 christos default:
262 1.1 christos printf("UNK ID=%d\n", obj->type);
263 1.1 christos }
264 1.1 christos
265 1.1 christos aml_debug = debug;
266 1.1 christos }
267 1.1 christos
268 1.1 christos void
269 1.1 christos aml_showtree(struct aml_name * aname, int lev)
270 1.1 christos {
271 1.1 christos int i;
272 1.1 christos struct aml_name *ptr;
273 1.1 christos char name[5];
274 1.1 christos
275 1.1 christos for (i = 0; i < lev; i++) {
276 1.1 christos printf(" ");
277 1.1 christos }
278 1.1 christos strncpy(name, aname->name, 4);
279 1.1 christos name[4] = 0;
280 1.1 christos printf("%s ", name);
281 1.1 christos if (aname->property != NULL) {
282 1.1 christos aml_showobject(aname->property);
283 1.1 christos } else {
284 1.1 christos printf("\n");
285 1.1 christos }
286 1.1 christos for (ptr = aname->child; ptr; ptr = ptr->brother)
287 1.1 christos aml_showtree(ptr, lev + 1);
288 1.1 christos }
289 1.1 christos
290 1.1 christos /*
291 1.1 christos * Common Region I/O Stuff
292 1.1 christos */
293 1.1 christos
294 1.1 christos static __inline u_int64_t
295 1.1 christos aml_adjust_bitmask(u_int32_t flags, u_int32_t bitlen)
296 1.1 christos {
297 1.1 christos u_int64_t bitmask;
298 1.1 christos
299 1.1 christos switch (AML_FIELDFLAGS_ACCESSTYPE(flags)) {
300 1.1 christos case AML_FIELDFLAGS_ACCESS_ANYACC:
301 1.1 christos if (bitlen <= 8) {
302 1.1 christos bitmask = 0x000000ff;
303 1.1 christos break;
304 1.1 christos }
305 1.1 christos if (bitlen <= 16) {
306 1.1 christos bitmask = 0x0000ffff;
307 1.1 christos break;
308 1.1 christos }
309 1.1 christos bitmask = 0xffffffff;
310 1.1 christos break;
311 1.1 christos case AML_FIELDFLAGS_ACCESS_BYTEACC:
312 1.1 christos bitmask = 0x000000ff;
313 1.1 christos break;
314 1.1 christos case AML_FIELDFLAGS_ACCESS_WORDACC:
315 1.1 christos bitmask = 0x0000ffff;
316 1.1 christos break;
317 1.1 christos case AML_FIELDFLAGS_ACCESS_DWORDACC:
318 1.1 christos default:
319 1.1 christos bitmask = 0xffffffff;
320 1.1 christos break;
321 1.1 christos }
322 1.1 christos
323 1.1 christos switch (bitlen) {
324 1.1 christos case 16:
325 1.1 christos bitmask |= 0x0000ffff;
326 1.1 christos break;
327 1.1 christos case 32:
328 1.1 christos bitmask |= 0xffffffff;
329 1.1 christos break;
330 1.1 christos }
331 1.1 christos
332 1.1 christos return (bitmask);
333 1.1 christos }
334 1.1 christos
335 1.1 christos u_int32_t
336 1.1 christos aml_adjust_readvalue(u_int32_t flags, u_int32_t bitoffset, u_int32_t bitlen,
337 1.1 christos u_int32_t orgval)
338 1.1 christos {
339 1.1 christos u_int32_t offset, retval;
340 1.1 christos u_int64_t bitmask;
341 1.1 christos
342 1.1 christos offset = bitoffset; /* XXX bitoffset may change in this function! */
343 1.1 christos bitmask = aml_adjust_bitmask(flags, bitlen);
344 1.1 christos retval = (orgval >> offset) & (~(bitmask << bitlen)) & bitmask;
345 1.1 christos
346 1.1 christos return (retval);
347 1.1 christos }
348 1.1 christos
349 1.1 christos u_int32_t
350 1.1 christos aml_adjust_updatevalue(u_int32_t flags, u_int32_t bitoffset, u_int32_t bitlen,
351 1.1 christos u_int32_t orgval, u_int32_t value)
352 1.1 christos {
353 1.1 christos u_int32_t offset, retval;
354 1.1 christos u_int64_t bitmask;
355 1.1 christos
356 1.1 christos offset = bitoffset; /* XXX bitoffset may change in this function! */
357 1.1 christos bitmask = aml_adjust_bitmask(flags, bitlen);
358 1.1 christos retval = orgval;
359 1.1 christos switch (AML_FIELDFLAGS_UPDATERULE(flags)) {
360 1.1 christos case AML_FIELDFLAGS_UPDATE_PRESERVE:
361 1.1 christos retval &= (~(((u_int64_t)1 << bitlen) - 1) << offset) |
362 1.1 christos (~(bitmask << offset));
363 1.1 christos break;
364 1.1 christos case AML_FIELDFLAGS_UPDATE_WRITEASONES:
365 1.1 christos retval = (~(((u_int64_t)1 << bitlen) - 1) << offset) |
366 1.1 christos (~(bitmask << offset));
367 1.1 christos retval &= bitmask; /* trim the upper bits */
368 1.1 christos break;
369 1.1 christos case AML_FIELDFLAGS_UPDATE_WRITEASZEROS:
370 1.1 christos retval = 0;
371 1.1 christos break;
372 1.1 christos default:
373 1.1 christos printf("illegal update rule: %d\n", flags);
374 1.1 christos return (orgval);
375 1.1 christos }
376 1.1 christos
377 1.1 christos retval |= (value << (offset & bitmask));
378 1.1 christos return (retval);
379 1.1 christos }
380 1.1 christos
381 1.1 christos /*
382 1.1 christos * BufferField I/O
383 1.1 christos */
384 1.1 christos
385 1.1 christos #define AML_BUFFER_INPUT 0
386 1.1 christos #define AML_BUFFER_OUTPUT 1
387 1.1 christos
388 1.1 christos static int aml_bufferfield_io(int io, u_int32_t *valuep,
389 1.1 christos u_int8_t *origin, u_int32_t bitoffset,
390 1.1 christos u_int32_t bitlen);
391 1.1 christos
392 1.1 christos static int
393 1.1 christos aml_bufferfield_io(int io, u_int32_t *valuep, u_int8_t *origin,
394 1.1 christos u_int32_t bitoffset, u_int32_t bitlen)
395 1.1 christos {
396 1.1 christos u_int8_t val, tmp, masklow, maskhigh;
397 1.1 christos u_int8_t offsetlow, offsethigh;
398 1.1 christos u_int8_t *addr;
399 1.1 christos u_int32_t value, readval;
400 1.2 lukem u_int32_t byteoffset, bytelen, i;
401 1.1 christos
402 1.1 christos masklow = maskhigh = 0xff;
403 1.1 christos val = readval = 0;
404 1.1 christos value = *valuep;
405 1.1 christos
406 1.1 christos byteoffset = bitoffset / 8;
407 1.1 christos bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0);
408 1.1 christos addr = origin + byteoffset;
409 1.1 christos
410 1.1 christos /* simple I/O ? */
411 1.1 christos if (bitlen <= 8 || bitlen == 16 || bitlen == 32) {
412 1.1 christos bcopy(addr, &readval, bytelen);
413 1.1 christos AML_DEBUGPRINT("\n\t[bufferfield:0x%x@%p:%d,%d]",
414 1.1 christos readval, addr, bitoffset % 8, bitlen);
415 1.1 christos switch (io) {
416 1.1 christos case AML_BUFFER_INPUT:
417 1.1 christos value = aml_adjust_readvalue(AML_FIELDFLAGS_ACCESS_BYTEACC,
418 1.1 christos bitoffset % 8, bitlen, readval);
419 1.1 christos *valuep = value;
420 1.1 christos AML_DEBUGPRINT("\n[read(bufferfield, %p)&mask:0x%x]\n",
421 1.1 christos addr, value);
422 1.1 christos break;
423 1.1 christos case AML_BUFFER_OUTPUT:
424 1.1 christos value = aml_adjust_updatevalue(AML_FIELDFLAGS_ACCESS_BYTEACC,
425 1.1 christos bitoffset % 8, bitlen, readval, value);
426 1.1 christos bcopy(&value, addr, bytelen);
427 1.1 christos AML_DEBUGPRINT("->[bufferfield:0x%x@%p:%d,%d]",
428 1.1 christos value, addr, bitoffset % 8, bitlen);
429 1.1 christos break;
430 1.1 christos }
431 1.1 christos goto out;
432 1.1 christos }
433 1.1 christos
434 1.1 christos offsetlow = bitoffset % 8;
435 1.1 christos if (bytelen > 1) {
436 1.1 christos offsethigh = (bitlen - (8 - offsetlow)) % 8;
437 1.1 christos } else {
438 1.1 christos offsethigh = 0;
439 1.1 christos }
440 1.1 christos
441 1.1 christos if (offsetlow) {
442 1.1 christos masklow = (~((1 << bitlen) - 1) << offsetlow) | ~(0xff << offsetlow);
443 1.1 christos AML_DEBUGPRINT("\t[offsetlow = 0x%x, masklow = 0x%x, ~masklow = 0x%x]\n",
444 1.1 christos offsetlow, masklow, ~masklow & 0xff);
445 1.1 christos }
446 1.1 christos if (offsethigh) {
447 1.1 christos maskhigh = 0xff << offsethigh;
448 1.1 christos AML_DEBUGPRINT("\t[offsethigh = 0x%x, maskhigh = 0x%x, ~maskhigh = 0x%x]\n",
449 1.1 christos offsethigh, maskhigh, ~maskhigh & 0xff);
450 1.1 christos }
451 1.1 christos for (i = bytelen; i > 0; i--, addr++) {
452 1.1 christos val = *addr;
453 1.1 christos
454 1.1 christos AML_DEBUGPRINT("\t[bufferfield:0x%02x@%p]", val, addr);
455 1.1 christos
456 1.1 christos switch (io) {
457 1.1 christos case AML_BUFFER_INPUT:
458 1.1 christos tmp = val;
459 1.1 christos /* the lowest byte? */
460 1.1 christos if (i == bytelen) {
461 1.1 christos if (offsetlow) {
462 1.1 christos readval = tmp & ~masklow;
463 1.1 christos } else {
464 1.1 christos readval = tmp;
465 1.1 christos }
466 1.1 christos } else {
467 1.1 christos if (i == 1 && offsethigh) {
468 1.1 christos tmp = tmp & ~maskhigh;
469 1.1 christos }
470 1.1 christos readval = (tmp << (8 * (bytelen - i))) | readval;
471 1.1 christos }
472 1.1 christos
473 1.1 christos AML_DEBUGPRINT("\n");
474 1.1 christos /* goto to next byte... */
475 1.1 christos if (i > 1) {
476 1.1 christos continue;
477 1.1 christos }
478 1.1 christos /* final adjustment before finishing region access */
479 1.1 christos if (offsetlow) {
480 1.1 christos readval = readval >> offsetlow;
481 1.1 christos }
482 1.1 christos AML_DEBUGPRINT("[read(bufferfield, %p)&mask:0x%x]\n",
483 1.1 christos addr, readval);
484 1.1 christos *valuep = readval;
485 1.1 christos
486 1.1 christos break;
487 1.1 christos
488 1.1 christos case AML_BUFFER_OUTPUT:
489 1.1 christos tmp = value & 0xff;
490 1.1 christos /* the lowest byte? */
491 1.1 christos if (i == bytelen) {
492 1.1 christos if (offsetlow) {
493 1.1 christos tmp = (val & masklow) | tmp << offsetlow;
494 1.1 christos }
495 1.1 christos value = value >> (8 - offsetlow);
496 1.1 christos } else {
497 1.1 christos if (i == 1 && offsethigh) {
498 1.1 christos tmp = (val & maskhigh) | tmp;
499 1.1 christos }
500 1.1 christos value = value >> 8;
501 1.1 christos }
502 1.1 christos
503 1.1 christos AML_DEBUGPRINT("->[bufferfield:0x%02x@%p]\n",
504 1.1 christos tmp, addr);
505 1.1 christos *addr = tmp;
506 1.1 christos }
507 1.1 christos }
508 1.1 christos out:
509 1.1 christos return (0);
510 1.1 christos }
511 1.1 christos
512 1.1 christos u_int32_t
513 1.1 christos aml_bufferfield_read(u_int8_t *origin, u_int32_t bitoffset,
514 1.1 christos u_int32_t bitlen)
515 1.1 christos {
516 1.1 christos int value;
517 1.1 christos
518 1.1 christos value = 0;
519 1.1 christos aml_bufferfield_io(AML_BUFFER_INPUT, (u_int32_t *)&value, origin,
520 1.1 christos bitoffset, bitlen);
521 1.1 christos return (value);
522 1.1 christos }
523 1.1 christos
524 1.1 christos int
525 1.1 christos aml_bufferfield_write(u_int32_t value, u_int8_t *origin,
526 1.1 christos u_int32_t bitoffset, u_int32_t bitlen)
527 1.1 christos {
528 1.1 christos int status;
529 1.1 christos
530 1.1 christos status = aml_bufferfield_io(AML_BUFFER_OUTPUT, &value,
531 1.1 christos origin, bitoffset, bitlen);
532 1.1 christos return (status);
533 1.1 christos }
534 1.1 christos
535 1.1 christos int
536 1.1 christos aml_region_handle_alloc(struct aml_environ *env, int regtype, u_int32_t flags,
537 1.1 christos u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen,
538 1.1 christos struct aml_region_handle *h)
539 1.1 christos {
540 1.1 christos int state;
541 1.1 christos struct aml_name *pci_info;
542 1.1 christos
543 1.1 christos state = 0;
544 1.1 christos pci_info = NULL;
545 1.1 christos bzero(h, sizeof(struct aml_region_handle));
546 1.1 christos
547 1.1 christos h->env = env;
548 1.1 christos h->regtype = regtype;
549 1.1 christos h->flags = flags;
550 1.1 christos h->baseaddr = baseaddr;
551 1.1 christos h->bitoffset = bitoffset;
552 1.1 christos h->bitlen = bitlen;
553 1.1 christos
554 1.1 christos switch (AML_FIELDFLAGS_ACCESSTYPE(flags)) {
555 1.1 christos case AML_FIELDFLAGS_ACCESS_ANYACC:
556 1.1 christos if (bitlen <= 8) {
557 1.1 christos h->unit = 1;
558 1.1 christos break;
559 1.1 christos }
560 1.1 christos if (bitlen <= 16) {
561 1.1 christos h->unit = 2;
562 1.1 christos break;
563 1.1 christos }
564 1.1 christos h->unit = 4;
565 1.1 christos break;
566 1.1 christos case AML_FIELDFLAGS_ACCESS_BYTEACC:
567 1.1 christos h->unit = 1;
568 1.1 christos break;
569 1.1 christos case AML_FIELDFLAGS_ACCESS_WORDACC:
570 1.1 christos h->unit = 2;
571 1.1 christos break;
572 1.1 christos case AML_FIELDFLAGS_ACCESS_DWORDACC:
573 1.1 christos h->unit = 4;
574 1.1 christos break;
575 1.1 christos default:
576 1.1 christos h->unit = 1;
577 1.1 christos break;
578 1.1 christos }
579 1.1 christos
580 1.1 christos h->addr = baseaddr + h->unit * ((bitoffset / 8) / h->unit);
581 1.1 christos h->bytelen = baseaddr + ((bitoffset + bitlen) / 8) - h->addr +
582 1.1 christos ((bitlen % 8) ? 1 : 0);
583 1.1 christos
584 1.1 christos #ifdef _KERNEL
585 1.1 christos switch (h->regtype) {
586 1.1 christos case AML_REGION_SYSMEM:
587 1.1 christos OsdMapMemory((void *)h->addr, h->bytelen, (void **)&h->vaddr);
588 1.1 christos break;
589 1.1 christos
590 1.1 christos case AML_REGION_PCICFG:
591 1.1 christos /* Obtain PCI bus number */
592 1.1 christos pci_info = aml_search_name(env, "_BBN");
593 1.1 christos if (pci_info == NULL || pci_info->property->type != aml_t_num) {
594 1.1 christos AML_DEBUGPRINT("Cannot locate _BBN. Using default 0\n");
595 1.1 christos h->pci_bus = 0;
596 1.1 christos } else {
597 1.1 christos AML_DEBUGPRINT("found _BBN: %d\n",
598 1.1 christos pci_info->property->num.number);
599 1.1 christos h->pci_bus = pci_info->property->num.number & 0xff;
600 1.1 christos }
601 1.1 christos
602 1.1 christos /* Obtain device & function number */
603 1.1 christos pci_info = aml_search_name(env, "_ADR");
604 1.1 christos if (pci_info == NULL || pci_info->property->type != aml_t_num) {
605 1.1 christos printf("Cannot locate: _ADR\n");
606 1.1 christos state = -1;
607 1.1 christos goto out;
608 1.1 christos }
609 1.1 christos h->pci_devfunc = pci_info->property->num.number;
610 1.1 christos
611 1.1 christos AML_DEBUGPRINT("[pci%d.%d]", h->pci_bus, h->pci_devfunc);
612 1.1 christos break;
613 1.1 christos
614 1.1 christos default:
615 1.1 christos break;
616 1.1 christos }
617 1.1 christos
618 1.1 christos out:
619 1.1 christos #endif /* _KERNEL */
620 1.1 christos return (state);
621 1.1 christos }
622 1.1 christos
623 1.1 christos void
624 1.1 christos aml_region_handle_free(struct aml_region_handle *h)
625 1.1 christos {
626 1.1 christos #ifdef _KERNEL
627 1.1 christos switch (h->regtype) {
628 1.1 christos case AML_REGION_SYSMEM:
629 1.1 christos OsdUnMapMemory((void *)h->vaddr, h->bytelen);
630 1.1 christos break;
631 1.1 christos
632 1.1 christos default:
633 1.1 christos break;
634 1.1 christos }
635 1.1 christos #endif /* _KERNEL */
636 1.1 christos }
637 1.1 christos
638 1.1 christos static int
639 1.1 christos aml_region_io_simple(struct aml_environ *env, int io, int regtype,
640 1.1 christos u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr,
641 1.1 christos u_int32_t bitoffset, u_int32_t bitlen)
642 1.1 christos {
643 1.2 lukem int state;
644 1.2 lukem u_int32_t readval, value, offset, bytelen, i;
645 1.1 christos struct aml_region_handle handle;
646 1.1 christos
647 1.1 christos state = aml_region_handle_alloc(env, regtype, flags,
648 1.1 christos baseaddr, bitoffset, bitlen, &handle);
649 1.1 christos if (state == -1) {
650 1.1 christos goto out;
651 1.1 christos }
652 1.1 christos
653 1.1 christos readval = 0;
654 1.1 christos offset = bitoffset % (handle.unit * 8);
655 1.1 christos /* limitation of 32 bits alignment */
656 1.1 christos bytelen = (handle.bytelen > 4) ? 4 : handle.bytelen;
657 1.1 christos
658 1.1 christos if (io == AML_REGION_INPUT ||
659 1.1 christos AML_FIELDFLAGS_UPDATERULE(flags) == AML_FIELDFLAGS_UPDATE_PRESERVE) {
660 1.1 christos for (i = 0; i < bytelen; i += handle.unit) {
661 1.1 christos state = aml_region_read_simple(&handle, i, &value);
662 1.1 christos if (state == -1) {
663 1.1 christos goto out;
664 1.1 christos }
665 1.1 christos readval |= (value << (i * 8));
666 1.1 christos }
667 1.1 christos AML_DEBUGPRINT("\t[%d:0x%x@0x%lx:%d,%d]",
668 1.1 christos regtype, readval, handle.addr, offset, bitlen);
669 1.1 christos }
670 1.1 christos
671 1.1 christos switch (io) {
672 1.1 christos case AML_REGION_INPUT:
673 1.1 christos AML_DEBUGPRINT("\n");
674 1.1 christos readval = aml_adjust_readvalue(flags, offset, bitlen, readval);
675 1.1 christos value = readval;
676 1.1 christos value = aml_region_prompt_read(&handle, value);
677 1.1 christos state = aml_region_prompt_update_value(readval, value, &handle);
678 1.1 christos if (state == -1) {
679 1.1 christos goto out;
680 1.1 christos }
681 1.1 christos
682 1.1 christos *valuep = value;
683 1.1 christos break;
684 1.1 christos case AML_REGION_OUTPUT:
685 1.1 christos value = *valuep;
686 1.1 christos value = aml_adjust_updatevalue(flags, offset,
687 1.1 christos bitlen, readval, value);
688 1.1 christos value = aml_region_prompt_write(&handle, value);
689 1.1 christos AML_DEBUGPRINT("\t->[%d:0x%x@0x%lx:%d,%d]\n", regtype, value,
690 1.1 christos handle.addr, offset, bitlen);
691 1.1 christos for (i = 0; i < bytelen; i += handle.unit) {
692 1.1 christos state = aml_region_write_simple(&handle, i, value);
693 1.1 christos if (state == -1) {
694 1.1 christos goto out;
695 1.1 christos }
696 1.1 christos value = value >> (handle.unit * 8);
697 1.1 christos }
698 1.1 christos break;
699 1.1 christos }
700 1.1 christos
701 1.1 christos aml_region_handle_free(&handle);
702 1.1 christos out:
703 1.1 christos return (state);
704 1.1 christos }
705 1.1 christos
706 1.1 christos int
707 1.1 christos aml_region_io(struct aml_environ *env, int io, int regtype,
708 1.1 christos u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr,
709 1.1 christos u_int32_t bitoffset, u_int32_t bitlen)
710 1.1 christos {
711 1.1 christos u_int32_t unit, offset;
712 1.1 christos u_int32_t offadj, bitadj;
713 1.2 lukem u_int32_t value, readval, i;
714 1.2 lukem int state;
715 1.1 christos
716 1.1 christos readval = 0;
717 1.1 christos state = 0;
718 1.1 christos unit = 4; /* limitation of 32 bits alignment */
719 1.1 christos offset = bitoffset % (unit * 8);
720 1.1 christos offadj = 0;
721 1.1 christos bitadj = 0;
722 1.1 christos if (offset + bitlen > unit * 8) {
723 1.1 christos bitadj = bitlen - (unit * 8 - offset);
724 1.1 christos }
725 1.1 christos for (i = 0; i < offset + bitlen; i += unit * 8) {
726 1.1 christos value = (*valuep) >> offadj;
727 1.1 christos state = aml_region_io_simple(env, io, regtype, flags,
728 1.1 christos &value, baseaddr, bitoffset + offadj, bitlen - bitadj);
729 1.1 christos if (state == -1) {
730 1.1 christos goto out;
731 1.1 christos }
732 1.1 christos readval |= value << offadj;
733 1.1 christos bitadj = offadj = bitlen - bitadj;
734 1.1 christos }
735 1.1 christos *valuep = readval;
736 1.1 christos
737 1.1 christos out:
738 1.1 christos return (state);
739 1.1 christos }
740