xref: /netbsd/sys/arch/prep/prep/residual.c (revision bf9ec67e)
1 /*	$Id: residual.c,v 1.1 2002/05/02 14:36:43 nonaka Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by NONAKA Kimihiro.
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 
42 #include <machine/residual.h>
43 #include <machine/pnp.h>
44 
45 int dump_residual_data = 1;
46 
47 static void make_pnp_device_tree(void *);
48 static void bustype_subr(DEVICE_ID *);
49 
50 #define	NELEMS(array)	((size_t)(sizeof(array)/sizeof(array[0])))
51 
52 static char *FirmwareSupplier[] = {
53 	"IBMFirmware",
54 	"MotoFirmware",
55 	"FirmWorks",
56 	"Bull",
57 };
58 
59 static char *FirmwareSupports[] = {
60 	"Conventional",
61 	"OpenFirmware",
62 	"Diagnostics",
63 	"LowDebug",
64 	"Multiboot",
65 	"LowClient",
66 	"Hex41",
67 	"FAT",
68 	"ISO9660",
69 	"SCSI_InitiatorID_Override",
70 	"Tape_Boot",
71 	"FW_Boot_Path",
72 };
73 
74 static char *EndianSwitchMethod[] = {
75 	"Unknown",
76 	"UsePort92",
77 	"UsePCIConfigA8",
78 	"UseFF001030",
79 };
80 
81 static char *SpreadIOMethod[] = {
82 	"UsePort850",
83 };
84 
85 static char *CacheAttrib[] = {
86 	"None",
87 	"Split cache",
88 	"Combined cache",
89 };
90 
91 static char *Usage[] = {
92 	"FirmwareStack",
93 	"FirmwareHeap",
94 	"FirmwareCode",
95 	"BootImage",
96 	"Free",
97 	"Unpopulated",
98 	"ISAAddr",
99 	"PCIConfig",
100 	"PCIAddr",
101 	"SystemRegs",
102 	"SystemIO",
103 	"IOMemory",
104 	"UnPopSystemROM",
105 	"SystemROM",
106 	"ResumeBlock",
107 	"Other",
108 };
109 
110 static char *BusId[] = {
111 	"ISA",
112 	"EISA",
113 	"PCI",
114 	"PCMCIA",
115 	"ISAPNP",
116 	"MCA",
117 	"MX",
118 	"PROCESSOR",
119 	"VME",
120 };
121 
122 static char *Flags[] = {
123 	"Output",
124 	"Input",
125 	"ConsoleOut",
126 	"ConsoleIn",
127 	"Removable",
128 	"ReadOnly",
129 	"PowerManaged",
130 	"Disableable",
131 	"Configurable",
132 	"Boot",
133 	"Dock",
134 	"Static",
135 	"Failed",
136 	"Integrated",
137 	"Enabled",
138 };
139 
140 static char hextochr[] = "0123456789ABCDEF";
141 
142 void
143 print_residual_device_info(void)
144 {
145 	VPD *vpd;
146 	PPC_CPU *ppc_cpu;
147 	MEM_MAP *mem_map;
148 	PPC_MEM *ppc_mem;
149 	PPC_DEVICE *ppc_dev;
150 	char *str;
151 	unsigned long l;
152 	unsigned short s;
153 	unsigned long nmseg;
154 	unsigned long nmem;
155 	unsigned long ndev;
156 	unsigned long page_size;
157 	int ncpu;
158 	int first;
159 	int i, j;
160 	unsigned char p[4];
161 
162 	if (!dump_residual_data)
163 		return;
164 
165 	if (be32toh(res->ResidualLength) == 0)
166 		return;
167 
168 	printf("ResidualLength = %ld\n", be32toh(res->ResidualLength));
169 	printf("Version = %d\n", res->Version);
170 	printf("Revision = %d\n", res->Revision);
171 	printf("EC = %d\n", be16toh(res->EC));
172 
173 	/*
174 	 * VPD
175 	 */
176 	vpd = &res->VitalProductData;
177 	printf("\nVPD\n");
178 	printf("\tPrintableModel = %-32s\n", vpd->PrintableModel);
179 	printf("\tSerial = %-16s\n", vpd->Serial);
180 
181 	l = be32toh(vpd->FirmwareSupplier);
182 	printf("\tFirmwareSupplier = %s\n",
183 	    (l >= NELEMS(FirmwareSupplier)) ? "Unknown" : FirmwareSupplier[l]);
184 	l = be32toh(vpd->FirmwareSupports);
185 	printf("\tFirmwareSupports = 0x%08lx\n", l);
186 	for (first = 1, i = 0; i < sizeof(unsigned long) * 8; i++) {
187 		if ((l & (1UL << i)) != 0) {
188 			printf("\t\t: %s\n", i >= NELEMS(FirmwareSupports)
189 			    ? "Unknown" : FirmwareSupports[i]);
190 			   first = 0;
191 		}
192 	}
193 	if (first)
194 		printf("\t\t: None\n");
195 
196 	printf("\tNvramSize = %ld\n", be32toh(vpd->NvramSize));
197 	printf("\tNumSIMMSlots = %ld\n", be32toh(vpd->NumSIMMSlots));
198 	s = be16toh(vpd->EndianSwitchMethod);
199 	printf("\tEndianSwitchMethod = %s\n",
200 	    (s >= NELEMS(EndianSwitchMethod))
201 	      ? "Unknown" : EndianSwitchMethod[s]);
202 	s = be16toh(vpd->SpreadIOMethod);
203 	printf("\tSpreadIOMethod = %s\n",
204 	    (s >= NELEMS(SpreadIOMethod)) ? "Unknown" : SpreadIOMethod[s]);
205 	printf("\tSmpIar = %ld\n", be32toh(vpd->SmpIar));
206 	printf("\tRAMErrLogOffset = %ld\n", be32toh(vpd->RAMErrLogOffset));
207 	printf("\tProcessorHz = %ld\n", be32toh(vpd->ProcessorHz));
208 	printf("\tProcessorBusHz = %ld\n", be32toh(vpd->ProcessorBusHz));
209 	printf("\tTimeBaseDivisor = %ld\n", be32toh(vpd->TimeBaseDivisor));
210 	printf("\tWordWidth = %ld\n", be32toh(vpd->WordWidth));
211 	page_size = be32toh(vpd->PageSize);
212 	printf("\tPageSize = %ld\n", page_size);
213 	printf("\tCoherenceBlockSize = %ld\n",be32toh(vpd->CoherenceBlockSize));
214 	printf("\tGranuleSize = %ld\n", be32toh(vpd->GranuleSize));
215 
216 	printf("\tL1 Cache variables\n");
217 	printf("\t\tCacheSize = %ld\n", be32toh(vpd->CacheSize));
218 	l = be32toh(vpd->CacheAttrib);
219 	printf("\t\tCacheAttrib = %s\n",
220 	    (s >= NELEMS(CacheAttrib)) ? "Unknown" : CacheAttrib[s]);
221 	printf("\t\tCacheAssoc = %ld\n", be32toh(vpd->CacheAssoc));
222 	printf("\t\tCacheLineSize = %ld\n", be32toh(vpd->CacheLineSize));
223 
224 	/*
225 	 * PPC_CPU
226 	 */
227 	printf("\n");
228 	printf("MaxNumCpus = %d\n", be16toh(res->MaxNumCpus));
229 	ncpu = be16toh(res->ActualNumCpus);
230 	printf("ActualNumCpus = %d\n", ncpu);
231 	ppc_cpu = res->Cpus;
232 	for (i = 0; i < ((ncpu > MAX_CPUS) ? MAX_CPUS : ncpu); i++) {
233 		printf("%d:\n", i);
234 		printf("\tCpuType = %08lx\n", be32toh(ppc_cpu[i].CpuType));
235 		printf("\tCpuNumber = %d\n", ppc_cpu[i].CpuNumber);
236 		switch (ppc_cpu[i].CpuState) {
237 		case CPU_GOOD:
238 			str = "CPU is present, and active";
239 			break;
240 		case CPU_GOOD_FW:
241 			str = "CPU is present, and in firmware";
242 			break;
243 		case CPU_OFF:
244 			str = "CPU is present, but inactive";
245 			break;
246 		case CPU_FAILED:
247 			str = "CPU is present, but failed POST";
248 			break;
249 		case CPU_NOT_PRESENT:
250 			str = "CPU not present";
251 			break;
252 		default:
253 			str = "Unknown state";
254 			break;
255 		}
256 		printf("\tCpuState: %s (%d)\n", str, ppc_cpu[i].CpuState);
257 	}
258 
259 	printf("\n");
260 	printf("TotalMemory = %ld (0x%08lx)\n",
261 	    be32toh(res->TotalMemory) ,be32toh(res->TotalMemory));
262 	printf("GoodMemory  = %ld (0x%08lx)\n",
263 	    be32toh(res->GoodMemory), be32toh(res->GoodMemory));
264 
265 	/*
266 	 * MEM_MAP
267 	 */
268 	printf("\n");
269 	nmseg = be32toh(res->ActualNumMemSegs);
270 	printf("ActualNumMemSegs = %ld\n", nmseg);
271 	mem_map = res->Segs;
272 	for (i = 0; i < ((nmseg > MAX_MEM_SEGS) ? MAX_MEM_SEGS : nmseg); i++) {
273 		unsigned long pc;
274 
275 		printf("%d:\n", i);
276 		l = be32toh(mem_map[i].Usage);
277 		printf("\tUsage = ");
278 		for (first = 1, j = 0; j < sizeof(unsigned long) * 8; j++) {
279 			if ((l & (1UL << j)) != 0) {
280 				printf("%s%s", first ? "" : ", ",
281 				    j >= NELEMS(Usage) ? "Unknown" : Usage[j]);
282 				first = 0;
283 			}
284 		}
285 		printf(" (0x%08lx)\n", l);
286 		printf("\tBasePage  = 0x%05lx000\n",
287 		    be32toh(mem_map[i].BasePage));
288 		pc = be32toh(mem_map[i].PageCount);
289 		printf("\tPageCount = 0x%08lx (%ld page%s)\n",
290 		    page_size * pc, pc, pc == 1 ? "" : "s");
291 	}
292 
293 	/*
294 	 * PPC_MEM
295 	 */
296 	printf("\n");
297 	nmem = be32toh(res->ActualNumMemories);
298 	printf("ActualNumMemories = %ld\n", nmem);
299 	ppc_mem = res->Memories;
300 	for (i = 0; i < ((nmem > MAX_MEMS) ? MAX_MEMS : nmem); i++) {
301 		printf("%d:\n", i);
302 		printf("\tSIMMSize = %ld MB\n", be32toh(ppc_mem[i].SIMMSize));
303 	}
304 
305 	/*
306 	 * PPC_DEVICE
307 	 */
308 	printf("\n");
309 	ndev = be32toh(res->ActualNumDevices);
310 	printf("ActualNumDevices = %ld\n", ndev);
311 	ppc_dev = res->Devices;
312 	for (i = 0; i < ((ndev > MAX_DEVICES) ? MAX_DEVICES : ndev); i++) {
313 		DEVICE_ID *id = &ppc_dev[i].DeviceId;
314 		BUS_ACCESS *bus = &ppc_dev[i].BusAccess;
315 
316 		printf("\n%d:\n", i);
317 
318 		printf("\tDEVICE_ID\n");
319 		l = be32toh(id->BusId);
320 		printf("\t\tBusId = ");
321 		for (j = 0; j < sizeof(unsigned long) * 8; j++) {
322 			if ((l & (1UL << j)) != 0) {
323 				printf("%s",
324 				    j >= NELEMS(BusId) ? "Unknown" : BusId[j]);
325 				break;
326 			}
327 		}
328 		printf("\n");
329 		l = be32toh(id->DevId);
330 		p[0] = (l >> 24) & 0xff;
331 		p[1] = (l >> 16) & 0xff;
332 		p[2] = (l >> 8) & 0xff;
333 		p[3] = l & 0xff;
334 		printf("\t\tDevId = 0x%08lx (%c%c%c%c%c%c%c)\n", l,
335 		    ((p[0] >> 2) & 0x1f) + 'A' - 1,
336 		    (((p[0] & 0x03) << 3) | ((p[1] >> 5) & 0x07)) + 'A' - 1,
337 		    (p[1] & 0x1f) + 'A' - 1,
338 		    hextochr[(p[2] >> 4) & 0xf], hextochr[p[2] & 0xf],
339 		    hextochr[(p[3] >> 4) & 0xf], hextochr[p[3] & 0xf]);
340 		printf("\t\tSerialNum = 0x%08lx\n", be32toh(id->SerialNum));
341 		l = be32toh(id->Flags);
342 		printf("\t\tFlags = 0x%08lx\n", l);
343 		for (first = 1, j = 0; j < sizeof(unsigned long) * 8; j++) {
344 			if ((l & (1UL << j)) != 0) {
345 				printf("\t\t\t: %s\n",
346 				    j >= NELEMS(Flags) ? "Unknown" : Flags[j]);
347 				first = 0;
348 			}
349 		}
350 		if (first)
351 			printf("\t\t\t: None\n");
352 
353 		bustype_subr(id);
354 
355 		printf("\tBUS_ACCESS\n");
356 		printf("\t\tinfo0 = %d\n", bus->PnPAccess.CSN);
357 		printf("\t\tinfo1 = %d\n", bus->PnPAccess.LogicalDevNumber);
358 
359 		l = be32toh(ppc_dev[i].AllocatedOffset);
360 		printf("\tAllocatedOffset  = 0x%08lx\n", l);
361 		make_pnp_device_tree(res->DevicePnPHeap + l);
362 
363 		l = be32toh(ppc_dev[i].PossibleOffset);
364 		printf("\tPossibleOffset   = 0x%08lx\n", l);
365 		make_pnp_device_tree(res->DevicePnPHeap + l);
366 
367 		l = be32toh(ppc_dev[i].CompatibleOffset);
368 		printf("\tCompatibleOffset = 0x%08lx\n", l);
369 		make_pnp_device_tree(res->DevicePnPHeap + l);
370 	}
371 }
372 
373 enum {
374 	TAG_SMALL = 0,
375 	TAG_LARGE
376 };
377 
378 /*--
379  * pnp device
380  */
381 static int pnp_small_pkt(void *);
382 static int pnp_large_pkt(void *);
383 
384 static void
385 make_pnp_device_tree(void *v)
386 {
387 	unsigned char *p = v;
388 	int size;
389 
390 	if (p == NULL)
391 		return;
392 
393 	for (; p[0] != END_TAG; p += size) {
394 		if (tag_type(p[0]) == TAG_SMALL)
395 			size = pnp_small_pkt(p);
396 		else
397 			size = pnp_large_pkt(p);
398 	}
399 }
400 
401 static int
402 pnp_small_pkt(void *v)
403 {
404 	int tag = *(unsigned char *)v;
405 	int item, size;
406 	int i, j;
407 	int first;
408 
409 	item = tag_small_item_name(tag);
410 	size = tag_small_count(tag) + 1 /* tag */;
411 
412 	switch (item) {
413 	case CompatibleDevice: {
414 		struct _S3_Pack *p = v;
415 		unsigned char *q = p->CompatId;
416 
417 		printf("\t\tCompatibleDevice = %c%c%c%c%c%c%c\n",
418 		    ((q[0] >> 2) & 0x1f) + 'A' - 1,
419 		    (((q[0] & 0x03) << 3) | ((q[1] >> 5) & 0x07)) + 'A' - 1,
420 		    (q[1] & 0x1f) + 'A' - 1,
421 		    hextochr[(q[2] >> 4) & 0xf], hextochr[q[2] & 0xf],
422 		    hextochr[(q[3] >> 4) & 0xf], hextochr[q[3] & 0xf]);
423 		}
424 		break;
425 
426 	case IRQFormat: {
427 		struct _S4_Pack *p = v;
428 
429 		printf("\t\tIRQ: ");
430 		for (first = 1, j = 0; j < 2; j++) {
431 			for (i = 0; i < 8; i++) {
432 				if (p->IRQMask[j] & (1 << i)) {
433 					printf("%s%d",
434 					    first ? "" : ", ", j * 8 + i);
435 					first = 0;
436 				}
437 			}
438 		}
439 		if (first)
440 			printf("None ");
441 
442 		if (size == 3) {
443 			static char *IRQInfo[] = {
444 				"high true edge sensitive",
445 				"low true edge sensitive",
446 				"high true level sensitive",
447 				"low true level sensitive",
448 			};
449 
450 			if (p->IRQInfo & 0xf0)
451 				goto IRQout;
452 
453 			for (first = 1, i = 0; i < NELEMS(IRQInfo); i++) {
454 				if (p->IRQInfo & (1 << i)) {
455 					printf("%s%s", first ? " (" : ", ",
456 					    IRQInfo[i]);
457 					first = 0;
458 				}
459 			}
460 			if (!first)
461 				printf(")");
462 		}
463 IRQout:
464 		printf("\n");
465 		}
466 		break;
467 
468 	case DMAFormat: {
469 		struct _S5_Pack *p = v;
470 
471 		printf("\t\tDMA: ");
472 		for (first = 1, i = 0; i < 8; i++) {
473 			if (p->DMAMask & (1 << i)) {
474 				printf("%s%d", first ? "" : ", ", i);
475 				first = 0;
476 			}
477 		}
478 		printf("%s", first ? "None" : "");
479 
480 		printf("\n");
481 		}
482 		break;
483 
484 	case StartDepFunc:
485 	case EndDepFunc:
486 		break;
487 
488 	case IOPort: {
489 		struct _S8_Pack *p = v;
490 		unsigned short mask;
491 		unsigned short iomin, iomax;
492 		int align, len;
493 
494 		mask = p->IOInfo & ISAAddr16bit ? 0xffff : 0x03ff;
495 		iomin = (p->RangeMin[0] | (p->RangeMin[1] << 8)) & mask;
496 		iomax = (p->RangeMax[0] | (p->RangeMax[1] << 8)) & mask;
497 		align = p->IOAlign;
498 		len = p->IONum;
499 
500 		if (len != 1) {
501 			if (iomin == iomax)
502 				printf("\t\tIOPort: 0x%x-0x%x",
503 				    iomin, iomin + len-1);
504 			else
505 				printf("\t\tIOPort: min 0x%x-0x%x,"
506 				    " max 0x%x-0x%x (%d byte%s align)",
507 				      iomin, iomin + len-1,
508 				      iomax, iomax + len-1,
509 				      align, align != 1 ? "s" : "");
510 		} else {
511 			if (iomin == iomax)
512 				printf("\t\tIOPort: 0x%x", iomin);
513 			else
514 				printf("\t\tIOPort: min 0x%x, max 0x%x"
515 				    " (%d byte%s align)",
516 				      iomin, iomax,
517 				      align, align != 1 ? "s" : "");
518 		}
519 		printf("\n");
520 		}
521 		break;
522 
523 	case FixedIOPort: {
524 		struct _S9_Pack *p = v;
525 		unsigned short ioport;
526 		int len;
527 
528 		ioport = (p->Range[0] | (p->Range[1] << 8)) & 0x3ff;
529 		len = p->IONum;
530 
531 		if (len != 1)
532 			printf("\t\tFixedIOPort: 0x%x-0x%x",
533 			    ioport, ioport + len - 1);
534 		else
535 			printf("\t\tFixedIOPort: 0x%x", ioport);
536 		printf("\n");
537 		}
538 		break;
539 
540 	case SmallVendorItem: {
541 		unsigned char *p = v;
542 
543 		printf("\t\tSmallVendorItem: ");
544 		switch (p[1]) {
545 		case 1:
546 			printf("%c%c%c",
547 			    ((p[2] >> 2) & 0x1f) + 'A' - 1,
548 			    (((p[2] & 3) << 3) | ((p[3] >> 5) & 7)) + 'A' - 1,
549 			    (p[3] & 0x1f) + 'A' - 1);
550 			break;
551 
552 		default:
553 			break;
554 		}
555 
556 		printf("\n");
557 		for (i = 0; i < size - 1; i++) {
558 			if ((i % 16) == 0)
559 				printf("\t\t\t");
560 			printf("%02x ", p[i + 1]);
561 			if ((i % 16) == 15)
562 				printf("\n");
563 		}
564 		if ((i % 16) != 0)
565 			printf("\n");
566 		}
567 		break;
568 
569 	default: {
570 		unsigned char *p = v;
571 
572 		printf("small\n");
573 		printf("item = %d\n", item);
574 		printf("size = %d\n", size);
575 
576 		for (i = 1; i < size; i++)
577 			printf("%02x ", p[i]);
578 		printf("\n");
579 		}
580 		break;
581 	}
582 
583 	return size;
584 }
585 
586 static int
587 pnp_large_pkt(void *v)
588 {
589 	int tag = *(unsigned char *)v;
590 	unsigned char *q = v;
591 	int item, size;
592 	int i;
593 
594 	item = tag_large_item_name(tag);
595 	size = (q[1] | (q[2] << 8)) + 3 /* tag + length */;
596 
597 	switch (item) {
598 	case LargeVendorItem: {
599 		unsigned char *p = v;
600 
601 		printf("\t\tLargeVendorItem:\n");
602 		for (i = 0; i < size - 3; i++) {
603 			if ((i % 16) == 0)
604 				printf("\t\t\t");
605 			printf("%02x ", p[i + 3]);
606 			if ((i % 16) == 15)
607 				printf("\n");
608 		}
609 		if ((i % 16) != 0)
610 			printf("\n");
611 		}
612 		break;
613 
614 	default: {
615 		unsigned char *p = v;
616 
617 		printf("large\n");
618 		printf("item = %d\n", item);
619 		printf("size = %d\n", size);
620 
621 		for (i = 3; i < size; i++)
622 			printf("%02x ", p[i]);
623 		printf("\n");
624 		}
625 		break;
626 	}
627 
628 	return size;
629 }
630 
631 /*--
632  * bus type
633  */
634 static void mass_subr(DEVICE_ID *);
635 static void nic_subr(DEVICE_ID *);
636 static void display_subr(DEVICE_ID *);
637 static void mm_subr(DEVICE_ID *);
638 static void mem_subr(DEVICE_ID *);
639 static void bridge_subr(DEVICE_ID *);
640 static void comm_subr(DEVICE_ID *);
641 static void sys_subr(DEVICE_ID *);
642 static void input_subr(DEVICE_ID *);
643 static void service_subr(DEVICE_ID *);
644 
645 static void
646 bustype_subr(DEVICE_ID *id)
647 {
648 	static struct bustype {
649 		char	*str;
650 		void	(*func)(DEVICE_ID *);
651 	} BaseType[] = {
652 		{ "Reserved"			, NULL },
653 		{ "MassStorageDevice"		, mass_subr },
654 		{ "NetworkInterfaceController"	, nic_subr },
655 		{ "DisplayController"		, display_subr },
656 		{ "MultimediaController"	, mm_subr },
657 		{ "MemoryController"		, mem_subr },
658 		{ "BridgeController"		, bridge_subr },
659 		{ "CommunicationsDevice"	, comm_subr },
660 		{ "SystemPeripheral"		, sys_subr },
661 		{ "InputDevice"			, input_subr },
662 		{ "ServiceProcessor"		, service_subr },
663 	};
664 	int type;
665 
666 	type = (id->BaseType >= NELEMS(BaseType)) ? 0 : id->BaseType;
667 
668 	printf("\t\tBaseType = %s (%d)\n", BaseType[type].str, id->BaseType);
669 	if (BaseType[type].func != NULL)
670 		(*BaseType[type].func)(id);
671 }
672 
673 static void
674 mass_subr(DEVICE_ID *id)
675 {
676 	static char *IDEController_tabel[] = {
677 		"GeneralIDE",
678 		"ATACompatible",
679 	};
680 	static char *FloppyController_table[] = {
681 		"GeneralFloppy",
682 		"Compatible765",
683 		"NS398_Floppy",
684 		"NS26E_Floppy",
685 		"NS15C_Floppy",
686 		"NS2E_Floppy",
687 		"CHRP_Floppy",
688 	};
689 	char *p, *q = NULL;
690 
691 	switch (id->SubType) {
692 	case SCSIController:
693 		p = "SCSIController";
694 		q = "GeneralSCSI";
695 		break;
696 	case IDEController:
697 		p = "IDEController";
698 		q = id->Interface >= NELEMS(IDEController_tabel)
699 		    ? NULL : IDEController_tabel[id->Interface];
700 		break;
701 	case FloppyController:
702 		p = "FloppyController";
703 		q = id->Interface >= NELEMS(FloppyController_table)
704 		    ? NULL : FloppyController_table[id->Interface];
705 		break;
706 	case IPIController:
707 		p = "IPIController";
708 		q = "GeneralIPI";
709 		break;
710 	case OtherMassStorageController:
711 		p = "OtherMassStorageController";
712 		break;
713 	default:
714 		p = "UnknownStorageController";
715 		break;
716 	}
717 
718 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
719 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
720 }
721 
722 static void
723 nic_subr(DEVICE_ID *id)
724 {
725 	char *p, *q = NULL;
726 
727 	switch (id->SubType) {
728 	case EthernetController:
729 		p = "EthernetController";
730 		q = "GeneralEther";
731 		break;
732 	case TokenRingController:
733 		p = "TokenRingController";
734 		q = "GeneralToken";
735 		break;
736 	case FDDIController:
737 		p = "FDDIController";
738 		q = "GeneralFDDI";
739 		break;
740 	case OtherNetworkController:
741 		p = "OtherNetworkController";
742 		break;
743 	default:
744 		p = "UnknownNetworkController";
745 		break;
746 	}
747 
748 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
749 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
750 }
751 
752 static void
753 display_subr(DEVICE_ID *id)
754 {
755 	char *p, *q = NULL;
756 
757 	switch (id->SubType) {
758 	case VGAController:
759 		p = "VGAController";
760 		q = "GeneralVGA";
761 		break;
762 	case SVGAController:
763 		p = "SVGAController";
764 		q = "GeneralSVGA";
765 		break;
766 	case XGAController:
767 		p = "XGAController";
768 		q = "GeneralXGA";
769 		break;
770 	case OtherDisplayController:
771 		p = "OtherDisplayController";
772 		break;
773 	default:
774 		p = "UnknownDisplayController";
775 		break;
776 	}
777 
778 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
779 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
780 }
781 
782 static void
783 mm_subr(DEVICE_ID *id)
784 {
785 	static char *AudioController_table[] = {
786 		"GeneralAudio",
787 		"CS4232Audio",
788 	};
789 	char *p, *q = NULL;
790 
791 	switch (id->SubType) {
792 	case VideoController:
793 		p = "VideoController";
794 		q = "GeneralVideo";
795 		break;
796 	case AudioController:
797 		p = "AudioController";
798 		q = id->Interface >= NELEMS(AudioController_table)
799 		    ? NULL : AudioController_table[id->Interface];
800 		break;
801 	case OtherMultimediaController:
802 		p = "OtherMultimediaController";
803 		break;
804 	default:
805 		p = "UnknownMultimediaController";
806 		break;
807 	}
808 
809 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
810 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
811 }
812 
813 static void
814 mem_subr(DEVICE_ID *id)
815 {
816 	char *p, *q = NULL;
817 
818 	switch (id->SubType) {
819 	case RAM:
820 		p = "RAM";
821 		q = "GeneralRAM";
822 		break;
823 	case FLASH:
824 		p = "FLASH";
825 		q = "GeneralFLASH";
826 		break;
827 	case OtherMemoryDevice:
828 		p = "OtherMemoryDevice";
829 		break;
830 	default:
831 		p = "UnknownMemoryDevice";
832 		break;
833 	}
834 
835 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
836 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
837 }
838 
839 static void
840 bridge_subr(DEVICE_ID *id)
841 {
842 	static char *PCIBridge_table[] = {
843 		"GeneralPCIBridge",
844 		"PCIBridgeIndirect",
845 		"PCIBridgeRS6K",
846 	};
847 	char *p, *q = NULL;
848 
849 	switch (id->SubType) {
850 	case HostProcessorBridge:
851 		p = "HostProcessorBridge";
852 		q = "GeneralHostBridge";
853 		break;
854 	case ISABridge:
855 		p = "ISABridge";
856 		q = "GeneralISABridge";
857 		break;
858 	case EISABridge:
859 		p = "EISABridge";
860 		q = "GeneralEISABridge";
861 		break;
862 	case MicroChannelBridge:
863 		p = "MicroChannelBridge";
864 		q = "GeneralMCABridge";
865 		break;
866 	case PCIBridge:
867 		p = "PCIBridge";
868 		q = id->Interface >= NELEMS(PCIBridge_table)
869 		    ? NULL : PCIBridge_table[id->Interface];
870 		break;
871 	case PCMCIABridge:
872 		p = "PCMCIABridge";
873 		q = "GeneralPCMCIABridge";
874 		break;
875 	case VMEBridge:
876 		p = "VMEBridge";
877 		q = "GeneralVMEBridge";
878 		break;
879 	case OtherBridgeDevice:
880 		p = "OtherBridgeDevice";
881 		break;
882 	default:
883 		p = "UnknownBridgeDevice";
884 		break;
885 	}
886 
887 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
888 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
889 }
890 
891 static void
892 comm_subr(DEVICE_ID *id)
893 {
894 	static char *RS232Device_table[] = {
895 		"GeneralRS232",
896 		"COMx",
897 		"Compatible16450",
898 		"Compatible16550",
899 		"NS398SerPort",
900 		"NS26ESerPort",
901 		"NS15CSerPort",
902 		"NS2ESerPort",
903 	};
904 	static char *ATCompatibleParallelPort_table[] = {
905 		"GeneralParPort",
906 		"LPTx",
907 		"NS398ParPort",
908 		"NS26EParPort",
909 		"NS15CParPort",
910 		"NS2EParPort",
911 	};
912 	char *p, *q = NULL;
913 
914 	switch (id->SubType) {
915 	case RS232Device:
916 		p = "RS232Device";
917 		q = id->Interface >= NELEMS(RS232Device_table)
918 		    ? NULL : RS232Device_table[id->Interface];
919 		break;
920 	case ATCompatibleParallelPort:
921 		p = "ATCompatibleParallelPort";
922 		q = id->Interface >= NELEMS(ATCompatibleParallelPort_table)
923 		    ? NULL : ATCompatibleParallelPort_table[id->Interface];
924 		break;
925 	case OtherCommunicationsDevice:
926 		p = "OtherCommunicationsDevice";
927 		break;
928 	default:
929 		p = "UnknownCommunicationsDevice";
930 		break;
931 	}
932 
933 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
934 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
935 }
936 
937 static void
938 sys_subr(DEVICE_ID *id)
939 {
940 	static char *PIC_table[] = {
941 		"GeneralPIC",
942 		"ISA_PIC",
943 		"EISA_PIC",
944 		"MPIC",
945 		"RS6K_PIC",
946 	};
947 	static char *DMAController_table[] = {
948 		"GeneralDMA",
949 		"ISA_DMA",
950 		"EISA_DMA",
951 	};
952 	static char *SystemTimer_table[] = {
953 		"GeneralTimer",
954 		"ISA_Timer",
955 		"EISA_Timer",
956 	};
957 	static char *RealTimeClock_table[] = {
958 		"GeneralRTC",
959 		"ISA_RTC",
960 	};
961 	static char *L2Cache_table[] = {
962 		"None",
963 		"StoreThruOnly",
964 		"StoreInEnabled",
965 		"RS6KL2Cache",
966 	};
967 	static char *NVRAM_table[] = {
968 		"IndirectNVRAM",
969 		"DirectNVRAM",
970 		"IndirectNVRAM24",
971 	};
972 	static char *PowerManagement_table[] = {
973 		"GeneralPowerManagement",
974 		"EPOWPowerManagement",
975 		"PowerControl",
976 	};
977 	static char *GraphicAssist_table[] = {
978 		"Unknown",
979 		"TransferData",
980 		"IGMC32",
981 		"IGMC64",
982 	};
983 	static char *OperatorPanel_table[] = {
984 		"GeneralOPPanel",
985 		"HarddiskLight",
986 		"CDROMLight",
987 		"PowerLight",
988 		"KeyLock",
989 		"ANDisplay",
990 		"SystemStatusLED",
991 		"CHRP_SystemStatusLED",
992 	};
993 	char *p, *q = NULL;
994 
995 	switch (id->SubType) {
996 	case ProgrammableInterruptController:
997 		p = "ProgrammableInterruptController";
998 		q = id->Interface >= NELEMS(PIC_table)
999 		    ? NULL : PIC_table[id->Interface];
1000 		break;
1001 	case DMAController:
1002 		p = "DMAController";
1003 		q = id->Interface >= NELEMS(DMAController_table)
1004 		    ? NULL : DMAController_table[id->Interface];
1005 		break;
1006 	case SystemTimer:
1007 		p = "SystemTimer";
1008 		q = id->Interface >= NELEMS(SystemTimer_table)
1009 		    ? NULL : SystemTimer_table[id->Interface];
1010 		break;
1011 	case RealTimeClock:
1012 		p = "RealTimeClock";
1013 		q = id->Interface >= NELEMS(RealTimeClock_table)
1014 		    ? NULL : RealTimeClock_table[id->Interface];
1015 		break;
1016 	case L2Cache:
1017 		p = "L2Cache";
1018 		q = id->Interface >= NELEMS(L2Cache_table)
1019 		    ? NULL : L2Cache_table[id->Interface];
1020 		break;
1021 	case NVRAM:
1022 		p = "NVRAM";
1023 		q = id->Interface >= NELEMS(NVRAM_table)
1024 		    ? NULL : NVRAM_table[id->Interface];
1025 		break;
1026 	case PowerManagement:
1027 		p = "PowerManagement";
1028 		q = id->Interface >= NELEMS(PowerManagement_table)
1029 		    ? NULL : PowerManagement_table[id->Interface];
1030 		break;
1031 	case CMOS:
1032 		p = "CMOS";
1033 		q = "GeneralCMOS";
1034 		break;
1035 	case OperatorPanel:
1036 		p = "OperatorPanel";
1037 		q = id->Interface >= NELEMS(OperatorPanel_table)
1038 		    ? NULL : OperatorPanel_table[id->Interface];
1039 		break;
1040 	case ServiceProcessorClass1:
1041 		p = "ServiceProcessorClass1";
1042 		q = "GeneralServiceProcessor";
1043 		break;
1044 	case ServiceProcessorClass2:
1045 		p = "ServiceProcessorClass2";
1046 		q = "GeneralServiceProcessor";
1047 		break;
1048 	case ServiceProcessorClass3:
1049 		p = "ServiceProcessorClass3";
1050 		q = "GeneralServiceProcessor";
1051 		break;
1052 	case GraphicAssist:
1053 		p = "GraphicAssist";
1054 		q = id->Interface >= NELEMS(GraphicAssist_table)
1055 		    ? NULL : GraphicAssist_table[id->Interface];
1056 		break;
1057 	case SystemPlanar:
1058 		p = "SystemPlanar";
1059 		q = "GeneralSystemPlanar";
1060 		break;
1061 	case OtherSystemPeripheral:
1062 		p = "OtherSystemPeripheral";
1063 		break;
1064 	default:
1065 		p = "UnknownSystemPeripheral";
1066 		break;
1067 	}
1068 
1069 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
1070 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
1071 }
1072 
1073 static void
1074 input_subr(DEVICE_ID *id)
1075 {
1076 	char *p, *q = NULL;
1077 
1078 	switch (id->SubType) {
1079 	case KeyboardController:
1080 		p = "KeyboardController";
1081 		break;
1082 	case Digitizer:
1083 		p = "Digitizer";
1084 		break;
1085 	case MouseController:
1086 		p = "MouseController";
1087 		break;
1088 	case TabletController:
1089 		p = "TabletController";
1090 		break;
1091 	case OtherInputController:
1092 		p = "OtherInputController";
1093 		break;
1094 	default:
1095 		p = "UnknownInputController";
1096 		break;
1097 	}
1098 
1099 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
1100 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
1101 }
1102 
1103 static void
1104 service_subr(DEVICE_ID *id)
1105 {
1106 	char *p, *q = NULL;
1107 
1108 	switch (id->SubType) {
1109 	case GeneralMemoryController:
1110 		p = "GeneralMemoryController";
1111 		break;
1112 	default:
1113 		p = "UnknownMemoryController";
1114 		break;
1115 	}
1116 
1117 	printf("\t\tSubType = %s (%d)\n", p, id->SubType);
1118 	printf("\t\tInterface = %s (%d)\n", q ? q : "None", id->Interface);
1119 }
1120