1139823Simp/*
244165Sjulian * Copyright 2003-2005, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
344165Sjulian * Distributed under the terms of the MIT License.
444165Sjulian */
544165Sjulian
644165Sjulian#include <platform/openfirmware/devices.h>
744165Sjulian#include <platform/openfirmware/openfirmware.h>
844165Sjulian#include <util/kernel_cpp.h>
944165Sjulian
1044165Sjulian#include <string.h>
1144165Sjulian
1244165Sjulian
1344165Sjulian/** Gets all device types of the specified type by doing a
1444165Sjulian *	depth-first search of the OpenFirmware device tree.
1544165Sjulian *	If a root != 0 is given, the function only traverses the subtree spanned
1644165Sjulian *	by the root (inclusively). Otherwise the whole device tree is searched.
1744165Sjulian *
1844165Sjulian *	The cookie has to be initialized to zero.
1944165Sjulian */
2044165Sjulianstatus_t
2144165Sjulianof_get_next_device(intptr_t *_cookie, intptr_t root, const char *type,
2244165Sjulian	char *path, size_t pathSize)
2344165Sjulian{
2444165Sjulian	intptr_t node = *_cookie;
2544165Sjulian
2644165Sjulian	while (true) {
2744165Sjulian		intptr_t next;
2844165Sjulian
2944165Sjulian		if (node == 0) {
3044165Sjulian			// node is NULL, meaning that this is the initial function call.
3144165Sjulian			// If a root was supplied, we take that, otherwise the device tree
3244165Sjulian			// root.
3350477Speter			if (root != 0)
3444165Sjulian				node = root;
3544165Sjulian			else
3644165Sjulian				node = of_peer(0);
3744165Sjulian
3844165Sjulian			if (node == OF_FAILED)
3944165Sjulian				return B_ERROR;
4044165Sjulian			if (node == 0)
4144165Sjulian				return B_ENTRY_NOT_FOUND;
4244165Sjulian
4344165Sjulian			// We want to visit the root first.
44112305Smdodd			next = node;
4544165Sjulian		} else
4644165Sjulian			next = of_child(node);
4758313Slile
4844165Sjulian		if (next == OF_FAILED)
4944165Sjulian			return B_ERROR;
50112305Smdodd
51112305Smdodd		if (next == 0) {
52112305Smdodd			// no child node found
53112305Smdodd			next = of_peer(node);
54112305Smdodd			if (next == OF_FAILED)
5544165Sjulian				return B_ERROR;
56112305Smdodd
57112305Smdodd			while (next == 0) {
5844165Sjulian				// no peer node found, we are using the device
59112305Smdodd				// tree itself as our search stack
60112305Smdodd
61112305Smdodd				next = of_parent(node);
6244165Sjulian				if (next == OF_FAILED)
6344165Sjulian					return B_ERROR;
6458313Slile
6544165Sjulian				if (next == root || next == 0) {
6658313Slile					// We have searched the whole device tree
67112305Smdodd					return B_ENTRY_NOT_FOUND;
68112305Smdodd				}
69112305Smdodd
70112305Smdodd				// look into the next tree
7144165Sjulian				node = next;
72112305Smdodd				next = of_peer(node);
7358313Slile			}
7444165Sjulian		}
7558313Slile
7644165Sjulian		*_cookie = node = next;
7758313Slile
7874407Smdodd		char nodeType[16];
7974407Smdodd		int length;
8074407Smdodd		if (of_getprop(node, "device_type", nodeType, sizeof(nodeType))
8144165Sjulian				== OF_FAILED
8244165Sjulian			|| strcmp(nodeType, type)
8344165Sjulian			|| (length = of_package_to_path(node, path, pathSize - 1))
8444165Sjulian					== OF_FAILED) {
8544165Sjulian			continue;
8644165Sjulian		}
8744165Sjulian
88145002Smdodd		path[length] = '\0';
89145002Smdodd		return B_OK;
90145002Smdodd	}
91145002Smdodd}
92145002Smdodd
93145002Smdodd