1/* $NetBSD: aml_name.c,v 1.3 2008/01/15 19:08:00 jmcneill Exp $ */ 2 3/*- 4 * Copyright (c) 1999 Takanori Watanabe 5 * Copyright (c) 1999, 2000 Yasuo Yokoyama 6 * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * Id: aml_name.c,v 1.15 2000/08/16 18:14:53 iwasaki Exp 31 * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_name.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $ 32 */ 33#include <sys/cdefs.h> 34__RCSID("$NetBSD: aml_name.c,v 1.3 2008/01/15 19:08:00 jmcneill Exp $"); 35 36#include <sys/param.h> 37 38#include <acpi_common.h> 39#include <aml/aml_amlmem.h> 40#include <aml/aml_common.h> 41#include <aml/aml_env.h> 42#include <aml/aml_name.h> 43 44#ifndef _KERNEL 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48 49#include "debug.h" 50#else /* _KERNEL */ 51#include <sys/systm.h> 52#endif /* !_KERNEL */ 53 54static struct aml_name *aml_find_name(struct aml_name *, const u_int8_t *); 55static struct aml_name *aml_new_name(struct aml_name *, const u_int8_t *); 56static void aml_delete_name(struct aml_name *); 57 58static struct aml_name rootname = {"\\", NULL, NULL, NULL, NULL, NULL}; 59 60static struct aml_name_group root_group = { 61 AML_NAME_GROUP_ROOT, 62 &rootname, 63 NULL 64}; 65 66struct aml_name_group *name_group_list = &root_group; 67struct aml_local_stack *stack_top = NULL; 68 69struct aml_name * 70aml_get_rootname() 71{ 72 73 return (&rootname); 74} 75 76static struct aml_name * 77aml_find_name(struct aml_name *parent, const u_int8_t *name) 78{ 79 struct aml_name *result; 80 81 if (!parent) 82 parent = &rootname; 83 for (result = parent->child; result; result = result->brother) 84 if (!strncmp(result->name, (const char *)name, 4)) 85 break; 86 return (result); 87} 88 89/* 90 * Parse given namesppace expression and find a first matched object 91 * under given level of the tree by depth first search. 92 */ 93 94struct aml_name * 95aml_find_from_namespace(struct aml_name *parent, const char *name) 96{ 97 const char *ptr; 98 int len; 99 struct aml_name *result; 100 101 ptr = name; 102 if (!parent) 103 parent = &rootname; 104 105 if (ptr[0] == '\\') { 106 ptr++; 107 parent = &rootname; 108 } 109 for (len = 0; ptr[len] != '.' && ptr[len] != '\0'; len++) 110 ; 111 112 for (result = parent->child; result; result = result->brother) { 113 if (!strncmp(result->name, ptr, len)) { 114 if (ptr[len] == '\0' || ptr[len + 1] == '\0') { 115 return (result); 116 } 117 ptr += len; 118 if (ptr[0] != '.') { 119 return (NULL); 120 } 121 ptr++; 122 return (aml_find_from_namespace(result, ptr)); 123 } 124 } 125 126 return (NULL); 127} 128 129static void 130_aml_apply_foreach_found_objects(struct aml_name *parent, char *name, 131 int len, int shallow, int (*func)(struct aml_name *, va_list), va_list ap) 132{ 133 struct aml_name *child, *ptr; 134 135 child = ptr = NULL; 136 137 /* function to apply must be specified */ 138 if (func == NULL) { 139 return; 140 } 141 142 for (child = parent->child; child; child = child->brother) { 143 if (!strncmp(child->name, name, len)) { 144 /* if function call was failed, stop searching */ 145 if (func(child, ap) != 0) { 146 return; 147 } 148 } 149 } 150 151 if (shallow == 1) { 152 return; 153 } 154 155 for (ptr = parent->child; ptr; ptr = ptr->brother) { 156 /* do more searching */ 157 _aml_apply_foreach_found_objects(ptr, name, len, 0, func, ap); 158 } 159} 160 161/* 162 * Find named objects as many as possible under given level of 163 * namespace, and apply given callback function for each 164 * named objects found. If the callback function returns non-zero 165 * value, then the search terminates immediately. 166 * Note that object name expression is used as forward substring match, 167 * not exact match. The name expression "_L" will match for objects 168 * which have name starting with "_L" such as "\_SB_.LID_._LID" and 169 * "\_GPE._L00" and so on. The name expression can include parent object 170 * name in it like "\_GPE._L". In this case, GPE X level wake handlers 171 * will be found under "\_GPE" in shallow level. 172 */ 173 174void 175aml_apply_foreach_found_objects(struct aml_name *start, char *name, 176 int (*func)(struct aml_name *, va_list), ...) 177{ 178 int i, len, has_dot, last_is_dot, shallow; 179 struct aml_name *child, *parent; 180 va_list ap; 181 182 shallow = 0; 183 if (start == NULL) { 184 parent = &rootname; 185 } else { 186 parent = start; 187 } 188 if (name[0] == '\\') { 189 name++; 190 parent = &rootname; 191 shallow = 1; 192 } 193 194 len = strlen(name); 195 last_is_dot = 0; 196 /* the last dot should be ignored */ 197 if (len > 0 && name[len - 1] == '.') { 198 len--; 199 last_is_dot = 1; 200 } 201 202 has_dot = 0; 203 for (i = 0; i < len - 1; i++) { 204 if (name[i] == '.') { 205 has_dot = 1; 206 break; 207 } 208 } 209 210 /* try to parse expression and find any matched object. */ 211 if (has_dot == 1) { 212 child = aml_find_from_namespace(parent, name); 213 if (child == NULL) { 214 return; 215 } 216 217 /* 218 * we have at least one object matched, search all objects 219 * under upper level of the found object. 220 */ 221 parent = child->parent; 222 223 /* find the last `.' */ 224 for (name = name + len - 1; *name != '.'; name--) 225 ; 226 name++; 227 len = strlen(name) - last_is_dot; 228 shallow = 1; 229 } 230 231 if (len > 4) { 232 return; 233 } 234 235 va_start(ap, func); 236 _aml_apply_foreach_found_objects(parent, name, len, shallow, func, ap); 237 va_end(ap); 238} 239 240struct aml_name_group * 241aml_new_name_group(void *id) 242{ 243 struct aml_name_group *result; 244 245 result = memman_alloc(aml_memman, memid_aml_name_group); 246 result->id = id; 247 result->head = NULL; 248 result->next = name_group_list; 249 name_group_list = result; 250 return (result); 251} 252 253void 254aml_delete_name_group(struct aml_name_group *target) 255{ 256 struct aml_name_group *previous; 257 258 previous = name_group_list; 259 if (previous == target) 260 name_group_list = target->next; 261 else { 262 while (previous && previous->next != target) 263 previous = previous->next; 264 if (previous) 265 previous->next = target->next; 266 } 267 target->next = NULL; 268 if (target->head) 269 aml_delete_name(target->head); 270 memman_free(aml_memman, memid_aml_name_group, target); 271} 272 273static struct aml_name * 274aml_new_name(struct aml_name *parent, const u_int8_t *name) 275{ 276 struct aml_name *newname; 277 278 if ((newname = aml_find_name(parent, name)) != NULL) 279 return (newname); 280 281 newname = memman_alloc(aml_memman, memid_aml_name); 282 strncpy(newname->name, (const char *)name, 4); 283 newname->parent = parent; 284 newname->child = NULL; 285 newname->property = NULL; 286 if (parent && parent->child) 287 newname->brother = parent->child; 288 else 289 newname->brother = NULL; 290 if (parent) 291 parent->child = newname; 292 293 newname->chain = name_group_list->head; 294 name_group_list->head = newname; 295 296 return (newname); 297} 298 299/* 300 * NOTE: 301 * aml_delete_name() doesn't maintain aml_name_group::{head,tail}. 302 */ 303static void 304aml_delete_name(struct aml_name *target) 305{ 306 struct aml_name *next; 307 struct aml_name *ptr; 308 309 for (; target; target = next) { 310 next = target->chain; 311 if (target->child) { 312 target->chain = NULL; 313 continue; 314 } 315 if (target->brother) { 316 if (target->parent) { 317 if (target->parent->child == target) { 318 target->parent->child = target->brother; 319 } else { 320 ptr = target->parent->child; 321 while (ptr && ptr->brother != target) 322 ptr = ptr->brother; 323 if (ptr) 324 ptr->brother = target->brother; 325 } 326 target->brother = NULL; 327 } 328 } else if (target->parent) { 329 target->parent->child = NULL; 330 } 331 aml_free_object(&target->property); 332 memman_free(aml_memman, memid_aml_name, target); 333 } 334} 335 336#define AML_SEARCH_NAME 0 337#define AML_CREATE_NAME 1 338static struct aml_name *aml_nameman(struct aml_environ *, const u_int8_t *, int); 339 340struct aml_name * 341aml_search_name(struct aml_environ *env, const u_int8_t *dp) 342{ 343 344 return (aml_nameman(env, dp, AML_SEARCH_NAME)); 345} 346 347struct aml_name * 348aml_create_name(struct aml_environ *env, const u_int8_t *dp) 349{ 350 351 return (aml_nameman(env, dp, AML_CREATE_NAME)); 352} 353 354static struct aml_name * 355aml_nameman(struct aml_environ *env, const u_int8_t *dp, int flag) 356{ 357 int segcount; 358 int i; 359 struct aml_name *newname, *curname; 360 struct aml_name *(*searchfunc) (struct aml_name *, const u_int8_t *); 361 362#define CREATECHECK() do { \ 363 if (newname == NULL) { \ 364 AML_DEBUGPRINT("ERROR CANNOT FIND NAME\n"); \ 365 env->stat = aml_stat_panic; \ 366 return (NULL); \ 367 } \ 368} while(0) 369 370 searchfunc = (flag == AML_CREATE_NAME) ? aml_new_name : aml_find_name; 371 newname = env->curname; 372 if (dp[0] == '\\') { 373 newname = &rootname; 374 dp++; 375 } else if (dp[0] == '^') { 376 while (dp[0] == '^') { 377 newname = newname->parent; 378 CREATECHECK(); 379 dp++; 380 } 381 } 382 if (dp[0] == 0x00) { /* NullName */ 383 dp++; 384 } else if (dp[0] == 0x2e) { /* DualNamePrefix */ 385 newname = (*searchfunc) (newname, dp + 1); 386 CREATECHECK(); 387 newname = (*searchfunc) (newname, dp + 5); 388 CREATECHECK(); 389 } else if (dp[0] == 0x2f) { /* MultiNamePrefix */ 390 segcount = dp[1]; 391 for (i = 0, dp += 2; i < segcount; i++, dp += 4) { 392 newname = (*searchfunc) (newname, dp); 393 CREATECHECK(); 394 } 395 } else if (flag == AML_CREATE_NAME) { /* NameSeg */ 396 newname = aml_new_name(newname, dp); 397 CREATECHECK(); 398 } else { 399 curname = newname; 400 for (;;) { 401 newname = aml_find_name(curname, dp); 402 if (newname != NULL) 403 break; 404 if (curname == &rootname || curname == NULL) 405 break; 406 curname = curname->parent; 407 } 408 } 409 return (newname); 410} 411 412#undef CREATECHECK 413 414struct aml_local_stack * 415aml_local_stack_create() 416{ 417 struct aml_local_stack *result; 418 419 result = memman_alloc(aml_memman, memid_aml_local_stack); 420 memset(result, 0, sizeof(struct aml_local_stack)); 421 return (result); 422} 423 424void 425aml_local_stack_push(struct aml_local_stack *stack) 426{ 427 428 stack->next = stack_top; 429 stack_top = stack; 430} 431 432struct aml_local_stack * 433aml_local_stack_pop() 434{ 435 struct aml_local_stack *result; 436 437 result = stack_top; 438 stack_top = result->next; 439 result->next = NULL; 440 return (result); 441} 442 443void 444aml_local_stack_delete(struct aml_local_stack *stack) 445{ 446 int i; 447 448 for (i = 0; i < 8; i++) 449 aml_free_object(&stack->localvalue[i].property); 450 for (i = 0; i < 7; i++) 451 aml_free_object(&stack->argumentvalue[i].property); 452 aml_delete_name(stack->temporary); 453 memman_free(aml_memman, memid_aml_local_stack, stack); 454} 455 456struct aml_name * 457aml_local_stack_getLocalX(int idx) 458{ 459 460 if (stack_top == NULL) 461 return (NULL); 462 return (&stack_top->localvalue[idx]); 463} 464 465struct aml_name * 466aml_local_stack_getArgX(struct aml_local_stack *stack, int idx) 467{ 468 469 if (!stack) 470 stack = stack_top; 471 if (stack == NULL) 472 return (NULL); 473 return (&stack->argumentvalue[idx]); 474} 475 476struct aml_name * 477aml_create_local_object() 478{ 479 struct aml_name *result; 480 481 result = memman_alloc(aml_memman, memid_aml_name); 482 result->child = result->brother = result->parent = NULL; 483 result->property = NULL; 484 result->chain = stack_top->temporary; 485 stack_top->temporary = result; 486 return (result); 487} 488