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