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 54 static struct aml_name *aml_find_name(struct aml_name *, const u_int8_t *); 55 static struct aml_name *aml_new_name(struct aml_name *, const u_int8_t *); 56 static void aml_delete_name(struct aml_name *); 57 58 static struct aml_name rootname = {"\\", NULL, NULL, NULL, NULL, NULL}; 59 60 static struct aml_name_group root_group = { 61 AML_NAME_GROUP_ROOT, 62 &rootname, 63 NULL 64 }; 65 66 struct aml_name_group *name_group_list = &root_group; 67 struct aml_local_stack *stack_top = NULL; 68 69 struct aml_name * 70 aml_get_rootname() 71 { 72 73 return (&rootname); 74 } 75 76 static struct aml_name * 77 aml_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 94 struct aml_name * 95 aml_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 129 static 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 174 void 175 aml_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 240 struct aml_name_group * 241 aml_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 253 void 254 aml_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 273 static struct aml_name * 274 aml_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->child) 287 newname->brother = parent->child; 288 else 289 newname->brother = NULL; 290 parent->child = newname; 291 292 newname->chain = name_group_list->head; 293 name_group_list->head = newname; 294 295 return (newname); 296 } 297 298 /* 299 * NOTE: 300 * aml_delete_name() doesn't maintain aml_name_group::{head,tail}. 301 */ 302 static void 303 aml_delete_name(struct aml_name *target) 304 { 305 struct aml_name *next; 306 struct aml_name *ptr; 307 308 for (; target; target = next) { 309 next = target->chain; 310 if (target->child) { 311 target->chain = NULL; 312 continue; 313 } 314 if (target->brother) { 315 if (target->parent) { 316 if (target->parent->child == target) { 317 target->parent->child = target->brother; 318 } else { 319 ptr = target->parent->child; 320 while (ptr && ptr->brother != target) 321 ptr = ptr->brother; 322 if (ptr) 323 ptr->brother = target->brother; 324 } 325 target->brother = NULL; 326 } 327 } else if (target->parent) { 328 target->parent->child = NULL; 329 } 330 aml_free_object(&target->property); 331 memman_free(aml_memman, memid_aml_name, target); 332 } 333 } 334 335 #define AML_SEARCH_NAME 0 336 #define AML_CREATE_NAME 1 337 static struct aml_name *aml_nameman(struct aml_environ *, const u_int8_t *, int); 338 339 struct aml_name * 340 aml_search_name(struct aml_environ *env, const u_int8_t *dp) 341 { 342 343 return (aml_nameman(env, dp, AML_SEARCH_NAME)); 344 } 345 346 struct aml_name * 347 aml_create_name(struct aml_environ *env, const u_int8_t *dp) 348 { 349 350 return (aml_nameman(env, dp, AML_CREATE_NAME)); 351 } 352 353 static struct aml_name * 354 aml_nameman(struct aml_environ *env, const u_int8_t *dp, int flag) 355 { 356 int segcount; 357 int i; 358 struct aml_name *newname, *curname; 359 struct aml_name *(*searchfunc) (struct aml_name *, const u_int8_t *); 360 361 #define CREATECHECK() do { \ 362 if (newname == NULL) { \ 363 AML_DEBUGPRINT("ERROR CANNOT FIND NAME\n"); \ 364 env->stat = aml_stat_panic; \ 365 return (NULL); \ 366 } \ 367 } while(0) 368 369 searchfunc = (flag == AML_CREATE_NAME) ? aml_new_name : aml_find_name; 370 newname = env->curname; 371 if (dp[0] == '\\') { 372 newname = &rootname; 373 dp++; 374 } else if (dp[0] == '^') { 375 while (dp[0] == '^') { 376 newname = newname->parent; 377 CREATECHECK(); 378 dp++; 379 } 380 } 381 if (dp[0] == 0x00) { /* NullName */ 382 dp++; 383 } else if (dp[0] == 0x2e) { /* DualNamePrefix */ 384 newname = (*searchfunc) (newname, dp + 1); 385 CREATECHECK(); 386 newname = (*searchfunc) (newname, dp + 5); 387 CREATECHECK(); 388 } else if (dp[0] == 0x2f) { /* MultiNamePrefix */ 389 segcount = dp[1]; 390 for (i = 0, dp += 2; i < segcount; i++, dp += 4) { 391 newname = (*searchfunc) (newname, dp); 392 CREATECHECK(); 393 } 394 } else if (flag == AML_CREATE_NAME) { /* NameSeg */ 395 newname = aml_new_name(newname, dp); 396 CREATECHECK(); 397 } else { 398 curname = newname; 399 for (;;) { 400 newname = aml_find_name(curname, dp); 401 if (newname != NULL) 402 break; 403 if (curname == &rootname || curname == NULL) 404 break; 405 curname = curname->parent; 406 } 407 } 408 return (newname); 409 } 410 411 #undef CREATECHECK 412 413 struct aml_local_stack * 414 aml_local_stack_create() 415 { 416 struct aml_local_stack *result; 417 418 result = memman_alloc(aml_memman, memid_aml_local_stack); 419 memset(result, 0, sizeof(struct aml_local_stack)); 420 return (result); 421 } 422 423 void 424 aml_local_stack_push(struct aml_local_stack *stack) 425 { 426 427 stack->next = stack_top; 428 stack_top = stack; 429 } 430 431 struct aml_local_stack * 432 aml_local_stack_pop() 433 { 434 struct aml_local_stack *result; 435 436 result = stack_top; 437 stack_top = result->next; 438 result->next = NULL; 439 return (result); 440 } 441 442 void 443 aml_local_stack_delete(struct aml_local_stack *stack) 444 { 445 int i; 446 447 for (i = 0; i < 8; i++) 448 aml_free_object(&stack->localvalue[i].property); 449 for (i = 0; i < 7; i++) 450 aml_free_object(&stack->argumentvalue[i].property); 451 aml_delete_name(stack->temporary); 452 memman_free(aml_memman, memid_aml_local_stack, stack); 453 } 454 455 struct aml_name * 456 aml_local_stack_getLocalX(int idx) 457 { 458 459 if (stack_top == NULL) 460 return (NULL); 461 return (&stack_top->localvalue[idx]); 462 } 463 464 struct aml_name * 465 aml_local_stack_getArgX(struct aml_local_stack *stack, int idx) 466 { 467 468 if (!stack) 469 stack = stack_top; 470 if (stack == NULL) 471 return (NULL); 472 return (&stack->argumentvalue[idx]); 473 } 474 475 struct aml_name * 476 aml_create_local_object() 477 { 478 struct aml_name *result; 479 480 result = memman_alloc(aml_memman, memid_aml_name); 481 result->child = result->brother = result->parent = NULL; 482 result->property = NULL; 483 result->chain = stack_top->temporary; 484 stack_top->temporary = result; 485 return (result); 486 } 487