OpenSolaris_b135/lib/efcode/fcdriver/build_tree.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1999 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <fcntl.h>

#include <fcode/private.h>
#include <fcode/log.h>

#include <fcdriver/fcdriver.h>

static fc_phandle_t
fc_nodeop(common_data_t *cdp, fc_phandle_t node, char *svc)
{
	fc_cell_t hcell;
	int error;

	error = fc_run_priv(cdp, svc, 1, 1, fc_phandle2cell(node), &hcell);
	if (error)
		return (NULL);
	return (fc_cell2phandle(hcell));
}

void
recurse_tree(fcode_env_t *env, device_t *d,
    void (*fn)(fcode_env_t *, device_t *))
{
	if (d != NULL) {
		device_t *p;

		fn(env, d);
		recurse_tree(env, d->child, fn);
		recurse_tree(env, d->peer, fn);
	}
}

static void
get_prom_nodeid(fcode_env_t *env, device_t *d)
{
	common_data_t *cdp = env->private;
	private_data_t *pd = d->private;
	char *name;
	int namelen;
	char *namebuf;

	if ((pd != NULL) && (pd->node)) {
		if (os_get_prop_common(cdp, pd->node, "name",
		    0, &namebuf, &namelen))
			namebuf = "<unknown>";
		debug_msg(DEBUG_UPLOAD, "Populated: %s = %p\n", namebuf,
		    pd->node);
		return;
	}

	name = get_package_name(env, d);
	debug_msg(DEBUG_UPLOAD, "Node %s: %p (%p)\n", name, d, pd);
	if (d->parent) {
		private_data_t *ppd = (private_data_t *) d->parent->private;
		fc_phandle_t thisnode;

		if (os_get_prop_common(cdp, ppd->node, "name",
		    0, &namebuf, &namelen))
			namebuf = "<unknown>";
		debug_msg(DEBUG_UPLOAD, "Parent: %p (%p) %s = %p\n", d->parent,
		    ppd, namebuf, ppd->node);
		for (thisnode = fc_nodeop(cdp, ppd->node, FC_CHILD_FCODE);
		    thisnode != NULL;
		    thisnode = fc_nodeop(cdp, thisnode, FC_PEER_FCODE)) {
			int status;

			namebuf = "";
			namelen = 0;
			status = os_get_prop_common(cdp, thisnode, "name",
			    0, &namebuf, &namelen);
			debug_msg(DEBUG_UPLOAD, "Lookup: %p name '%s'\n"
			    " status: %d", thisnode, namebuf, status);
			if (status == 0 && strcmp(name, namebuf) == 0)
				break;
		}
		if (thisnode) {
			pd = MALLOC(sizeof (private_data_t));
			pd->common = cdp;
			pd->node = thisnode;
			pd->upload = 0;
			d->private = pd;
			add_my_handle(env, pd->node, d);
			install_property_vectors(env, d);
			debug_msg(DEBUG_UPLOAD, "Found: %p\n", thisnode);
		}
	}
}

static void
update_nodeids(fcode_env_t *env)
{
	/*
	 * We scan through the tree looking for nodes that don't have
	 * one of my structures attached, and for each of those nodes
	 * I attempt to match it with a real firmware node
	 */
	recurse_tree(env, env->root_node, get_prom_nodeid);
}

static void
build_nodes(fcode_env_t *env, common_data_t *cdp, fc_phandle_t h)
{
	char *name;
	int len;
	int n, allocd, depth;
	fc_phandle_t p;
	device_t *current, *attach;
	private_data_t *pd;
	private_data_t **node_array;

	/*
	 * This is not nice; new_device calls the allocate_phandle
	 * routine without exception, we need to disable the allocation
	 * while we are building the tree to the attachment point
	 * which is why the init_done variable exists.
	 */
	cdp->init_done = 0;
	node_array = NULL;
	depth = 0;
	allocd = sizeof (private_data_t *);
	do {
		node_array = REALLOC(node_array, allocd*(depth+1));
		pd = MALLOC(sizeof (private_data_t));
		pd->node = h;
		node_array[depth] = pd;
		name = NULL;
		(void) os_get_prop_common(cdp, pd->node, "name", 0, &name,
		    &len);
		if (name)
			debug_msg(DEBUG_UPLOAD, "Node: %p name: '%s'\n", h,
			    name);
		else
			log_message(MSG_ERROR, "Node: %p Unnamed node!!\n", h);
		depth++;
		h = fc_nodeop(cdp, h, FC_PARENT);
	} while (h);

	for (n = 0; n < (depth-1); n++) {
		new_device(env);
	}

	env->attachment_pt = current = attach = env->current_device;

	for (n = 0; n < depth; n++) {
		pd = node_array[n];
		pd->common = cdp;
		current->private = pd;
		add_my_handle(env, pd->node, current);
		install_property_vectors(env, current);
		current = current->parent;
	}

	for (current = attach; current != NULL; current = current->parent) {
		install_node_data(env, current);
		if (current->parent)
			finish_device(env);
	}

	FREE(node_array);
	cdp->init_done = 2;
	update_nodeids(env);
	cdp->init_done = 1;
	cdp->first_node = 1;
}

void
build_tree(fcode_env_t *env)
{
	common_data_t *cdp = env->private;
	instance_t *ih;

	root_node(env);
	ih = open_instance_chain(env, env->current_device, 0);
	MYSELF = ih;
	build_nodes(env, cdp, cdp->attach);
	close_instance_chain(env, ih, 0);
	MYSELF = 0;
	device_end(env);
}

/*
 * Installs /openprom and /packages nodes and sub-nodes.
 */
void
install_builtin_nodes(fcode_env_t *env)
{
	common_data_t *cdp = env->private;
	int saved_first_node;
	int saved_init_done;

	if (cdp) {
		saved_first_node = cdp->first_node;
		saved_init_done = cdp->init_done;
		cdp->first_node = 0;
		cdp->init_done = 2;
		install_openprom_nodes(env);
		install_package_nodes(env);
		cdp->first_node = saved_first_node;
		cdp->init_done = saved_init_done;
	}
}


#pragma init(_init)

static void
_init(void)
{
	fcode_env_t *env = initial_env;

	ASSERT(env);
	NOTICE;

	FORTH(0,		"update-nodes",		update_nodeids);
	FORTH(0,		"build-tree",		build_tree);
}