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