1 1.15 thorpej /* $NetBSD: ieee1212.c,v 1.15 2021/08/07 16:19:16 thorpej Exp $ */ 2 1.1 jmc 3 1.1 jmc /* 4 1.1 jmc * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 1.1 jmc * All rights reserved. 6 1.1 jmc * 7 1.1 jmc * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jmc * by James Chacon. 9 1.1 jmc * 10 1.1 jmc * Redistribution and use in source and binary forms, with or without 11 1.1 jmc * modification, are permitted provided that the following conditions 12 1.1 jmc * are met: 13 1.1 jmc * 1. Redistributions of source code must retain the above copyright 14 1.1 jmc * notice, this list of conditions and the following disclaimer. 15 1.1 jmc * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jmc * notice, this list of conditions and the following disclaimer in the 17 1.1 jmc * documentation and/or other materials provided with the distribution. 18 1.1 jmc * 19 1.1 jmc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jmc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jmc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jmc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jmc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jmc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jmc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jmc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jmc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jmc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jmc * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jmc */ 31 1.6 lukem 32 1.6 lukem #include <sys/cdefs.h> 33 1.15 thorpej __KERNEL_RCSID(0, "$NetBSD: ieee1212.c,v 1.15 2021/08/07 16:19:16 thorpej Exp $"); 34 1.1 jmc 35 1.1 jmc #include <sys/param.h> 36 1.1 jmc #include <sys/systm.h> 37 1.1 jmc #include <sys/device.h> 38 1.1 jmc #include <sys/kernel.h> 39 1.1 jmc #include <sys/malloc.h> 40 1.1 jmc 41 1.1 jmc #include <dev/std/ieee1212reg.h> 42 1.1 jmc #include <dev/std/ieee1212var.h> 43 1.1 jmc 44 1.1 jmc static const char * const p1212_keytype_strings[] = P1212_KEYTYPE_STRINGS ; 45 1.9 perry static const char * const p1212_keyvalue_strings[] = P1212_KEYVALUE_STRINGS ; 46 1.1 jmc 47 1.1 jmc static u_int16_t p1212_calc_crc(u_int32_t, u_int32_t *, int, int); 48 1.1 jmc static int p1212_parse_directory(struct p1212_dir *, u_int32_t *, u_int32_t); 49 1.1 jmc static struct p1212_leafdata *p1212_parse_leaf(u_int32_t *); 50 1.1 jmc static int p1212_parse_textdir(struct p1212_com *, u_int32_t *); 51 1.1 jmc static struct p1212_textdata *p1212_parse_text_desc(u_int32_t *); 52 1.1 jmc static void p1212_print_node(struct p1212_key *, void *); 53 1.1 jmc static int p1212_validate_offset(u_int16_t, u_int32_t); 54 1.1 jmc static int p1212_validate_immed(u_int16_t, u_int32_t); 55 1.1 jmc static int p1212_validate_leaf(u_int16_t, u_int32_t); 56 1.1 jmc static int p1212_validate_dir(u_int16_t, u_int32_t); 57 1.1 jmc 58 1.1 jmc #ifdef P1212_DEBUG 59 1.1 jmc #define DPRINTF(x) if (p1212debug) printf x 60 1.1 jmc #define DPRINTFN(n,x) if (p1212debug>(n)) printf x 61 1.1 jmc int p1212debug = 1; 62 1.1 jmc #else 63 1.1 jmc #define DPRINTF(x) 64 1.1 jmc #define DPRINTFN(n,x) 65 1.1 jmc #endif 66 1.1 jmc 67 1.1 jmc /* 68 1.1 jmc * Routines to parse the ROM into a tree that's usable. Also verify integrity 69 1.1 jmc * vs. the P1212 standard 70 1.1 jmc */ 71 1.1 jmc 72 1.1 jmc /* 73 1.1 jmc * A buffer of u_int32_t's and a size in quads gets passed in. The output will 74 1.1 jmc * return -1 on error, or 0 on success and possibly reset *size to a larger 75 1.1 jmc * value. 76 1.1 jmc * 77 1.5 wiz * NOTE: Rom's are guaranteed per the ISO spec to be contiguous but only the 78 1.1 jmc * first 1k is directly mapped. Anything past 1k is supposed to use a loop 79 1.1 jmc * around the indirect registers to read in the rom. This code only assumes the 80 1.1 jmc * buffer passed in represents a total rom regardless of end size. It is the 81 1.1 jmc * callers responsibility to treat a size > 1024 as a special case. 82 1.1 jmc */ 83 1.1 jmc 84 1.1 jmc int 85 1.1 jmc p1212_iscomplete(u_int32_t *t, u_int32_t *size) 86 1.1 jmc { 87 1.9 perry u_int16_t infolen, crclen, len; 88 1.1 jmc u_int32_t newlen, offset, test; 89 1.1 jmc int complete, i, numdirs, type, val, *dirs; 90 1.1 jmc 91 1.1 jmc dirs = NULL; 92 1.1 jmc 93 1.1 jmc if (*size == 0) { 94 1.1 jmc DPRINTF(("Invalid size for ROM: %d\n", (unsigned int)*size)); 95 1.1 jmc return -1; 96 1.1 jmc } 97 1.1 jmc 98 1.1 jmc infolen = P1212_ROMFMT_GET_INFOLEN((ntohl(t[0]))); 99 1.1 jmc if (infolen <= 1) { 100 1.1 jmc DPRINTF(("ROM not initialized or minimal ROM: Info " 101 1.1 jmc "length: %d\n", infolen)); 102 1.1 jmc return -1; 103 1.1 jmc } 104 1.1 jmc crclen = P1212_ROMFMT_GET_CRCLEN((ntohl(t[0]))); 105 1.1 jmc if (crclen < infolen) { 106 1.1 jmc DPRINTF(("CRC len less than info len. CRC len: %d, " 107 1.1 jmc "Info len: %d\n", crclen, infolen)); 108 1.1 jmc return -1; 109 1.1 jmc } 110 1.9 perry 111 1.1 jmc /* 112 1.1 jmc * Now loop through it to check if all the offsets referenced are 113 1.1 jmc * within the image stored so far. If not, get those as well. 114 1.1 jmc */ 115 1.9 perry 116 1.1 jmc offset = P1212_ROMFMT_GET_INFOLEN((ntohl(t[0]))) + 1; 117 1.1 jmc 118 1.1 jmc /* 119 1.1 jmc * Make sure at least the bus info block is in memory + the root dir 120 1.1 jmc * header quad. Add 1 here since offset is an array offset and size is 121 1.1 jmc * the total array size we want. If this is getting the root dir 122 1.1 jmc * then add another since infolen doesn't end on the root dir entry but 123 1.1 jmc * right before it. 124 1.1 jmc */ 125 1.9 perry 126 1.1 jmc if ((*size == 1) || (*size < (offset + 1))) { 127 1.1 jmc *size = (crclen > infolen) ? crclen : infolen; 128 1.1 jmc if (crclen == infolen) 129 1.1 jmc (*size)++; 130 1.1 jmc (*size)++; 131 1.1 jmc return 0; 132 1.1 jmc } 133 1.1 jmc 134 1.1 jmc complete = 0; 135 1.1 jmc numdirs = 0; 136 1.1 jmc newlen = 0; 137 1.9 perry 138 1.1 jmc while (!complete) { 139 1.9 perry 140 1.1 jmc /* 141 1.1 jmc * Make sure the whole directory is in memory. If not, bail now 142 1.1 jmc * and read it in. 143 1.1 jmc */ 144 1.1 jmc 145 1.1 jmc newlen = P1212_DIRENT_GET_LEN((ntohl(t[offset]))); 146 1.1 jmc if ((offset + newlen + 1) > *size) { 147 1.1 jmc newlen += offset + 1; 148 1.1 jmc break; 149 1.1 jmc } 150 1.9 perry 151 1.1 jmc if (newlen == 0) { 152 1.1 jmc DPRINTF(("Impossible directory length of 0!\n")); 153 1.1 jmc return -1; 154 1.1 jmc } 155 1.1 jmc 156 1.1 jmc /* 157 1.1 jmc * Starting with the first byte of the directory, read through 158 1.1 jmc * and check the values found. On offsets and directories read 159 1.1 jmc * them in if appropriate (always for offsets, if not in memory 160 1.1 jmc * for leaf/directories). 161 1.1 jmc */ 162 1.1 jmc 163 1.1 jmc offset++; 164 1.1 jmc len = newlen; 165 1.1 jmc newlen = 0; 166 1.1 jmc for (i = 0; i < len; i++) { 167 1.2 jmc type = P1212_DIRENT_GET_KEYTYPE((ntohl(t[offset+i]))); 168 1.2 jmc val = P1212_DIRENT_GET_VALUE((ntohl(t[offset+i]))); 169 1.1 jmc switch (type) { 170 1.1 jmc case P1212_KEYTYPE_Immediate: 171 1.1 jmc case P1212_KEYTYPE_Offset: 172 1.1 jmc break; 173 1.1 jmc case P1212_KEYTYPE_Leaf: 174 1.9 perry 175 1.1 jmc /* 176 1.1 jmc * If a leaf is found, and it's beyond the 177 1.1 jmc * current rom length and it's beyond the 178 1.1 jmc * current newlen setting, 179 1.1 jmc * then set newlen accordingly. 180 1.1 jmc */ 181 1.9 perry 182 1.1 jmc test = offset + i + val + 1; 183 1.1 jmc if ((test > *size) && (test > newlen)) { 184 1.1 jmc newlen = test; 185 1.1 jmc break; 186 1.1 jmc } 187 1.9 perry 188 1.1 jmc /* 189 1.1 jmc * For leaf nodes just make sure the whole leaf 190 1.1 jmc * length is in the buffer. There's no data 191 1.1 jmc * inside of them that can refer to outside 192 1.1 jmc * nodes. (Uless it's vendor specific and then 193 1.1 jmc * you're on your own anyways). 194 1.1 jmc */ 195 1.1 jmc 196 1.1 jmc test--; 197 1.9 perry infolen = 198 1.2 jmc P1212_DIRENT_GET_LEN((ntohl(t[test]))); 199 1.1 jmc test++; 200 1.1 jmc test += infolen; 201 1.1 jmc if ((test > *size) && (test > newlen)) { 202 1.1 jmc newlen = test; 203 1.1 jmc } 204 1.1 jmc break; 205 1.9 perry 206 1.1 jmc case P1212_KEYTYPE_Directory: 207 1.9 perry 208 1.1 jmc /* Make sure the first quad is in memory. */ 209 1.9 perry 210 1.1 jmc test = offset + i + val + 1; 211 1.1 jmc if ((test > *size) && (test > newlen)) { 212 1.1 jmc newlen = test; 213 1.1 jmc break; 214 1.1 jmc } 215 1.9 perry 216 1.1 jmc /* 217 1.9 perry * Can't just walk the ROM looking at type 218 1.9 perry * codes since these are only valid on 219 1.2 jmc * directory entries. So save any directories 220 1.1 jmc * we find into a queue and the bottom of the 221 1.9 perry * while loop will pop the last one off and 222 1.2 jmc * walk that directory. 223 1.1 jmc */ 224 1.9 perry 225 1.1 jmc test--; 226 1.1 jmc dirs = realloc(dirs, 227 1.1 jmc sizeof(int) * (numdirs + 1), M_DEVBUF, 228 1.1 jmc M_WAITOK); 229 1.1 jmc dirs[numdirs++] = test; 230 1.1 jmc break; 231 1.1 jmc default: 232 1.1 jmc panic("Impossible type code: 0x%04hx", 233 1.1 jmc (unsigned short)type); 234 1.1 jmc break; 235 1.1 jmc } 236 1.1 jmc } 237 1.9 perry 238 1.1 jmc if (newlen) { 239 1.1 jmc /* Cleanup. */ 240 1.9 perry if (dirs) 241 1.1 jmc free(dirs, M_DEVBUF); 242 1.1 jmc break; 243 1.1 jmc } 244 1.1 jmc if (dirs) { 245 1.1 jmc offset = dirs[--numdirs]; 246 1.1 jmc dirs = realloc(dirs, sizeof(int) * numdirs, M_DEVBUF, 247 1.1 jmc M_WAITOK); 248 1.1 jmc } else 249 1.1 jmc complete = 1; 250 1.1 jmc } 251 1.9 perry 252 1.1 jmc if (newlen) 253 1.1 jmc *size = newlen; 254 1.1 jmc return 0; 255 1.9 perry 256 1.1 jmc } 257 1.1 jmc 258 1.1 jmc struct p1212_rom * 259 1.1 jmc p1212_parse(u_int32_t *t, u_int32_t size, u_int32_t mask) 260 1.1 jmc { 261 1.1 jmc 262 1.1 jmc u_int16_t crc, romcrc, crc1; 263 1.1 jmc u_int32_t next, check; 264 1.1 jmc struct p1212_rom *rom; 265 1.1 jmc int i; 266 1.9 perry 267 1.1 jmc check = size; 268 1.1 jmc 269 1.1 jmc if (p1212_iscomplete(t, &check) == -1) { 270 1.1 jmc DPRINTF(("ROM is not complete\n")); 271 1.1 jmc return NULL; 272 1.1 jmc } 273 1.1 jmc if (check != size) { 274 1.1 jmc DPRINTF(("ROM is not complete (check != size)\n")); 275 1.1 jmc return NULL; 276 1.1 jmc } 277 1.1 jmc 278 1.1 jmc /* Calculate both a good and known bad crc. */ 279 1.9 perry 280 1.1 jmc /* CRC's are calculated from everything except the first quad. */ 281 1.9 perry 282 1.9 perry crc = p1212_calc_crc(0, &t[1], P1212_ROMFMT_GET_CRCLEN((ntohl(t[0]))), 283 1.1 jmc 0); 284 1.9 perry 285 1.1 jmc romcrc = P1212_ROMFMT_GET_CRC((ntohl(t[0]))); 286 1.1 jmc if (crc != romcrc) { 287 1.1 jmc crc1 = p1212_calc_crc(0, &t[1], 288 1.1 jmc P1212_ROMFMT_GET_CRCLEN((ntohl(t[0]))), 1); 289 1.1 jmc if (crc1 != romcrc) { 290 1.1 jmc DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated " 291 1.1 jmc "CRC: 0x%04hx, CRC1: 0x%04hx\n", 292 1.1 jmc (unsigned short)romcrc, (unsigned short)crc, 293 1.1 jmc (unsigned short)crc1)); 294 1.1 jmc return NULL; 295 1.1 jmc } 296 1.1 jmc } 297 1.1 jmc 298 1.1 jmc /* Now, walk the ROM. */ 299 1.9 perry 300 1.1 jmc /* Get the initial offset for the root dir. */ 301 1.9 perry 302 1.9 perry rom = malloc(sizeof(struct p1212_rom), M_DEVBUF, M_WAITOK); 303 1.1 jmc rom->len = P1212_ROMFMT_GET_INFOLEN((ntohl(t[0]))); 304 1.1 jmc next = rom->len + 1; 305 1.1 jmc 306 1.1 jmc if ((rom->len < 1) || (rom->len > size)) { 307 1.1 jmc DPRINTF(("Invalid ROM info length: %d\n", rom->len)); 308 1.1 jmc free(rom, M_DEVBUF); 309 1.1 jmc return NULL; 310 1.1 jmc } 311 1.9 perry 312 1.1 jmc /* Exclude the quad which covers the bus name. */ 313 1.1 jmc rom->len--; 314 1.1 jmc 315 1.1 jmc if (rom->len) { 316 1.1 jmc rom->data = malloc(sizeof(u_int32_t) * rom->len, M_DEVBUF, 317 1.1 jmc M_WAITOK); 318 1.2 jmc /* Add 2 to account for info/crc and bus name skipped. */ 319 1.1 jmc for (i = 0; i < rom->len; i++) 320 1.1 jmc rom->data[i] = t[i + 2]; 321 1.1 jmc } 322 1.1 jmc 323 1.1 jmc /* The name field is always 4 bytes and always the 2nd field. */ 324 1.1 jmc strncpy(rom->name, (char *)&t[1], 4); 325 1.1 jmc rom->name[4] = 0; 326 1.9 perry 327 1.1 jmc /* 328 1.1 jmc * Fill out the root directory. All these values are hardcoded so the 329 1.1 jmc * parse/print/match routines have a standard layout to work against. 330 1.1 jmc */ 331 1.9 perry 332 1.2 jmc rom->root = malloc(sizeof(*rom->root), M_DEVBUF, M_WAITOK|M_ZERO); 333 1.1 jmc rom->root->com.key.key_type = P1212_KEYTYPE_Directory; 334 1.1 jmc rom->root->com.key.key_value = 0; 335 1.1 jmc rom->root->com.key.key = (u_int8_t)P1212_KEYTYPE_Directory; 336 1.1 jmc rom->root->com.key.val = 0; 337 1.1 jmc TAILQ_INIT(&rom->root->data_root); 338 1.1 jmc TAILQ_INIT(&rom->root->subdir_root); 339 1.9 perry 340 1.1 jmc if (p1212_parse_directory(rom->root, &t[next], mask)) { 341 1.1 jmc DPRINTF(("Parse error in ROM. Bailing\n")); 342 1.1 jmc p1212_free(rom); 343 1.1 jmc return NULL; 344 1.1 jmc } 345 1.1 jmc return rom; 346 1.1 jmc } 347 1.1 jmc 348 1.1 jmc static int 349 1.1 jmc p1212_parse_directory(struct p1212_dir *root, u_int32_t *addr, u_int32_t mask) 350 1.1 jmc { 351 1.1 jmc struct p1212_dir *dir, *sdir; 352 1.1 jmc struct p1212_data *data; 353 1.1 jmc struct p1212_com *com; 354 1.1 jmc u_int32_t *t, desc; 355 1.1 jmc u_int16_t crclen, crc, crc1, romcrc; 356 1.1 jmc u_int8_t type, val; 357 1.1 jmc unsigned long size; 358 1.1 jmc int i, module_vendor_flag, module_sw_flag, node_sw_flag, unit_sw_flag; 359 1.1 jmc int node_capabilities_flag, offset, unit_location_flag, unitdir_cnt; 360 1.1 jmc int leafoff; 361 1.9 perry 362 1.1 jmc t = addr; 363 1.1 jmc dir = root; 364 1.1 jmc 365 1.1 jmc module_vendor_flag = 0; 366 1.1 jmc module_sw_flag = 0; 367 1.1 jmc node_sw_flag = 0; 368 1.1 jmc node_capabilities_flag = 0; 369 1.1 jmc unitdir_cnt = 0; 370 1.1 jmc offset = 0; 371 1.1 jmc 372 1.9 perry while (dir) { 373 1.1 jmc dir->match = 0; 374 1.1 jmc crclen = P1212_DIRENT_GET_LEN((ntohl(t[offset]))); 375 1.1 jmc romcrc = P1212_DIRENT_GET_CRC((ntohl(t[offset]))); 376 1.9 perry 377 1.1 jmc crc = p1212_calc_crc(0, &t[offset + 1], crclen, 0); 378 1.1 jmc if (crc != romcrc) { 379 1.1 jmc crc1 = p1212_calc_crc(0, &t[offset + 1], crclen, 1); 380 1.1 jmc if (crc1 != romcrc) { 381 1.1 jmc DPRINTF(("Invalid ROM: CRC: 0x%04hx, " 382 1.1 jmc "Calculated CRC: " 383 1.1 jmc "0x%04hx, CRC1: 0x%04hx\n", 384 1.1 jmc (unsigned short)romcrc, 385 1.1 jmc (unsigned short)crc, 386 1.1 jmc (unsigned short)crc1)); 387 1.1 jmc return 1; 388 1.1 jmc } 389 1.1 jmc } 390 1.1 jmc com = NULL; 391 1.1 jmc unit_sw_flag = 0; 392 1.1 jmc unit_location_flag = 0; 393 1.1 jmc offset++; 394 1.9 perry 395 1.1 jmc if ((dir->parent == NULL) && dir->com.key.val) { 396 1.1 jmc DPRINTF(("Invalid root dir. key.val is 0x%0x and not" 397 1.1 jmc " 0x0\n", dir->com.key.val)); 398 1.1 jmc return 1; 399 1.1 jmc } 400 1.1 jmc 401 1.1 jmc for (i = offset; i < (offset + crclen); i++) { 402 1.1 jmc desc = ntohl(t[i]); 403 1.1 jmc type = P1212_DIRENT_GET_KEYTYPE(desc); 404 1.1 jmc val = P1212_DIRENT_GET_KEYVALUE(desc); 405 1.9 perry 406 1.1 jmc /* 407 1.1 jmc * Sanity check for valid types/locations/etc. 408 1.1 jmc * 409 1.1 jmc * See pages 79-100 of 410 1.2 jmc * ISO/IEC 13213:1194(ANSI/IEEE Std 1212, 1994 edition) 411 1.1 jmc * for specifics. 412 1.1 jmc * 413 1.9 perry * XXX: These all really should be broken out into 414 1.1 jmc * subroutines as it's grown large and complicated 415 1.1 jmc * in certain cases. 416 1.1 jmc */ 417 1.1 jmc 418 1.1 jmc switch (val) { 419 1.1 jmc case P1212_KEYVALUE_Unit_Spec_Id: 420 1.1 jmc case P1212_KEYVALUE_Unit_Sw_Version: 421 1.1 jmc case P1212_KEYVALUE_Unit_Dependent_Info: 422 1.1 jmc case P1212_KEYVALUE_Unit_Location: 423 1.1 jmc case P1212_KEYVALUE_Unit_Poll_Mask: 424 1.1 jmc if (dir->parent == NULL) { 425 1.1 jmc DPRINTF(("Invalid ROM: %s is not " 426 1.1 jmc "valid in the root directory.\n", 427 1.1 jmc p1212_keyvalue_strings[val])); 428 1.1 jmc return 1; 429 1.1 jmc } 430 1.1 jmc break; 431 1.1 jmc default: 432 1.1 jmc if (dir->com.key.val == 433 1.1 jmc P1212_KEYVALUE_Unit_Directory) { 434 1.1 jmc DPRINTF(("Invalid ROM: %s is " 435 1.1 jmc "not valid in a unit directory.\n", 436 1.1 jmc p1212_keyvalue_strings[val])); 437 1.1 jmc return 1; 438 1.1 jmc } 439 1.1 jmc break; 440 1.1 jmc } 441 1.9 perry 442 1.1 jmc switch (type) { 443 1.1 jmc case P1212_KEYTYPE_Immediate: 444 1.1 jmc if (p1212_validate_immed(val, mask)) { 445 1.1 jmc DPRINTF(("Invalid ROM: Can't have an " 446 1.2 jmc "immediate type with %s value. Key" 447 1.2 jmc " used at location 0x%0x in ROM\n", 448 1.1 jmc p1212_keyvalue_strings[val], 449 1.1 jmc (unsigned int)(&t[i]-&addr[0]))); 450 1.1 jmc return 1; 451 1.1 jmc } 452 1.1 jmc break; 453 1.1 jmc case P1212_KEYTYPE_Offset: 454 1.1 jmc if (p1212_validate_offset(val, mask)) { 455 1.1 jmc DPRINTF(("Invalid ROM: Can't have " 456 1.1 jmc "an offset type with key %s." 457 1.1 jmc " Used at location 0x%0x in ROM\n", 458 1.1 jmc p1212_keyvalue_strings[val], 459 1.1 jmc (unsigned int)(&t[i]-&addr[0]))); 460 1.1 jmc return 1; 461 1.1 jmc } 462 1.1 jmc break; 463 1.1 jmc case P1212_KEYTYPE_Leaf: 464 1.1 jmc if (p1212_validate_leaf(val, mask)) { 465 1.1 jmc DPRINTF(("Invalid ROM: Can't have a " 466 1.1 jmc "leaf type with %s value. Key " 467 1.1 jmc "used at location 0x%0x in ROM\n", 468 1.1 jmc p1212_keyvalue_strings[val], 469 1.1 jmc (unsigned int)(&t[i]-&addr[0]))); 470 1.1 jmc return 1; 471 1.1 jmc } 472 1.1 jmc break; 473 1.1 jmc case P1212_KEYTYPE_Directory: 474 1.1 jmc if (p1212_validate_dir(val, mask)) { 475 1.1 jmc DPRINTF(("Invalid ROM: Can't have a " 476 1.2 jmc "directory type with %s value. Key" 477 1.2 jmc " used at location 0x%0x in ROM\n", 478 1.1 jmc p1212_keyvalue_strings[val], 479 1.1 jmc (unsigned int)(&t[i]-&addr[0]))); 480 1.1 jmc return 1; 481 1.1 jmc } 482 1.1 jmc break; 483 1.1 jmc default: 484 1.1 jmc panic("Impossible type code: 0x%04hx", 485 1.1 jmc (unsigned short)type); 486 1.1 jmc break; 487 1.1 jmc } 488 1.9 perry 489 1.1 jmc /* Note flags for required fields. */ 490 1.1 jmc 491 1.1 jmc if (val == P1212_KEYVALUE_Module_Vendor_Id) { 492 1.1 jmc module_vendor_flag = 1; 493 1.1 jmc } 494 1.1 jmc 495 1.1 jmc if (val == P1212_KEYVALUE_Node_Capabilities) { 496 1.1 jmc node_capabilities_flag = 1; 497 1.1 jmc } 498 1.9 perry 499 1.1 jmc if (val == P1212_KEYVALUE_Unit_Sw_Version) 500 1.1 jmc unit_sw_flag = 1; 501 1.1 jmc 502 1.1 jmc if (val == P1212_KEYVALUE_Unit_Location) 503 1.1 jmc unit_location_flag = 1; 504 1.9 perry 505 1.1 jmc /* 506 1.1 jmc * This is just easier to spell out. You can't have 507 1.1 jmc * a module sw version if you include a node sw version 508 1.1 jmc * and vice-versa. Both aren't allowed if you have unit 509 1.1 jmc * dirs. 510 1.1 jmc */ 511 1.1 jmc 512 1.1 jmc if (val == P1212_KEYVALUE_Module_Sw_Version) { 513 1.1 jmc if (node_sw_flag) { 514 1.2 jmc DPRINTF(("Can't have a module software" 515 1.2 jmc " version along with a node " 516 1.1 jmc "software version entry\n")); 517 1.1 jmc return 1; 518 1.1 jmc } 519 1.1 jmc if (unitdir_cnt) { 520 1.1 jmc DPRINTF(("Can't have unit directories " 521 1.1 jmc "with module software version " 522 1.1 jmc "defined.\n")); 523 1.1 jmc return 1; 524 1.1 jmc } 525 1.1 jmc module_sw_flag = 1; 526 1.1 jmc } 527 1.1 jmc 528 1.1 jmc if (val == P1212_KEYVALUE_Node_Sw_Version) { 529 1.1 jmc if (module_sw_flag) { 530 1.1 jmc DPRINTF(("Can't have a node software " 531 1.1 jmc "version along with a module " 532 1.1 jmc "software version entry\n")); 533 1.1 jmc return 1; 534 1.1 jmc } 535 1.1 jmc if (unitdir_cnt) { 536 1.1 jmc DPRINTF(("Can't have unit directories " 537 1.1 jmc "with node software version " 538 1.1 jmc "defined.\n")); 539 1.1 jmc return 1; 540 1.1 jmc } 541 1.1 jmc node_sw_flag = 1; 542 1.1 jmc } 543 1.9 perry 544 1.1 jmc if (val == P1212_KEYVALUE_Unit_Directory) { 545 1.1 jmc if (module_sw_flag || node_sw_flag) { 546 1.1 jmc DPRINTF(("Can't have unit directories " 547 1.1 jmc "with either module or node " 548 1.1 jmc "software version defined.\n")); 549 1.1 jmc return 1; 550 1.1 jmc } 551 1.1 jmc unitdir_cnt++; 552 1.1 jmc } 553 1.9 perry 554 1.1 jmc /* 555 1.1 jmc * Text descriptors are special. They describe the 556 1.1 jmc * last entry they follow. So they need to be included 557 1.13 snj * with its struct and there's nothing in the spec 558 1.1 jmc * preventing one from putting text descriptors after 559 1.1 jmc * directory descriptors. Also they can be a single 560 1.1 jmc * value or a list of them in a directory format so 561 1.9 perry * account for either. Finally if they're in a 562 1.9 perry * directory those can be the only types in a 563 1.2 jmc * directory. 564 1.1 jmc */ 565 1.1 jmc 566 1.1 jmc if (val == P1212_KEYVALUE_Textual_Descriptor) { 567 1.1 jmc 568 1.1 jmc size = sizeof(struct p1212_textdata *); 569 1.1 jmc leafoff = P1212_DIRENT_GET_VALUE(desc); 570 1.1 jmc leafoff += i; 571 1.1 jmc 572 1.1 jmc if (com == NULL) { 573 1.2 jmc DPRINTF(("Can't have a text descriptor" 574 1.2 jmc " as the first entry in a " 575 1.1 jmc "directory\n")); 576 1.1 jmc return 1; 577 1.1 jmc } 578 1.1 jmc 579 1.1 jmc if (com->textcnt != 0) { 580 1.1 jmc DPRINTF(("Text descriptors can't " 581 1.1 jmc "follow each other in a " 582 1.1 jmc "directory\n")); 583 1.1 jmc return 1; 584 1.1 jmc } 585 1.1 jmc 586 1.1 jmc if (type == P1212_KEYTYPE_Leaf) { 587 1.1 jmc com->text = 588 1.1 jmc malloc(size, M_DEVBUF, M_WAITOK); 589 1.1 jmc com->text[0] = 590 1.1 jmc p1212_parse_text_desc(&t[leafoff]); 591 1.1 jmc if (com->text[0] == NULL) { 592 1.2 jmc DPRINTF(("Got an error parsing" 593 1.2 jmc " text descriptor at " 594 1.2 jmc "offset 0x%0x\n", 595 1.1 jmc &t[leafoff]-&addr[0])); 596 1.1 jmc free(com->text, M_DEVBUF); 597 1.1 jmc return 1; 598 1.1 jmc } 599 1.1 jmc com->textcnt = 1; 600 1.1 jmc } else { 601 1.9 perry i = p1212_parse_textdir(com, 602 1.1 jmc &t[leafoff]); 603 1.1 jmc if (i) 604 1.1 jmc return 1; 605 1.1 jmc } 606 1.1 jmc } 607 1.1 jmc 608 1.1 jmc if ((type != P1212_KEYTYPE_Directory) && 609 1.1 jmc (val != P1212_KEYVALUE_Textual_Descriptor)) { 610 1.1 jmc data = malloc(sizeof(struct p1212_data), 611 1.1 jmc M_DEVBUF, M_WAITOK|M_ZERO); 612 1.1 jmc data->com.key.key_type = type; 613 1.1 jmc data->com.key.key_value = val; 614 1.1 jmc data->com.key.key = 615 1.1 jmc P1212_DIRENT_GET_KEY((ntohl(t[i]))); 616 1.1 jmc data->com.key.val = 617 1.1 jmc P1212_DIRENT_GET_VALUE((ntohl(t[i]))); 618 1.1 jmc com = &data->com; 619 1.1 jmc 620 1.9 perry /* 621 1.1 jmc * Don't try and read the offset. It may be 622 1.1 jmc * a register or something special. Generally 623 1.1 jmc * these are node specific so let the upper 624 1.1 jmc * level code figure it out. 625 1.1 jmc */ 626 1.1 jmc 627 1.1 jmc if ((type == P1212_KEYTYPE_Immediate) || 628 1.9 perry (type == P1212_KEYTYPE_Offset)) 629 1.1 jmc data->val = data->com.key.val; 630 1.9 perry 631 1.1 jmc data->leafdata = NULL; 632 1.1 jmc TAILQ_INSERT_TAIL(&dir->data_root, data, data); 633 1.9 perry 634 1.1 jmc if (type == P1212_KEYTYPE_Leaf) { 635 1.1 jmc leafoff = i + data->com.key.val; 636 1.1 jmc data->leafdata = 637 1.1 jmc p1212_parse_leaf(&t[leafoff]); 638 1.1 jmc if (data->leafdata == NULL) { 639 1.1 jmc DPRINTF(("Error parsing leaf\n")); 640 1.1 jmc return 1; 641 1.1 jmc } 642 1.1 jmc } 643 1.9 perry } 644 1.1 jmc if (type == P1212_KEYTYPE_Directory) { 645 1.9 perry 646 1.9 perry sdir = malloc(sizeof(struct p1212_dir), 647 1.1 jmc M_DEVBUF, M_WAITOK|M_ZERO); 648 1.1 jmc sdir->parent = dir; 649 1.1 jmc sdir->com.key.key_type = type; 650 1.1 jmc sdir->com.key.key_value = val; 651 1.1 jmc sdir->com.key.key = 652 1.1 jmc P1212_DIRENT_GET_KEY((ntohl(t[i]))); 653 1.1 jmc sdir->com.key.val = 654 1.1 jmc P1212_DIRENT_GET_VALUE((ntohl(t[i]))); 655 1.1 jmc com = &sdir->com; 656 1.1 jmc sdir->match = sdir->com.key.val + i; 657 1.1 jmc TAILQ_INIT(&sdir->data_root); 658 1.1 jmc TAILQ_INIT(&sdir->subdir_root); 659 1.2 jmc TAILQ_INSERT_TAIL(&dir->subdir_root, sdir,dir); 660 1.1 jmc } 661 1.1 jmc } 662 1.1 jmc 663 1.1 jmc /* More validity checks. */ 664 1.1 jmc 665 1.1 jmc if (dir->parent == NULL) { 666 1.1 jmc if (module_vendor_flag == 0) { 667 1.1 jmc DPRINTF(("Missing module vendor entry in root " 668 1.1 jmc "directory.\n")); 669 1.1 jmc return 1; 670 1.1 jmc } 671 1.1 jmc if (node_capabilities_flag == 0) { 672 1.1 jmc DPRINTF(("Missing node capabilities entry in " 673 1.1 jmc "root directory.\n")); 674 1.1 jmc return 1; 675 1.1 jmc } 676 1.1 jmc } else { 677 1.1 jmc if ((unitdir_cnt > 1) && (unit_location_flag == 0)) { 678 1.1 jmc DPRINTF(("Must have a unit location in each " 679 1.1 jmc "unit directory when more than one unit " 680 1.1 jmc "directory exists.\n")); 681 1.1 jmc return 1; 682 1.1 jmc } 683 1.1 jmc } 684 1.1 jmc 685 1.1 jmc /* 686 1.1 jmc * Ok, done with this directory and it's sanity checked. Now 687 1.1 jmc * loop through and either find an unparsed subdir or one 688 1.1 jmc * farther back up the chain. 689 1.1 jmc */ 690 1.1 jmc 691 1.1 jmc if (!TAILQ_EMPTY(&dir->subdir_root)) { 692 1.1 jmc sdir = TAILQ_FIRST(&dir->subdir_root); 693 1.1 jmc } else { 694 1.1 jmc do { 695 1.1 jmc sdir = TAILQ_NEXT(dir, dir); 696 1.1 jmc if (sdir == NULL) { 697 1.1 jmc dir = dir->parent; 698 1.1 jmc } 699 1.1 jmc } while ((sdir == NULL) && (dir != NULL)); 700 1.1 jmc } 701 1.1 jmc if (dir) { 702 1.1 jmc dir = sdir; 703 1.1 jmc if (!dir->match) { 704 1.1 jmc DPRINTF(("Invalid subdir..Has no offset\n")); 705 1.1 jmc return 1; 706 1.1 jmc } 707 1.1 jmc offset = dir->match; 708 1.1 jmc } 709 1.1 jmc } 710 1.1 jmc return 0; 711 1.1 jmc } 712 1.1 jmc 713 1.1 jmc static struct p1212_leafdata * 714 1.1 jmc p1212_parse_leaf(u_int32_t *t) 715 1.1 jmc { 716 1.1 jmc u_int16_t crclen, crc, crc1, romcrc; 717 1.1 jmc struct p1212_leafdata *leafdata; 718 1.1 jmc int i; 719 1.1 jmc 720 1.1 jmc crclen = P1212_DIRENT_GET_LEN((ntohl(t[0]))); 721 1.1 jmc romcrc = P1212_DIRENT_GET_CRC((ntohl(t[0]))); 722 1.1 jmc crc = p1212_calc_crc(0, &t[1], crclen, 0); 723 1.1 jmc crc1 = p1212_calc_crc(0,&t[1], crclen, 1); 724 1.1 jmc if ((crc != romcrc) && (crc1 != romcrc)) { 725 1.1 jmc DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated CRC: " 726 1.1 jmc "0x%04hx, CRC1: 0x%04hx\n", (unsigned short)romcrc, 727 1.1 jmc (unsigned short)crc, (unsigned short)crc1)); 728 1.1 jmc return NULL; 729 1.1 jmc } 730 1.1 jmc t++; 731 1.9 perry 732 1.1 jmc /* 733 1.1 jmc * Most of these are vendor specific so don't bother trying to map them 734 1.1 jmc * out. Anything which needs them later on can extract them. 735 1.1 jmc */ 736 1.1 jmc 737 1.1 jmc leafdata = malloc(sizeof(struct p1212_leafdata), M_DEVBUF, M_WAITOK); 738 1.1 jmc leafdata->data = malloc((sizeof(u_int32_t) * crclen), M_DEVBUF, 739 1.1 jmc M_WAITOK); 740 1.1 jmc leafdata->len = crclen; 741 1.1 jmc for (i = 0; i < crclen; i++) 742 1.2 jmc leafdata->data[i] = ntohl(t[i]); 743 1.1 jmc return leafdata; 744 1.1 jmc } 745 1.1 jmc 746 1.1 jmc static int 747 1.1 jmc p1212_parse_textdir(struct p1212_com *com, u_int32_t *addr) 748 1.1 jmc { 749 1.1 jmc u_int32_t *t, entry, new; 750 1.1 jmc u_int16_t crclen, crc, crc1, romcrc; 751 1.1 jmc u_int8_t type, val; 752 1.1 jmc int i, size; 753 1.1 jmc 754 1.1 jmc /* 755 1.1 jmc * A bit more complicated. A directory for a text descriptor can 756 1.1 jmc * contain text descriptor leaf nodes only. 757 1.1 jmc */ 758 1.9 perry 759 1.1 jmc com->text = NULL; 760 1.1 jmc size = sizeof(struct p1212_text *); 761 1.7 fvdl t = addr; 762 1.9 perry 763 1.1 jmc crclen = P1212_DIRENT_GET_LEN((ntohl(t[0]))); 764 1.1 jmc romcrc = P1212_DIRENT_GET_CRC((ntohl(t[0]))); 765 1.1 jmc crc = p1212_calc_crc(0, &t[1], crclen, 0); 766 1.1 jmc crc1 = p1212_calc_crc(0,&t[1], crclen, 1); 767 1.1 jmc if ((crc != romcrc) && (crc1 != romcrc)) { 768 1.1 jmc DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated CRC: " 769 1.1 jmc "0x%04hx, CRC1: 0x%04hx\n", (unsigned short)romcrc, 770 1.1 jmc (unsigned short)crc, (unsigned short)crc1)); 771 1.1 jmc return 1; 772 1.1 jmc } 773 1.1 jmc t++; 774 1.1 jmc for (i = 0; i < crclen; i++) { 775 1.1 jmc entry = ntohl(t[i]); 776 1.9 perry 777 1.1 jmc type = P1212_DIRENT_GET_KEYTYPE(entry); 778 1.1 jmc val = P1212_DIRENT_GET_KEYVALUE(entry); 779 1.1 jmc if ((type != P1212_KEYTYPE_Leaf) || 780 1.1 jmc (val != P1212_KEYVALUE_Textual_Descriptor)) { 781 1.1 jmc DPRINTF(("Text descriptor directories can only " 782 1.1 jmc "contain text descriptors. Type: %s, value: %s " 783 1.1 jmc "isn't valid at offset 0x%0x\n", 784 1.1 jmc p1212_keytype_strings[type], 785 1.1 jmc p1212_keyvalue_strings[val], &t[i]-&addr[0])); 786 1.1 jmc return 1; 787 1.1 jmc } 788 1.9 perry 789 1.1 jmc new = P1212_DIRENT_GET_VALUE(entry); 790 1.1 jmc com->text = realloc(com->text, size * (com->textcnt + 1), 791 1.1 jmc M_DEVBUF, M_WAITOK); 792 1.1 jmc if ((com->text[i] = p1212_parse_text_desc(&t[i+new])) == NULL) { 793 1.1 jmc DPRINTF(("Got an error parsing text descriptor.\n")); 794 1.1 jmc if (com->textcnt == 0) 795 1.1 jmc free(com->text, M_DEVBUF); 796 1.1 jmc return 1; 797 1.1 jmc } 798 1.1 jmc com->textcnt++; 799 1.1 jmc } 800 1.1 jmc return 0; 801 1.1 jmc } 802 1.1 jmc 803 1.1 jmc static struct p1212_textdata * 804 1.1 jmc p1212_parse_text_desc(u_int32_t *addr) 805 1.1 jmc { 806 1.1 jmc u_int32_t *t; 807 1.1 jmc u_int16_t crclen, crc, crc1, romcrc; 808 1.1 jmc struct p1212_textdata *text; 809 1.1 jmc int size; 810 1.9 perry 811 1.1 jmc t = addr; 812 1.9 perry 813 1.1 jmc crclen = P1212_DIRENT_GET_LEN((ntohl(t[0]))); 814 1.1 jmc romcrc = P1212_DIRENT_GET_CRC((ntohl(t[0]))); 815 1.9 perry 816 1.1 jmc if (crclen < P1212_TEXT_Min_Leaf_Length) { 817 1.1 jmc DPRINTF(("Invalid ROM: text descriptor too short\n")); 818 1.1 jmc return NULL; 819 1.1 jmc } 820 1.1 jmc 821 1.1 jmc crc = p1212_calc_crc(0, &t[1], crclen, 0); 822 1.1 jmc if (crc != romcrc) { 823 1.1 jmc crc1 = p1212_calc_crc(0, &t[1], crclen, 1); 824 1.1 jmc if (crc1 != romcrc) { 825 1.1 jmc DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated CRC: " 826 1.1 jmc "0x%04hx, CRC1: 0x%04hx\n", (unsigned short)romcrc, 827 1.1 jmc (unsigned short)crc, (unsigned short)crc1)); 828 1.1 jmc return NULL; 829 1.1 jmc } 830 1.1 jmc } 831 1.1 jmc 832 1.1 jmc t++; 833 1.1 jmc text = malloc(sizeof(struct p1212_textdata), M_DEVBUF, M_WAITOK); 834 1.1 jmc text->spec_type = P1212_TEXT_GET_Spec_Type((ntohl(t[0]))); 835 1.1 jmc text->spec_id = P1212_TEXT_GET_Spec_Id((ntohl(t[0]))); 836 1.1 jmc text->lang_id = ntohl(t[1]); 837 1.1 jmc 838 1.1 jmc t++; 839 1.1 jmc t++; 840 1.1 jmc crclen -= 2; 841 1.2 jmc size = (crclen * sizeof(u_int32_t)); 842 1.1 jmc 843 1.2 jmc text->text = malloc(size + 1, M_DEVBUF, M_WAITOK|M_ZERO); 844 1.1 jmc 845 1.1 jmc memcpy(text->text, &t[0], size); 846 1.1 jmc 847 1.1 jmc return text; 848 1.1 jmc } 849 1.1 jmc 850 1.1 jmc struct p1212_key ** 851 1.1 jmc p1212_find(struct p1212_dir *root, int type, int value, int flags) 852 1.1 jmc { 853 1.1 jmc struct p1212_key **retkeys; 854 1.1 jmc struct p1212_dir *dir, *sdir, *parent; 855 1.1 jmc struct p1212_data *data; 856 1.1 jmc int numkeys; 857 1.1 jmc 858 1.1 jmc numkeys = 0; 859 1.1 jmc retkeys = NULL; 860 1.9 perry 861 1.1 jmc if ((type < P1212_KEYTYPE_Immediate) || 862 1.1 jmc (type > P1212_KEYTYPE_Directory)) { 863 1.1 jmc #ifdef DIAGNOSTIC 864 1.1 jmc printf("p1212_find: invalid type - %d\n", type); 865 1.1 jmc #endif 866 1.1 jmc return NULL; 867 1.1 jmc } 868 1.1 jmc 869 1.1 jmc if ((value < -1) || 870 1.1 jmc (value > (sizeof(p1212_keyvalue_strings) / sizeof(char *)))) { 871 1.1 jmc #ifdef DIAGNOSTIC 872 1.1 jmc printf("p1212_find: invalid value - %d\n", value); 873 1.1 jmc #endif 874 1.1 jmc return NULL; 875 1.1 jmc } 876 1.9 perry 877 1.1 jmc if (flags & ~(P1212_FIND_SEARCHALL | P1212_FIND_RETURNALL)) { 878 1.1 jmc #ifdef DIAGNOSTIC 879 1.1 jmc printf("p1212_find: invalid flags - %d\n", flags); 880 1.1 jmc #endif 881 1.1 jmc return NULL; 882 1.1 jmc } 883 1.1 jmc 884 1.1 jmc /* 885 1.1 jmc * Part of this is copied from p1212_walk to do depth first traversal 886 1.1 jmc * without using recursion. Using the walk API would have made things 887 1.1 jmc * more complicated in trying to build up the return struct otherwise. 888 1.1 jmc */ 889 1.9 perry 890 1.1 jmc dir = root; 891 1.1 jmc sdir = NULL; 892 1.1 jmc 893 1.1 jmc parent = root->parent; 894 1.1 jmc root->parent = NULL; 895 1.1 jmc 896 1.1 jmc while (dir) { 897 1.1 jmc if (type == P1212_KEYTYPE_Directory) { 898 1.1 jmc TAILQ_FOREACH(sdir, &dir->subdir_root, dir) { 899 1.1 jmc if ((sdir->com.key.key_value == value) || 900 1.1 jmc (value == -1)) { 901 1.1 jmc numkeys++; 902 1.1 jmc retkeys = realloc(retkeys, 903 1.1 jmc sizeof(struct p1212_key *) * 904 1.4 ichiro (numkeys + 1), M_DEVBUF, M_WAITOK); 905 1.1 jmc retkeys[numkeys - 1] = &sdir->com.key; 906 1.1 jmc retkeys[numkeys] = NULL; 907 1.1 jmc if ((flags & P1212_FIND_RETURNALL) 908 1.1 jmc == 0) { 909 1.1 jmc root->parent = parent; 910 1.1 jmc return retkeys; 911 1.1 jmc } 912 1.1 jmc } 913 1.1 jmc } 914 1.1 jmc } else { 915 1.1 jmc TAILQ_FOREACH(data, &dir->data_root, data) { 916 1.1 jmc if (((data->com.key.key_type == type) && 917 1.1 jmc (data->com.key.key_value == value)) || 918 1.1 jmc ((data->com.key.key_type == type) && 919 1.1 jmc (value == -1))) { 920 1.1 jmc numkeys++; 921 1.1 jmc retkeys = realloc(retkeys, 922 1.1 jmc sizeof(struct p1212_key *) * 923 1.4 ichiro (numkeys + 1), M_DEVBUF, M_WAITOK); 924 1.1 jmc retkeys[numkeys - 1] = &data->com.key; 925 1.1 jmc retkeys[numkeys] = NULL; 926 1.1 jmc if ((flags & P1212_FIND_RETURNALL) 927 1.1 jmc == 0) { 928 1.1 jmc root->parent = parent; 929 1.1 jmc return retkeys; 930 1.1 jmc } 931 1.1 jmc } 932 1.1 jmc } 933 1.1 jmc } 934 1.1 jmc if (flags & P1212_FIND_SEARCHALL) { 935 1.1 jmc do { 936 1.1 jmc sdir = TAILQ_NEXT(dir, dir); 937 1.1 jmc if (sdir == NULL) { 938 1.1 jmc dir = dir->parent; 939 1.1 jmc } 940 1.1 jmc } while ((sdir == NULL) && (dir != NULL)); 941 1.1 jmc dir = sdir; 942 1.1 jmc } else 943 1.1 jmc dir = NULL; 944 1.1 jmc } 945 1.1 jmc root->parent = parent; 946 1.1 jmc return retkeys; 947 1.1 jmc } 948 1.1 jmc 949 1.9 perry void 950 1.1 jmc p1212_walk(struct p1212_dir *root, void *arg, 951 1.1 jmc void (*func)(struct p1212_key *, void *)) 952 1.1 jmc { 953 1.1 jmc struct p1212_data *data; 954 1.1 jmc struct p1212_dir *sdir, *dir, *parent; 955 1.1 jmc 956 1.1 jmc dir = root; 957 1.1 jmc sdir = NULL; 958 1.1 jmc 959 1.1 jmc if (func == NULL) { 960 1.1 jmc #ifdef DIAGNOSTIC 961 1.1 jmc printf("p1212_walk: Passed in NULL function\n"); 962 1.1 jmc #endif 963 1.1 jmc return; 964 1.1 jmc } 965 1.1 jmc if (root == NULL) { 966 1.1 jmc #ifdef DIAGNOSTIC 967 1.1 jmc printf("p1212_walk: Called with NULL root\n"); 968 1.1 jmc #endif 969 1.1 jmc return; 970 1.1 jmc } 971 1.9 perry 972 1.1 jmc /* Allow walking from any point. Just mark the starting point. */ 973 1.1 jmc parent = root->parent; 974 1.1 jmc root->parent = NULL; 975 1.9 perry 976 1.1 jmc /* 977 1.1 jmc * Depth first traversal that doesn't use recursion. 978 1.1 jmc * 979 1.1 jmc * Call the function first for the directory node and then loop through 980 1.1 jmc * all the data nodes and call the function for them. 981 1.1 jmc * 982 1.1 jmc * Finally, figure out the next possible directory node if one is 983 1.1 jmc * available or bail out. 984 1.1 jmc */ 985 1.1 jmc 986 1.1 jmc while (dir) { 987 1.1 jmc func((struct p1212_key *) dir, arg); 988 1.9 perry TAILQ_FOREACH(data, &dir->data_root, data) 989 1.1 jmc func((struct p1212_key *) data, arg); 990 1.1 jmc if (!TAILQ_EMPTY(&dir->subdir_root)) { 991 1.1 jmc sdir = TAILQ_FIRST(&dir->subdir_root); 992 1.1 jmc } else { 993 1.1 jmc do { 994 1.1 jmc sdir = TAILQ_NEXT(dir, dir); 995 1.1 jmc if (sdir == NULL) { 996 1.1 jmc dir = dir->parent; 997 1.1 jmc } 998 1.1 jmc } while ((sdir == NULL) && dir); 999 1.1 jmc } 1000 1.1 jmc dir = sdir; 1001 1.9 perry } 1002 1.1 jmc 1003 1.1 jmc root->parent = parent; 1004 1.1 jmc } 1005 1.1 jmc 1006 1.1 jmc void 1007 1.1 jmc p1212_print(struct p1212_dir *dir) 1008 1.1 jmc { 1009 1.1 jmc int indent; 1010 1.9 perry 1011 1.1 jmc indent = 0; 1012 1.9 perry 1013 1.1 jmc p1212_walk(dir, &indent, p1212_print_node); 1014 1.1 jmc printf("\n"); 1015 1.1 jmc } 1016 1.9 perry 1017 1.1 jmc static void 1018 1.1 jmc p1212_print_node(struct p1212_key *key, void *arg) 1019 1.1 jmc { 1020 1.9 perry 1021 1.1 jmc struct p1212_data *data; 1022 1.1 jmc struct p1212_dir *sdir, *dir; 1023 1.1 jmc int i, j, *indent; 1024 1.1 jmc 1025 1.1 jmc indent = arg; 1026 1.1 jmc 1027 1.1 jmc if (key->key_type == P1212_KEYTYPE_Directory) { 1028 1.1 jmc dir = (struct p1212_dir *) key; 1029 1.1 jmc data = NULL; 1030 1.1 jmc } else { 1031 1.1 jmc data = (struct p1212_data *) key; 1032 1.1 jmc dir = NULL; 1033 1.1 jmc } 1034 1.1 jmc 1035 1.1 jmc /* Recompute the indent level on each directory. */ 1036 1.1 jmc if (dir) { 1037 1.1 jmc *indent = 0; 1038 1.1 jmc sdir = dir->parent; 1039 1.1 jmc while (sdir != NULL) { 1040 1.1 jmc (*indent)++; 1041 1.1 jmc sdir = sdir->parent; 1042 1.1 jmc } 1043 1.1 jmc } 1044 1.1 jmc 1045 1.1 jmc if (dir && dir->parent) 1046 1.1 jmc printf("\n"); 1047 1.1 jmc 1048 1.1 jmc /* Set the indent string up. 4 spaces per level. */ 1049 1.1 jmc for (i = 0; i < (*indent * 4); i++) 1050 1.1 jmc printf(" "); 1051 1.9 perry 1052 1.1 jmc if (dir) { 1053 1.1 jmc printf("Directory: "); 1054 1.1 jmc if (dir->print) 1055 1.1 jmc dir->print(dir); 1056 1.1 jmc else { 1057 1.1 jmc if (key->key_value >= 1058 1.9 perry (sizeof(p1212_keyvalue_strings) / sizeof(char *))) 1059 1.1 jmc printf("Unknown type 0x%04hx\n", 1060 1.1 jmc (unsigned short)key->key_value); 1061 1.1 jmc else 1062 1.1 jmc printf("%s\n", 1063 1.1 jmc p1212_keyvalue_strings[key->key_value]); 1064 1.1 jmc } 1065 1.1 jmc if (dir->com.textcnt) { 1066 1.1 jmc for (i = 0; i < dir->com.textcnt; i++) { 1067 1.1 jmc for (j = 0; j < (*indent * 4); j++) 1068 1.1 jmc printf(" "); 1069 1.1 jmc printf("Text descriptor: %s\n", 1070 1.1 jmc dir->com.text[i]->text); 1071 1.1 jmc } 1072 1.1 jmc } 1073 1.1 jmc printf("\n"); 1074 1.1 jmc } else { 1075 1.1 jmc if (data->print) 1076 1.1 jmc data->print(data); 1077 1.1 jmc else { 1078 1.1 jmc if (key->key_value >= 1079 1.9 perry (sizeof(p1212_keyvalue_strings) / sizeof(char *))) 1080 1.1 jmc printf("Unknown type 0x%04hx: ", 1081 1.1 jmc (unsigned short)key->key_value); 1082 1.1 jmc else 1083 1.1 jmc printf("%s: ", 1084 1.1 jmc p1212_keyvalue_strings[key->key_value]); 1085 1.1 jmc 1086 1.1 jmc printf("0x%08x\n", key->val); 1087 1.1 jmc #ifdef DIAGNOSTIC 1088 1.1 jmc if ((data->com.key.key_type == P1212_KEYTYPE_Leaf) && 1089 1.9 perry (data->leafdata == NULL)) 1090 1.1 jmc panic("Invalid data node in configrom tree"); 1091 1.1 jmc #endif 1092 1.9 perry 1093 1.1 jmc if (data->leafdata) { 1094 1.1 jmc for (i = 0; i < data->leafdata->len; i++) { 1095 1.1 jmc for (j = 0; j < (*indent * 4); j++) 1096 1.1 jmc printf(" "); 1097 1.1 jmc printf ("Leaf data: 0x%08x\n", 1098 1.1 jmc data->leafdata->data[i]); 1099 1.1 jmc } 1100 1.1 jmc } 1101 1.9 perry if (data->com.textcnt) 1102 1.1 jmc for (i = 0; i < data->com.textcnt; i++) { 1103 1.1 jmc for (j = 0; j < (*indent * 4); j++) 1104 1.1 jmc printf(" "); 1105 1.1 jmc printf("Text descriptor: %s\n", 1106 1.1 jmc data->com.text[i]->text); 1107 1.1 jmc } 1108 1.9 perry 1109 1.1 jmc } 1110 1.1 jmc } 1111 1.1 jmc } 1112 1.1 jmc 1113 1.1 jmc 1114 1.1 jmc void 1115 1.1 jmc p1212_free(struct p1212_rom *rom) 1116 1.1 jmc { 1117 1.1 jmc struct p1212_dir *sdir, *dir; 1118 1.1 jmc struct p1212_data *data; 1119 1.1 jmc int i; 1120 1.1 jmc 1121 1.1 jmc dir = rom->root; 1122 1.9 perry 1123 1.1 jmc /* Avoid recursing. Find the bottom most node and work back. */ 1124 1.1 jmc while (dir) { 1125 1.1 jmc if (!TAILQ_EMPTY(&dir->subdir_root)) { 1126 1.1 jmc sdir = TAILQ_FIRST(&dir->subdir_root); 1127 1.1 jmc if (TAILQ_EMPTY(&sdir->subdir_root)) { 1128 1.1 jmc TAILQ_REMOVE(&dir->subdir_root, sdir, dir); 1129 1.1 jmc dir = sdir; 1130 1.1 jmc } 1131 1.1 jmc else { 1132 1.1 jmc dir = sdir; 1133 1.1 jmc continue; 1134 1.1 jmc } 1135 1.1 jmc } else { 1136 1.1 jmc if (dir->parent) 1137 1.1 jmc TAILQ_REMOVE(&dir->parent->subdir_root, dir, 1138 1.1 jmc dir); 1139 1.1 jmc } 1140 1.9 perry 1141 1.1 jmc while ((data = TAILQ_FIRST(&dir->data_root))) { 1142 1.1 jmc if (data->leafdata) { 1143 1.1 jmc if (data->leafdata->data) 1144 1.1 jmc free(data->leafdata->data, M_DEVBUF); 1145 1.1 jmc free(data->leafdata, M_DEVBUF); 1146 1.1 jmc } 1147 1.1 jmc TAILQ_REMOVE(&dir->data_root, data, data); 1148 1.1 jmc if (data->com.textcnt) { 1149 1.1 jmc for (i = 0; i < data->com.textcnt; i++) 1150 1.1 jmc free(data->com.text[i], M_DEVBUF); 1151 1.1 jmc free(data->com.text, M_DEVBUF); 1152 1.1 jmc } 1153 1.1 jmc free(data, M_DEVBUF); 1154 1.1 jmc } 1155 1.1 jmc sdir = dir; 1156 1.9 perry if (dir->parent) 1157 1.1 jmc dir = dir->parent; 1158 1.1 jmc else 1159 1.1 jmc dir = NULL; 1160 1.1 jmc if (sdir->com.textcnt) { 1161 1.1 jmc for (i = 0; i < sdir->com.textcnt; i++) 1162 1.1 jmc free(sdir->com.text[i], M_DEVBUF); 1163 1.1 jmc free(sdir->com.text, M_DEVBUF); 1164 1.1 jmc } 1165 1.1 jmc free(sdir, M_DEVBUF); 1166 1.1 jmc } 1167 1.1 jmc if (rom->len) 1168 1.1 jmc free(rom->data, M_DEVBUF); 1169 1.1 jmc free(rom, M_DEVBUF); 1170 1.1 jmc } 1171 1.1 jmc 1172 1.1 jmc /* 1173 1.1 jmc * A fairly well published reference implementation of the CRC routine had 1174 1.1 jmc * a typo in it and some devices may be using it rather than the correct one 1175 1.1 jmc * in calculating their ROM CRC's. To compensate an interface for generating 1176 1.1 jmc * either is provided. 1177 1.1 jmc * 1178 1.1 jmc * len is the number of u_int32_t entries, not bytes. 1179 1.1 jmc */ 1180 1.1 jmc 1181 1.1 jmc static u_int16_t 1182 1.1 jmc p1212_calc_crc(u_int32_t crc, u_int32_t *data, int len, int broke) 1183 1.1 jmc { 1184 1.1 jmc int shift; 1185 1.1 jmc u_int32_t sum; 1186 1.1 jmc int i; 1187 1.9 perry 1188 1.1 jmc for (i = 0; i < len; i++) { 1189 1.1 jmc for (shift = 28; shift > 0; shift -= 4) { 1190 1.1 jmc sum = ((crc >> 12) ^ (ntohl(data[i]) >> shift)) & 1191 1.1 jmc 0x0000000f; 1192 1.1 jmc crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; 1193 1.1 jmc } 1194 1.9 perry 1195 1.9 perry 1196 1.1 jmc /* The broken implementation doesn't do the last shift. */ 1197 1.1 jmc if (!broke) { 1198 1.1 jmc sum = ((crc >> 12) ^ ntohl(data[i])) & 0x0000000f; 1199 1.1 jmc crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; 1200 1.1 jmc } 1201 1.1 jmc } 1202 1.1 jmc return (u_int16_t)crc; 1203 1.1 jmc } 1204 1.1 jmc 1205 1.1 jmc /* 1206 1.1 jmc * This is almost identical to the standard autoconf *match idea except it 1207 1.1 jmc * can match and attach multiple children in one pass. 1208 1.1 jmc */ 1209 1.1 jmc 1210 1.12 cegger device_t * 1211 1.12 cegger p1212_match_units(device_t sc, struct p1212_dir *dir, 1212 1.1 jmc int (*print)(void *, const char *)) 1213 1.1 jmc { 1214 1.1 jmc struct p1212_dir **udirs; 1215 1.12 cegger device_t *devret, *dev; 1216 1.1 jmc int numdev; 1217 1.9 perry 1218 1.1 jmc /* 1219 1.1 jmc * Setup typical return val. Always allocate one extra pointer for a 1220 1.1 jmc * NULL guard end pointer. 1221 1.1 jmc */ 1222 1.1 jmc 1223 1.1 jmc numdev = 0; 1224 1.12 cegger devret = malloc(sizeof(device_t) * 2, M_DEVBUF, M_WAITOK); 1225 1.1 jmc devret[1] = NULL; 1226 1.1 jmc 1227 1.1 jmc udirs = (struct p1212_dir **)p1212_find(dir, P1212_KEYTYPE_Directory, 1228 1.9 perry P1212_KEYVALUE_Unit_Directory, 1229 1.1 jmc P1212_FIND_SEARCHALL|P1212_FIND_RETURNALL); 1230 1.9 perry 1231 1.1 jmc if (udirs) { 1232 1.3 jmc do { 1233 1.14 thorpej dev = config_found(sc, udirs, print, 1234 1.15 thorpej CFARGS(.iattr = "fwnode")); 1235 1.1 jmc if (dev && numdev) { 1236 1.1 jmc devret = realloc(devret, 1237 1.12 cegger sizeof(device_t) * 1238 1.1 jmc (numdev + 2), M_DEVBUF, M_WAITOK); 1239 1.1 jmc devret[numdev++] = dev; 1240 1.1 jmc devret[numdev] = NULL; 1241 1.1 jmc } else if (dev) { 1242 1.1 jmc devret[0] = dev; 1243 1.1 jmc numdev++; 1244 1.1 jmc } 1245 1.3 jmc udirs++; 1246 1.3 jmc } while (*udirs); 1247 1.1 jmc } 1248 1.1 jmc if (numdev == 0) { 1249 1.1 jmc free(devret, M_DEVBUF); 1250 1.1 jmc return NULL; 1251 1.1 jmc } 1252 1.1 jmc return devret; 1253 1.1 jmc } 1254 1.1 jmc 1255 1.9 perry /* 1256 1.1 jmc * Make these their own functions as they have slightly complicated rules. 1257 1.1 jmc * 1258 1.1 jmc * For example: 1259 1.1 jmc * 1260 1.1 jmc * Under normal circumstances only the 2 extent types can be offset 1261 1.1 jmc * types. However some spec's which use p1212 like SBP2 for 1262 1.9 perry * firewire/1394 will define a dependent info type as an offset value. 1263 1.9 perry * Allow the upper level code to flag this and pass it down during 1264 1.1 jmc * parsing. The same thing applies to immediate types. 1265 1.1 jmc */ 1266 1.1 jmc 1267 1.1 jmc static int 1268 1.1 jmc p1212_validate_offset(u_int16_t val, u_int32_t mask) 1269 1.1 jmc { 1270 1.1 jmc if ((val == P1212_KEYVALUE_Node_Units_Extent) || 1271 1.1 jmc (val == P1212_KEYVALUE_Node_Memory_Extent) || 1272 1.1 jmc ((mask & P1212_ALLOW_DEPENDENT_INFO_OFFSET_TYPE) && 1273 1.9 perry ((val == P1212_KEYVALUE_Unit_Dependent_Info) || 1274 1.9 perry (val == P1212_KEYVALUE_Node_Dependent_Info) || 1275 1.1 jmc (val == P1212_KEYVALUE_Module_Dependent_Info)))) 1276 1.1 jmc return 0; 1277 1.1 jmc return 1; 1278 1.1 jmc } 1279 1.1 jmc 1280 1.9 perry static int 1281 1.1 jmc p1212_validate_immed(u_int16_t val, u_int32_t mask) 1282 1.1 jmc { 1283 1.1 jmc switch (val) { 1284 1.1 jmc case P1212_KEYVALUE_Textual_Descriptor: 1285 1.1 jmc case P1212_KEYVALUE_Bus_Dependent_Info: 1286 1.1 jmc case P1212_KEYVALUE_Module_Dependent_Info: 1287 1.1 jmc case P1212_KEYVALUE_Node_Unique_Id: 1288 1.1 jmc case P1212_KEYVALUE_Node_Dependent_Info: 1289 1.1 jmc case P1212_KEYVALUE_Unit_Directory: 1290 1.1 jmc case P1212_KEYVALUE_Unit_Dependent_Info: 1291 1.1 jmc case P1212_KEYVALUE_Unit_Location: 1292 1.1 jmc if ((mask & P1212_ALLOW_DEPENDENT_INFO_IMMED_TYPE) && 1293 1.1 jmc ((val == P1212_KEYVALUE_Module_Dependent_Info) || 1294 1.1 jmc (val == P1212_KEYVALUE_Node_Dependent_Info) || 1295 1.1 jmc (val == P1212_KEYVALUE_Unit_Dependent_Info))) 1296 1.1 jmc break; 1297 1.1 jmc return 1; 1298 1.1 jmc break; 1299 1.1 jmc default: 1300 1.1 jmc break; 1301 1.1 jmc } 1302 1.1 jmc return 0; 1303 1.1 jmc } 1304 1.1 jmc 1305 1.1 jmc static int 1306 1.1 jmc p1212_validate_leaf(u_int16_t val, u_int32_t mask) 1307 1.1 jmc { 1308 1.1 jmc switch(val) { 1309 1.1 jmc case P1212_KEYVALUE_Textual_Descriptor: 1310 1.1 jmc case P1212_KEYVALUE_Bus_Dependent_Info: 1311 1.1 jmc case P1212_KEYVALUE_Module_Dependent_Info: 1312 1.1 jmc case P1212_KEYVALUE_Node_Unique_Id: 1313 1.1 jmc case P1212_KEYVALUE_Node_Dependent_Info: 1314 1.1 jmc case P1212_KEYVALUE_Unit_Dependent_Info: 1315 1.1 jmc case P1212_KEYVALUE_Unit_Location: 1316 1.1 jmc break; 1317 1.1 jmc default: 1318 1.1 jmc return 1; 1319 1.1 jmc break; 1320 1.1 jmc } 1321 1.1 jmc return 0; 1322 1.1 jmc } 1323 1.1 jmc 1324 1.1 jmc static int 1325 1.1 jmc p1212_validate_dir(u_int16_t val, u_int32_t mask) 1326 1.1 jmc { 1327 1.1 jmc switch(val) { 1328 1.1 jmc case P1212_KEYVALUE_Textual_Descriptor: 1329 1.1 jmc case P1212_KEYVALUE_Bus_Dependent_Info: 1330 1.1 jmc case P1212_KEYVALUE_Module_Dependent_Info: 1331 1.1 jmc case P1212_KEYVALUE_Node_Dependent_Info: 1332 1.1 jmc case P1212_KEYVALUE_Unit_Directory: 1333 1.1 jmc case P1212_KEYVALUE_Unit_Dependent_Info: 1334 1.1 jmc break; 1335 1.1 jmc default: 1336 1.2 jmc if ((mask & P1212_ALLOW_VENDOR_DIRECTORY_TYPE) && 1337 1.2 jmc (val == P1212_KEYVALUE_Module_Vendor_Id)) 1338 1.2 jmc break; 1339 1.1 jmc return 1; 1340 1.1 jmc break; 1341 1.1 jmc } 1342 1.1 jmc return 0; 1343 1.1 jmc } 1344