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