1 /*        $NetBSD: aml_name.c,v 1.4 2009/10/08 13:16:13 cegger 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.4 2009/10/08 13:16:13 cegger 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 *
aml_get_rootname()70 aml_get_rootname()
71 {
72 
73           return (&rootname);
74 }
75 
76 static struct aml_name *
aml_find_name(struct aml_name * parent,const u_int8_t * 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 *
aml_find_from_namespace(struct aml_name * parent,const char * 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
_aml_apply_foreach_found_objects(struct aml_name * parent,char * name,int len,int shallow,int (* func)(struct aml_name *,va_list),va_list ap)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
aml_apply_foreach_found_objects(struct aml_name * start,char * name,int (* func)(struct aml_name *,va_list),...)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 *
aml_new_name_group(void * id)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
aml_delete_name_group(struct aml_name_group * target)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 *
aml_new_name(struct aml_name * parent,const u_int8_t * 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 && 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  */
303 static void
aml_delete_name(struct aml_name * target)304 aml_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
338 static struct aml_name        *aml_nameman(struct aml_environ *, const u_int8_t *, int);
339 
340 struct aml_name *
aml_search_name(struct aml_environ * env,const u_int8_t * dp)341 aml_search_name(struct aml_environ *env, const u_int8_t *dp)
342 {
343 
344           return (aml_nameman(env, dp, AML_SEARCH_NAME));
345 }
346 
347 struct aml_name *
aml_create_name(struct aml_environ * env,const u_int8_t * dp)348 aml_create_name(struct aml_environ *env, const u_int8_t *dp)
349 {
350 
351           return (aml_nameman(env, dp, AML_CREATE_NAME));
352 }
353 
354 static struct aml_name *
aml_nameman(struct aml_environ * env,const u_int8_t * dp,int flag)355 aml_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 
414 struct aml_local_stack *
aml_local_stack_create()415 aml_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 
424 void
aml_local_stack_push(struct aml_local_stack * stack)425 aml_local_stack_push(struct aml_local_stack *stack)
426 {
427 
428           stack->next = stack_top;
429           stack_top = stack;
430 }
431 
432 struct aml_local_stack *
aml_local_stack_pop()433 aml_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 
443 void
aml_local_stack_delete(struct aml_local_stack * stack)444 aml_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 
456 struct aml_name *
aml_local_stack_getLocalX(int idx)457 aml_local_stack_getLocalX(int idx)
458 {
459 
460           if (stack_top == NULL)
461                     return (NULL);
462           return (&stack_top->localvalue[idx]);
463 }
464 
465 struct aml_name *
aml_local_stack_getArgX(struct aml_local_stack * stack,int idx)466 aml_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 
476 struct aml_name *
aml_create_local_object()477 aml_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