1 /*
2  * pnpdump - PnP BIOS information dumper
3  */
4 
5 #include <windows.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <conio.h>
10 
11 #include <ntddk.h>
12 
13 #include <pshpack1.h>
14 
15 typedef struct _CM_PNP_BIOS_DEVICE_NODE
16 {
17   USHORT Size;
18   UCHAR Node;
19   ULONG ProductId;
20   UCHAR DeviceType[3];
21   USHORT DeviceAttributes;
22 } CM_PNP_BIOS_DEVICE_NODE,*PCM_PNP_BIOS_DEVICE_NODE;
23 
24 typedef struct _CM_PNP_BIOS_INSTALLATION_CHECK
25 {
26   UCHAR Signature[4];             // $PnP (ascii)
27   UCHAR Revision;
28   UCHAR Length;
29   USHORT ControlField;
30   UCHAR Checksum;
31   ULONG EventFlagAddress;         // Physical address
32   USHORT RealModeEntryOffset;
33   USHORT RealModeEntrySegment;
34   USHORT ProtectedModeEntryOffset;
35   ULONG ProtectedModeCodeBaseAddress;
36   ULONG OemDeviceId;
37   USHORT RealModeDataBaseAddress;
38   ULONG ProtectedModeDataBaseAddress;
39 } CM_PNP_BIOS_INSTALLATION_CHECK, *PCM_PNP_BIOS_INSTALLATION_CHECK;
40 
41 #include <poppack.h>
42 
43 typedef struct _PNP_ID_NAME_
44 {
45   char *PnpId;
46   char *DeviceName;
47 } PNP_ID_NAME, *PPNP_ID_NAME;
48 
49 
50 static char Hex[] = "0123456789ABCDEF";
51 
52 static PNP_ID_NAME PnpName[] =
53 {
54   /* Interrupt Controllers */
55   {"PNP0000", "AT Interrupt Controller"},
56   {"PNP0001", "EISA Interrupt Controller"},
57   {"PNP0002", "MCA Interrupt Controller"},
58   {"PNP0003", "APIC"},
59   {"PNP0004", "Cyrix SLiC MP Interrupt Controller"},
60 
61   /* Timers */
62   {"PNP0100", "AT Timer"},
63   {"PNP0101", "EISA Timer"},
64   {"PNP0102", "MCA Timer"},
65 
66   /* DMA Controllers */
67   {"PNP0200", "AT DMA Controller"},
68   {"PNP0201", "EISA DMA Controller"},
69   {"PNP0202", "MCA DMA Controller"},
70 
71   /* Keyboards */
72   {"PNP0300", "IBM PC/XT Keyboard (83 keys)"},
73   {"PNP0301", "IBM PC/AT Keyboard (86 keys)"},
74   {"PNP0302", "IBM PC/XT Keyboard (84 keys)"},
75   {"PNP0303", "IBM Enhanced (101/102 keys)"},
76   {"PNP0304", "Olivetti Keyboard (83 keys)"},
77   {"PNP0305", "Olivetti Keyboard (102 keys)"},
78   {"PNP0306", "Olivetti Keyboard (86 keys)"},
79   {"PNP0307", "Microsoft Windows(R) Keyboard"},
80   {"PNP0308", "General Input Device Emulation Interface (GIDEI) legacy"},
81   {"PNP0309", "Olivetti Keyboard (A101/102 key)"},
82   {"PNP030A", "AT&T 302 keyboard"},
83   {"PNP030B", "Reserved by Microsoft"},
84   {"PNP0320", "Japanese 101-key keyboard"},
85   {"PNP0321", "Japanese AX keyboard"},
86   {"PNP0322", "Japanese 106-key keyboard A01"},
87   {"PNP0323", "Japanese 106-key keyboard 002/003"},
88   {"PNP0324", "Japanese 106-key keyboard 001"},
89   {"PNP0325", "Japanese Toshiba Desktop keyboard"},
90   {"PNP0326", "Japanese Toshiba Laptop keyboard"},
91   {"PNP0327", "Japanese Toshiba Notebook keyboard"},
92   {"PNP0340", "Korean 84-key keyboard"},
93   {"PNP0341", "Korean 86-key keyboard"},
94   {"PNP0342", "Korean Enhanced keyboard"},
95   {"PNP0343", "Korean Enhanced keyboard 101b"},
96   {"PNP0343", "Korean Enhanced keyboard 101c"},
97   {"PNP0344", "Korean Enhanced keyboard 103"},
98 
99   /* Parallel Ports */
100   {"PNP0400", "Standard LPT printer port"},
101   {"PNP0401", "ECP printer port"},
102 
103   /* Serial Ports */
104   {"PNP0500", "Standard PC COM port"},
105   {"PNP0501", "16550A-compatible COM port"},
106   {"PNP0510", "Generic IRDA-compatible port"},
107 
108   /* Harddisk Controllers */
109   {"PNP0600", "Generic ESDI/ATA/IDE harddisk controller"},
110   {"PNP0601", "Plus Hardcard II"},
111   {"PNP0602", "Plus Hardcard IIXL/EZ"},
112   {"PNP0603", "Generic IDE supporting Microsoft Device Bay Specification"},
113 
114   /* Floppy Controllers */
115   {"PNP0700", "PC standard floppy disk controller"},
116   {"PNP0701", "Standard floppy controller supporting MS Device Bay Specification"},
117 
118   /* obsolete devices */
119   {"PNP0800", "Microsoft Sound System compatible device"},
120 
121   /* Display Adapters */
122   {"PNP0900", "VGA Compatible"},
123   {"PNP0901", "Video Seven VRAM/VRAM II/1024i"},
124   {"PNP0902", "8514/A Compatible"},
125   {"PNP0903", "Trident VGA"},
126   {"PNP0904", "Cirrus Logic Laptop VGA"},
127   {"PNP0905", "Cirrus Logic VGA"},
128   {"PNP0906", "Tseng ET4000"},
129   {"PNP0907", "Western Digital VGA"},
130   {"PNP0908", "Western Digital Laptop VGA"},
131   {"PNP0909", "S3 Inc. 911/924"},
132   {"PNP090A", "ATI Ultra Pro/Plus (Mach 32)"},
133   {"PNP090B", "ATI Ultra (Mach 8)"},
134   {"PNP090C", "XGA Compatible"},
135   {"PNP090D", "ATI VGA Wonder"},
136   {"PNP090E", "Weitek P9000 Graphics Adapter"},
137   {"PNP090F", "Oak Technology VGA"},
138   {"PNP0910", "Compaq QVision"},
139   {"PNP0911", "XGA/2"},
140   {"PNP0912", "Tseng Labs W32/W32i/W32p"},
141   {"PNP0913", "S3 Inc. 801/928/964"},
142   {"PNP0914", "Cirrus Logic 5429/5434 (memory mapped)"},
143   {"PNP0915", "Compaq Advanced VGA (AVGA)"},
144   {"PNP0916", "ATI Ultra Pro Turbo (Mach64)"},
145   {"PNP0917", "Reserved by Microsoft"},
146   {"PNP0918", "Matrox MGA"},
147   {"PNP0919", "Compaq QVision 2000"},
148   {"PNP091A", "Tseng W128"},
149   {"PNP0930", "Chips & Technologies Super VGA"},
150   {"PNP0931", "Chips & Technologies Accelerator"},
151   {"PNP0940", "NCR 77c22e Super VGA"},
152   {"PNP0941", "NCR 77c32blt"},
153   {"PNP09FF", "Plug and Play Monitors (VESA DDC)"},
154 
155   /* Peripheral Buses */
156   {"PNP0A00", "ISA Bus"},
157   {"PNP0A01", "EISA Bus"},
158   {"PNP0A02", "MCA Bus"},
159   {"PNP0A03", "PCI Bus"},
160   {"PNP0A04", "VESA/VL Bus"},
161   {"PNP0A05", "Generic ACPI Bus"},
162   {"PNP0A06", "Generic ACPI Extended-IO Bus (EIO bus)"},
163 
164   /* System devices */
165   {"PNP0800", "AT-style speaker sound"},
166   {"PNP0B00", "AT Real-Time Clock"},
167   {"PNP0C00", "Plug and Play BIOS (only created by the root enumerator)"},
168   {"PNP0C01", "System Board"},
169   {"PNP0C02", "General Plug and Play motherboard registers."},
170   {"PNP0C03", "Plug and Play BIOS Event Notification Interrupt"},
171   {"PNP0C04", "Math Coprocessor"},
172   {"PNP0C05", "APM BIOS (Version independent)"},
173   {"PNP0C06", "Reserved for identification of early Plug and Play BIOS implementation"},
174   {"PNP0C07", "Reserved for identification of early Plug and Play BIOS implementation"},
175   {"PNP0C08", "ACPI system board hardware"},
176   {"PNP0C09", "ACPI Embedded Controller"},
177   {"PNP0C0A", "ACPI Control Method Battery"},
178   {"PNP0C0B", "ACPI Fan"},
179   {"PNP0C0C", "ACPI power button device"},
180   {"PNP0C0D", "ACPI lid device"},
181   {"PNP0C0E", "ACPI sleep button device"},
182   {"PNP0C0F", "PCI interrupt link device"},
183   {"PNP0C10", "ACPI system indicator device"},
184   {"PNP0C11", "ACPI thermal zone"},
185   {"PNP0C12", "Device Bay Controller"},
186 
187   /* PCMCIA Controllers */
188   {"PNP0E00", "Intel 82365-Compatible PCMCIA Controller"},
189   {"PNP0E01", "Cirrus Logic CL-PD6720 PCMCIA Controller"},
190   {"PNP0E02", "VLSI VL82C146 PCMCIA Controller"},
191   {"PNP0E03", "Intel 82365-compatible CardBus controller"},
192 
193   /* Mice */
194   {"PNP0F00", "Microsoft Bus Mouse"},
195   {"PNP0F01", "Microsoft Serial Mouse"},
196   {"PNP0F02", "Microsoft InPort Mouse"},
197   {"PNP0F03", "Microsoft PS/2-style Mouse"},
198   {"PNP0F04", "Mouse Systems Mouse"},
199   {"PNP0F05", "Mouse Systems 3-Button Mouse (COM2)"},
200   {"PNP0F06", "Genius Mouse (COM1)"},
201   {"PNP0F07", "Genius Mouse (COM2)"},
202   {"PNP0F08", "Logitech Serial Mouse"},
203   {"PNP0F09", "Microsoft BallPoint Serial Mouse"},
204   {"PNP0F0A", "Microsoft Plug and Play Mouse"},
205   {"PNP0F0B", "Microsoft Plug and Play BallPoint Mouse"},
206   {"PNP0F0C", "Microsoft-compatible Serial Mouse"},
207   {"PNP0F0D", "Microsoft-compatible InPort-compatible Mouse"},
208   {"PNP0F0E", "Microsoft-compatible PS/2-style Mouse"},
209   {"PNP0F0F", "Microsoft-compatible Serial BallPoint-compatible Mouse"},
210   {"PNP0F10", "Texas Instruments QuickPort Mouse"},
211   {"PNP0F11", "Microsoft-compatible Bus Mouse"},
212   {"PNP0F12", "Logitech PS/2-style Mouse"},
213   {"PNP0F13", "PS/2 Port for PS/2-style Mice"},
214   {"PNP0F14", "Microsoft Kids Mouse"},
215   {"PNP0F15", "Logitech bus mouse"},
216   {"PNP0F16", "Logitech SWIFT device"},
217   {"PNP0F17", "Logitech-compatible serial mouse"},
218   {"PNP0F18", "Logitech-compatible bus mouse"},
219   {"PNP0F19", "Logitech-compatible PS/2-style Mouse"},
220   {"PNP0F1A", "Logitech-compatible SWIFT Device"},
221   {"PNP0F1B", "HP Omnibook Mouse"},
222   {"PNP0F1C", "Compaq LTE Trackball PS/2-style Mouse"},
223   {"PNP0F1D", "Compaq LTE Trackball Serial Mouse"},
224   {"PNP0F1E", "Microsoft Kids Trackball Mouse"},
225   {"PNP0F1F", "Reserved by Microsoft Input Device Group"},
226   {"PNP0F20", "Reserved by Microsoft Input Device Group"},
227   {"PNP0F21", "Reserved by Microsoft Input Device Group"},
228   {"PNP0F22", "Reserved by Microsoft Input Device Group"},
229   {"PNP0F23", "Reserved by Microsoft Input Device Group"},
230   {"PNP0FFF", "Reserved by Microsoft Systems"},
231 
232   /* List Terminator */
233   {NULL, NULL}
234 };
235 
236 
237 /* FUNCTIONS ****************************************************************/
238 
239 static char *
240 GetDeviceName(char *PnpId)
241 {
242   PPNP_ID_NAME IdName;
243 
244   IdName = PnpName;
245   while (IdName->PnpId != NULL)
246     {
247       if (!strcmp(IdName->PnpId, PnpId))
248 	return IdName->DeviceName;
249 
250       IdName++;
251     }
252 
253   return "Unknown Device";
254 }
255 
256 
257 LONG
258 GetPnpKey(PHKEY PnpKey)
259 {
260   LONG lError;
261   char szBuffer[80];
262   HKEY hAdapterKey;
263   HKEY hBusKey;
264   DWORD dwBus;
265   DWORD dwType;
266   DWORD dwSize;
267 
268   *PnpKey = 0;
269 
270   lError = RegOpenKey(HKEY_LOCAL_MACHINE,
271 		      "HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter",
272 		      &hAdapterKey);
273   if (lError != ERROR_SUCCESS)
274     return 0;
275 
276   /* Enumerate buses */
277   for (dwBus = 0; ; dwBus++)
278     {
279       sprintf(szBuffer, "%lu", dwBus);
280 
281       lError = RegOpenKey(hAdapterKey,
282 			  szBuffer,
283 			  &hBusKey);
284       if (lError != ERROR_SUCCESS)
285 	{
286 	  RegCloseKey(hAdapterKey);
287 	  return lError;
288 	}
289 
290       dwSize = 80;
291       lError = RegQueryValueEx(hBusKey,
292 			       "Identifier",
293 			       NULL,
294 			       &dwType,
295 			       (LPBYTE)szBuffer,
296 			       &dwSize);
297       if (lError != ERROR_SUCCESS)
298 	{
299 	  RegCloseKey(hBusKey);
300 	  RegCloseKey(hAdapterKey);
301 	  return lError;
302 	}
303 
304       if (dwType == REG_SZ && stricmp(szBuffer, "pnp bios") == 0)
305 	{
306 	  *PnpKey = hBusKey;
307 	  RegCloseKey(hAdapterKey);
308 	  return ERROR_SUCCESS;
309 	}
310 
311       RegCloseKey(hBusKey);
312     }
313 
314   return 1;
315 }
316 
317 
318 static VOID
319 PnpDecodeIrq(unsigned char *Ptr)
320 {
321   USHORT IrqMask;
322   int i;
323 
324   IrqMask = *Ptr;
325   Ptr++;
326   IrqMask |= (*Ptr << 8);
327 
328   printf("      IRQs:");
329 
330   for (i = 0; i < 16; i++)
331     {
332       if (IrqMask & (1 << i))
333 	{
334 	  printf(" %u", i);
335 	}
336     }
337 
338   printf("\n");
339 }
340 
341 
342 static VOID
343 PnpDecodeDma(unsigned char *Ptr)
344 {
345   unsigned char DmaChannel;
346   unsigned char DmaStatus;
347   int i;
348 
349   DmaChannel = *Ptr;
350   Ptr++;
351   DmaStatus = *Ptr;
352 
353   printf("      DMAs:");
354 
355   for (i = 0; i < 8; i++)
356     {
357       if (DmaChannel & (1 << i))
358 	{
359 	  printf(" %u", i);
360 	}
361     }
362 
363   printf("\n");
364 }
365 
366 
367 static VOID
368 PnpDecodeIoPort(unsigned char *Ptr)
369 {
370   USHORT MinBase;
371   USHORT MaxBase;
372   UCHAR Align;
373   UCHAR Length;
374 
375   // Info = *Ptr;
376   Ptr++;
377   MinBase = *Ptr;
378   Ptr++;
379   MinBase += (*Ptr << 8);
380   Ptr++;
381   MaxBase = *Ptr;
382   Ptr++;
383   MaxBase += (*Ptr << 8);
384   Ptr++;
385   Align = *Ptr;
386   Ptr++;
387   Length = *Ptr;
388 
389   printf("  I/O Port descriptor\n");
390   printf("    MinBase 0x%x  MaxBase 0x%x  Align %u  Length %u\n",
391 	 MinBase, MaxBase, Align, Length);
392 }
393 
394 
395 static VOID
396 PnpDecodeFixedIoPort(unsigned char *Ptr)
397 {
398   USHORT IoPort;
399   UCHAR Length;
400 
401   IoPort = *Ptr;
402   Ptr++;
403   IoPort += (*Ptr << 8);
404   Ptr++;
405   Length = *Ptr;
406 
407   printf("  Fixed I/O Port descriptor\n");
408   printf("    PortBase 0x%hx  Length 0x%x\n",
409 	 IoPort, Length);
410 
411 #if 0
412   if (Length == 1)
413     {
414       printf("  Fixed location I/O Port descriptor: 0x%x\n",
415 	     IoPort);
416     }
417   else
418     {
419       printf("  Fixed location I/O Port descriptor: 0x%x - 0x%x\n",
420 	     IoPort,
421 	     IoPort + Length - 1);
422     }
423 #endif
424 }
425 
426 
427 static VOID
428 PnpDecodeMemory16(unsigned char *Ptr)
429 {
430   UCHAR Info;
431   USHORT MinBase;
432   USHORT MaxBase;
433   USHORT Align;
434   USHORT Length;
435 
436   Info = *Ptr;
437   Ptr++;
438 
439   MinBase = *Ptr;
440   Ptr++;
441   MinBase += (*Ptr << 8);
442   Ptr++;
443 
444   MaxBase = *Ptr;
445   Ptr++;
446   MaxBase += (*Ptr << 8);
447   Ptr++;
448 
449   Align = *Ptr;
450   Ptr++;
451   Align += (*Ptr << 8);
452   Ptr++;
453 
454   Length = *Ptr;
455   Ptr++;
456   Length += (*Ptr << 8);
457 
458   printf("  16-Bit memory range descriptor\n");
459   printf("    MinBase 0x%hx  MaxBase 0x%hx  Align 0x%hx  Length 0x%hx  Flags 0x%02x\n",
460 	 MinBase, MaxBase, Align,Length, Info);
461 }
462 
463 
464 static VOID
465 PnpDecodeMemory32(unsigned char *Ptr)
466 {
467   UCHAR Info;
468   ULONG MinBase;
469   ULONG MaxBase;
470   ULONG Align;
471   ULONG Length;
472 
473   Info = *Ptr;
474   Ptr++;
475 
476   MinBase = *Ptr;
477   Ptr++;
478   MinBase += (*Ptr << 8);
479   Ptr++;
480   MinBase += (*Ptr << 16);
481   Ptr++;
482   MinBase += (*Ptr << 24);
483   Ptr++;
484 
485   MaxBase = *Ptr;
486   Ptr++;
487   MaxBase += (*Ptr << 8);
488   Ptr++;
489   MaxBase += (*Ptr << 16);
490   Ptr++;
491   MaxBase += (*Ptr << 24);
492   Ptr++;
493 
494   Align = *Ptr;
495   Ptr++;
496   Align += (*Ptr << 8);
497   Ptr++;
498   Align += (*Ptr << 16);
499   Ptr++;
500   Align += (*Ptr << 24);
501   Ptr++;
502 
503   Length = *Ptr;
504   Ptr++;
505   Length += (*Ptr << 8);
506   Ptr++;
507   Length += (*Ptr << 16);
508   Ptr++;
509   Length += (*Ptr << 24);
510 
511   printf("  32-Bit memory range descriptor\n");
512   printf("    MinBase 0x%lx  MaxBase 0x%lx  Align 0x%lx  Length 0x%lx  Flags 0x%02x\n",
513 	 MinBase, MaxBase, Align,Length, Info);
514 }
515 
516 
517 static VOID
518 PnpDecodeFixedMemory(unsigned char *Ptr)
519 {
520   UCHAR Info;
521   ULONG Base;
522   ULONG Length;
523 
524   Info = *Ptr;
525   Ptr++;
526 
527   Base = *Ptr;
528   Ptr++;
529   Base += (*Ptr << 8);
530   Ptr++;
531   Base += (*Ptr << 16);
532   Ptr++;
533   Base += (*Ptr << 24);
534   Ptr++;
535 
536   Length = *Ptr;
537   Ptr++;
538   Length += (*Ptr << 8);
539   Ptr++;
540   Length += (*Ptr << 16);
541   Ptr++;
542   Length += (*Ptr << 24);
543 
544   printf("  32-Bit fixed location memory range descriptor\n");
545   printf("    Base 0x%lx  Length 0x%lx  Flags 0x%02x\n",
546 	 Base, Length, Info);
547 }
548 
549 
550 void PrintDeviceData (PCM_PNP_BIOS_DEVICE_NODE DeviceNode)
551 {
552   char PnpId[8];
553   unsigned char *Ptr;
554   unsigned int TagSize;
555   unsigned int TagType;
556 
557   unsigned char Id[4];
558 
559   printf ("Node: %x  Size %hu (0x%hx)\n",
560 	  DeviceNode->Node,
561 	  DeviceNode->Size,
562 	  DeviceNode->Size);
563 
564   memcpy(Id, &DeviceNode->ProductId, 4);
565 
566   PnpId[0] = ((Id[0] >> 2) & 0x1F) + 0x40;
567   PnpId[1] = ((Id[0] << 3) & 0x18) +
568 	     ((Id[1] >> 5) & 0x07) + 0x40;
569   PnpId[2] = (Id[1] & 0x1F) + 0x40;
570 
571   PnpId[3] = Hex[(Id[2] >> 4) & 0xF];
572   PnpId[4] = Hex[Id[2] & 0x0F];
573 
574   PnpId[5] = Hex[(Id[3] >> 4) & 0x0F];
575   PnpId[6] = Hex[Id[3] & 0x0F];
576   PnpId[7] = 0;
577 
578   printf("  '%s' (%s)\n",
579 	 PnpId, GetDeviceName(PnpId));
580 
581   if (DeviceNode->Size > sizeof(CM_PNP_BIOS_DEVICE_NODE))
582     {
583       Ptr = (unsigned char *)(DeviceNode + 1);
584       while (TRUE)
585 	{
586 	  if (*Ptr & 0x80)
587 	    {
588 	      TagType = *Ptr & 0x7F;
589 	      Ptr++;
590 	      TagSize = *Ptr;
591 	      Ptr++;
592 	      TagSize += (*Ptr << 16);
593 	      Ptr++;
594 
595 
596 	      switch (TagType)
597 		{
598 		  case 1:
599 		    PnpDecodeMemory16(Ptr);
600 		    break;
601 
602 		  case 5:
603 		    PnpDecodeMemory32(Ptr);
604 		    break;
605 
606 		  case 6:
607 		    PnpDecodeFixedMemory(Ptr);
608 		    break;
609 
610 		  default:
611 		    printf("      Large tag: type %u  size %u\n",
612 			   TagType,
613 			   TagSize);
614 		    break;
615 		}
616 	    }
617 	  else
618 	    {
619 	      TagType = (*Ptr >> 3) & 0x0F;
620 	      TagSize = *Ptr & 0x07;
621 	      Ptr++;
622 
623 	      switch (TagType)
624 		{
625 		  case 2:
626 		    printf("      Logical device ID\n");
627 		    break;
628 
629 		  case 3:
630 		    printf("      Compatible device ID\n");
631 		    break;
632 
633 		  case 4:
634 		    PnpDecodeIrq(Ptr);
635 		    break;
636 
637 		  case 5:
638 		    PnpDecodeDma(Ptr);
639 		    break;
640 
641 		  case 8:
642 		    PnpDecodeIoPort(Ptr);
643 		    break;
644 
645 		  case 9:
646 		    PnpDecodeFixedIoPort(Ptr);
647 		    break;
648 
649 		  case 0x0F: /* end tag */
650 		    break;
651 
652 		  default:
653 		    printf("      Small tag: type %u  size %u\n",
654 			   TagType,
655 			   TagSize);
656 		    break;
657 		}
658 
659 	      /* end tag */
660 	      if (TagType == 0x0F)
661 		break;
662 	    }
663 
664 	  Ptr = Ptr + TagSize;
665 	}
666     }
667 }
668 
669 
670 int main (int argc, char *argv[])
671 {
672   LONG lError;
673   HKEY hPnpKey;
674   DWORD dwType;
675   DWORD dwSize;
676   BOOL Ask;
677   PCM_FULL_RESOURCE_DESCRIPTOR lpBuffer;
678   PCM_PNP_BIOS_INSTALLATION_CHECK lpPnpInst;
679   PCM_PNP_BIOS_DEVICE_NODE lpDevNode;
680   DWORD dwDataSize;
681   DWORD dwResourceSize;
682 
683   hPnpKey = 0;
684 
685   Ask = TRUE;
686   if (argc >1 && (!strcmp(argv[1],"/S") || !strcmp(argv[1],"/s")))
687     {
688       Ask = FALSE;
689     }
690 
691   if (argc >1 && !strcmp(argv[1],"/?"))
692     {
693       printf("This utility prints the PnP-nodes from the registry\n");
694       printf("\"/s\" prevents the \"Press any key\"\n\n");
695       return 0;
696     }
697 
698   lError = GetPnpKey(&hPnpKey);
699   if (lError != ERROR_SUCCESS)
700     {
701       printf("Failed to get PnP-BIOS key\n");
702       return 0;
703     }
704 
705   if (hPnpKey != 0)
706     {
707       printf("Found PnP-BIOS key\n");
708     }
709 
710   /* Allocate buffer */
711   dwSize = 2048;
712   lpBuffer = malloc(dwSize);
713   if (lpBuffer == NULL)
714     {
715       printf("Error: malloc() failed\n");
716       RegCloseKey(hPnpKey);
717       return 0;
718     }
719 
720   do
721     {
722       lError = RegQueryValueEx(hPnpKey,
723 			       "Configuration Data",
724 			       NULL,
725 			       &dwType,
726 			       (LPBYTE)lpBuffer,
727 			       &dwSize);
728       if (lError == ERROR_MORE_DATA)
729         {
730           lpBuffer = realloc(lpBuffer, dwSize);
731           if (lpBuffer == NULL)
732             {
733               printf("Error: realloc() of %u bytes failed\n", (unsigned) dwSize);
734               RegCloseKey(hPnpKey);
735               return 0;
736             }
737         }
738     }
739   while (lError == ERROR_MORE_DATA);
740   if (lError != ERROR_SUCCESS)
741     {
742       printf("Failed to read 'Configuration Data' value\n");
743       free(lpBuffer);
744       RegCloseKey(hPnpKey);
745       return 0;
746     }
747 
748 //  printf ("Data size: %lu\n", dwSize);
749 
750   RegCloseKey(hPnpKey);
751 
752 //  printf("Resource count %lu\n", lpBuffer->PartialResourceList.Count);
753 
754   if (lpBuffer->PartialResourceList.Count == 0)
755     {
756       printf("Invalid resource count!\n");
757       free(lpBuffer);
758       return 0;
759     }
760 
761 //  printf("lpBuffer %p\n", lpBuffer);
762 
763   dwResourceSize = lpBuffer->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize;
764 //  printf("ResourceSize: %lu\n", dwResourceSize);
765 
766   lpPnpInst = (PCM_PNP_BIOS_INSTALLATION_CHECK)
767 	((ULONG_PTR)(&lpBuffer->PartialResourceList.PartialDescriptors[0]) +
768 	  sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
769 
770 //  printf("lpPnpInst %p\n", lpPnpInst);
771 
772   printf("Signature '%.4s'\n", lpPnpInst->Signature);
773   if (strncmp((PCHAR)lpPnpInst->Signature, "$PnP", 4))
774     {
775       printf("Error: Invalid PnP signature\n");
776       free(lpBuffer);
777       return 0;
778     }
779 
780 //  printf("InstCheck length: %lu\n", lpPnpInst->Length);
781 
782   dwDataSize = sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
783   lpDevNode = (PCM_PNP_BIOS_DEVICE_NODE)((DWORD)lpPnpInst + sizeof(CM_PNP_BIOS_INSTALLATION_CHECK));
784 
785   if (lpDevNode->Size == 0)
786     {
787       printf("Error: Device node size is zero!\n");
788       return 0;
789     }
790 
791 #if 0
792       printf("Node: %x  Size %hu (0x%hx)\n",
793 	      lpDevNode->Node,
794 	      lpDevNode->Size,
795 	      lpDevNode->Size);
796 
797   printf("Done.\n");
798 return 0;
799 #endif
800 
801 
802   while (dwDataSize < dwResourceSize)
803     {
804       if (lpDevNode->Size == 0)
805 	break;
806 
807       printf("Node: %x  Size %hu (0x%hx)\n",
808 	     lpDevNode->Node,
809 	     lpDevNode->Size,
810 	     lpDevNode->Size);
811 
812       dwDataSize += lpDevNode->Size;
813       lpDevNode = (PCM_PNP_BIOS_DEVICE_NODE)((DWORD)lpDevNode + lpDevNode->Size);
814     }
815 
816   if (Ask)
817     {
818       printf("\n Press any key...\n");
819       getch();
820     }
821   else
822     {
823       printf("\n");
824     }
825 
826   dwDataSize = sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
827   lpDevNode = (PCM_PNP_BIOS_DEVICE_NODE)((DWORD)lpPnpInst + sizeof(CM_PNP_BIOS_INSTALLATION_CHECK));
828 
829   while (dwDataSize < dwResourceSize)
830     {
831       if (lpDevNode->Size == 0)
832 	break;
833 
834       PrintDeviceData(lpDevNode);
835 
836       if (Ask)
837         {
838           printf("\n Press any key...\n");
839           getch();
840         }
841       else
842         {
843           printf("\n");
844         }
845 
846       dwDataSize += lpDevNode->Size;
847       lpDevNode = (PCM_PNP_BIOS_DEVICE_NODE)((DWORD)lpDevNode + lpDevNode->Size);
848     }
849 
850   free(lpBuffer);
851 
852   return 0;
853 }
854 
855 /* EOF */
856