xref: /netbsd-src/usr.sbin/acpitools/aml/aml_name.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
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