home *** CD-ROM | disk | FTP | other *** search
/ Hot Shareware 32 / hot34.iso / ficheros / DTOOL / INTER57E.ZIP / PCICFG11.ZIP / PCICFG.CPP < prev    next >
C/C++ Source or Header  |  1998-01-04  |  61KB  |  2,206 lines

  1. /************************************************************************/
  2. /*                                    */
  3. /*  Version 1.10                            */
  4. /*     by Ralf Brown                            */
  5. /*                                    */
  6. /*  File pcicfg.cpp           PCI configuration data dumper        */
  7. /*  LastEdit: 04jan98                            */
  8. /*                                    */
  9. /*  (c) Copyright 1995,1996,1997,1998 Ralf Brown            */
  10. /*                                    */
  11. /*  This code may be freely redistributed in its entirety.  Excerpts    */
  12. /*  may be incorporated into other programs provided that credit is     */
  13. /*  given.                                */
  14. /*                                    */
  15. /************************************************************************/
  16.  
  17. #include <ctype.h>
  18. #include <dos.h>
  19. #include <io.h>
  20. #include <limits.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24.  
  25. #define VERSION "1.10"
  26.  
  27. #define lengthof(x) ((sizeof(x))/(sizeof(x[0])))
  28.  
  29. #ifdef __TURBOC__
  30. # pragma option -a-  /* byte alignment */
  31. #endif /* __TURBOC__ */
  32.  
  33. #ifndef FALSE
  34. # define FALSE (0)
  35. #endif /* FALSE */
  36.  
  37. #ifndef TRUE
  38. # define TRUE (!FALSE)
  39. #endif /* TRUE */
  40.  
  41. /************************************************************************/
  42. /*    Manifest Constants                        */
  43. /************************************************************************/
  44.  
  45. #define CAPLIST_BIT 0x0010        // does device have capabilities list?
  46.  
  47. #define MAX_LINE     512        // max length of a line in .PCI files
  48. #define MAX_VENDOR_NAME 50        // max length of vendor's name
  49. #define MAX_DEVICE_NAME 50        // max length of device name
  50. #define MAX_VENDOR_DATA 16384        // maximum data per vendor
  51.  
  52. #define SIGNATURE "PCICFG"        // PCICFG.DAT signature at start of file
  53. #define SIGNATURE_LENGTH (sizeof(SIGNATURE)-1)
  54.  
  55. /************************************************************************/
  56. /*    Types                                */
  57. /************************************************************************/
  58.  
  59. typedef unsigned char  BYTE ;
  60. typedef unsigned short WORD ;
  61. typedef unsigned long DWORD ;
  62.  
  63. //----------------------------------------------------------------------
  64.  
  65. struct PCIcfg
  66.    {
  67.    WORD     vendorID ;
  68.    WORD     deviceID ;
  69.    WORD     command_reg ;
  70.    WORD     status_reg ;
  71.    BYTE     revisionID ;
  72.    BYTE     progIF ;
  73.    BYTE     subclass ;
  74.    BYTE     classcode ;
  75.    BYTE     cacheline_size ;
  76.    BYTE     latency ;
  77.    BYTE     header_type ;
  78.    BYTE     BIST ;
  79.    union
  80.       {
  81.       struct
  82.      {
  83.      DWORD base_address0 ;
  84.      DWORD base_address1 ;
  85.      DWORD base_address2 ;
  86.      DWORD base_address3 ;
  87.      DWORD base_address4 ;
  88.      DWORD base_address5 ;
  89.      DWORD CardBus_CIS ;
  90.      WORD  subsystem_vendorID ;
  91.      WORD  subsystem_deviceID ;
  92.      DWORD expansion_ROM ;
  93.      BYTE  cap_ptr ;
  94.      BYTE  reserved1[3] ;
  95.      DWORD reserved2[1] ;
  96.      BYTE  interrupt_line ;
  97.      BYTE  interrupt_pin ;
  98.      BYTE  min_grant ;
  99.      BYTE  max_latency ;
  100.      DWORD device_specific[48] ;
  101.      } nonbridge ;
  102.       struct
  103.      {
  104.      DWORD base_address0 ;
  105.      DWORD base_address1 ;
  106.      BYTE  primary_bus ;
  107.      BYTE  secondary_bus ;
  108.      BYTE  subordinate_bus ;
  109.      BYTE  secondary_latency ;
  110.      BYTE  IO_base_low ;
  111.      BYTE  IO_limit_low ;
  112.      WORD  secondary_status ;
  113.      WORD  memory_base_low ;
  114.      WORD  memory_limit_low ;
  115.      WORD  prefetch_base_low ;
  116.      WORD  prefetch_limit_low ;
  117.      DWORD prefetch_base_high ;
  118.      DWORD prefetch_limit_high ;
  119.      WORD  IO_base_high ;
  120.      WORD  IO_limit_high ;
  121.      DWORD reserved2[1] ;
  122.      DWORD expansion_ROM ;
  123.      BYTE  interrupt_line ;
  124.      BYTE  interrupt_pin ;
  125.      WORD  bridge_control ;
  126.      DWORD device_specific[48] ;
  127.      } bridge ;
  128.       struct
  129.      {
  130.      DWORD ExCa_base ;
  131.      BYTE  cap_ptr ;
  132.      BYTE  reserved05 ;
  133.      WORD  secondary_status ;
  134.      BYTE  PCI_bus ;
  135.      BYTE  CardBus_bus ;
  136.      BYTE  subordinate_bus ;
  137.      BYTE  latency_timer ;
  138.      DWORD memory_base0 ;
  139.      DWORD memory_limit0 ;
  140.      DWORD memory_base1 ;
  141.      DWORD memory_limit1 ;
  142.      WORD  IObase_0low ;
  143.      WORD  IObase_0high ;
  144.      WORD  IOlimit_0low ;
  145.      WORD  IOlimit_0high ;
  146.      WORD  IObase_1low ;
  147.      WORD  IObase_1high ;
  148.      WORD  IOlimit_1low ;
  149.      WORD  IOlimit_1high ;
  150.      BYTE  interrupt_line ;
  151.      BYTE  interrupt_pin ;
  152.      WORD  bridge_control ;
  153.      WORD  subsystem_vendorID ;
  154.      WORD  subsystem_deviceID ;
  155.      DWORD legacy_baseaddr ;
  156.      DWORD cardbus_reserved[14] ;
  157.      DWORD vendor_specific[32] ;
  158.      } cardbus ;
  159.       } ;
  160.    } ;
  161.  
  162. struct subclass_info
  163.    {
  164.    int subclass_code ;
  165.    const char *subclass_name ;
  166.    } ;
  167.  
  168. /************************************************************************/
  169. /*    Global Data                            */
  170. /************************************************************************/
  171.  
  172. static const char * const class_names[] =
  173.    {
  174.     "reserved",        // 00
  175.     "disk",        // 01
  176.     "network",        // 02
  177.     "display",        // 03
  178.     "multimedia",    // 04
  179.     "memory",        // 05
  180.     "bridge",        // 06
  181.     "communication",    // 07
  182.     "system peripheral",// 08
  183.     "input",        // 09
  184.     "docking station",    // 0A
  185.     "CPU",        // 0B
  186.     "serial bus",    // 0C
  187.    } ;
  188.  
  189. static const subclass_info subclass_info_01[] =
  190.    {
  191.      { 0x00, "SCSI" },
  192.      { 0x01, "IDE" },
  193.      { 0x02, "floppy" },
  194.      { 0x03, "IPI"},
  195.      { 0x04, "RAID" },
  196.      { 0x80, "other" },
  197.      { -1, 0 },
  198.    } ;
  199.  
  200. static const subclass_info subclass_info_02[] =
  201.    {
  202.      { 0x00, "Ethernet" },
  203.      { 0x01, "TokenRing" },
  204.      { 0x02, "FDDI" },
  205.      { 0x03, "ATM" },
  206.      { 0x80, "other" },
  207.      { -1, 0 },
  208.    } ;
  209.  
  210. static const subclass_info subclass_info_03[] =
  211.    {
  212.      { 0x00, "VGA" },
  213.      { 0x01, "SuperVGA" },
  214.      { 0x02, "XGA" },
  215.      { 0x80, "other" },
  216.      { -1, 0 },
  217.    } ;
  218.  
  219. static const subclass_info subclass_info_04[] =
  220.    {
  221.      { 0x00, "video" },
  222.      { 0x01, "audio" },
  223.      { 0x80, "other" },
  224.      { -1, 0 },
  225.    } ;
  226.  
  227. static const subclass_info subclass_info_05[] =
  228.    {
  229.      { 0x00, "RAM" },
  230.      { 0x01, "Flash memory" },
  231.      { 0x80, "other" },
  232.      { -1, 0 },
  233.    } ;
  234.  
  235. static const subclass_info subclass_info_06[] =
  236.    {
  237.      { 0x00, "CPU/PCI" },
  238.      { 0x01, "PCI/ISA" },
  239.      { 0x02, "PCI/EISA" },
  240.      { 0x03, "PCI/MCA" },
  241.      { 0x04, "PCI/PCI" },
  242.      { 0x05, "PCI/PCMCIA" },
  243.      { 0x06, "PCI/NuBus" },
  244.      { 0x07, "PCI/CardBus" },
  245.      { 0x80, "other" },
  246.      { -1, 0 },
  247.    } ;
  248.  
  249. static const subclass_info subclass_info_07[] =
  250.    {
  251.      { 0x00, "serial" },
  252.      { 0x01, "parallel" },
  253.      { 0x80, "other" },
  254.      { -1, 0 },
  255.    } ;
  256.  
  257. static const subclass_info subclass_info_08[] =
  258.    {
  259.      { 0x00, "PIC" },
  260.      { 0x01, "DMAC" },
  261.      { 0x02, "timer" },
  262.      { 0x03, "RTC" },
  263.      { 0x80, "other" },
  264.      { -1, 0 },
  265.    } ;
  266.  
  267. static const subclass_info subclass_info_09[] =
  268.    {
  269.      { 0x00, "keyboard" },
  270.      { 0x01, "digitizer" },
  271.      { 0x02, "mouse" },
  272.      { 0x80, "other" },
  273.      { -1, 0 },
  274.    } ;
  275.  
  276. static const subclass_info subclass_info_0A[] =
  277.    {
  278.      { 0x00, "generic" },
  279.      { 0x80, "other" },
  280.      { -1, 0 },
  281.    } ;
  282.  
  283. static const subclass_info subclass_info_0B[] =
  284.    {
  285.      { 0x00, "386" },
  286.      { 0x01, "486" },
  287.      { 0x02, "Pentium" },
  288.      { 0x03, "P6" },
  289.      { 0x10, "Alpha" },
  290.      { 0x40, "coproc" },
  291.      { 0x80, "other" },
  292.      { -1, 0 },
  293.    } ;
  294.  
  295. static const subclass_info subclass_info_0C[] =
  296.    {
  297.      { 0x00, "Firewire" },
  298.      { 0x01, "ACCESS.bus" },
  299.      { 0x02, "SSA" },
  300.      { 0x03, "USB" },
  301.      { 0x04, "Fiber Channel" },
  302.      { 0x80, "other" },
  303.      { -1, 0 },
  304.    } ;
  305.  
  306. static const subclass_info *subclass_data[] =
  307.    {
  308.    0, subclass_info_01, subclass_info_02,
  309.    subclass_info_03, subclass_info_04, subclass_info_05,
  310.    subclass_info_06, subclass_info_07, subclass_info_08,
  311.    subclass_info_09, subclass_info_0A, subclass_info_0B,
  312.    subclass_info_0C,
  313.    } ;
  314.  
  315. //----------------------------------------------------------------------
  316.  
  317. static const char *const command_bits[] =
  318.    {
  319.      "I/O-on",
  320.      "mem-on",
  321.      "busmstr",
  322.      "spec-cyc",
  323.      "invalidate",
  324.      "VGAsnoop",
  325.      "parity-err",
  326.      "wait-cyc",
  327.      "sys-err",                         // bit 8
  328.      "fast-trns",            // bit 9
  329.      0,                    // bit 10
  330.      0,                    // bit 11
  331.      0,                    // bit 12
  332.      0,                    // bit 13
  333.      0,                    // bit 14
  334.      0,                    // bit 15
  335.    } ;
  336.  
  337. static const char *const status_bits[] =
  338.    {
  339.      0,                    // bit 0
  340.      0,                    // bit 1
  341.      0,                    // bit 2
  342.      0,                    // bit 3
  343.      "CapList",                         // bit 4
  344.      "66Mhz",                // bit 5
  345.      "UDF",                // bit 6
  346.      "fast-trns",            // bit 7
  347.      "parity-err",            // bit 8
  348.      0,                    // bits 9-10 are select timing
  349.      0,
  350.      "sig-abort",            // bit 11
  351.      "rcv-abort",            // bit 12
  352.      "mst-abort",            // bit 13
  353.      "sig-serr",            // bit 14
  354.      "det-parity",            // bit 15
  355.    } ;
  356.  
  357. static const char *const select_timing[] =
  358.    {
  359.     "fast",
  360.     "med",
  361.     "slow",
  362.     "???"
  363.    } ;
  364.  
  365. static const char *const PMC_bits[] =
  366.    {
  367.      0,                 // bits 0-2: version (001)
  368.      0,
  369.      0,
  370.      0,                 // bits 3-4: reserved (00)
  371.      0,
  372.      "DevSpec Init",                    // bit 5
  373.      0,                 // bits 6-7: DynClk
  374.      0,
  375.      "FullClk",
  376.      "D1-supp",
  377.      "D2-supp",
  378.      0,                 // bit 11: reserved (0)
  379.      "PME#-D0",                         // bit 12
  380.      "PME#-D1",                         // bit 13
  381.      "PME#-D2",                         // bit 14
  382.      "PME#-D3",                         // bit 15
  383.    } ;
  384.  
  385. /************************************************************************/
  386. /*    global variables                            */
  387. /************************************************************************/
  388.  
  389. static int verbose = FALSE ;
  390. static int terse = FALSE ;
  391. static int first_device = TRUE ;
  392.  
  393. static char *exe_directory = "." ;
  394.  
  395. static char *device_ID_data = 0 ;
  396. /* format of ID data once loaded:
  397.           char*  -> next vendor or 0
  398.       WORD   vendor ID
  399.       ASCIZ     vendor name
  400.       WORD   device ID
  401.       ASCIZ     device name
  402.       ...
  403.       char*     -> next vendor or 0
  404.       WORD   vendor ID
  405.       ASCIZ     vendor name
  406.       .....
  407. */
  408.  
  409. /************************************************************************/
  410. /*    Helper Functions                        */
  411. /************************************************************************/
  412.  
  413. static void get_exe_directory(const char *argv0)
  414. {
  415.    char *pathname = (char*)malloc(strlen(argv0)+2) ;
  416.    strcpy(pathname,argv0) ;
  417.    // strip off any existing extension
  418.    char *slash = strrchr(pathname,'/') ;
  419.    char *backslash = strrchr(pathname,'\\') ;
  420.    if (backslash && (!slash || backslash > slash))
  421.       slash = backslash ;
  422.    if (slash)
  423.       *slash = '\0' ;
  424.    else
  425.       strcpy(pathname,".") ;
  426.    exe_directory = pathname ;
  427. }
  428.  
  429. //----------------------------------------------------------------------
  430.  
  431. static const char *skip_whitespace(const char *line)
  432. {
  433.    while (*line && isspace(*line))
  434.       line++ ;
  435.    return line ;
  436. }
  437.  
  438. //----------------------------------------------------------------------
  439.  
  440. inline char *skip_whitespace(char *line)
  441. {
  442.    return (char*)skip_whitespace((const char *)line) ;
  443. }
  444.  
  445. //----------------------------------------------------------------------
  446.  
  447. static int is_comment_line(const char *line)
  448. {
  449.    line = skip_whitespace(line) ;
  450.    if (*line == '\0' || *line == '\n' || *line == ';')
  451.       return TRUE ;
  452.    else
  453.       return FALSE ;
  454. }
  455.  
  456. //----------------------------------------------------------------------
  457.  
  458. static int read_nonblank_line(char *buf, int size, FILE *fp)
  459. {
  460.    do {
  461.       buf[0] = '\0' ;
  462.       if (!fgets(buf,size,fp) || feof(fp))
  463.      return FALSE ;
  464.       } while (is_comment_line(buf)) ;
  465.    return TRUE ;
  466. }
  467.  
  468. //----------------------------------------------------------------------
  469.  
  470. static WORD hextoint(const char *&digits)
  471. {
  472.    WORD hex = 0 ;
  473.    while (isxdigit(*digits))
  474.       {
  475.       int digit = toupper(*digits++) - '0' ;
  476.       if (digit > 9)
  477.      digit -= ('A'-'0'-10) ;
  478.       hex = 16*hex + digit ;
  479.       }
  480.    return hex ;
  481. }
  482.  
  483. //----------------------------------------------------------------------
  484.  
  485. static FILE *open_PCICFG_DAT(const char *fopen_mode)
  486. {
  487.    int dir_len = strlen(exe_directory) ;
  488.    char *datafile = (char*)malloc(dir_len+15) ;
  489.    if (!datafile)
  490.       {
  491.       fprintf(stderr,"Insufficient memory for PCICFG.DAT pathname\n") ;
  492.       return FALSE ;
  493.       }
  494.    sprintf(datafile,"%s/PCICFG.DAT",exe_directory) ;
  495.    FILE *fp = fopen(datafile,fopen_mode) ;
  496.    free(datafile) ;
  497.    if (!fp)
  498.       fprintf(stderr,"Unable to open PCICFG.DAT in mode \"%s\"\n",fopen_mode) ;
  499.    return fp ;
  500. }
  501.  
  502. //----------------------------------------------------------------------
  503.  
  504. static int backup_PCICFG_DAT()
  505. {
  506.    int dir_len = strlen(exe_directory) ;
  507.    char *datafile = (char*)malloc(dir_len+15) ;
  508.    if (!datafile)
  509.       {
  510.       fprintf(stderr,"Insufficient memory for PCICFG.DAT pathname\n") ;
  511.       return FALSE ;
  512.       }
  513.    sprintf(datafile,"%s/PCICFG.DAT",exe_directory) ;
  514.    FILE *fp = fopen(datafile,"r") ;
  515.    if (!fp)
  516.       {
  517.       free(datafile) ;
  518.       return FALSE ;
  519.       }
  520.    strcpy(datafile+strlen(datafile)-4,".BAK") ;
  521.    FILE *backup = fopen(datafile,"w") ;
  522.    if (!backup)
  523.       {
  524.       free(datafile) ;
  525.       return FALSE ;
  526.       }
  527.    char buffer[BUFSIZ] ;
  528.    int count ;
  529.    int success = TRUE ;
  530.    while ((count = fread(buffer,sizeof(char),sizeof(buffer),fp)) > 0)
  531.       {
  532.       if (fwrite(buffer,sizeof(char),count,backup) < count)
  533.      success = FALSE ;
  534.       }
  535.    fclose(fp) ;
  536.    fclose(backup) ;
  537.    if (!success)
  538.       {
  539.       fprintf(stderr,"Backup of PCICFG.DAT failed!\n") ;
  540.       unlink(datafile) ;
  541.       }
  542.    free(datafile) ;
  543.    return success ;
  544. }
  545.  
  546. /************************************************************************/
  547. /************************************************************************/
  548.  
  549. static int check_PCI_BIOS()
  550. {
  551.    union REGS regs ;
  552.    regs.x.ax = 0xB101 ;
  553.    int86(0x1A,®s,®s) ;
  554.    if (regs.h.ah == 0x00)
  555.       return regs.h.cl ;        // last PCI bus in system
  556.    else
  557.       return -1 ;            // no PCI BIOS detected
  558. }
  559.  
  560. //----------------------------------------------------------------------
  561.  
  562. static PCIcfg *read_PCI_config(int bus, int device, int func)
  563. {
  564.    static PCIcfg cfg ;
  565.    union REGS regs ;
  566.  
  567.    regs.x.ax = 0xB109 ;
  568.    regs.h.bh = bus ;
  569.    regs.h.bl = (device<<3) | (func & 0x07) ;
  570.    for (int i = 0 ; i < sizeof(cfg) ; i += sizeof(short))
  571.       {
  572.       regs.x.di = i ;
  573.       union REGS outregs ;
  574.       int86(0x1A,®s,&outregs) ;
  575.       if (outregs.x.cflag != 0)
  576.      return 0 ;
  577.       WORD word = outregs.x.cx ;
  578.       *((WORD*)(((BYTE*)&cfg)+i)) = word ;
  579.       }
  580.    return &cfg ;
  581. }
  582.  
  583. //----------------------------------------------------------------------
  584.  
  585. static const char *get_subclass_name(int classcode, int subclass)
  586. {
  587.    if (classcode < 0 || classcode >= lengthof(subclass_data) ||
  588.        subclass_data[classcode] == 0)
  589.       return "???" ;
  590.    const subclass_info *subinfo = subclass_data[classcode] ;
  591.    while (subinfo->subclass_code != -1)
  592.       {
  593.       if (subinfo->subclass_code == subclass)
  594.      return subinfo->subclass_name ;
  595.       subinfo++ ;
  596.       }
  597.    return "???" ;
  598. }
  599.  
  600. //----------------------------------------------------------------------
  601.  
  602. static const char *get_vendor_name(WORD vendorID)
  603. {
  604.    if (vendorID == 0x0000 || vendorID == 0xFFFF)
  605.       return "Not Present" ;
  606.    char *next ;
  607.    for (char *data = device_ID_data ; data ; data = next)
  608.       {
  609.       next = *((char**)data)++ ;
  610.       data += sizeof(WORD) ;        // skip the length field
  611.       WORD ID = *((WORD*)data)++ ;
  612.       if (ID == vendorID)
  613.      return data ;
  614.       }
  615.    // if we get here, there was no matching ID in the file,
  616.    return "???" ;
  617. }
  618.  
  619. //----------------------------------------------------------------------
  620.  
  621. static const char *get_device_name(WORD vendorID, WORD deviceID)
  622. {
  623.    if (vendorID == 0x0000 || vendorID == 0xFFFF || deviceID == 0xFFFF)
  624.       return "Not Present" ;
  625.    char *data = device_ID_data ;
  626.    while (data)
  627.       {
  628.       char *next = *((char**)data)++ ;
  629.       WORD length = *((WORD*)data)++ ;
  630.       char *end = data + length ;
  631.       WORD ID = *((WORD*)data)++ ;
  632.       if (ID == vendorID)
  633.      {
  634.      // OK, we've found the vendor, now scan for the device
  635.      // 1. skip the vendor name
  636.      while (*data)
  637.         data++ ;
  638.      if (data < end)        // skip the NUL
  639.         data++ ;
  640.      // 2. check each device ID in turn
  641.      while (data < end)
  642.         {
  643.         ID = *((WORD*)data)++ ;
  644.         if (ID == deviceID)
  645.            return data ;
  646.         while (*data)
  647.            data++ ;
  648.         data++ ;            // skip the NUL
  649.         }
  650.      // if we get here, there was no match for the device ID
  651.      break ;
  652.      }
  653.       data = next ;
  654.       }
  655.    // if we get here, there was no matching ID in the file,
  656.    return "???" ;
  657. }
  658.  
  659. //----------------------------------------------------------------------
  660.  
  661. static int load_device_info(FILE *fp, char * &format_string,
  662.                 char const * &enum_list)
  663. {
  664.    if (!fp)
  665.       return FALSE ;
  666.    long int filesize = lseek(fileno(fp),0L,SEEK_END) ;
  667.    fseek(fp,0L,SEEK_SET) ;        // back to beginning of file
  668.    char line[MAX_LINE] ;
  669.    // read until we find the actual beginning of the device definition
  670.    do {
  671.       line[0] = '\0' ;            // catch EOF or read error
  672.       fgets(line,sizeof(line),fp) ;
  673.       } while (!feof(fp) && strncmp(line,"!begin",6) != 0) ;
  674.    int datasize = (int)(filesize - ftell(fp)) ;
  675.    char *buffer = (char*)malloc(datasize+3) ;
  676.    int readsize ;
  677.    char *newline ;
  678.    if (buffer && (readsize = fread(buffer,sizeof(char),datasize,fp)) > 0)
  679.       {
  680.       buffer[readsize] = '\0' ;        // ensure proper string termination
  681.       format_string = buffer ;
  682.       enum_list = format_string ;
  683.       if (*enum_list == '\n')
  684.      enum_list++ ;
  685.       // look forward to end of format string, then chop into two strings
  686.       do {
  687.      newline = strchr(enum_list,'\n') ;
  688.      if (newline && strncmp(newline+1,"!end",4) == 0)
  689.         {
  690.         newline[1] = '\0' ;
  691.         newline = strchr(newline+2,'\n') ;
  692.         if (newline)
  693.            enum_list = newline ;
  694.         else
  695.            enum_list = newline+2 ;
  696.         break ;
  697.         }
  698.      if (newline)
  699.         enum_list = newline+1 ;
  700.      } while (newline) ;
  701.       }
  702.    else
  703.       return FALSE ;
  704.    // scan until we find the actual beginning of the 'enum' definition
  705.    char *result = (char*)enum_list ;
  706.    newline = (char*)enum_list ;
  707.    do {
  708.       newline = strchr(newline,'\n') ;
  709.       if (newline)
  710.      {
  711.      newline++ ;
  712.      if (strncmp(newline,"!enum",5) == 0)
  713.         break ;
  714.      }
  715.       } while (newline) ;
  716.    if (newline)
  717.       {
  718.       newline++ ;
  719.       // format of the enum:
  720.       //    !enum enum_name
  721.       //     enumvalue0
  722.       //     enumvalue1
  723.       //     ...
  724.       //     enumvalueN
  725.       //    !end
  726.       do {
  727.      // extract the enum's name
  728.      //assert(strcmp(newline,"!enum",5) == 0) ;
  729.      newline = skip_whitespace(newline+5) ;
  730.      const char *end = strchr(newline,'\n') ;
  731.      if (!end)
  732.         break ;
  733.      memcpy(result,newline,end-newline+1) ;
  734.      result += (end-newline+1) ;
  735.      newline = (char*)end+1 ;
  736.      while (*newline && strncmp(newline,"!end",4) != 0)
  737.         {
  738.         newline = skip_whitespace(newline) ;
  739.         char *end = strchr(newline,'\n') ;
  740.         if (!end)
  741.            end = strchr(newline,'\0') ;
  742.         char *next = *end ? end+1 : end ;
  743.         while (end > newline && isspace(end[-1]))
  744.            end-- ;
  745.         memcpy(result,newline,end-newline+1) ;
  746.         result += (end-newline+1) ;
  747.         newline = next ;
  748.         }
  749.      *result++ = '\0' ;
  750.      // one enum is done, so scan for the next (if any)
  751.      while ((newline = strchr(newline,'\n')) != 0)
  752.         {
  753.         newline++ ;
  754.         if (strncmp(newline,"!enum",5) == 0)
  755.            break ;
  756.         }
  757.      } while (newline && *newline) ;
  758.       }
  759.    *result++ = '\0' ;
  760.    return TRUE ;
  761. }
  762.  
  763. //----------------------------------------------------------------------
  764.  
  765. static int know_device(WORD vendor, WORD device,
  766.                char * &format_string, char const * &enum_list)
  767. {
  768.    if (vendor == 0x0000 || vendor == 0xFFFF || device == 0xFFFF)
  769.       return FALSE ;
  770.    // see if there's a data file for this device
  771.    int dir_len = strlen(exe_directory) ;
  772.    char *device_file = (char*)malloc(dir_len+14) ;
  773.    if (device_file)
  774.       {
  775.       sprintf(device_file,"%s/%4.04X%4.04X.PCI",exe_directory,vendor,device) ;
  776.       device_file[dir_len+13] = '\0' ;
  777.       FILE *fp = fopen(device_file,"r") ;
  778.       free(device_file) ;
  779.       if (fp)
  780.      {
  781.      int success = load_device_info(fp,format_string,enum_list) ;
  782.      fclose(fp) ;
  783.      return success ;
  784.      }
  785.       }
  786.    return FALSE ;
  787. }
  788.  
  789. //----------------------------------------------------------------------
  790.  
  791. static void write_bits(WORD bitflags, const char *const *flagnames, int numbits)
  792. {
  793.    for (int i = 0 ; i < numbits ; i++)
  794.       {
  795.       if ((bitflags & (1 << i)) != 0 && flagnames[i])
  796.      printf(" %s",flagnames[i]) ;
  797.       }
  798. }
  799.  
  800. #define WRITE_CMD_BITS(x) write_bits((x),command_bits,lengthof(command_bits))
  801. #define WRITE_STAT_BITS(x) write_bits((x),status_bits,lengthof(status_bits))
  802.  
  803. //----------------------------------------------------------------------
  804.  
  805. static DWORD extract_field(const char *&s, const char *cfg)
  806. {
  807.    DWORD value = 0 ;
  808.    int addr = 0 ;
  809.    while (*s == '[' || *s == '|')
  810.       {
  811.       s++ ;
  812.       int lowbit = 0 ;
  813.       int highbit = 7 ;
  814.       while (*s && isxdigit(*s))
  815.      {
  816.      int digit = *s - '0' ;
  817.      if (digit > 9)
  818.         digit -= ('A'-10-'0') ;
  819.      addr = 16*addr + digit ;
  820.      s++ ;
  821.      }
  822.       addr &= 0x00FF ;
  823.       if (*s == ':')
  824.      {
  825.      s++ ;
  826.      while (*s && isdigit(*s))
  827.         {
  828.         lowbit = 10*lowbit + (*s-'0') ;
  829.         s++ ;
  830.         }
  831.      if (*s == '-')
  832.         {
  833.         highbit = 0 ;
  834.         s++ ;
  835.         while (*s && isdigit(*s))
  836.            {
  837.            highbit = 10*highbit + (*s-'0') ;
  838.            s++ ;
  839.            }
  840.         }
  841.      else
  842.         highbit = lowbit ;
  843.      if (highbit < lowbit)
  844.         {
  845.         int tmp = lowbit ;
  846.         lowbit = highbit ;
  847.         highbit = tmp ;
  848.         }
  849.      if (highbit > 31)
  850.         highbit = 31 ;
  851.      if (lowbit/8)
  852.         {
  853.         int adj = lowbit/8 ;
  854.         addr += adj ;
  855.         adj *= 8 ;
  856.         lowbit -= adj ;
  857.         highbit -= adj ;
  858.         }
  859.      }
  860.       DWORD prev_value = value << (highbit-lowbit+1) ;
  861.       if (highbit > 16)
  862.      {
  863.      value = cfg[addr] + (cfg[addr+1] << 8) + ((DWORD)cfg[addr+2] << 16) +
  864.          ((DWORD)cfg[addr+3] << 24) ;
  865.      }
  866.       else if (highbit > 8)
  867.      value = cfg[addr] + (cfg[addr+1] << 8) ;
  868.       else
  869.      value = cfg[addr] ;
  870.       DWORD mask = 0 ;
  871.       for (int i = lowbit ; i <= highbit ; i++)
  872.      mask |= (1L << i-lowbit) ;
  873.       while (lowbit-- > 0)
  874.          value >>= 1 ;
  875.       value &= mask ;
  876.       if (*s == '<')
  877.      {
  878.      s++ ;
  879.      int shift = 0 ;
  880.      while (*s && isdigit(*s))
  881.         {
  882.         shift = 10*shift + (*s-'0') ;
  883.         s++ ;
  884.         }
  885.      while (shift-- > 0)
  886.         {
  887.         value <<= 1 ;
  888.         prev_value <<= 1 ;
  889.         }
  890.      }
  891.       value |= prev_value ;
  892.       if (*s == '+')
  893.      {
  894.      *s++ ;
  895.      int negative = 0 ;
  896.      if (*s == '-')
  897.         negative = 1 ;
  898.      int offset = 0 ;
  899.      while (*s && isdigit(*s))
  900.         {
  901.         offset = 10*offset + (*s-'0') ;
  902.         s++ ;
  903.         }
  904.      if (negative)
  905.         offset = -offset ;
  906.      value += offset ;
  907.      }
  908.       if (*s == ']')
  909.      {
  910.      s++ ;
  911.      break ;
  912.      }
  913.       }
  914.    return value ;
  915. }
  916.  
  917. //----------------------------------------------------------------------
  918.  
  919. static void format_number(FILE *out, DWORD val, int width, int base)
  920. {
  921.    char buf[38] ;            // enough for DWORD, plus fudge factor
  922.    static char digits[] = "0123456789ABCDEF" ;
  923.    int count = 0 ;
  924.    do {
  925.       int digit = (int)(val % base) ;
  926.       val /= base ;
  927.       buf[count++] = digits[digit] ;
  928.       } while (val) ;
  929.    buf[count] = '\0' ;
  930.    for (int i = 0 ; i < count/2 ; i++)
  931.       {
  932.       char tmp = buf[count-i-1] ;
  933.       buf[count-i-1] = buf[i] ;
  934.       buf[i] = tmp ;
  935.       }
  936.    if (count < width)
  937.       {
  938.       for (int i = count ; i < width ; i++)
  939.      fputc(base == 10 ? ' ' : '0',out) ;
  940.       }
  941.    fputs(buf,out) ;
  942.    return ;
  943. }
  944.  
  945. //----------------------------------------------------------------------
  946.  
  947. static void format_enabled(FILE *out, DWORD value, int width)
  948. {
  949.    int w = value ? 6 : 7 ;
  950.    for (int i = w ; i < width ; i++)
  951.       fputc(' ',out) ;
  952.    fputs(value ? "enable" : "disable",out) ;
  953. }
  954.  
  955. //----------------------------------------------------------------------
  956.  
  957. static void format_flag(FILE *out, DWORD value, int width)
  958. {
  959.    for (int i = 1 ; i < width ; i++)
  960.       fputc(' ',out) ;
  961.    fputc(value ? '√' : '-',out) ;
  962. }
  963.  
  964.  
  965. //----------------------------------------------------------------------
  966.  
  967. static void format_yesno(FILE *out, DWORD value, int width)
  968. {
  969.    for (int i = 1 ; i < width ; i++)
  970.       fputc(' ',out) ;
  971.    fputc(value ? 'Y' : 'N',out) ;
  972. }
  973.  
  974. //----------------------------------------------------------------------
  975.  
  976. static void format_charlist(FILE *out, DWORD value, int width,
  977.                 const char *&chars)
  978. {
  979.    for (int i = 1 ; i < width ; i++)
  980.       fputc(' ',out) ;
  981.    int n = 0 ;
  982.    chars++ ;                // skip opening brace
  983.    const char *ch = chars ;
  984.    while (*chars && *chars != '}')
  985.       {
  986.       n++ ;
  987.       chars++ ;
  988.       }
  989.    if (value >= n)
  990.       value = n-1 ;
  991.    fputc(ch[(size_t)value],out) ;
  992. }
  993.  
  994. //----------------------------------------------------------------------
  995.  
  996. static const char *find_enum(const char *name, const char *name_end,
  997.                  const char *enums)
  998. {
  999.    const char *e = 0 ;
  1000.    if (name && enums)
  1001.       {
  1002.       size_t len = name_end - name ;
  1003.       const char *enum_list = enums ;
  1004.       while (*enums)
  1005.      {
  1006.      if (strncmp(name,enums,len) == 0 && enums[len] == '\n')
  1007.         return enums ;
  1008.      enums = strchr(enums,'\0') + 1 ;
  1009.      }
  1010.       // OK, first pass didn't find any exact match, so try to find a prefix
  1011.       enums = enum_list ;
  1012.       while (*enums)
  1013.      {
  1014.      if (strncmp(name,enums,len) == 0)
  1015.         return enums ;
  1016.      enums = strchr(enums,'\0') + 1 ;
  1017.      }
  1018.       }
  1019.    return e ;
  1020. }
  1021.  
  1022. //----------------------------------------------------------------------
  1023.  
  1024. static const char *format_enum(FILE *out, DWORD value, int width,
  1025.                    const char *name, const char *enums)
  1026. {
  1027.    if (!out || !enums)
  1028.       return name ;
  1029.    //asssert(*name == '(') ;
  1030.    name++ ;                // skip the open paren
  1031.    const char *end = name ;
  1032.    while (*end && *end != ')')
  1033.       end++ ;
  1034.    const char *e = find_enum(name,end,enums) ;
  1035.    if (e)
  1036.       {
  1037.       // format of string pointed at by 'e':
  1038.       //      name \n value0 \n value1 \n value2 \n ... \n valueN \0
  1039.       e = strchr(e,'\n') ;
  1040.       if (e) e++ ;
  1041.       while (value > 0)
  1042.      {
  1043.      const char *next = strchr(e,'\n') ;
  1044.      if (!next)
  1045.         return end ;
  1046.      e = next+1 ;
  1047.      value-- ;
  1048.      }
  1049.       // OK, we have the desired string, so output it
  1050.       while (*e && *e != '\n')
  1051.      {
  1052.      fputc(*e++,out) ;
  1053.      width-- ;
  1054.      }
  1055.       }
  1056.    else
  1057.       {
  1058.       fputs("■enum■",out) ;
  1059.       width-- ;
  1060.       }
  1061.    for (int i = 0 ; i < width ; i++)
  1062.       fputc(' ',out) ;
  1063.    return end ;
  1064. }
  1065.  
  1066. //----------------------------------------------------------------------
  1067.  
  1068. static const char *format_option(FILE *out, DWORD value, int width,
  1069.                  const char *option)
  1070. {
  1071.    if (!out || !option)
  1072.       return option ;
  1073.    char terminator = *option++ ;
  1074.    const char *end = strchr(option,terminator) ;
  1075.    if (!end)
  1076.       return option ;
  1077.    int len = end-option ;
  1078.    if (width == 0)
  1079.       width = len ;
  1080.    for (int i = len ; i < width ; i++)
  1081.       fputc(' ',out) ;
  1082.    if (value)
  1083.       fwrite(option,sizeof(char),len,out) ;
  1084.    else
  1085.       {
  1086.       while (len-- > 0)
  1087.      fputc('-',out) ;
  1088.       }
  1089.    return end ;
  1090. }
  1091.  
  1092. //----------------------------------------------------------------------
  1093.  
  1094. static const char *format_alternative(FILE *out, DWORD value, int width,
  1095.                       const char *option)
  1096. {
  1097.    if (!out || !option)
  1098.       return option ;
  1099.    char terminator = *option++ ;
  1100.    const char *end = strchr(option,terminator) ;
  1101.    if (!end)
  1102.       return option ;
  1103.    const char *alternates[5] = { 0, 0, 0, 0, 0 } ;
  1104.    alternates[0] = option ;
  1105.    int num_alts = 1 ;
  1106.    for (const char *alt = option ; alt < end ; alt++)
  1107.       if (*alt == ';')
  1108.      {
  1109.      alternates[num_alts++] = alt+1 ;
  1110.      if (num_alts >= lengthof(alternates)-1)
  1111.         break ;
  1112.      }
  1113.    alternates[num_alts] = end+1 ;
  1114.    if (value >= num_alts)
  1115.       value = num_alts-1 ;
  1116.    int len = (int)(alternates[(int)value+1] - alternates[(int)value]) - 1 ;
  1117.    if (width == 0)
  1118.       width = len ;
  1119.    for (int i = len ; i < width ; i++)
  1120.       fputc(' ',out) ;
  1121.    fwrite(alternates[(int)value],sizeof(char),len,out) ;
  1122.    return end ;
  1123. }
  1124.  
  1125. //----------------------------------------------------------------------
  1126.  
  1127. static int format(FILE *out, const char *cfg, const char *fmt,
  1128.           const char *enums)
  1129. {
  1130.    if (!out || !cfg || !fmt)
  1131.       return FALSE ;
  1132.    for (const char *s = fmt ; *s ; fmt = s)
  1133.       {
  1134.       while (*s && *s != '%' && *s != '\\')
  1135.      s++ ;
  1136.       if (s != fmt)
  1137.      fwrite(fmt,sizeof(char),s-fmt,out) ;
  1138.       if (*s == '\\')
  1139.      {
  1140.      s++ ;                // consume the backslash
  1141.      switch (*s)
  1142.         {
  1143.         case '\\':            // literal backslash
  1144.            fputc('\\',out) ;
  1145.            break ;
  1146.         case 't':            // tab
  1147.            fputc('\t',out) ;
  1148.            break ;
  1149.         default:            // don't know, so just print the char
  1150.            fputc(*s,out) ;
  1151.            break ;
  1152.         }
  1153.      s++ ;                // consume the char after backslash
  1154.      }
  1155.       else if (*s == '%')
  1156.      {
  1157.      DWORD cfgval = 0 ;
  1158.      fmt = s ;
  1159.      s++ ;                // skip the percent sign
  1160.      if (*s == '[')
  1161.         cfgval = extract_field(s,cfg) ;
  1162.      int width = 0 ;
  1163.      while (isdigit(*s))
  1164.         {
  1165.         width = 10*width + (*s-'0') ;
  1166.         s++ ;
  1167.         }
  1168.      switch (*s)            // dispatch on format character
  1169.         {
  1170.         case 'b':            // binary
  1171.            format_number(out,cfgval,width,2) ;
  1172.            break ;
  1173.         case 'o':            // octal
  1174.            format_number(out,cfgval,width,8) ;
  1175.            break ;
  1176.         case 'd':            // decimal
  1177.            format_number(out,cfgval,width,10) ;
  1178.            break ;
  1179.         case 'x':            // hex
  1180.            format_number(out,cfgval,width,16) ;
  1181.            break ;
  1182.         case 'e':
  1183.            format_enabled(out,cfgval,width) ;
  1184.            break ;
  1185.         case 'E':
  1186.            format_enabled(out,cfgval==0,width) ;
  1187.            break ;
  1188.         case 'f':            // flag
  1189.            format_flag(out,cfgval,width) ;
  1190.            break ;
  1191.         case 'n':
  1192.            format_yesno(out,cfgval == 0, width) ;
  1193.            break ;
  1194.         case 'y':
  1195.            format_yesno(out,cfgval,width) ;
  1196.            break ;
  1197.         case '(':            // enumerated list of values
  1198.            s = format_enum(out,cfgval,width,s,enums) ;
  1199.            break ;
  1200.         case '{':
  1201.            format_charlist(out,cfgval,width,s) ;
  1202.            break ;
  1203.         case '/':
  1204.            s = format_option(out,cfgval,width,s) ;
  1205.            break ;
  1206.         case '|':
  1207.            s = format_alternative(out,cfgval,width,s) ;
  1208.            break ;
  1209.         case '%':            // literal percent sign
  1210.            fputc('%',out) ;
  1211.            break ;
  1212.         case '!':            // rest of line is a comment
  1213.            while (*s && *s != '\n')
  1214.           s++ ;
  1215.            if (!*s)            // back up if we hit the end of string
  1216.           s-- ;
  1217.            s-- ;            // pre-undo the s++ below
  1218.            break ;
  1219.         case '\n':            // paste together two lines
  1220.            // do nothing, already skipping the newline
  1221.            break ;
  1222.         default:
  1223.            // don't know how to handle!  so, just output the format spec
  1224.            fwrite(fmt,sizeof(char),s-fmt,out) ;
  1225.            break ;
  1226.         }
  1227.      s++ ;
  1228.      }
  1229.       }
  1230.    fflush(out) ;
  1231.    return TRUE ;
  1232. }
  1233.  
  1234.  
  1235. //----------------------------------------------------------------------
  1236.  
  1237. static int read_DWORD_register(int bus, int device, int func, int reg,
  1238.                    WORD *lo, WORD *hi)
  1239. {
  1240.    union REGS regs, outregs ;
  1241.    regs.x.ax = 0xB109 ;
  1242.    regs.h.bh = bus ;
  1243.    regs.h.bl = (device<<3) | (func & 0x07) ;
  1244.    regs.x.di = reg ;
  1245.    int86(0x1A,®s,&outregs) ;
  1246.    if (outregs.x.cflag != 0)
  1247.       return FALSE ;
  1248.    *lo = outregs.x.cx ;
  1249.    regs.x.di += 2 ;
  1250.    int86(0x1A,®s,&outregs) ;
  1251.    if (outregs.x.cflag != 0)
  1252.       return FALSE ;
  1253.    *hi = outregs.x.cx ;
  1254.    return TRUE ;
  1255. }
  1256.  
  1257. //----------------------------------------------------------------------
  1258.  
  1259. static void write_DWORD_register(int bus,int device,int func,
  1260.                  int reg, WORD lo, WORD hi)
  1261. {
  1262.    union REGS regs, outregs ;
  1263.    
  1264.    regs.x.ax = 0xB10C ;            // write configuration word
  1265.    regs.x.di = 0x30 ;
  1266.    regs.h.bh = bus ;
  1267.    regs.h.bl = (device<<3) | (func & 0x07) ;
  1268.    regs.x.di = reg ;
  1269.    regs.x.cx = lo ;
  1270.    int86(0x1A,®s,&outregs) ;
  1271.    regs.x.di += 2 ;
  1272.    regs.x.cx = hi ;
  1273.    int86(0x1A,®s,&outregs) ;
  1274. }
  1275.  
  1276. //----------------------------------------------------------------------
  1277.  
  1278. static void determine_ROM_size(int bus, int device, int func, int reg)
  1279. {
  1280.    WORD orig_lo, orig_hi ;
  1281.    WORD new_lo, new_hi ;
  1282.    read_DWORD_register(bus,device,func,reg,&orig_lo,&orig_hi) ;
  1283.    // try setting all address bits
  1284.    write_DWORD_register(bus,device,func,reg,0xFC00,0xFFFF) ;
  1285.    // check which actually got set
  1286.    int read_error = FALSE ;
  1287.    if (!read_DWORD_register(bus,device,func,reg,&new_lo,&new_hi))
  1288.       read_error = TRUE ;
  1289.    // restore original state
  1290.    write_DWORD_register(bus,device,func,reg,orig_lo,orig_hi) ;
  1291.    if (read_error)
  1292.       printf("(error)") ;
  1293.    else if (new_lo == 0x0000 && new_hi == 0x0000)
  1294.       printf("(no ROM)") ;
  1295.    else
  1296.       {
  1297.       new_lo &= 0xFC00 ;        // mask out low ten bits
  1298.       int lowbit = 0 ;
  1299.       if (new_lo)
  1300.      for (int i = 10 ; i < 16 ; i++)
  1301.         if ((new_lo & (1U << i)) != 0)
  1302.            {
  1303.            lowbit = i ;
  1304.            break ;
  1305.            }
  1306.       if (!lowbit)
  1307.      for (int i = 0 ; i < 16 ; i++)
  1308.         if ((new_hi & (1U << i)) != 0)
  1309.            {
  1310.            lowbit = i + 16 ;
  1311.            break ;
  1312.            }
  1313.       const char *ROMstate = (orig_lo & 1) ? "enabled" : "disabled" ;
  1314.       if (lowbit < 20)
  1315.      printf("(%dK,%s)",1 << (lowbit - 10),ROMstate) ;
  1316.       else
  1317.      printf("(%dM,%s)",1 << (lowbit - 20),ROMstate) ;
  1318.       }
  1319. }
  1320.  
  1321. //----------------------------------------------------------------------
  1322.  
  1323. static void determine_region_size(int bus, int device, int func, int reg)
  1324. {
  1325.    WORD orig_lo, orig_hi ;
  1326.    WORD new_lo, new_hi ;
  1327.    read_DWORD_register(bus,device,func,reg,&orig_lo,&orig_hi) ;
  1328.    // try setting all address bits (preserving the I/O-memory bit)
  1329.    write_DWORD_register(bus,device,func,reg,0xFFFC|(orig_lo&1),0xFFFF) ;
  1330.    // check which actually got set
  1331.    int read_error = FALSE ;
  1332.    if (!read_DWORD_register(bus,device,func,reg,&new_lo,&new_hi))
  1333.       read_error = TRUE ;
  1334.    // restore original state
  1335.    write_DWORD_register(bus,device,func,reg,orig_lo,orig_hi) ;
  1336.    if (read_error)
  1337.       printf("(error)") ;
  1338.    else if (new_lo == 0x0000 && new_hi == 0x0000)
  1339.       printf("(no region)") ;
  1340.    else
  1341.       {
  1342.       if (orig_lo & 1)            // is it an I/O region?
  1343.      new_lo &= 0xFFFC ;        // mask out low two bits
  1344.       else
  1345.      new_lo &= 0xFFF0 ;        // mask out low four bits
  1346.       int lowbit = 0 ;
  1347.       if (new_lo)
  1348.      for (int i = 2 ; i < 16 ; i++)
  1349.         if ((new_lo & (1U << i)) != 0)
  1350.            {
  1351.            lowbit = i ;
  1352.            break ;
  1353.            }
  1354.       if (!lowbit)
  1355.      for (int i = 0 ; i < 16 ; i++)
  1356.         if ((new_hi & (1U << i)) != 0)
  1357.            {
  1358.            lowbit = i + 16 ;
  1359.            break ;
  1360.            }
  1361.       if (lowbit < 10)
  1362.      printf("len=%d",1 << lowbit) ;
  1363.       else if (lowbit < 20)
  1364.      printf("len=%dK",1 << (lowbit - 10)) ;
  1365.       else
  1366.      printf("len=%dM",1 << (lowbit - 20)) ;
  1367.       }
  1368. }
  1369.  
  1370. //----------------------------------------------------------------------
  1371.  
  1372. static int dump_base_address(int bus, int device, int func, int number,
  1373.                  DWORD base, DWORD nextbase)
  1374. {
  1375.    if (base)
  1376.       {
  1377.       printf("\t(%d) %8.08lX = %s ",number,base,((base & 1) ? "I/O" : "mem")) ;
  1378.       if (base & 1)
  1379.      {
  1380.      // I/O base address
  1381.      printf("base=%8.08lX ",(base & ~3)) ;
  1382.      determine_region_size(bus,device,func,4*number+0x10) ;
  1383.      putchar('\n') ;
  1384.      }
  1385.       else
  1386.      {
  1387.      // memory base address
  1388.      int type = (int)((base & 6) >> 1) ;
  1389.      int used = FALSE ;
  1390.      switch (type)
  1391.         {
  1392.         case 0:
  1393.            printf("base=%8.08lX ",(base & 0xFFFFFFF0L)) ;
  1394.            break ;
  1395.         case 1:
  1396.            printf("base=%6.06lX ",(base & 0x00FFFFF0L)) ;
  1397.            break ;
  1398.         case 2:
  1399.            printf("base=%8.08lX%8.08lX ",nextbase,(base & ~0x0F)) ;
  1400.            used = TRUE ;
  1401.            break ;
  1402.         case 3:
  1403.            printf("!reserved! ") ;
  1404.            break ;
  1405.         }
  1406.      determine_region_size(bus,device,func,4*number+0x10) ;
  1407.      if ((base & 8) != 0)
  1408.         printf(" prefetchable") ;
  1409.      putchar('\n') ;
  1410.      return used ;            // indicate whether next reg. used up
  1411.      }
  1412.       }
  1413.    return FALSE ;            // base does not extend to next reg.
  1414. }
  1415.  
  1416. //----------------------------------------------------------------------
  1417.  
  1418. static void dump_base_addresses(int bus, int device, int func,
  1419.                 DWORD base0, DWORD base1, DWORD base2,
  1420.                 DWORD base3, DWORD base4, DWORD base5)
  1421. {
  1422.    if (base0 == 0 && base1 == 0 && base2 == 0 && base3 == 0 &&
  1423.        base4 == 0 && base5 == 0)
  1424.       printf("No base addresses\n") ;
  1425.    else
  1426.       {
  1427.       printf("Base Addresses:\n") ;
  1428.       int used ;
  1429.       used = dump_base_address(bus,device,func,0,base0,base1) ;
  1430.       if (!used)
  1431.      used = dump_base_address(bus,device,func,1,base1,base2) ;
  1432.       else
  1433.      used = FALSE ;
  1434.       if (!used)
  1435.      used = dump_base_address(bus,device,func,2,base2,base3) ;
  1436.       else
  1437.      used = FALSE ;
  1438.       if (!used)
  1439.      used = dump_base_address(bus,device,func,3,base3,base4) ;
  1440.       else
  1441.      used = FALSE ;
  1442.       if (!used)
  1443.      used = dump_base_address(bus,device,func,4,base4,base5) ;
  1444.       else
  1445.      used = FALSE ;
  1446.       if (!used)
  1447.      dump_base_address(bus,device,func,5,base5,0) ;
  1448.       }
  1449. }
  1450.  
  1451. //----------------------------------------------------------------------
  1452.  
  1453. static void dump_PCI_PM_capabilities(const char *caplist)
  1454. {
  1455.    unsigned int PMC = *(unsigned int*)(caplist+2) ;
  1456.    unsigned int PMCSR = *(unsigned int*)(caplist+4) ;
  1457.    int PMCSR_ext = caplist[6] ;
  1458.    int data = caplist[7] ;
  1459.    printf("\t PMC    = ") ;
  1460.    write_bits(PMC,PMC_bits,lengthof(PMC_bits)) ;
  1461.    printf("\n\t\tDynClk = %d, PCI_PM version = %d\n",
  1462.           (PMC & 0x00C0) >> 6,
  1463.           (PMC & 0x0007)) ;
  1464.    printf("\t PMCSR  = %4.04X, data-select=%d ",PMCSR, (PMCSR & 0x1E00) >> 9) ;
  1465.    if (PMCSR & 0x6000)
  1466.       printf("scale=0.%s1\n","00"+(3-((PMCSR & 0x1E00)>>9))) ;
  1467.    else
  1468.       printf("unknown/unimplemented\n") ;
  1469.    printf("\t\tstate=D%d %s %s %s\n",
  1470.                   PMCSR & 0x0003,
  1471.                   PMCSR & 0x0010 ? "DynReport" : "",
  1472.                   PMCSR & 0x0100 ? "PME#-ena"  : "",
  1473.                   PMCSR & 0x8000 ? "PME#-active" : "") ;
  1474.    printf("\t PMCSRX = %s %s %s %s\n",
  1475.           PMCSR_ext & 0x80 ? "BusPowerCtrl" : "",
  1476.           PMCSR_ext & 0x20 ? "state-B2" : "",
  1477.                   PMCSR_ext & 0x40 ? "state-B3" : "",
  1478.           PMCSR_ext & 0x10 ? "DynamicClock" : "") ;
  1479.    printf("\t Data   = %2.02X\n",data) ;
  1480. }
  1481.  
  1482. //----------------------------------------------------------------------
  1483.  
  1484. static void dump_capabilities_list(int start_offset, const char *cfgdata)
  1485. {
  1486.    if (!start_offset)
  1487.       return ;
  1488.    printf("Capabilities List:\n") ;
  1489.    do {
  1490.       int next = cfgdata[start_offset] ;
  1491.       int ID = cfgdata[start_offset+1] ;
  1492.       printf("\tID = %2.02X ",ID) ;
  1493.       switch (ID)
  1494.      {
  1495.      case 0x01:
  1496.         printf("PCI Power Management\n") ;
  1497.         dump_PCI_PM_capabilities(cfgdata+start_offset) ;
  1498.         break ;
  1499.      default:
  1500.         printf("(unknown)\n") ;
  1501.         break ;
  1502.      }
  1503.       start_offset = next ;
  1504.       } while (start_offset != 0) ;
  1505. }
  1506.  
  1507. //----------------------------------------------------------------------
  1508.  
  1509. static void dump_device_specific_data(unsigned vendor, unsigned device,
  1510.                       const char *cfgdata)
  1511. {
  1512.    if (!cfgdata)
  1513.       return ;
  1514.    char *format_string ;
  1515.    char const *enum_list = 0 ;
  1516.    if (!know_device(vendor,device,format_string,enum_list))
  1517.       return ;
  1518.    format(stdout,cfgdata,format_string,enum_list) ;
  1519.    free(format_string) ;
  1520.    return ;
  1521. }
  1522.  
  1523. //----------------------------------------------------------------------
  1524.  
  1525. #define setp setprecision
  1526.  
  1527. static int dump_PCI_config(int bus, int device, int func, int report_missing,
  1528.                int is_multifunc)
  1529. {
  1530.    int i ;
  1531.    PCIcfg *cfg = read_PCI_config(bus,device,func) ;
  1532.    if (!cfg || cfg->vendorID == 0xFFFF || cfg->deviceID == 0xFFFF)
  1533.       {
  1534.       if (report_missing)
  1535.      printf("No PCI device at bus %2.02X device %2.02X function %2.02X\n",
  1536.         bus,device,func) ;
  1537.       return FALSE ;
  1538.       }
  1539.    if (!first_device)
  1540.       printf("-----------------------------------------------------------\n") ;
  1541.    first_device = FALSE ;
  1542.    printf("PCI bus %2.02X device %2.02X function %2.02X:  ",bus,device,func) ;
  1543.    printf("Header Type '") ;
  1544.    switch (cfg->header_type & 0x7F)
  1545.       {
  1546.       case 0x00:
  1547.      printf("non-bridge") ;
  1548.      break ;
  1549.       case 0x01:
  1550.      printf("PCI-PCI bridge") ;
  1551.      break ;
  1552.       case 0x02:
  1553.      printf("CardBus bridge") ;
  1554.      break ;
  1555.       default:
  1556.      printf("other") ;
  1557.       }
  1558.    printf("' (%s-func)\n",
  1559.       (is_multifunc || (cfg->header_type & 0x80)) ? "multi" : "single") ;
  1560.    const char *class_name = "???" ;
  1561.    if (cfg->classcode < lengthof(class_names))
  1562.       class_name = class_names[cfg->classcode] ;
  1563.    const char *subclass_name = get_subclass_name(cfg->classcode,cfg->subclass);
  1564.    if (terse)
  1565.       {
  1566.       const char *vendorname = get_vendor_name(cfg->vendorID) ;
  1567.       char unkvendor[40] ;
  1568.       if (strcmp(vendorname,"???") == 0)
  1569.      {
  1570.      sprintf(unkvendor,"(Vendor %4.04X)",cfg->vendorID) ;
  1571.      vendorname = unkvendor ;
  1572.      }
  1573.       const char *devname = get_device_name(cfg->vendorID,cfg->deviceID) ;
  1574.       char unkdevice[40] ;
  1575.       if (strcmp(devname,"???") == 0)
  1576.      {
  1577.      sprintf(unkdevice,"(DeviceID %4.04X)",cfg->deviceID) ;
  1578.      devname = unkdevice ;
  1579.      }
  1580.       printf("%-38.38s ║ Class %2.02X: %-20.20s\tI/F: %2.02X\n"
  1581.          "%-38.38s ║ SubCl %2.02X: %-20.20s\tRev: %2.02X\n",
  1582.          vendorname,cfg->classcode,class_name,cfg->progIF,
  1583.          devname,cfg->subclass,subclass_name,cfg->revisionID) ;
  1584.       return is_multifunc || (cfg->header_type & 0x80) != 0 ;
  1585.       }
  1586.    else
  1587.       {
  1588.       printf("Vendor:\t%4.04X\t%-50.50s\n",cfg->vendorID,
  1589.          get_vendor_name(cfg->vendorID)) ;
  1590.       printf("Device:\t%4.04X\t%-50.50s\n",
  1591.          cfg->deviceID,get_device_name(cfg->vendorID,cfg->deviceID)) ;
  1592.       printf("Class:\t  %2.02X\t%-20.20s\tRevision:\t%2.02X\n",
  1593.          cfg->classcode,class_name,cfg->revisionID) ;
  1594.       printf("SubClass: %2.02X\t%-20.20s\tProgramI/F:\t%2.02X\n",
  1595.          cfg->subclass,subclass_name,cfg->progIF) ;
  1596.       }
  1597.    printf("CommandReg:     %4.04X =",cfg->command_reg) ;
  1598.    WRITE_CMD_BITS(cfg->command_reg) ;
  1599.    printf("\n"
  1600.       "Status Reg:     %4.04X =",cfg->status_reg) ;
  1601.    WRITE_STAT_BITS(cfg->status_reg) ;
  1602.    printf(" (%s)\n",select_timing[(cfg->status_reg & 0x0600) >> 9]) ;
  1603.    printf("CacheLine:       %2.02X\tLatency:\t%2.02X\tBIST:\t     %2.02X\n",
  1604.       cfg->cacheline_size,cfg->latency,cfg->BIST) ;
  1605.    switch(cfg->header_type & 0x7F)
  1606.       {
  1607.       case 0x00:  // non-bridge
  1608.      printf("SubsysVendor:    %4.04X\tSubsysDevice: %4.04X\n",
  1609.         cfg->nonbridge.subsystem_vendorID,
  1610.         cfg->nonbridge.subsystem_deviceID) ;
  1611.      dump_base_addresses(bus,device,func,
  1612.                  cfg->nonbridge.base_address0,
  1613.                  cfg->nonbridge.base_address1,
  1614.                  cfg->nonbridge.base_address2,
  1615.                  cfg->nonbridge.base_address3,
  1616.                  cfg->nonbridge.base_address4,
  1617.                  cfg->nonbridge.base_address5) ;
  1618.      printf("CardBus:     %8.08lX\tExpansionROM: %8.08lX ",
  1619.         cfg->nonbridge.CardBus_CIS,cfg->nonbridge.expansion_ROM) ;
  1620.      determine_ROM_size(bus,device,func,0x30) ;
  1621.      printf("\n") ;
  1622.      printf("INTline:\t   %2.02X\tINTpin:       %2.02X\n",
  1623.         cfg->nonbridge.interrupt_line,cfg->nonbridge.interrupt_pin) ;
  1624.      printf("MinGrant:\t   %2.02X\tMaxLatency:   %2.02X\n",
  1625.         cfg->nonbridge.min_grant,cfg->nonbridge.max_latency) ;
  1626.      printf("Device-Specific Data:\n 40:") ;
  1627.      for (i = 0 ; i < 48 ; i++)
  1628.         {
  1629.         printf(" %8.08lX ",cfg->nonbridge.device_specific[i]) ;
  1630.         if (i % 6 == 5 && i < 47)
  1631.            printf("\n %2.02X:",4*(i+17)) ;
  1632.         }
  1633.      putchar('\n') ;
  1634.      if (cfg->status_reg & CAPLIST_BIT)
  1635.         dump_capabilities_list(cfg->nonbridge.cap_ptr,(char*)cfg) ;
  1636.      break ;
  1637.       case 0x01:  // bridge
  1638.      printf("PrimaryBus:     %2.02X\tSecondaryBus:     %2.02X\tSubordinBus:    %2.02X\n",
  1639.         cfg->bridge.primary_bus,cfg->bridge.secondary_bus,
  1640.         cfg->bridge.subordinate_bus) ;
  1641.      dump_base_addresses(bus,device,func,
  1642.                  cfg->bridge.base_address0,
  1643.                  cfg->bridge.base_address1,0,0,0,0) ;
  1644.      printf("IObase low:     %2.02X\tIOlimit low:     %2.02X\n",
  1645.         cfg->bridge.IO_base_low,cfg->bridge.IO_limit_low) ;
  1646.      printf("...more...\n") ;
  1647.      //!!!
  1648.      printf("INTline:  %2.02X\tINTpin:  %2.02X\tBridgeCntrl: %4.04X\n",
  1649.         cfg->bridge.interrupt_line,cfg->bridge.interrupt_pin,
  1650.         cfg->bridge.bridge_control) ;
  1651.      printf("Expansion ROM: %8.08lX ",cfg->bridge.expansion_ROM) ;
  1652.      determine_ROM_size(bus,device,func,0x38) ;
  1653.      printf("\n") ;
  1654.      printf("Device-Specific Data:\n 40:") ;
  1655.       for (i = 0 ; i < 48 ; i++)
  1656.         {
  1657.         printf(" %8.08lX ",cfg->bridge.device_specific[i]) ;
  1658.         if (i % 6 == 5 && i < 47)
  1659.            printf("\n %2.02X:",4*(i+17)) ;
  1660.         }
  1661.      putchar('\n') ;
  1662.      break    ;
  1663.       case 0x02:
  1664.      printf("SubsysVendor: %4.04X\tSubsysDevice: %4.04X\n",
  1665.         cfg->cardbus.subsystem_vendorID,
  1666.         cfg->cardbus.subsystem_deviceID) ;
  1667.      printf("PCI bus: %2.02X\tCardBus bus: %2.02X\tSubordBus: %2.02X\tLatency: %2.02X\n",
  1668.         cfg->cardbus.PCI_bus, cfg->cardbus.CardBus_bus,
  1669.         cfg->cardbus.subordinate_bus, cfg->cardbus.latency_timer) ;
  1670.      printf("Memory0: %8.08lX bytes at %8.08lX\n",
  1671.         cfg->cardbus.memory_limit0, cfg->cardbus.memory_base0) ;
  1672.      printf("Memory1: %8.08lX bytes at %8.08lX\n",
  1673.         cfg->cardbus.memory_limit1, cfg->cardbus.memory_base1) ;
  1674.      printf("I/O range 0: %4.04X ports at %4.04X\n",
  1675.         cfg->cardbus.IOlimit_0low, cfg->cardbus.IObase_0low) ;
  1676.      printf("I/O range 1: %4.04X ports at %4.04X\n",
  1677.         cfg->cardbus.IOlimit_1low, cfg->cardbus.IObase_1low) ;
  1678.      printf("INTline:  %2.02X\tINTpin:  %2.02X\tBridgeCntrl: %4.04X\n",
  1679.         cfg->cardbus.interrupt_line,cfg->cardbus.interrupt_pin,
  1680.         cfg->cardbus.bridge_control) ;
  1681.      printf("Legacy Mode base address: %8.08lX\n",
  1682.         cfg->cardbus.legacy_baseaddr) ;
  1683.      printf("Device-Specific Data:\n 80:") ;
  1684.      for (int i = 0 ; i < 32 ; i++)
  1685.         {
  1686.         printf(" %8.08lX ",cfg->cardbus.vendor_specific[i]) ;
  1687.         if (i % 6 == 5 && i < 47)
  1688.            printf("\n %2.02X:",4*(i+33)) ;
  1689.         }
  1690.      putchar('\n') ;
  1691.      if (cfg->status_reg & CAPLIST_BIT)
  1692.         dump_capabilities_list(cfg->cardbus.cap_ptr,(char*)cfg) ;
  1693.      break ;
  1694.       default:
  1695.      printf("Unknown header format!\n") ;
  1696.       }
  1697.    if (verbose)
  1698.       dump_device_specific_data(cfg->vendorID,cfg->deviceID,(char*)cfg) ;
  1699.    if (!report_missing)
  1700.       putchar('\n') ;
  1701.    return is_multifunc || (cfg->header_type & 0x80) != 0 ;
  1702. }
  1703.  
  1704. //----------------------------------------------------------------------
  1705.  
  1706. static int read_device_ID(FILE *fp, char *&ID_data, int maxsize,
  1707.               int pcicfg_format)
  1708. {
  1709.    char line[MAX_LINE] ;
  1710.    long startpos = ftell(fp) ;
  1711.    if (!read_nonblank_line(line,sizeof(line),fp))
  1712.       return FALSE ;
  1713.    char *data_end = ID_data + maxsize - (MAX_DEVICE_NAME + 5) ;
  1714.    const char *l = line ;
  1715.    int is_vendor_line ;
  1716.    if (pcicfg_format)
  1717.       {
  1718.       l = skip_whitespace(l) ;
  1719.       is_vendor_line = strncmp(l,"Vendor",6) == 0 ;
  1720.       if (is_vendor_line)
  1721.      l = skip_whitespace(l+6) ;    // skip to vendor ID
  1722.       }
  1723.    else
  1724.       is_vendor_line = isxdigit(*l) ;
  1725.    if (is_vendor_line)
  1726.       {
  1727.       *((char**)ID_data)++ = 0 ;    // pointer to next vendor ID
  1728.       WORD *length = (WORD*)ID_data ;
  1729.       *((WORD*)ID_data)++ = 0 ;        // length of data for vendor
  1730.       WORD ID = hextoint(l) ;        // get the vendor's ID
  1731.       *((WORD*)ID_data)++ = ID ;
  1732.       l = skip_whitespace(l) ;        // skip to vendor name
  1733.       int count = 0 ;
  1734.       // copy the vendor name
  1735.       while (*l && *l != '\n' && count++ < MAX_VENDOR_NAME)
  1736.      *ID_data++ = *l++ ;
  1737.       *ID_data++ = '\0' ;        // ensure termination
  1738.       do {
  1739.      startpos = ftell(fp) ;
  1740.      if (!read_nonblank_line(line,sizeof(line),fp))
  1741.         break ;
  1742.      l = line ;
  1743.      int is_device_line ;
  1744.      if (pcicfg_format)
  1745.         {
  1746.         l = skip_whitespace(l) ;
  1747.         is_vendor_line = strncmp(l,"Vendor",6) == 0 ;
  1748.         is_device_line = isxdigit(*l) ;
  1749.         }
  1750.      else
  1751.         {
  1752.         is_vendor_line = isxdigit(*l) ;
  1753.         is_device_line = FALSE ;
  1754.         if (!is_vendor_line)
  1755.            {
  1756.            l = skip_whitespace(l) ;
  1757.            is_device_line = isxdigit(*l) ;
  1758.            }
  1759.         }
  1760.      if (is_device_line)
  1761.         {
  1762.         ID = hextoint(l) ;        // convert device ID
  1763.         if (ID != 0xFFFF)
  1764.            {
  1765.            *((WORD*)ID_data)++ = ID ;
  1766.            l = skip_whitespace(l) ; // skip to device name
  1767.            // copy the device name
  1768.            count = 0 ;
  1769.            while (*l && *l != '\n' && count++ < MAX_DEVICE_NAME)
  1770.           *ID_data++ = *l++ ;
  1771.            *ID_data++ = '\0' ;    // ensure termination
  1772.            if (ID_data >= data_end)
  1773.           {
  1774.           fprintf(stderr,"Too much information for a single vendor!\n") ;
  1775.           return TRUE ;
  1776.           }
  1777.            }
  1778.         }
  1779.      } while (!is_vendor_line) ;
  1780.       *length = (ID_data - (char*)length) - sizeof(*length) ;
  1781.       // back up to start of Vendor line
  1782.       (void)fseek(fp,startpos,SEEK_SET) ;
  1783.       return TRUE ;
  1784.       }
  1785.    else
  1786.       return FALSE ;
  1787. }
  1788.  
  1789. //----------------------------------------------------------------------
  1790.  
  1791. static int check_PCICFG_DAT_signature(FILE *fp, int complain = FALSE)
  1792. {
  1793.    char signature[SIGNATURE_LENGTH] ;
  1794.    (void)fseek(fp,0L,SEEK_SET) ;
  1795.    fread(signature,sizeof(char),sizeof(signature),fp) ;
  1796.    int present = strncmp(signature,SIGNATURE,SIGNATURE_LENGTH) == 0 ;
  1797.    if (present)
  1798.       {
  1799.       // skip the rest of the first line
  1800.       int c ;
  1801.       while ((c = fgetc(fp)) != EOF && c != '\n')
  1802.      ;
  1803.       }
  1804.    else
  1805.       {
  1806.       (void)fseek(fp,0L,SEEK_SET) ;
  1807.       if (complain)
  1808.      fprintf(stderr,"Invalid PCICFG.DAT\n") ;
  1809.       }
  1810.    return present ;
  1811. }
  1812.  
  1813. //----------------------------------------------------------------------
  1814.  
  1815. static int load_device_IDs()
  1816. {
  1817.    FILE *fp = open_PCICFG_DAT("r") ;
  1818.    if (fp)
  1819.       {
  1820.       int pcicfg_format = check_PCICFG_DAT_signature(fp,TRUE) ;
  1821.       char *prev_ID_data = 0 ;
  1822.       while (!feof(fp))
  1823.      {
  1824.      char *vendor_ID_data = (char*)malloc(MAX_VENDOR_DATA) ;
  1825.      if (!vendor_ID_data)
  1826.         {
  1827.         fprintf(stderr,"Insufficient memory for PCICFG.DAT contents\n"
  1828.                    "Some vendors/devices will not be shown by name\n") ;
  1829.         return FALSE ;
  1830.         }
  1831.      char *ID_data = vendor_ID_data ;
  1832.      if (!read_device_ID(fp,ID_data,MAX_VENDOR_DATA,pcicfg_format))
  1833.         break ;
  1834.      ID_data = (char*)realloc(vendor_ID_data, ID_data - vendor_ID_data) ;
  1835.      if (ID_data)
  1836.         vendor_ID_data = ID_data ;
  1837.      if (prev_ID_data)
  1838.         *((char**)prev_ID_data) = vendor_ID_data ;
  1839.      else
  1840.         device_ID_data = vendor_ID_data ;
  1841.      prev_ID_data = vendor_ID_data ;
  1842.      }
  1843.       return TRUE ;
  1844.       }
  1845.    return FALSE ;   
  1846. }
  1847.  
  1848. //----------------------------------------------------------------------
  1849.  
  1850. static int write_PCICFG_DAT_header(FILE *outfp)
  1851. {
  1852.    fputs("PCICFG ;<<-- signature - DO NOT CHANGE\n",outfp) ;
  1853.    return TRUE ;
  1854. }
  1855.  
  1856. //----------------------------------------------------------------------
  1857.  
  1858. static int copy_initial_comments(FILE *outfp, FILE *datfp)
  1859. {
  1860.    char line[MAX_LINE] ;
  1861.    int is_comment ;
  1862.    long startpos ;
  1863.    do {
  1864.       line[0] = '\0' ;
  1865.       startpos = ftell(datfp) ;
  1866.       if (!fgets(line,sizeof(line),datfp))
  1867.      return FALSE ;
  1868.       is_comment = is_comment_line(line) ;
  1869.       if (is_comment)
  1870.      fputs(line,outfp) ;
  1871.       } while (is_comment) ;
  1872.    fseek(datfp,startpos,SEEK_SET) ;
  1873.    return TRUE ;
  1874. }
  1875.  
  1876. //----------------------------------------------------------------------
  1877.  
  1878. static char *skip_string(char *s, char *end)
  1879. {
  1880.    while (s < end && *s)
  1881.       s++ ;
  1882.    if (s < end)
  1883.       s++ ;                // skip terminating NUL
  1884.    return s ;
  1885. }
  1886.  
  1887. //----------------------------------------------------------------------
  1888.  
  1889. static int write_vendor_data(FILE *outfp, WORD ID, char *data, char *end)
  1890. {
  1891.    if (!outfp || !data || data >= end)
  1892.       return FALSE ;
  1893.    // output the vendor's name and ID
  1894.    fprintf(outfp,"Vendor %4.04X %s\n",ID,data) ;
  1895.    data = skip_string(data,end) ;
  1896.    // output all of the devices listed under the vendor
  1897.    while (data < end)
  1898.       {
  1899.       ID = *((WORD*)data)++ ;
  1900.       fprintf(outfp,"  %4.04X %s\n",ID,data) ;
  1901.       data = skip_string(data,end) ;
  1902.       }
  1903.    return TRUE ;
  1904. }
  1905.  
  1906. //----------------------------------------------------------------------
  1907.  
  1908. static int merge_vendor_data(FILE *outfp, char *data1, char *data2)
  1909. {
  1910.    data1 += sizeof(char*) ;        // skip the 'next' field
  1911.    WORD length1 = *((WORD*)data1)++ ;    // get length of data
  1912.    char *end1 = data1 + length1 ;
  1913.    WORD ID1 = *((WORD*)data1)++ ;    // get vendor ID
  1914.    data2 += sizeof(char*) ;        // skip the 'next' field
  1915.    WORD length2 = *((WORD*)data2)++ ;    // get length of data
  1916.    char *end2 = data2 + length2 ;
  1917.    WORD ID2 = *((WORD*)data2)++ ;    // get vendor ID
  1918.    if (ID1 == ID2)
  1919.       {
  1920.       fprintf(outfp,"Vendor %4.04X %s\n",ID1,data1) ;
  1921.       data1 = skip_string(data1,end1) ;
  1922.       data2 = skip_string(data2,end2) ;
  1923.       ID1 = *((WORD*)data1)++ ;
  1924.       ID2 = *((WORD*)data2)++ ;
  1925.       while (data1 < end1 && data2 < end2)
  1926.      {
  1927.      if (ID1 <= ID2)
  1928.         {
  1929.         fprintf(outfp,"  %4.04X %s\n",ID1,data1) ;
  1930.         if (ID1 == ID2)
  1931.            {
  1932.            data2 = skip_string(data2,end2) ;
  1933.            ID2 = *((WORD*)data2)++ ;
  1934.            }
  1935.         data1 = skip_string(data1,end1) ;
  1936.         ID1 = *((WORD*)data1)++ ;
  1937.         }
  1938.      else // if (ID1 > ID2)
  1939.         {
  1940.         fprintf(outfp,"  %4.04X %s\n",ID2,data2) ;
  1941.         data2 = skip_string(data2,end2) ;
  1942.         ID2 = *((WORD*)data2)++ ;
  1943.         }
  1944.      }
  1945.       while (data1 < end1)
  1946.      {
  1947.      // copy the remainder of the first file's device IDs
  1948.      fprintf(outfp,"  %4.04X %s\n",ID1,data1) ;
  1949.      data1 = skip_string(data1,end1) ;
  1950.      ID1 = *((WORD*)data1)++ ;
  1951.      }
  1952.       while (data2 < end2)
  1953.      {
  1954.      // copy the remainder of the second file's device IDs
  1955.      fprintf(outfp,"  %4.04X %s\n",ID2,data2) ;
  1956.      data2 = skip_string(data2,end2) ;
  1957.      ID2 = *((WORD*)data2)++ ;
  1958.      }
  1959.       return 0 ;
  1960.       }
  1961.    else if (ID1 < ID2)
  1962.       {
  1963.       write_vendor_data(outfp,ID1,data1,end1) ;
  1964.       return -1 ;
  1965.       }
  1966.    else // ID1 > ID2
  1967.       {
  1968.       write_vendor_data(outfp,ID2,data2,end2) ;
  1969.       return +1 ;
  1970.       }
  1971. }
  1972.  
  1973. //----------------------------------------------------------------------
  1974.  
  1975. static int merge_info(FILE *outfp, FILE *datfp, FILE *newfp)
  1976. {
  1977.    if (!outfp || !datfp || !newfp)
  1978.       return FALSE ;
  1979.    if (!check_PCICFG_DAT_signature(datfp,TRUE))
  1980.       return FALSE ;
  1981.    if (!write_PCICFG_DAT_header(outfp) || !copy_initial_comments(outfp,datfp))
  1982.       return FALSE ;
  1983.    int pcicfg_format = check_PCICFG_DAT_signature(newfp,FALSE) ;
  1984.    if (!copy_initial_comments(outfp,newfp))
  1985.       return FALSE ;
  1986.    char *data1 = (char*)malloc(MAX_VENDOR_DATA) ;
  1987.    char *data2 = (char*)malloc(MAX_VENDOR_DATA) ;
  1988.    if (!data1 || !data2)
  1989.       {
  1990.       fprintf(stderr,"Insufficient memory to merge data!\n") ;
  1991.       if (data1)
  1992.      free(data1) ;
  1993.       return FALSE ;
  1994.       }
  1995.    char *dat1 = data1 ;
  1996.    char *dat2 = data2 ;
  1997.    // load up the first vendor from each file
  1998.    if (!read_device_ID(datfp,dat1,MAX_VENDOR_DATA,TRUE) ||
  1999.        !read_device_ID(newfp,dat2,MAX_VENDOR_DATA,pcicfg_format))
  2000.       {
  2001.       free(data1) ;
  2002.       free(data2) ;
  2003.       return FALSE ;
  2004.       }
  2005.    int done1 = FALSE ;
  2006.    int done2 = FALSE ;
  2007.    do {
  2008.       int merge = merge_vendor_data(outfp,data1,data2) ;
  2009.       switch (merge)
  2010.      {
  2011.      case -1:
  2012.         dat1 = data1 ;
  2013.         if (!read_device_ID(datfp,dat1,MAX_VENDOR_DATA,TRUE))
  2014.            done1 = TRUE ;
  2015.         break ;
  2016.      case 0:
  2017.         dat1 = data1 ;
  2018.         if (!read_device_ID(datfp,dat1,MAX_VENDOR_DATA,TRUE))
  2019.            done1 = TRUE ;
  2020.         // fall through to +1
  2021.      case +1:
  2022.         dat2 = data2 ;
  2023.         if (!read_device_ID(newfp,dat2,MAX_VENDOR_DATA,pcicfg_format))
  2024.            done2 = TRUE ;
  2025.         break ;
  2026.      default:
  2027.         fprintf(stderr,"Missed case in switch()!\n") ;
  2028.         return FALSE ;
  2029.      }
  2030.       } while (!done1 && !done2) ;
  2031.    if (!done1)
  2032.       {
  2033.       // copy any remaining items from first file (we can't possibly have any
  2034.       // left over from the second file, since PCICFG.DAT goes up to FFFFh)
  2035.       do {
  2036.      dat1 = data1 + sizeof(char*) ;    // reset, but skip the 'next' field
  2037.      WORD length1 = *((WORD*)dat1)++ ;
  2038.      char *end1 = data1 + length1 ;
  2039.      WORD ID1 = *((WORD*)dat1)++ ;    // get vendor ID
  2040.      write_vendor_data(outfp,ID1,dat1,end1) ;
  2041.      dat1 = data1 ;
  2042.      } while (read_device_ID(datfp,dat1,MAX_VENDOR_DATA,TRUE)) ;
  2043.       }
  2044.    free(data1) ;
  2045.    free(data2) ;
  2046.    return TRUE ;
  2047. }
  2048.  
  2049. //----------------------------------------------------------------------
  2050.  
  2051. static int merge_new_info(const char *filename)
  2052. {
  2053.    if (!filename || !*filename)
  2054.       return FALSE ;
  2055.    FILE *fp = fopen(filename,"r") ;
  2056.    if (fp)
  2057.       {
  2058.       static char tempfile[] = "pcicfg.$$$" ;
  2059.       FILE *datfp = open_PCICFG_DAT("r") ;
  2060.       FILE *merged = fopen(tempfile,"w") ;
  2061.       if (!datfp)
  2062.      return FALSE ;
  2063.       if (!merged)
  2064.      {
  2065.      fprintf(stderr,"Unable to open temporary file for merge\n") ;
  2066.      return FALSE ;
  2067.      }
  2068.       int success = merge_info(merged,datfp,fp) ;
  2069.       (void) fclose(datfp) ;
  2070.       (void) fclose(fp) ;
  2071.       (void) fclose(merged) ;
  2072.       if (success)
  2073.      {
  2074.      // copy the temporary file over PCICFG.DAT
  2075.      merged = fopen(tempfile,"r") ;
  2076.      fp = open_PCICFG_DAT("w") ;
  2077.      char buffer[BUFSIZ] ;
  2078.      int count ;
  2079.      while ((count = fread(buffer,sizeof(char),sizeof(buffer),merged)) > 0)
  2080.         {
  2081.         if (fwrite(buffer,sizeof(char),count,fp) < count)
  2082.            {
  2083.            fprintf(stderr,"Error copying temporary file to PCICFG.DAT!!\n") ;
  2084.            break ;
  2085.            }
  2086.         }
  2087.      (void) fclose(fp) ;
  2088.      (void) fclose(merged) ;
  2089.      }
  2090.       else
  2091.      fprintf(stderr,"Unable to merge new data!\n") ;
  2092.       unlink(tempfile) ;
  2093.       return success ;
  2094.       }
  2095.    return FALSE ;
  2096. }
  2097.  
  2098. //----------------------------------------------------------------------
  2099.  
  2100. static int merge_new_info(int argc, char **argv)
  2101. {
  2102.     if (!backup_PCICFG_DAT())
  2103.        {
  2104.        fprintf(stderr,"Unable to backup PCICFG.DAT\n") ;
  2105.        return 1 ;
  2106.        }
  2107.     while (argc > 0 && *argv)
  2108.        {
  2109.        if (!merge_new_info(argv[0]))
  2110.       return 2 ;
  2111.        argc-- ;
  2112.        argv++ ;
  2113.        }
  2114.     return 0 ;
  2115. }
  2116.  
  2117. //----------------------------------------------------------------------
  2118.  
  2119. int main(int argc, char **argv)
  2120. {
  2121.    fprintf(stderr,"PCICFG v" VERSION " (c) Copyright 1997,1998 Ralf Brown\n") ;
  2122.    get_exe_directory(argv[0]) ;
  2123.    int maxbus = check_PCI_BIOS() ;
  2124.    if (maxbus < 0)
  2125.       {
  2126.       fprintf(stderr,"\nNo PCI BIOS detected\n") ;
  2127.       return 2 ;
  2128.       }
  2129.    while (argc > 1 && argv[1][0] == '-')
  2130.       {
  2131.       switch (argv[1][1])
  2132.      {
  2133.      case 'm':
  2134.         // merge new info into PCICFG.DAT
  2135.         return merge_new_info(argc-2,argv+2) ;
  2136.      case 't':
  2137.         terse = TRUE ;
  2138.         break ;
  2139.      case 'v':
  2140.         verbose = TRUE ;
  2141.         break ;
  2142.      default:
  2143.         fprintf(stderr,"unrecognized option '%s'\n",argv[1]) ;
  2144.         break ;
  2145.      }
  2146.       argv++ ;
  2147.       argc-- ;
  2148.       }
  2149.    if (!load_device_IDs())
  2150.       {
  2151.       fprintf(stderr,
  2152.           "Unable to load the list of vendor and device IDs (PCICFG.DAT).\n"
  2153.           "Devices will not be identified by name.\n") ;
  2154.       }
  2155.    if (argc == 2 && argv[1][0] == '*')
  2156.       {
  2157.       for (int bus = 0 ; bus <= maxbus ; bus++)
  2158.      {
  2159.      for (int device = 0 ; device < 32 ; device++)
  2160.         {
  2161.         int multifunc = 0 ;
  2162.         for (int func = 0 ; func < 8 ; func++)
  2163.            {
  2164.            if (!dump_PCI_config(bus,device,func,0,multifunc))
  2165.           break ;
  2166.            else if (func == 1)    // some devices only report multi-func
  2167.           multifunc = 1 ;    //   for function 0....
  2168.            }
  2169.         }
  2170.      }
  2171.       return 0 ;
  2172.       }
  2173.    if (argc < 4)
  2174.       {
  2175.       fprintf(stderr,
  2176.           "\nUsage:\tPCICFG [flag(s)] bus device func\n"
  2177.           "\tPCICFG [flag(s)] *         (to scan all devices)\n"
  2178.           "\tPCICFG -m file [file ...]  (to merge new info into PCICFG.DAT)\n"
  2179.           "\n"
  2180.           "Dumps info about the specified PCI device, or all devices\n"
  2181.           "Options:\n"
  2182.           "\t-t\tterse -- output only device type and ID\n"
  2183.           "\t-v\tverbose output for known devices\n"
  2184.           "\n"
  2185.           "Use -v for more verbose output on devices specifically\n"
  2186.           "recognized by PCICFG.  Output is generally quite lengthy\n"
  2187.           "even without -v, so you should redirect output into a\n"
  2188.           "file or pipe it to MORE or LIST\n") ;
  2189.       return 1 ;
  2190.       }
  2191.    char *end = 0 ;
  2192.    int bus = (int)strtol(argv[1],&end,0) ;
  2193.    int device = (int)strtol(argv[2],&end,0) ;
  2194.    int func = (int)strtol(argv[3],&end,0) ;
  2195.    if (bus > maxbus)
  2196.       {
  2197.       fprintf(stderr,"\nRequested PCI bus does not exist\n") ;
  2198.       return 3 ;
  2199.       }
  2200.    else
  2201.       dump_PCI_config(bus,device,func,1,0) ;
  2202.    return 0 ;
  2203. }
  2204.  
  2205. // end of file pcicfg.cpp //
  2206.