1/*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_FREE_COPYRIGHT@
30 */
31
32#include <pexpert/protos.h>
33#include <pexpert/boot.h>
34#include <pexpert/device_tree.h>
35
36#include <mach/mach_types.h>
37#include <mach/machine/vm_types.h>
38#include <kern/kern_types.h>
39#include <kern/kalloc.h>
40
41#include <sys/types.h>
42
43#ifndef NULL
44#define       NULL    ((void *) 0)
45#endif
46
47#define round_long(x)	(((x) + 3) & -4)
48#define next_prop(x)	((DeviceTreeNodeProperty *) (((int)x) + sizeof(DeviceTreeNodeProperty) + round_long(x->length)))
49
50/* Entry*/
51typedef DeviceTreeNode *RealDTEntry;
52
53typedef struct DTSavedScope {
54	struct DTSavedScope * nextScope;
55	RealDTEntry scope;
56	RealDTEntry entry;
57	unsigned long index;
58} *DTSavedScopePtr;
59
60/* Entry Iterator*/
61typedef struct OpaqueDTEntryIterator {
62	RealDTEntry outerScope;
63	RealDTEntry currentScope;
64	RealDTEntry currentEntry;
65	DTSavedScopePtr savedScope;
66	unsigned long currentIndex;
67} *RealDTEntryIterator;
68
69/* Property Iterator*/
70typedef struct OpaqueDTPropertyIterator {
71	RealDTEntry entry;
72	DeviceTreeNodeProperty *currentProperty;
73	unsigned long currentIndex;
74} *RealDTPropertyIterator;
75
76static int DTInitialized;
77static RealDTEntry DTRootNode;
78
79/*
80 * Support Routines
81 */
82static RealDTEntry
83skipProperties(RealDTEntry entry)
84{
85	DeviceTreeNodeProperty *prop;
86	unsigned int k;
87
88	if (entry == NULL || entry->nProperties == 0) {
89		return NULL;
90	} else {
91		prop = (DeviceTreeNodeProperty *) (entry + 1);
92		for (k = 0; k < entry->nProperties; k++) {
93			prop = next_prop(prop);
94		}
95	}
96	return ((RealDTEntry) prop);
97}
98
99static RealDTEntry
100skipTree(RealDTEntry root)
101{
102	RealDTEntry entry;
103	unsigned int k;
104
105	entry = skipProperties(root);
106	if (entry == NULL) {
107		return NULL;
108	}
109	for (k = 0; k < root->nChildren; k++) {
110		entry = skipTree(entry);
111	}
112	return entry;
113}
114
115static RealDTEntry
116GetFirstChild(RealDTEntry parent)
117{
118	return skipProperties(parent);
119}
120
121static RealDTEntry
122GetNextChild(RealDTEntry sibling)
123{
124	return skipTree(sibling);
125}
126
127static const char *
128GetNextComponent(const char *cp, char *bp)
129{
130	while (*cp != 0) {
131		if (*cp == kDTPathNameSeparator) {
132			cp++;
133			break;
134		}
135		*bp++ = *cp++;
136	}
137	*bp = 0;
138	return cp;
139}
140
141static RealDTEntry
142FindChild(RealDTEntry cur, char *buf)
143{
144	RealDTEntry	child;
145	unsigned long	index;
146	char *			str;
147	unsigned int	dummy;
148
149	if (cur->nChildren == 0) {
150		return NULL;
151	}
152	index = 1;
153	child = GetFirstChild(cur);
154	while (1) {
155		if (DTGetProperty(child, "name", (void **)&str, &dummy) != kSuccess) {
156			break;
157		}
158		if (strcmp(str, buf) == 0) {
159			return child;
160		}
161		if (index >= cur->nChildren) {
162			break;
163		}
164		child = GetNextChild(child);
165		index++;
166	}
167	return NULL;
168}
169
170
171/*
172 * External Routines
173 */
174void
175DTInit(void *base)
176{
177	DTRootNode = (RealDTEntry) base;
178	DTInitialized = (DTRootNode != 0);
179}
180
181int
182DTEntryIsEqual(const DTEntry ref1, const DTEntry ref2)
183{
184	/* equality of pointers */
185	return (ref1 == ref2);
186}
187
188static char *startingP;		// needed for find_entry
189int find_entry(const char *propName, const char *propValue, DTEntry *entryH);
190
191int DTFindEntry(const char *propName, const char *propValue, DTEntry *entryH)
192{
193	if (!DTInitialized) {
194		return kError;
195	}
196
197	startingP = (char *)DTRootNode;
198	return(find_entry(propName, propValue, entryH));
199}
200
201int find_entry(const char *propName, const char *propValue, DTEntry *entryH)
202{
203	DeviceTreeNode *nodeP = (DeviceTreeNode *) startingP;
204	unsigned int k;
205
206	if (nodeP->nProperties == 0) return(kError);	// End of the list of nodes
207	startingP = (char *) (nodeP + 1);
208
209	// Search current entry
210	for (k = 0; k < nodeP->nProperties; ++k) {
211		DeviceTreeNodeProperty *propP = (DeviceTreeNodeProperty *) startingP;
212
213		startingP += sizeof (*propP) + ((propP->length + 3) & -4);
214
215		if (strcmp (propP->name, propName) == 0) {
216			if (propValue == NULL || strcmp( (char *)(propP + 1), propValue) == 0)
217			{
218				*entryH = (DTEntry)nodeP;
219				return(kSuccess);
220			}
221		}
222	}
223
224	// Search child nodes
225	for (k = 0; k < nodeP->nChildren; ++k)
226	{
227		if (find_entry(propName, propValue, entryH) == kSuccess)
228			return(kSuccess);
229	}
230	return(kError);
231}
232
233int
234DTLookupEntry(const DTEntry searchPoint, const char *pathName, DTEntry *foundEntry)
235{
236	DTEntryNameBuf	buf;
237	RealDTEntry	cur;
238	const char *	cp;
239
240	if (!DTInitialized) {
241		return kError;
242	}
243	if (searchPoint == NULL) {
244		cur = DTRootNode;
245	} else {
246		cur = searchPoint;
247	}
248	cp = pathName;
249	if (*cp == kDTPathNameSeparator) {
250		cp++;
251		if (*cp == 0) {
252			*foundEntry = cur;
253			return kSuccess;
254		}
255	}
256	do {
257		cp = GetNextComponent(cp, buf);
258
259		/* Check for done */
260		if (*buf == 0) {
261			if (*cp == 0) {
262				*foundEntry = cur;
263				return kSuccess;
264			}
265			break;
266		}
267
268		cur = FindChild(cur, buf);
269
270	} while (cur != NULL);
271
272	return kError;
273}
274
275int
276DTCreateEntryIterator(const DTEntry startEntry, DTEntryIterator *iterator)
277{
278	RealDTEntryIterator iter;
279
280	if (!DTInitialized) {
281		return kError;
282	}
283
284	iter = (RealDTEntryIterator) kalloc(sizeof(struct OpaqueDTEntryIterator));
285	if (startEntry != NULL) {
286		iter->outerScope = (RealDTEntry) startEntry;
287		iter->currentScope = (RealDTEntry) startEntry;
288	} else {
289		iter->outerScope = DTRootNode;
290		iter->currentScope = DTRootNode;
291	}
292	iter->currentEntry = NULL;
293	iter->savedScope = NULL;
294	iter->currentIndex = 0;
295
296	*iterator = iter;
297	return kSuccess;
298}
299
300int
301DTDisposeEntryIterator(DTEntryIterator iterator)
302{
303	RealDTEntryIterator iter = iterator;
304	DTSavedScopePtr scope;
305
306	while ((scope = iter->savedScope) != NULL) {
307		iter->savedScope = scope->nextScope;
308		kfree(scope, sizeof(struct DTSavedScope));
309	}
310	kfree(iterator, sizeof(struct OpaqueDTEntryIterator));
311	return kSuccess;
312}
313
314int
315DTEnterEntry(DTEntryIterator iterator, DTEntry childEntry)
316{
317	RealDTEntryIterator iter = iterator;
318	DTSavedScopePtr newScope;
319
320	if (childEntry == NULL) {
321		return kError;
322	}
323	newScope = (DTSavedScopePtr) kalloc(sizeof(struct DTSavedScope));
324	newScope->nextScope = iter->savedScope;
325	newScope->scope = iter->currentScope;
326	newScope->entry = iter->currentEntry;
327	newScope->index = iter->currentIndex;
328
329	iter->currentScope = childEntry;
330	iter->currentEntry = NULL;
331	iter->savedScope = newScope;
332	iter->currentIndex = 0;
333
334	return kSuccess;
335}
336
337int
338DTExitEntry(DTEntryIterator iterator, DTEntry *currentPosition)
339{
340	RealDTEntryIterator iter = iterator;
341	DTSavedScopePtr newScope;
342
343	newScope = iter->savedScope;
344	if (newScope == NULL) {
345		return kError;
346	}
347	iter->savedScope = newScope->nextScope;
348	iter->currentScope = newScope->scope;
349	iter->currentEntry = newScope->entry;
350	iter->currentIndex = newScope->index;
351	*currentPosition = iter->currentEntry;
352
353	kfree(newScope, sizeof(struct DTSavedScope));
354
355	return kSuccess;
356}
357
358int
359DTIterateEntries(DTEntryIterator iterator, DTEntry *nextEntry)
360{
361	RealDTEntryIterator iter = iterator;
362
363	if (iter->currentIndex >= iter->currentScope->nChildren) {
364		*nextEntry = NULL;
365		return kIterationDone;
366	} else {
367		iter->currentIndex++;
368		if (iter->currentIndex == 1) {
369			iter->currentEntry = GetFirstChild(iter->currentScope);
370		} else {
371			iter->currentEntry = GetNextChild(iter->currentEntry);
372		}
373		*nextEntry = iter->currentEntry;
374		return kSuccess;
375	}
376}
377
378int
379DTRestartEntryIteration(DTEntryIterator iterator)
380{
381	RealDTEntryIterator iter = iterator;
382#if 0
383	// This commented out code allows a second argument (outer)
384	// which (if true) causes restarting at the outer scope
385	// rather than the current scope.
386	DTSavedScopePtr scope;
387
388	if (outer) {
389		while ((scope = iter->savedScope) != NULL) {
390			iter->savedScope = scope->nextScope;
391			kfree((vm_offset_t) scope, sizeof(struct DTSavedScope));
392		}
393		iter->currentScope = iter->outerScope;
394	}
395#endif
396	iter->currentEntry = NULL;
397	iter->currentIndex = 0;
398	return kSuccess;
399}
400
401int
402DTGetProperty(const DTEntry entry, const char *propertyName, void **propertyValue, unsigned int *propertySize)
403{
404	DeviceTreeNodeProperty *prop;
405	unsigned int k;
406
407	if (entry == NULL || entry->nProperties == 0) {
408		return kError;
409	} else {
410		prop = (DeviceTreeNodeProperty *) (entry + 1);
411		for (k = 0; k < entry->nProperties; k++) {
412			if (strcmp(prop->name, propertyName) == 0) {
413				*propertyValue = (void *) (((int)prop)
414						+ sizeof(DeviceTreeNodeProperty));
415				*propertySize = prop->length;
416				return kSuccess;
417			}
418			prop = next_prop(prop);
419		}
420	}
421	return kError;
422}
423
424int
425DTCreatePropertyIterator(const DTEntry entry, DTPropertyIterator *iterator)
426{
427	RealDTPropertyIterator iter;
428
429	iter = (RealDTPropertyIterator) kalloc(sizeof(struct OpaqueDTPropertyIterator));
430	iter->entry = entry;
431	iter->currentProperty = NULL;
432	iter->currentIndex = 0;
433
434	*iterator = iter;
435	return kSuccess;
436}
437
438int
439DTDisposePropertyIterator(DTPropertyIterator iterator)
440{
441	kfree(iterator, sizeof(struct OpaqueDTPropertyIterator));
442	return kSuccess;
443}
444
445int
446DTIterateProperties(DTPropertyIterator iterator, char **foundProperty)
447{
448	RealDTPropertyIterator iter = iterator;
449
450	if (iter->currentIndex >= iter->entry->nProperties) {
451		*foundProperty = NULL;
452		return kIterationDone;
453	} else {
454		iter->currentIndex++;
455		if (iter->currentIndex == 1) {
456			iter->currentProperty = (DeviceTreeNodeProperty *) (iter->entry + 1);
457		} else {
458			iter->currentProperty = next_prop(iter->currentProperty);
459		}
460		*foundProperty = iter->currentProperty->name;
461		return kSuccess;
462	}
463}
464
465int
466DTRestartPropertyIteration(DTPropertyIterator iterator)
467{
468	RealDTPropertyIterator iter = iterator;
469
470	iter->currentProperty = NULL;
471	iter->currentIndex = 0;
472	return kSuccess;
473}
474
475