/* * 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 #include #include #include #include #include #include #include #include #include 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 = ""; 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 = ""; 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); }