1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/stat.h> 30 #include <fcntl.h> 31 #include <unistd.h> 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <strings.h> 35 #include <fcntl.h> 36 37 #include <fcode/private.h> 38 #include <fcode/log.h> 39 40 #include <fcdriver/fcdriver.h> 41 42 static fc_phandle_t 43 fc_nodeop(common_data_t *cdp, fc_phandle_t node, char *svc) 44 { 45 fc_cell_t hcell; 46 int error; 47 48 error = fc_run_priv(cdp, svc, 1, 1, fc_phandle2cell(node), &hcell); 49 if (error) 50 return (NULL); 51 return (fc_cell2phandle(hcell)); 52 } 53 54 void 55 recurse_tree(fcode_env_t *env, device_t *d, 56 void (*fn)(fcode_env_t *, device_t *)) 57 { 58 if (d != NULL) { 59 device_t *p; 60 61 fn(env, d); 62 recurse_tree(env, d->child, fn); 63 recurse_tree(env, d->peer, fn); 64 } 65 } 66 67 static void 68 get_prom_nodeid(fcode_env_t *env, device_t *d) 69 { 70 common_data_t *cdp = env->private; 71 private_data_t *pd = d->private; 72 char *name; 73 int namelen; 74 char *namebuf; 75 76 if ((pd != NULL) && (pd->node)) { 77 if (os_get_prop_common(cdp, pd->node, "name", 78 0, &namebuf, &namelen)) 79 namebuf = "<unknown>"; 80 debug_msg(DEBUG_UPLOAD, "Populated: %s = %p\n", namebuf, 81 pd->node); 82 return; 83 } 84 85 name = get_package_name(env, d); 86 debug_msg(DEBUG_UPLOAD, "Node %s: %p (%p)\n", name, d, pd); 87 if (d->parent) { 88 private_data_t *ppd = (private_data_t *) d->parent->private; 89 fc_phandle_t thisnode; 90 91 if (os_get_prop_common(cdp, ppd->node, "name", 92 0, &namebuf, &namelen)) 93 namebuf = "<unknown>"; 94 debug_msg(DEBUG_UPLOAD, "Parent: %p (%p) %s = %p\n", d->parent, 95 ppd, namebuf, ppd->node); 96 for (thisnode = fc_nodeop(cdp, ppd->node, FC_CHILD_FCODE); 97 thisnode != NULL; 98 thisnode = fc_nodeop(cdp, thisnode, FC_PEER_FCODE)) { 99 int status; 100 101 namebuf = ""; 102 namelen = 0; 103 status = os_get_prop_common(cdp, thisnode, "name", 104 0, &namebuf, &namelen); 105 debug_msg(DEBUG_UPLOAD, "Lookup: %p name '%s'\n" 106 " status: %d", thisnode, namebuf, status); 107 if (status == 0 && strcmp(name, namebuf) == 0) 108 break; 109 } 110 if (thisnode) { 111 pd = MALLOC(sizeof (private_data_t)); 112 pd->common = cdp; 113 pd->node = thisnode; 114 pd->upload = 0; 115 d->private = pd; 116 add_my_handle(env, pd->node, d); 117 install_property_vectors(env, d); 118 debug_msg(DEBUG_UPLOAD, "Found: %p\n", thisnode); 119 } 120 } 121 } 122 123 static void 124 update_nodeids(fcode_env_t *env) 125 { 126 /* 127 * We scan through the tree looking for nodes that don't have 128 * one of my structures attached, and for each of those nodes 129 * I attempt to match it with a real firmware node 130 */ 131 recurse_tree(env, env->root_node, get_prom_nodeid); 132 } 133 134 static void 135 build_nodes(fcode_env_t *env, common_data_t *cdp, fc_phandle_t h) 136 { 137 char *name; 138 int len; 139 int n, allocd, depth; 140 fc_phandle_t p; 141 device_t *current, *attach; 142 private_data_t *pd; 143 private_data_t **node_array; 144 145 /* 146 * This is not nice; new_device calls the allocate_phandle 147 * routine without exception, we need to disable the allocation 148 * while we are building the tree to the attachment point 149 * which is why the init_done variable exists. 150 */ 151 cdp->init_done = 0; 152 node_array = NULL; 153 depth = 0; 154 allocd = sizeof (private_data_t *); 155 do { 156 node_array = REALLOC(node_array, allocd*(depth+1)); 157 pd = MALLOC(sizeof (private_data_t)); 158 pd->node = h; 159 node_array[depth] = pd; 160 name = NULL; 161 (void) os_get_prop_common(cdp, pd->node, "name", 0, &name, 162 &len); 163 if (name) 164 debug_msg(DEBUG_UPLOAD, "Node: %p name: '%s'\n", h, 165 name); 166 else 167 log_message(MSG_ERROR, "Node: %p Unnamed node!!\n", h); 168 depth++; 169 h = fc_nodeop(cdp, h, FC_PARENT); 170 } while (h); 171 172 for (n = 0; n < (depth-1); n++) { 173 new_device(env); 174 } 175 176 env->attachment_pt = current = attach = env->current_device; 177 178 for (n = 0; n < depth; n++) { 179 pd = node_array[n]; 180 pd->common = cdp; 181 current->private = pd; 182 add_my_handle(env, pd->node, current); 183 install_property_vectors(env, current); 184 current = current->parent; 185 } 186 187 for (current = attach; current != NULL; current = current->parent) { 188 install_node_data(env, current); 189 if (current->parent) 190 finish_device(env); 191 } 192 193 FREE(node_array); 194 cdp->init_done = 2; 195 update_nodeids(env); 196 cdp->init_done = 1; 197 cdp->first_node = 1; 198 } 199 200 void 201 build_tree(fcode_env_t *env) 202 { 203 common_data_t *cdp = env->private; 204 instance_t *ih; 205 206 root_node(env); 207 ih = open_instance_chain(env, env->current_device, 0); 208 MYSELF = ih; 209 build_nodes(env, cdp, cdp->attach); 210 close_instance_chain(env, ih, 0); 211 MYSELF = 0; 212 device_end(env); 213 } 214 215 /* 216 * Installs /openprom and /packages nodes and sub-nodes. 217 */ 218 void 219 install_builtin_nodes(fcode_env_t *env) 220 { 221 common_data_t *cdp = env->private; 222 int saved_first_node; 223 int saved_init_done; 224 225 if (cdp) { 226 saved_first_node = cdp->first_node; 227 saved_init_done = cdp->init_done; 228 cdp->first_node = 0; 229 cdp->init_done = 2; 230 install_openprom_nodes(env); 231 install_package_nodes(env); 232 cdp->first_node = saved_first_node; 233 cdp->init_done = saved_init_done; 234 } 235 } 236 237 238 #pragma init(_init) 239 240 static void 241 _init(void) 242 { 243 fcode_env_t *env = initial_env; 244 245 ASSERT(env); 246 NOTICE; 247 248 FORTH(0, "update-nodes", update_nodeids); 249 FORTH(0, "build-tree", build_tree); 250 } 251