home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / pcicf119.zip / PCICFG.CPP < prev    next >
C/C++ Source or Header  |  1999-01-10  |  74KB  |  2,649 lines

  1. /************************************************************************/
  2. /*                                    */
  3. /*  Version 1.19                            */
  4. /*     by Ralf Brown                            */
  5. /*                                    */
  6. /*  File pcicfg.cpp           PCI configuration data dumper        */
  7. /*  LastEdit: 10jan99                            */
  8. /*                                    */
  9. /*  (c) Copyright 1995,1996,1997,1998,1999 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.19"
  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 bctrl_bits[] =
  358.    {
  359.      "parity-resp",            // bit 0
  360.      0,                    // bit 1
  361.      "ISA",                // bit 2
  362.      "VGA",                // bit 3
  363.      0,                    // bit 4
  364.      "mst-abort",            // bit 5
  365.      "bus-reset",            // bit 6
  366.      "fast-b2b",            // bit 7
  367.    } ;
  368.  
  369. static const char *const select_timing[] =
  370.    {
  371.     "fast",
  372.     "med",
  373.     "slow",
  374.     "???"
  375.    } ;
  376.  
  377. static const char *const PMC_bits[] =
  378.    {
  379.      0,                 // bits 0-2: version (001)
  380.      0,
  381.      0,
  382.      "PME-Clk",                // bit 3: PM Event Clock
  383.      "aux-pwr-PME#",            // bit 4: need aux power for PME#
  384.      "DevSpec Init",                    // bit 5
  385.      0,                 // bits 6-7: DynClk
  386.      0,
  387.      "FullClk",
  388.      "D1-supp",
  389.      "D2-supp",
  390.      "PME#-D0",                         // bit 11
  391.      "PME#-D1",                         // bit 12
  392.      "PME#-D2",                         // bit 13
  393.      "PME#-D3hot",                      // bit 14
  394.      "PME#-D3cold",                     // bit 15
  395.    } ;
  396.  
  397. /************************************************************************/
  398. /*    global variables                            */
  399. /************************************************************************/
  400.  
  401. static int verbose = FALSE ;
  402. static int terse = FALSE ;
  403. static int first_device = TRUE ;
  404. static int bypass_BIOS = FALSE ;
  405. static int cfg_mech = 1 ;        // PCI access mechanism: 1 or 2
  406.  
  407. static char *exe_directory = "." ;
  408.  
  409. static char *device_ID_data = 0 ;
  410. /* format of ID data once loaded:
  411.           char*  -> next vendor or 0
  412.       WORD   vendor ID
  413.       ASCIZ     vendor name
  414.       WORD   device ID
  415.       ASCIZ     device name
  416.       ...
  417.       char*     -> next vendor or 0
  418.       WORD   vendor ID
  419.       ASCIZ     vendor name
  420.       .....
  421. */
  422.  
  423. /************************************************************************/
  424. /*    Helper Functions                        */
  425. /************************************************************************/
  426.  
  427. static void get_exe_directory(const char *argv0)
  428. {
  429.    char *pathname = (char*)malloc(strlen(argv0)+2) ;
  430.    strcpy(pathname,argv0) ;
  431.    // strip off any existing extension
  432.    char *slash = strrchr(pathname,'/') ;
  433.    char *backslash = strrchr(pathname,'\\') ;
  434.    if (backslash && (!slash || backslash > slash))
  435.       slash = backslash ;
  436.    if (slash)
  437.       *slash = '\0' ;
  438.    else
  439.       strcpy(pathname,".") ;
  440.    exe_directory = pathname ;
  441. }
  442.  
  443. //----------------------------------------------------------------------
  444.  
  445. static const char *skip_whitespace(const char *line)
  446. {
  447.    while (*line && isspace(*line))
  448.       line++ ;
  449.    return line ;
  450. }
  451.  
  452. //----------------------------------------------------------------------
  453.  
  454. inline char *skip_whitespace(char *line)
  455. {
  456.    return (char*)skip_whitespace((const char *)line) ;
  457. }
  458.  
  459. //----------------------------------------------------------------------
  460.  
  461. static int is_comment_line(const char *line,int pcicfg_format = 0)
  462. {
  463.    // if in Craig Hart's format, we want to skip the subsystem-vendor-ID
  464.    //   lines (those starting with two tab characters) because PCICFG doesn't
  465.    //   support them
  466.    if (!pcicfg_format && line[0] == '\t' && line[1] == '\t')
  467.       return TRUE ;
  468.    line = skip_whitespace(line) ;
  469.    // blank lines and lines whose first nonwhite character is a semicolon
  470.    // can be skipped as comments
  471.    if (*line == '\0' || *line == '\n' || *line == ';')
  472.       return TRUE ;
  473.    else
  474.       return FALSE ;
  475. }
  476.  
  477. //----------------------------------------------------------------------
  478.  
  479. static int read_nonblank_line(char *buf, int size, FILE *fp, int pcicfg_format)
  480. {
  481.    do {
  482.       buf[0] = '\0' ;
  483.       if (!fgets(buf,size,fp) || feof(fp))
  484.      return FALSE ;
  485.       } while (is_comment_line(buf,pcicfg_format)) ;
  486.    return TRUE ;
  487. }
  488.  
  489. //----------------------------------------------------------------------
  490.  
  491. static WORD hextoint(const char *&digits)
  492. {
  493.    WORD hex = 0 ;
  494.    while (isxdigit(*digits))
  495.       {
  496.       int digit = toupper(*digits++) - '0' ;
  497.       if (digit > 9)
  498.      digit -= ('A'-'0'-10) ;
  499.       hex = 16*hex + digit ;
  500.       }
  501.    return hex ;
  502. }
  503.  
  504. //----------------------------------------------------------------------
  505.  
  506. static FILE *open_PCICFG_DAT(const char *fopen_mode)
  507. {
  508.    int dir_len = strlen(exe_directory) ;
  509.    char *datafile = (char*)malloc(dir_len+15) ;
  510.    if (!datafile)
  511.       {
  512.       fprintf(stderr,"Insufficient memory for PCICFG.DAT pathname\n") ;
  513.       return FALSE ;
  514.       }
  515.    sprintf(datafile,"%s/PCICFG.DAT",exe_directory) ;
  516.    FILE *fp = fopen(datafile,fopen_mode) ;
  517.    free(datafile) ;
  518.    if (!fp)
  519.       fprintf(stderr,"Unable to open PCICFG.DAT in mode \"%s\"\n",fopen_mode) ;
  520.    return fp ;
  521. }
  522.  
  523. //----------------------------------------------------------------------
  524.  
  525. static int backup_PCICFG_DAT()
  526. {
  527.    int dir_len = strlen(exe_directory) ;
  528.    char *datafile = (char*)malloc(dir_len+15) ;
  529.    if (!datafile)
  530.       {
  531.       fprintf(stderr,"Insufficient memory for PCICFG.DAT pathname\n") ;
  532.       return FALSE ;
  533.       }
  534.    sprintf(datafile,"%s/PCICFG.DAT",exe_directory) ;
  535.    FILE *fp = fopen(datafile,"r") ;
  536.    if (!fp)
  537.       {
  538.       free(datafile) ;
  539.       return FALSE ;
  540.       }
  541.    strcpy(datafile+strlen(datafile)-4,".BAK") ;
  542.    FILE *backup = fopen(datafile,"w") ;
  543.    if (!backup)
  544.       {
  545.       free(datafile) ;
  546.       return FALSE ;
  547.       }
  548.    char buffer[BUFSIZ] ;
  549.    int count ;
  550.    int success = TRUE ;
  551.    while ((count = fread(buffer,sizeof(char),sizeof(buffer),fp)) > 0)
  552.       {
  553.       if (fwrite(buffer,sizeof(char),count,backup) < count)
  554.      success = FALSE ;
  555.       }
  556.    fclose(fp) ;
  557.    fclose(backup) ;
  558.    if (!success)
  559.       {
  560.       fprintf(stderr,"Backup of PCICFG.DAT failed!\n") ;
  561.       unlink(datafile) ;
  562.       }
  563.    free(datafile) ;
  564.    return success ;
  565. }
  566.  
  567. /************************************************************************/
  568. /************************************************************************/
  569.  
  570. #if defined(__WATCOMC__) && defined(__386__)
  571. extern DWORD inpd(int portnum) ;
  572. #pragma aux inpd = \
  573.    "in eax,dx" \
  574.    parm [edx] \
  575.    value [eax] \
  576.    modify exact [eax] ;
  577.  
  578. #else
  579. static DWORD inpd(int portnum)
  580. {
  581.    static DWORD value ;
  582.    asm mov dx,portnum ;
  583.    asm lea bx,value ;
  584. #if defined(__BORLANDC__)
  585.    __emit__(0x66,0x50,            // push EAX
  586.         0x66,0xED,            // in EAX,DX
  587.         0x66,0x89,0x07,        // mov [BX],EAX
  588.         0x66,0x58) ;        // pop EAX
  589. #else
  590.    asm push eax
  591.    asm in eax,dx ;
  592.    asm mov [bx],eax ;
  593.    asm pop eax
  594. #endif
  595.    return value ;
  596. }
  597. #endif /* __WATCOMC__ */
  598.  
  599. //----------------------------------------------------------------------
  600.  
  601. #if defined(__WATCOMC__) && defined(__386__)
  602. extern void outpd(int portnum, DWORD value) ;
  603. #pragma aux outpd = \
  604.    "out dx,eax" \
  605.    parm [edx][eax] \
  606.    modify exact [] ;
  607.    
  608. #else
  609. static void outpd(int portnum, DWORD val)
  610. {
  611.    static DWORD value = 0 ;
  612.  
  613.    value = val ;
  614.    asm mov dx,portnum ;
  615.    asm lea bx,value ;
  616. #if defined(__BORLANDC__)
  617.    __emit__(0x66,0x50,            // push EAX
  618.         0x66,0x8B,0x07,        // mov EAX,[BX]
  619.         0x66,0xEF,            // out DX,EAX
  620.         0x66,0x58) ;        // pop EAX
  621. #else
  622.    asm push eax
  623.    asm mov eax,[bx] ;
  624.    asm out dx,eax ;
  625.    asm pop eax
  626. #endif
  627.    return ;
  628. }
  629. #endif /* __WATCOMC__ */
  630.  
  631. //----------------------------------------------------------------------
  632.  
  633. #if defined(__WATCOMC__)
  634. extern void outp(short portnumber, BYTE value) ;
  635. #pragma aux outp = \
  636.    "out dx,al" \
  637.    parm [dx][al] \
  638.    modify exact [] ;
  639.  
  640. extern BYTE inp(short portnumber) ;
  641. #pragma aux inp = \
  642.    "in al,dx" \
  643.   parm [dx] \
  644.   value [al] \
  645.   modify exact [al] ;
  646. #endif /* __WATCOMC__ */
  647.  
  648.  
  649. /************************************************************************/
  650. /************************************************************************/
  651.  
  652. static int check_PCI_BIOS()
  653. {
  654.    union REGS regs ;
  655. #if defined(__WATCOMC__) && defined(__386__)
  656.    regs.w.ax = 0xB101 ;
  657.    int386(0x1A,®s,®s) ;
  658. #else
  659.    regs.x.ax = 0xB101 ;
  660.    int86(0x1A,®s,®s) ;
  661. #endif /* __WATCOMC__ && __386__ */
  662.    if (regs.h.ah == 0x00)
  663.       return regs.h.cl ;        // last PCI bus in system
  664.    else
  665.       return -1 ;            // no PCI BIOS detected
  666. }
  667.  
  668. //----------------------------------------------------------------------
  669.  
  670. static void determine_cfg_mech()
  671. {
  672.    union REGS regs ;
  673. #if defined(__WATCOMC__) && defined(__386__)
  674.    regs.w.ax = 0xB101 ;
  675.    int386(0x1A,®s,®s) ;
  676. #else
  677.    regs.x.ax = 0xB101 ;
  678.    int86(0x1A,®s,®s) ;
  679. #endif /* __WATCOMC__ && __386__ */
  680.    if (regs.h.ah == 0x00)
  681.       {
  682.       // we have a PCI BIOS, so check which configuration mechanism(s) it
  683.       // supports
  684.       int mechs = regs.h.al & 0x03 ;
  685.       if (mechs & 0x01)
  686.      cfg_mech = 1 ;
  687.       else if (mechs & 0x02)
  688.      cfg_mech = 2 ;
  689.       else
  690.      cfg_mech = 1 ;            // default is to assume mechanism #1
  691.       }
  692.    return ;
  693. }
  694.  
  695. //----------------------------------------------------------------------
  696.  
  697. static int read_DWORD_register(int bus, int device, int func, int reg,
  698.                    WORD *lo, WORD *hi)
  699. {
  700.    if (bypass_BIOS)
  701.       {
  702.       DWORD value ;
  703.       if (cfg_mech == 1)
  704.      {
  705.      DWORD addr = 0x80000000L | (((DWORD)(bus & 0xFF)) << 16) |
  706.               ((((unsigned)device) & 0x1F) << 11) |
  707.               ((((unsigned)func) & 0x07) << 8) | (reg & 0xFC) ;
  708.      DWORD orig = inp(0xCF8) ;    // get current state
  709.      outpd(0xCF8,addr) ;        // set up addressing to config data
  710.      value = inpd(0xCFC) ;        // get requested DWORD of config data
  711.      outpd(0xCF8,orig) ;        // restore configuration control
  712.      }
  713.       else // cfg_mech == 2
  714.      {
  715.      if (device > 0x0F)        // mech#2 only supports 16 devices
  716.         {                //   per bus
  717.         *lo = 0xFFFF ;
  718.         *hi = 0xFFFF ;
  719.         return FALSE ;
  720.         }
  721.      BYTE oldenable = inp(0xCF8) ;    // store current state of config space
  722.      BYTE oldbus = inp(0xCFA) ;
  723.      outp(0xCFA,bus) ;
  724.      outp(0xCF8,0x80) ;        // enable configuration space
  725.      WORD addr = 0xC000 | ((device & 0x0F) << 8) | (reg & 0xFF) ;
  726.      value = inpd(addr) ;
  727.      outp(0xCFA,oldbus) ;        // restore configuration space
  728.      outp(0xCF8,oldenable) ;
  729.      }
  730.       *hi = (WORD)(value >> 16) ;
  731.       *lo = (WORD)(value & 0xFFFF) ;
  732.       return TRUE ;
  733.       }
  734.    else // use BIOS
  735.       {
  736.       union REGS regs, outregs ;
  737.       regs.h.bh = bus ;
  738.       regs.h.bl = (device<<3) | (func & 0x07) ;
  739. #if defined(__WATCOMC__) && defined(__386__)
  740.       regs.w.ax = 0xB109 ;
  741.       regs.w.di = reg ;
  742.       int386(0x1A,®s,&outregs) ;
  743.       if (outregs.x.cflag != 0)
  744.      return FALSE ;
  745.       *lo = outregs.w.cx ;
  746.       regs.w.di += 2 ;
  747.       int386(0x1A,®s,&outregs) ;
  748.       if (outregs.x.cflag != 0)
  749.      return FALSE ;
  750.       *hi = outregs.w.cx ;
  751. #else
  752.       regs.x.ax = 0xB109 ;
  753.       regs.x.di = reg ;
  754.       int86(0x1A,®s,&outregs) ;
  755.       if (outregs.x.cflag != 0)
  756.      return FALSE ;
  757.       *lo = outregs.x.cx ;
  758.       regs.x.di += 2 ;
  759.       int86(0x1A,®s,&outregs) ;
  760.  
  761.       if (outregs.x.cflag != 0)
  762.      return FALSE ;
  763.       *hi = outregs.x.cx ;
  764. #endif /* __WATCOMC__ && __386__ */
  765.       }
  766.    return TRUE ;
  767. }
  768.  
  769. //----------------------------------------------------------------------
  770.  
  771. static void write_DWORD_register(int bus,int device,int func,
  772.                  int reg, WORD lo, WORD hi)
  773. {
  774.    if (bypass_BIOS)
  775.       {
  776.       DWORD value = ((DWORD)hi << 16) | lo ;
  777.       if (cfg_mech == 1)
  778.      {
  779.      DWORD addr = 0x80000000L | ((DWORD)(bus & 0xFF) << 16) |
  780.               ((device & 0x1F) << 11) | ((func & 0x07) << 8) |
  781.               (reg & 0xFC) ;
  782.      DWORD orig = inpd(0xCF8) ;
  783.      outpd(0xCF8,addr) ;
  784.      outpd(0xCFC,value) ;
  785.      outpd(0xCF8,orig) ;
  786.      }
  787.       else
  788.      {
  789.      if (device > 0x0F)
  790.         return ;
  791.      BYTE oldenable = inp(0xCF8) ;
  792.      BYTE oldbus = inp(0xCFA) ;
  793.      outp(0xCFA,bus) ;
  794.      outp(0xCF8,0x80) ;        // enable configuration space
  795.      WORD addr = 0xC000 | ((device & 0x0F) << 8) | reg ;
  796.      outpd(addr,value) ;
  797.      outp(0xCFA,oldbus) ;
  798.      outp(0xCF8,oldenable) ;
  799.      }
  800.       }
  801.    else
  802.       {
  803.       union REGS regs, outregs ;
  804.  
  805.       regs.h.bh = bus ;
  806.       regs.h.bl = (device<<3) | (func & 0x07) ;
  807. #if defined(__WATCOMC__) && defined(__386__)
  808.       regs.w.ax = 0xB10D ;        // write configuration DWORD
  809.       regs.w.di = reg ;
  810.       regs.x.ecx = ((long)hi) << 16 | ((unsigned)lo) ;
  811.       int386(0x1A,®s,&outregs) ;
  812. #else
  813.       regs.x.ax = 0xB10C ;        // write configuration word
  814.       regs.x.di = reg ;
  815.       regs.x.cx = lo ;
  816.       int86(0x1A,®s,&outregs) ;
  817.       regs.x.di += 2 ;
  818.       regs.x.cx = hi ;
  819.       int86(0x1A,®s,&outregs) ;
  820. #endif /* __WATCOMC__ && __386__ */
  821.       }
  822.    return ;
  823. }
  824.  
  825. //----------------------------------------------------------------------
  826.  
  827. static PCIcfg *read_PCI_config(int bus, int device, int func)
  828. {
  829.    static PCIcfg cfg ;
  830.  
  831.    for (int i = 0 ; i < sizeof(cfg)/sizeof(DWORD) ; i++)
  832.       {
  833.       WORD hi, lo ;
  834.       if (!read_DWORD_register(bus,device,func,i*sizeof(DWORD),&lo,&hi))
  835.      return 0 ;
  836.       ((WORD*)&cfg)[2*i] = lo ;
  837.       ((WORD*)&cfg)[2*i+1] = hi ;
  838.       }
  839.    return &cfg ;
  840. }
  841.  
  842. //----------------------------------------------------------------------
  843.  
  844. static const char *get_subclass_name(int classcode, int subclass)
  845. {
  846.    if (classcode < 0 || classcode >= lengthof(subclass_data) ||
  847.        subclass_data[classcode] == 0)
  848.       return "???" ;
  849.    const subclass_info *subinfo = subclass_data[classcode] ;
  850.    while (subinfo->subclass_code != -1)
  851.       {
  852.       if (subinfo->subclass_code == subclass)
  853.      return subinfo->subclass_name ;
  854.       subinfo++ ;
  855.       }
  856.    return "???" ;
  857. }
  858.  
  859. //----------------------------------------------------------------------
  860.  
  861. static const char *get_vendor_name(WORD vendorID)
  862. {
  863.    if (vendorID == 0x0000 || vendorID == 0xFFFF)
  864.       return "Not Present" ;
  865.    char *next ;
  866.    for (char *data = device_ID_data ; data ; data = next)
  867.       {
  868.       next = *((char**)data) ;
  869.       data += sizeof(char*) ;
  870.       data += sizeof(WORD) ;        // skip the length field
  871.       WORD ID = *((WORD*)data) ;
  872.       data += sizeof(WORD) ;
  873.       if (ID == vendorID)
  874.      return data ;
  875.       }
  876.    // if we get here, there was no matching ID in the file,
  877.    return "???" ;
  878. }
  879.  
  880. //----------------------------------------------------------------------
  881.  
  882. static const char *get_device_name(WORD vendorID, WORD deviceID)
  883. {
  884.    if (vendorID == 0x0000 || vendorID == 0xFFFF || deviceID == 0xFFFF)
  885.       return "Not Present" ;
  886.    char *data = device_ID_data ;
  887.    while (data)
  888.       {
  889.       char *next = *((char**)data) ;
  890.       data += sizeof(char*) ;
  891.       WORD length = *((WORD*)data) ;
  892.       data += sizeof(WORD) ;
  893.       char *end = data + length ;
  894.       WORD ID = *((WORD*)data) ;
  895.       data += sizeof(WORD) ;
  896.       if (ID == vendorID)
  897.      {
  898.      // OK, we've found the vendor, now scan for the device
  899.      // 1. skip the vendor name
  900.      while (*data)
  901.         data++ ;
  902.      if (data < end)        // skip the NUL
  903.         data++ ;
  904.      // 2. check each device ID in turn
  905.      while (data < end)
  906.         {
  907.         ID = *((WORD*)data) ;
  908.         data += sizeof(WORD) ;
  909.         if (ID == deviceID)
  910.            return data ;
  911.         while (*data)
  912.            data++ ;
  913.         data++ ;            // skip the NUL
  914.         }
  915.      // if we get here, there was no match for the device ID
  916.      break ;
  917.      }
  918.       data = next ;
  919.       }
  920.    // if we get here, there was no matching ID in the file,
  921.    return "???" ;
  922. }
  923.  
  924. //----------------------------------------------------------------------
  925.  
  926. static int load_device_info(FILE *fp, char * &format_string,
  927.                 char const * &enum_list)
  928. {
  929.    if (!fp)
  930.       return FALSE ;
  931.    long int filesize = lseek(fileno(fp),0L,SEEK_END) ;
  932.    fseek(fp,0L,SEEK_SET) ;        // back to beginning of file
  933.    char line[MAX_LINE] ;
  934.    // read until we find the actual beginning of the device definition
  935.    do {
  936.       line[0] = '\0' ;            // catch EOF or read error
  937.       fgets(line,sizeof(line),fp) ;
  938.       } while (!feof(fp) && strncmp(line,"!begin",6) != 0) ;
  939.    int datasize = (int)(filesize - ftell(fp)) ;
  940.    char *buffer = (char*)malloc(datasize+3) ;
  941.    int readsize ;
  942.    char *newline ;
  943.    if (buffer && (readsize = fread(buffer,sizeof(char),datasize,fp)) > 0)
  944.       {
  945.       buffer[readsize] = '\0' ;        // ensure proper string termination
  946.       format_string = buffer ;
  947.       enum_list = format_string ;
  948.       if (*enum_list == '\n')
  949.      enum_list++ ;
  950.       // look forward to end of format string, then chop into two strings
  951.       do {
  952.      newline = strchr(enum_list,'\n') ;
  953.      if (newline && strncmp(newline+1,"!end",4) == 0)
  954.         {
  955.         newline[1] = '\0' ;
  956.         newline = strchr(newline+2,'\n') ;
  957.         if (newline)
  958.            enum_list = newline ;
  959.         else
  960.            enum_list = newline+2 ;
  961.         break ;
  962.         }
  963.      if (newline)
  964.         enum_list = newline+1 ;
  965.      } while (newline) ;
  966.       }
  967.    else
  968.       return FALSE ;
  969.    // scan until we find the actual beginning of the 'enum' definition
  970.    char *result = (char*)enum_list ;
  971.    newline = (char*)enum_list ;
  972.    do {
  973.       newline = strchr(newline,'\n') ;
  974.       if (newline)
  975.      {
  976.      newline++ ;
  977.      if (strncmp(newline,"!enum",5) == 0)
  978.         break ;
  979.      }
  980.       } while (newline) ;
  981.    if (newline)
  982.       {
  983.       newline++ ;
  984.       // format of the enum:
  985.       //    !enum enum_name
  986.       //     enumvalue0
  987.       //     enumvalue1
  988.       //     ...
  989.       //     enumvalueN
  990.       //    !end
  991.       do {
  992.      // extract the enum's name
  993.      //assert(strcmp(newline,"!enum",5) == 0) ;
  994.      newline = skip_whitespace(newline+5) ;
  995.      const char *end = strchr(newline,'\n') ;
  996.      if (!end)
  997.         break ;
  998.      memcpy(result,newline,end-newline+1) ;
  999.      result += (end-newline+1) ;
  1000.      newline = (char*)end+1 ;
  1001.      while (*newline && strncmp(newline,"!end",4) != 0)
  1002.         {
  1003.         newline = skip_whitespace(newline) ;
  1004.         char *end = strchr(newline,'\n') ;
  1005.         if (!end)
  1006.            end = strchr(newline,'\0') ;
  1007.         char *next = *end ? end+1 : end ;
  1008.         while (end > newline && isspace(end[-1]))
  1009.            end-- ;
  1010.         memcpy(result,newline,end-newline) ;
  1011.         result[end-newline] = '\n' ;
  1012.         result += (end-newline+1) ;
  1013.         newline = next ;
  1014.         }
  1015.      *result++ = '\0' ;
  1016.      // one enum is done, so scan for the next (if any)
  1017.      while ((newline = strchr(newline,'\n')) != 0)
  1018.         {
  1019.         newline++ ;
  1020.         if (strncmp(newline,"!enum",5) == 0)
  1021.            break ;
  1022.         }
  1023.      } while (newline && *newline) ;
  1024.       }
  1025.    *result++ = '\0' ;
  1026.    return TRUE ;
  1027. }
  1028.  
  1029. //----------------------------------------------------------------------
  1030.  
  1031. static int know_device(WORD vendor, WORD device,
  1032.                char * &format_string, char const * &enum_list)
  1033. {
  1034.    if (vendor == 0x0000 || vendor == 0xFFFF || device == 0xFFFF)
  1035.       return FALSE ;
  1036.    // see if there's a data file for this device
  1037.    int dir_len = strlen(exe_directory) ;
  1038.    char *device_file = (char*)malloc(dir_len+14) ;
  1039.    if (device_file)
  1040.       {
  1041.       sprintf(device_file,"%s/%4.04X%4.04X.PCI",exe_directory,vendor,device) ;
  1042.       device_file[dir_len+13] = '\0' ;
  1043.       FILE *fp = fopen(device_file,"r") ;
  1044.       free(device_file) ;
  1045.       if (fp)
  1046.      {
  1047.      int success = load_device_info(fp,format_string,enum_list) ;
  1048.      fclose(fp) ;
  1049.      return success ;
  1050.      }
  1051.       }
  1052.    return FALSE ;
  1053. }
  1054.  
  1055. //----------------------------------------------------------------------
  1056.  
  1057. static void write_bits(WORD bitflags, const char *const *flagnames, int numbits)
  1058. {
  1059.    for (int i = 0 ; i < numbits ; i++)
  1060.       {
  1061.       if ((bitflags & (1 << i)) != 0 && flagnames[i])
  1062.      printf(" %s",flagnames[i]) ;
  1063.       }
  1064. }
  1065.  
  1066. #define WRITE_CMD_BITS(x) write_bits((x),command_bits,lengthof(command_bits))
  1067. #define WRITE_STAT_BITS(x) write_bits((x),status_bits,lengthof(status_bits))
  1068. #define WRITE_BCTRL_BITS(x) write_bits((x),bctrl_bits,lengthof(bctrl_bits))
  1069.  
  1070. //----------------------------------------------------------------------
  1071.  
  1072. static DWORD extract_field(const char *&s, const char *cfg)
  1073. {
  1074.    DWORD value = 0 ;
  1075.    int addr = 0 ;
  1076.    while (*s == '[' || *s == '|')
  1077.       {
  1078.       s++ ;
  1079.       int lowbit = 0 ;
  1080.       int highbit = 7 ;
  1081.       while (*s && isxdigit(*s))
  1082.      {
  1083.      int digit = *s - '0' ;
  1084.      if (digit > 9)
  1085.         digit -= ('A'-10-'0') ;
  1086.      addr = 16*addr + digit ;
  1087.      s++ ;
  1088.      }
  1089.       addr &= 0x00FF ;
  1090.       if (*s == ':')
  1091.      {
  1092.      s++ ;
  1093.      while (*s && isdigit(*s))
  1094.         {
  1095.         lowbit = 10*lowbit + (*s-'0') ;
  1096.         s++ ;
  1097.         }
  1098.      if (*s == '-')
  1099.         {
  1100.         highbit = 0 ;
  1101.         s++ ;
  1102.         while (*s && isdigit(*s))
  1103.            {
  1104.            highbit = 10*highbit + (*s-'0') ;
  1105.            s++ ;
  1106.            }
  1107.         }
  1108.      else
  1109.         highbit = lowbit ;
  1110.      if (highbit < lowbit)
  1111.         {
  1112.         int tmp = lowbit ;
  1113.         lowbit = highbit ;
  1114.         highbit = tmp ;
  1115.         }
  1116.      if (highbit > 31)
  1117.         {
  1118.         if (highbit - lowbit >= 32)
  1119.            highbit = 31 ;
  1120.         }
  1121.      if (lowbit/8)
  1122.         {
  1123.         int adj = lowbit/8 ;
  1124.         addr += adj ;
  1125.         adj *= 8 ;
  1126.         lowbit -= adj ;
  1127.         highbit -= adj ;
  1128.         }
  1129.      }
  1130.       DWORD prev_value = value << (highbit-lowbit+1) ;
  1131.       if (highbit > 16)
  1132.      {
  1133.      value = cfg[addr] + (cfg[addr+1] << 8) + ((DWORD)cfg[addr+2] << 16) +
  1134.          ((DWORD)cfg[addr+3] << 24) ;
  1135.      }
  1136.       else if (highbit > 8)
  1137.      value = cfg[addr] + (cfg[addr+1] << 8) ;
  1138.       else
  1139.      value = cfg[addr] ;
  1140.       DWORD mask = 0 ;
  1141.       for (int i = lowbit ; i <= highbit ; i++)
  1142.      mask |= (1L << i-lowbit) ;
  1143.       while (lowbit-- > 0)
  1144.          value >>= 1 ;
  1145.       value &= mask ;
  1146.       if (*s == '<')
  1147.      {
  1148.      s++ ;
  1149.      int shift = 0 ;
  1150.      while (*s && isdigit(*s))
  1151.         {
  1152.         shift = 10*shift + (*s-'0') ;
  1153.         s++ ;
  1154.         }
  1155.      while (shift-- > 0)
  1156.         {
  1157.         value <<= 1 ;
  1158.         prev_value <<= 1 ;
  1159.         }
  1160.      }
  1161.       if (*s == '*')
  1162.      {
  1163.      s++ ;
  1164.      unsigned mult = 0 ;
  1165.      while (*s && isdigit(*s))
  1166.         {
  1167.         mult = 10*mult + (*s-'0') ;
  1168.         s++ ;
  1169.         }
  1170.      if (mult == 0)
  1171.         mult =1 ;
  1172.      value *= mult ;
  1173.      prev_value *= mult ;
  1174.      }
  1175.       value |= prev_value ;
  1176.       if (*s == '+')
  1177.      {
  1178.      *s++ ;
  1179.      int negative = 0 ;
  1180.      if (*s == '-')
  1181.         negative = 1 ;
  1182.      long offset = 0 ;
  1183.      while (*s && isdigit(*s))
  1184.         {
  1185.         offset = 10*offset + (*s-'0') ;
  1186.         s++ ;
  1187.         }
  1188.      if (negative)
  1189.         offset = -offset ;
  1190.      value += offset ;
  1191.      }
  1192.       if (*s == ']')
  1193.      {
  1194.      s++ ;
  1195.      break ;
  1196.      }
  1197.       }
  1198.    return value ;
  1199. }
  1200.  
  1201. //----------------------------------------------------------------------
  1202.  
  1203. static void format_number(FILE *out, DWORD val, int width, int base)
  1204. {
  1205.    char buf[38] ;            // enough for DWORD, plus fudge factor
  1206.    static char digits[] = "0123456789ABCDEF" ;
  1207.    int count = 0 ;
  1208.    do {
  1209.       int digit = (int)(val % base) ;
  1210.       val /= base ;
  1211.       buf[count++] = digits[digit] ;
  1212.       } while (val) ;
  1213.    buf[count] = '\0' ;
  1214.    for (int i = 0 ; i < count/2 ; i++)
  1215.       {
  1216.       char tmp = buf[count-i-1] ;
  1217.       buf[count-i-1] = buf[i] ;
  1218.       buf[i] = tmp ;
  1219.       }
  1220.    if (count < width)
  1221.       {
  1222.       for (int i = count ; i < width ; i++)
  1223.      fputc(base == 10 ? ' ' : '0',out) ;
  1224.       }
  1225.    fputs(buf,out) ;
  1226.    return ;
  1227. }
  1228.  
  1229. //----------------------------------------------------------------------
  1230.  
  1231. static void format_enabled(FILE *out, DWORD value, int width)
  1232. {
  1233.    int w = value ? 6 : 7 ;
  1234.    for (int i = w ; i < width ; i++)
  1235.       fputc(' ',out) ;
  1236.    fputs(value ? "enable" : "disable",out) ;
  1237. }
  1238.  
  1239. //----------------------------------------------------------------------
  1240.  
  1241. static void format_flag(FILE *out, DWORD value, int width)
  1242. {
  1243.    for (int i = 1 ; i < width ; i++)
  1244.       fputc(' ',out) ;
  1245.    fputc(value ? '√' : '-',out) ;
  1246. }
  1247.  
  1248.  
  1249. //----------------------------------------------------------------------
  1250.  
  1251. static void format_yesno(FILE *out, DWORD value, int width)
  1252. {
  1253.    for (int i = 1 ; i < width ; i++)
  1254.       fputc(' ',out) ;
  1255.    fputc(value ? 'Y' : 'N',out) ;
  1256. }
  1257.  
  1258. //----------------------------------------------------------------------
  1259.  
  1260. static void format_full_yesno(FILE *out, DWORD value, int width)
  1261. {
  1262.    if (width < 3)
  1263.       width = 3 ;
  1264.    for (int i = (value ? 3 : 2) ; i < width ; i++)
  1265.       fputc(' ',out) ;
  1266.    fputs(value ? "Yes" : "No",out) ;
  1267. }
  1268.  
  1269. //----------------------------------------------------------------------
  1270.  
  1271. static void format_charlist(FILE *out, DWORD value, int width,
  1272.                 const char *&chars)
  1273. {
  1274.    for (int i = 1 ; i < width ; i++)
  1275.       fputc(' ',out) ;
  1276.    int n = 0 ;
  1277.    chars++ ;                // skip opening brace
  1278.    const char *ch = chars ;
  1279.    while (*chars && *chars != '}')
  1280.       {
  1281.       n++ ;
  1282.       chars++ ;
  1283.       }
  1284.    if (value >= n)
  1285.       value = n-1 ;
  1286.    fputc(ch[(size_t)value],out) ;
  1287. }
  1288.  
  1289. //----------------------------------------------------------------------
  1290.  
  1291. static const char *find_enum(const char *name, const char *name_end,
  1292.                  const char *enums)
  1293. {
  1294.    const char *e = 0 ;
  1295.    if (name && enums)
  1296.       {
  1297.       size_t len = name_end - name ;
  1298.       const char *enum_list = enums ;
  1299.       while (*enums)
  1300.      {
  1301.      if (strncmp(name,enums,len) == 0 && enums[len] == '\n')
  1302.         return enums ;
  1303.      enums = strchr(enums,'\0') + 1 ;
  1304.      }
  1305.       // OK, first pass didn't find any exact match, so try to find a prefix
  1306.       enums = enum_list ;
  1307.       while (*enums)
  1308.      {
  1309.      if (strncmp(name,enums,len) == 0)
  1310.         return enums ;
  1311.      enums = strchr(enums,'\0') + 1 ;
  1312.      }
  1313.       }
  1314.    return e ;
  1315. }
  1316.  
  1317. //----------------------------------------------------------------------
  1318.  
  1319. static const char *format_enum(FILE *out, DWORD value, int width,
  1320.                    const char *name, const char *enums)
  1321. {
  1322.    if (!out || !enums)
  1323.       return name ;
  1324.    //asssert(*name == '(') ;
  1325.    name++ ;                // skip the open paren
  1326.    const char *end = name ;
  1327.    while (*end && *end != ')')
  1328.       end++ ;
  1329.    const char *e = find_enum(name,end,enums) ;
  1330.    if (e)
  1331.       {
  1332.       // format of string pointed at by 'e':
  1333.       //      name \n value0 \n value1 \n value2 \n ... \n valueN \0
  1334.       e = strchr(e,'\n') ;
  1335.       if (e) e++ ;
  1336. //      size_t orig_value = value ;
  1337.       while (value > 0)
  1338.      {
  1339.      const char *next = strchr(e,'\n') ;
  1340.      if (!next)
  1341. #if 1
  1342.         break ;
  1343. #else
  1344.         {
  1345.         fflush(stdout) ;
  1346.         fprintf(stderr,"undefined value %d given for enum '%.4s'\n",
  1347.             orig_value,name) ;
  1348.         return end ;
  1349.         }
  1350. #endif /* 0/1 */
  1351.      e = next+1 ;
  1352.      value-- ;
  1353.      }
  1354.       // OK, we have the desired string, so output it
  1355.       size_t count = 0 ;
  1356.       while (*e && *e != '\n')
  1357.      {
  1358.      if (*e == '\\')
  1359.         {
  1360.         switch (*++e)
  1361.            {
  1362.            case '\n':
  1363.           // do nothing, this was just a dummy to retain trailing
  1364.           // white space
  1365.           break ;
  1366.            case 't':
  1367.           width -= (count%8) ;
  1368.           count = (8*((count+7)/8))-1 ;
  1369.           // fall through to default case
  1370.            default:
  1371.           fputc(*e++,out) ;
  1372.            }
  1373.         }
  1374.      else
  1375.         {
  1376.         fputc(*e++,out) ;
  1377.         count++ ;
  1378.         }
  1379.      width-- ;
  1380.      }
  1381.       }
  1382.    else
  1383.       {
  1384.       fputs("■enum■",out) ;
  1385.       width-- ;
  1386.       }
  1387.    for (int i = 0 ; i < width ; i++)
  1388.       fputc(' ',out) ;
  1389.    return end ;
  1390. }
  1391.  
  1392. //----------------------------------------------------------------------
  1393.  
  1394. static const char *format_option(FILE *out, DWORD value, int width,
  1395.                  const char *option)
  1396. {
  1397.    if (!out || !option)
  1398.       return option ;
  1399.    char terminator = *option++ ;
  1400.    const char *end = strchr(option,terminator) ;
  1401.    if (!end)
  1402.       return option ;
  1403.    int len = end-option ;
  1404.    if (width == 0)
  1405.       width = len ;
  1406.    for (int i = len ; i < width ; i++)
  1407.       fputc(' ',out) ;
  1408.    if (value)
  1409.       fwrite(option,sizeof(char),len,out) ;
  1410.    else
  1411.       {
  1412.       while (len-- > 0)
  1413.      fputc('-',out) ;
  1414.       }
  1415.    return end ;
  1416. }
  1417.  
  1418. //----------------------------------------------------------------------
  1419.  
  1420. static const char *format_alternative(FILE *out, DWORD value, int width,
  1421.                       const char *option)
  1422. {
  1423.    if (!out || !option)
  1424.       return option ;
  1425.    char terminator = *option++ ;
  1426.    const char *end = strchr(option,terminator) ;
  1427.    if (!end)
  1428.       return option ;
  1429.    const char *alternates[5] = { 0, 0, 0, 0, 0 } ;
  1430.    alternates[0] = option ;
  1431.    int num_alts = 1 ;
  1432.    for (const char *alt = option ; alt < end ; alt++)
  1433.       if (*alt == ';')
  1434.      {
  1435.      alternates[num_alts++] = alt+1 ;
  1436.      if (num_alts >= lengthof(alternates)-1)
  1437.         break ;
  1438.      }
  1439.    alternates[num_alts] = end+1 ;
  1440.    if (value >= num_alts)
  1441.       value = num_alts-1 ;
  1442.    int len = (int)(alternates[(int)value+1] - alternates[(int)value]) - 1 ;
  1443.    if (width == 0)
  1444.       width = len ;
  1445.    for (int i = len ; i < width ; i++)
  1446.       fputc(' ',out) ;
  1447.    fwrite(alternates[(int)value],sizeof(char),len,out) ;
  1448.    return end ;
  1449. }
  1450.  
  1451. //----------------------------------------------------------------------
  1452.  
  1453. static int format(FILE *out, const char *cfg, const char *fmt,
  1454.           const char *enums)
  1455. {
  1456.    if (!out || !cfg || !fmt)
  1457.       return FALSE ;
  1458.    for (const char *s = fmt ; *s ; fmt = s)
  1459.       {
  1460.       while (*s && *s != '%' && *s != '\\')
  1461.      s++ ;
  1462.       if (s != fmt)
  1463.      fwrite(fmt,sizeof(char),s-fmt,out) ;
  1464.       if (*s == '\\')
  1465.      {
  1466.      s++ ;                // consume the backslash
  1467.      switch (*s)
  1468.         {
  1469.         case '\\':            // literal backslash
  1470.            fputc('\\',out) ;
  1471.            break ;
  1472.         case 't':            // tab
  1473.            fputc('\t',out) ;
  1474.            break ;
  1475.         default:            // don't know, so just print the char
  1476.            fputc(*s,out) ;
  1477.            break ;
  1478.         }
  1479.      s++ ;                // consume the char after backslash
  1480.      }
  1481.       else if (*s == '%')
  1482.      {
  1483.      DWORD cfgval = 0 ;
  1484.      fmt = s ;
  1485.      s++ ;                // skip the percent sign
  1486.      if (*s == '[')
  1487.         cfgval = extract_field(s,cfg) ;
  1488.      int width = 0 ;
  1489.      while (isdigit(*s))
  1490.         {
  1491.         width = 10*width + (*s-'0') ;
  1492.         s++ ;
  1493.         }
  1494.      switch (*s)            // dispatch on format character
  1495.         {
  1496.         case 'b':            // binary
  1497.            format_number(out,cfgval,width,2) ;
  1498.            break ;
  1499.         case 'o':            // octal
  1500.            format_number(out,cfgval,width,8) ;
  1501.            break ;
  1502.         case 'd':            // decimal
  1503.            format_number(out,cfgval,width,10) ;
  1504.            break ;
  1505.         case 'x':            // hex
  1506.            format_number(out,cfgval,width,16) ;
  1507.            break ;
  1508.         case 'e':
  1509.            format_enabled(out,cfgval,width) ;
  1510.            break ;
  1511.         case 'E':
  1512.            format_enabled(out,cfgval==0,width) ;
  1513.            break ;
  1514.         case 'f':            // flag
  1515.            format_flag(out,cfgval,width) ;
  1516.            break ;
  1517.         case 'n':
  1518.            format_yesno(out,cfgval == 0, width) ;
  1519.            break ;
  1520.         case 'N':
  1521.            format_full_yesno(out,cfgval == 0, width) ;
  1522.            break ;
  1523.         case 'y':
  1524.            format_yesno(out,cfgval,width) ;
  1525.            break ;
  1526.         case 'Y':
  1527.            format_full_yesno(out,cfgval,width) ;
  1528.            break ;
  1529.         case '(':            // enumerated list of values
  1530.            s = format_enum(out,cfgval,width,s,enums) ;
  1531.            break ;
  1532.         case '{':
  1533.            format_charlist(out,cfgval,width,s) ;
  1534.            break ;
  1535.         case '/':
  1536.            s = format_option(out,cfgval,width,s) ;
  1537.            break ;
  1538.         case '|':
  1539.            s = format_alternative(out,cfgval,width,s) ;
  1540.            break ;
  1541.         case '%':            // literal percent sign
  1542.            fputc('%',out) ;
  1543.            break ;
  1544.         case '!':            // rest of line is a comment
  1545.            while (*s && *s != '\n')
  1546.           s++ ;
  1547.            if (!*s)            // back up if we hit the end of string
  1548.           s-- ;
  1549.            s-- ;            // pre-undo the s++ below
  1550.            break ;
  1551.         case '\n':            // paste together two lines
  1552.            // do nothing, already skipping the newline
  1553.            break ;
  1554.         default:
  1555.            // don't know how to handle!  so, just output the format spec
  1556.            fwrite(fmt,sizeof(char),s-fmt,out) ;
  1557.            break ;
  1558.         }
  1559.      s++ ;
  1560.      }
  1561.       }
  1562.    fflush(out) ;
  1563.    return TRUE ;
  1564. }
  1565.  
  1566.  
  1567. //----------------------------------------------------------------------
  1568.  
  1569. static void determine_ROM_size(int bus, int device, int func, int reg)
  1570. {
  1571.    WORD orig_lo, orig_hi ;
  1572.    WORD new_lo, new_hi ;
  1573.    read_DWORD_register(bus,device,func,reg,&orig_lo,&orig_hi) ;
  1574.    // try setting all address bits
  1575.    write_DWORD_register(bus,device,func,reg,0xFC00,0xFFFF) ;
  1576.    // check which actually got set
  1577.    int read_error = FALSE ;
  1578.    if (!read_DWORD_register(bus,device,func,reg,&new_lo,&new_hi))
  1579.       read_error = TRUE ;
  1580.    // restore original state
  1581.    write_DWORD_register(bus,device,func,reg,orig_lo,orig_hi) ;
  1582.    if (read_error)
  1583.       printf("(error)") ;
  1584.    else if (new_lo == 0x0000 && new_hi == 0x0000)
  1585.       printf("(no ROM)") ;
  1586.    else
  1587.       {
  1588.       new_lo &= 0xFC00 ;        // mask out low ten bits
  1589.       int lowbit = 0 ;
  1590.       if (new_lo)
  1591.      for (int i = 10 ; i < 16 ; i++)
  1592.         if ((new_lo & (1U << i)) != 0)
  1593.            {
  1594.            lowbit = i ;
  1595.            break ;
  1596.            }
  1597.       if (!lowbit)
  1598.      for (int i = 0 ; i < 16 ; i++)
  1599.         if ((new_hi & (1U << i)) != 0)
  1600.            {
  1601.            lowbit = i + 16 ;
  1602.            break ;
  1603.            }
  1604.       const char *ROMstate = (orig_lo & 1) ? "enabled" : "disabled" ;
  1605.       if (lowbit < 20)
  1606.      printf("(%dK,%s)",1 << (lowbit - 10),ROMstate) ;
  1607.       else
  1608.      printf("(%dM,%s)",1 << (lowbit - 20),ROMstate) ;
  1609.       }
  1610. }
  1611.  
  1612. //----------------------------------------------------------------------
  1613.  
  1614. static void determine_region_size(int bus, int device, int func, int reg)
  1615. {
  1616.    WORD orig_lo, orig_hi ;
  1617.    WORD new_lo, new_hi ;
  1618.    read_DWORD_register(bus,device,func,reg,&orig_lo,&orig_hi) ;
  1619.    // try setting all address bits (preserving the I/O-memory bit)
  1620.    write_DWORD_register(bus,device,func,reg,0xFFFC|(orig_lo&1),0xFFFF) ;
  1621.    // check which actually got set
  1622.    int read_error = FALSE ;
  1623.    if (!read_DWORD_register(bus,device,func,reg,&new_lo,&new_hi))
  1624.       read_error = TRUE ;
  1625.    // restore original state
  1626.    write_DWORD_register(bus,device,func,reg,orig_lo,orig_hi) ;
  1627.    if (read_error)
  1628.       printf("(error)") ;
  1629.    else if (new_lo == 0x0000 && new_hi == 0x0000)
  1630.       printf("(no region)") ;
  1631.    else
  1632.       {
  1633.       if (orig_lo & 1)            // is it an I/O region?
  1634.      new_lo &= 0xFFFC ;        // mask out low two bits
  1635.       else
  1636.      new_lo &= 0xFFF0 ;        // mask out low four bits
  1637.       int lowbit = 0 ;
  1638.       if (new_lo)
  1639.      for (int i = 2 ; i < 16 ; i++)
  1640.         if ((new_lo & (1U << i)) != 0)
  1641.            {
  1642.            lowbit = i ;
  1643.            break ;
  1644.            }
  1645.       if (!lowbit)
  1646.      for (int i = 0 ; i < 16 ; i++)
  1647.         if ((new_hi & (1U << i)) != 0)
  1648.            {
  1649.            lowbit = i + 16 ;
  1650.            break ;
  1651.            }
  1652.       if (lowbit < 10)
  1653.      printf("len=%d",1 << lowbit) ;
  1654.       else if (lowbit < 20)
  1655.      printf("len=%dK",1 << (lowbit - 10)) ;
  1656.       else
  1657.      printf("len=%dM",1 << (lowbit - 20)) ;
  1658.       }
  1659. }
  1660.  
  1661. //----------------------------------------------------------------------
  1662.  
  1663. static int dump_base_address(int bus, int device, int func, int number,
  1664.                  DWORD base, DWORD nextbase)
  1665. {
  1666.    if (base)
  1667.       {
  1668.       printf("\t(%d) %8.08lX = %s ",number,base,((base & 1) ? "I/O" : "mem")) ;
  1669.       if (base & 1)
  1670.      {
  1671.      // I/O base address
  1672.      printf("base=%8.08lX ",(base & ~3)) ;
  1673.      determine_region_size(bus,device,func,4*number+0x10) ;
  1674.      putchar('\n') ;
  1675.      }
  1676.       else
  1677.      {
  1678.      // memory base address
  1679.      int type = (int)((base & 6) >> 1) ;
  1680.      int used = FALSE ;
  1681.      switch (type)
  1682.         {
  1683.         case 0:
  1684.            printf("base=%8.08lX ",(base & 0xFFFFFFF0L)) ;
  1685.            break ;
  1686.         case 1:
  1687.            printf("base=%6.06lX ",(base & 0x00FFFFF0L)) ;
  1688.            break ;
  1689.         case 2:
  1690.            printf("base=%8.08lX%8.08lX ",nextbase,(base & ~0x0F)) ;
  1691.            used = TRUE ;
  1692.            break ;
  1693.         case 3:
  1694.            printf("!reserved! ") ;
  1695.            break ;
  1696.         }
  1697.      determine_region_size(bus,device,func,4*number+0x10) ;
  1698.      if ((base & 8) != 0)
  1699.         printf(" prefetchable") ;
  1700.      putchar('\n') ;
  1701.      return used ;            // indicate whether next reg. used up
  1702.      }
  1703.       }
  1704.    return FALSE ;            // base does not extend to next reg.
  1705. }
  1706.  
  1707. //----------------------------------------------------------------------
  1708.  
  1709. static void dump_base_addresses(int bus, int device, int func,
  1710.                 DWORD base0, DWORD base1, DWORD base2,
  1711.                 DWORD base3, DWORD base4, DWORD base5)
  1712. {
  1713.    if (base0 == 0 && base1 == 0 && base2 == 0 && base3 == 0 &&
  1714.        base4 == 0 && base5 == 0)
  1715.       printf("No base addresses\n") ;
  1716.    else
  1717.       {
  1718.       printf("Base Addresses:\n") ;
  1719.       int used ;
  1720.       used = dump_base_address(bus,device,func,0,base0,base1) ;
  1721.       if (!used)
  1722.      used = dump_base_address(bus,device,func,1,base1,base2) ;
  1723.       else
  1724.      used = FALSE ;
  1725.       if (!used)
  1726.      used = dump_base_address(bus,device,func,2,base2,base3) ;
  1727.       else
  1728.      used = FALSE ;
  1729.       if (!used)
  1730.      used = dump_base_address(bus,device,func,3,base3,base4) ;
  1731.       else
  1732.      used = FALSE ;
  1733.       if (!used)
  1734.      used = dump_base_address(bus,device,func,4,base4,base5) ;
  1735.       else
  1736.      used = FALSE ;
  1737.       if (!used)
  1738.      dump_base_address(bus,device,func,5,base5,0) ;
  1739.       }
  1740. }
  1741.  
  1742. //----------------------------------------------------------------------
  1743.  
  1744. static void dump_PCI_PM_capabilities(const char *caplist)
  1745. {
  1746.    unsigned int PMC = *(unsigned int*)(caplist+2) ;
  1747.    unsigned int PMCSR = *(unsigned int*)(caplist+4) ;
  1748.    int PMCSR_ext = caplist[6] ;
  1749.    int data = caplist[7] ;
  1750.    printf("\t PMC    = ") ;
  1751.    write_bits(PMC,PMC_bits,lengthof(PMC_bits)) ;
  1752.    printf("\n\t\tDynClk = %d, PCI_PM version = %d\n",
  1753.           (PMC & 0x00C0) >> 6,
  1754.           (PMC & 0x0007)) ;
  1755.    printf("\t PMCSR  = %4.04X, data-select=%d ",PMCSR, (PMCSR & 0x1E00) >> 9) ;
  1756.    if (PMCSR & 0x6000)
  1757.       printf("scale=0.%s1\n","00"+(3-((PMCSR & 0x1E00)>>9))) ;
  1758.    else
  1759.       printf("unknown/unimplemented\n") ;
  1760.    printf("\t\tstate=D%d %s %s %s\n",
  1761.                   PMCSR & 0x0003,
  1762.                   PMCSR & 0x0010 ? "DynReport" : "",
  1763.                   PMCSR & 0x0100 ? "PME#-ena"  : "",
  1764.                   PMCSR & 0x8000 ? "PME#-active" : "") ;
  1765.    printf("\t PMCSRX = %s %s %s %s\n",
  1766.           PMCSR_ext & 0x80 ? "BusPowerCtrl" : "--",
  1767.           PMCSR_ext & 0x20 ? "state-B2" : "--",
  1768.                   PMCSR_ext & 0x40 ? "state-B3" : "--",
  1769.           PMCSR_ext & 0x10 ? "DynamicClock" : "--") ;
  1770.    printf("\t Data   = %2.02X\n",data) ;
  1771.    return ;
  1772. }
  1773.  
  1774. //----------------------------------------------------------------------
  1775.  
  1776. static void dump_AGP_capabilities(const char *caplist)
  1777. {
  1778.    static char *agprate[] = { "default speed", "1x", "2x", "illegal",
  1779.                   "4x", "illegal", "illegal", "illegal" } ;
  1780.    BYTE AGPver = caplist[2] ;
  1781.    DWORD AGPstat = *((DWORD*)&caplist[4]) ;
  1782.    DWORD AGPcmd = *((DWORD*)&caplist[8]) ;
  1783.    printf("\t supported AGP version = %d.%d\n",AGPver/16,AGPver%16) ;
  1784.    printf("\t max request queue = %d, AGP side band addressing %ssupported\n",
  1785.       (int)((AGPstat >> 24)&0xFF),((AGPstat&0x200)?"":"not ")) ;
  1786.    printf("\t supported transfer type(s): %s%s%s\n",
  1787.       ((AGPstat&1)?"1x ":""),((AGPstat&2)?"2x ":""),
  1788.       ((AGPstat&4)?"4x ":"")) ;
  1789.    printf("\t AGP is currently %sabled at %s (sideband addr %s)\n",
  1790.       (AGPcmd&0x100?"en":"dis"),agprate[AGPcmd&7],
  1791.       (AGPcmd&0x200?"on":"off")) ;
  1792.    return ;
  1793. }
  1794.  
  1795. //----------------------------------------------------------------------
  1796.  
  1797. static void dump_capabilities_list(int start_offset, const char *cfgdata)
  1798. {
  1799.    if (!start_offset)
  1800.       {
  1801.       printf("empty Capabilities list!\n") ;
  1802.       return ;
  1803.       }
  1804.    printf("Capabilities List:\n",start_offset) ;
  1805.    do {
  1806.       unsigned ID = cfgdata[start_offset] ;
  1807.       unsigned next = cfgdata[start_offset+1] ;
  1808.       printf("\tID @%2.02X = %2.02X ",start_offset,ID) ;
  1809.       switch (ID)
  1810.      {
  1811.      case 0x00:
  1812.         printf("disabled capability\n") ;
  1813.         break ;
  1814.      case 0x01:
  1815.         printf("PCI Power Management\n") ;
  1816.         dump_PCI_PM_capabilities(cfgdata+start_offset) ;
  1817.         break ;
  1818.      case 0x02:
  1819.         printf("AGP Capabilities\n") ;
  1820.         dump_AGP_capabilities(cfgdata+start_offset) ;
  1821.         break ;
  1822.      default:
  1823.         printf("(unknown)\n") ;
  1824.         break ;
  1825.      }
  1826.       start_offset = next ;
  1827.       } while (start_offset != 0) ;
  1828. }
  1829.  
  1830. //----------------------------------------------------------------------
  1831.  
  1832. static void dump_device_specific_data(unsigned vendor, unsigned device,
  1833.                       const char *cfgdata)
  1834. {
  1835.    if (!cfgdata)
  1836.       return ;
  1837.    char *format_string ;
  1838.    char const *enum_list = 0 ;
  1839.    if (!know_device(vendor,device,format_string,enum_list))
  1840.       return ;
  1841.    format(stdout,cfgdata,format_string,enum_list) ;
  1842.    free(format_string) ;
  1843.    return ;
  1844. }
  1845.  
  1846. //----------------------------------------------------------------------
  1847.  
  1848. static void write_IO_base_limit(const char *leadin, BYTE low, WORD high)
  1849. {
  1850.    printf(leadin) ;
  1851.    int size = (low & 0x0F) ;
  1852.    if (size == 0)
  1853.       printf("%4.04X",(low & 0xF0) << 8) ;
  1854.    else if (size == 1)
  1855.       printf("%8.08lX",((DWORD)high)|((low & 0xF0) << 8)) ;
  1856.    else
  1857.       printf("<invalid>") ;
  1858.    return ;
  1859. }
  1860.  
  1861. //----------------------------------------------------------------------
  1862.  
  1863. static void write_mem_base_limit(const char *leadin, WORD low, DWORD high,
  1864.                  DWORD limit_low, DWORD limit_high)
  1865. {
  1866.    printf(leadin) ;
  1867.    int size = (low & 0x0F) ;
  1868.    if (size == 0)
  1869.       printf(" %4.04X0000",low & 0xFFF0) ;
  1870.    else if (size == 1)
  1871.       printf(" %8.08lX%4.04X0000",high,(low & 0xFFF0)) ;
  1872.    else
  1873.       printf(" <invalid>") ;
  1874.    size = (limit_low & 0x0F) ;
  1875.    if (size == 0)
  1876.       printf("/%4.04X0000",limit_low & 0xFFF0) ;
  1877.    else if (size == 1)
  1878.       printf("/%8.08lX%4.04X0000",limit_high,(limit_low & 0xFFF0)) ;
  1879.    else
  1880.       printf("/<invalid>") ;
  1881.    return ;
  1882. }
  1883.  
  1884. //----------------------------------------------------------------------
  1885.  
  1886. #define setp setprecision
  1887.  
  1888. static int dump_PCI_config(int bus, int device, int func, int report_missing,
  1889.                int &is_multifunc)
  1890. {
  1891.    int i ;
  1892.    PCIcfg *cfg = read_PCI_config(bus,device,func) ;
  1893.    if (!cfg || cfg->vendorID == 0xFFFF || cfg->deviceID == 0xFFFF)
  1894.       {
  1895.       if (report_missing)
  1896.      printf("No PCI device at bus %2.02X device %2.02X function %2.02X\n",
  1897.         bus,device,func) ;
  1898.       return FALSE ;
  1899.       }
  1900.    if (!first_device)
  1901.       printf("-----------------------------------------------------------\n") ;
  1902.    first_device = FALSE ;
  1903.    printf("PCI bus %2.02X device %2.02X function %2.02X:  ",bus,device,func) ;
  1904.    printf("Header Type '") ;
  1905.    switch (cfg->header_type & 0x7F)
  1906.       {
  1907.       case 0x00:
  1908.      printf("non-bridge") ;
  1909.      break ;
  1910.       case 0x01:
  1911.      printf("PCI-PCI bridge") ;
  1912.      break ;
  1913.       case 0x02:
  1914.      printf("CardBus bridge") ;
  1915.      break ;
  1916.       default:
  1917.      printf("other [%2.02X]",cfg->header_type & 0x7F) ;
  1918.      break ;
  1919.       }
  1920.    if ((cfg->header_type & 0x80) != 0)    // make multi-function flag sticky
  1921.       is_multifunc = 1 ;        // since some devs only show on func 0
  1922.    printf("' (%s-func)\n",is_multifunc ? "multi" : "single") ;
  1923.    const char *class_name = "???" ;
  1924.    if (cfg->classcode < lengthof(class_names))
  1925.       class_name = class_names[cfg->classcode] ;
  1926.    const char *subclass_name = get_subclass_name(cfg->classcode,cfg->subclass);
  1927.    if (terse)
  1928.       {
  1929.       const char *vendorname = get_vendor_name(cfg->vendorID) ;
  1930.       char unkvendor[40] ;
  1931.       if (strcmp(vendorname,"???") == 0)
  1932.      {
  1933.      sprintf(unkvendor,"(Vendor %4.04X)",cfg->vendorID) ;
  1934.      vendorname = unkvendor ;
  1935.      }
  1936.       const char *devname = get_device_name(cfg->vendorID,cfg->deviceID) ;
  1937.       char unkdevice[40] ;
  1938.       if (strcmp(devname,"???") == 0)
  1939.      {
  1940.      sprintf(unkdevice,"(DeviceID %4.04X)",cfg->deviceID) ;
  1941.      devname = unkdevice ;
  1942.      }
  1943.       printf("%-38.38s ║ Class %2.02X: %-20.20s\tI/F: %2.02X\n"
  1944.          "%-38.38s ║ SubCl %2.02X: %-20.20s\tRev: %2.02X\n",
  1945.          vendorname,cfg->classcode,class_name,cfg->progIF,
  1946.          devname,cfg->subclass,subclass_name,cfg->revisionID) ;
  1947.       return is_multifunc ;
  1948.       }
  1949.    else
  1950.       {
  1951.       printf("Vendor:\t%4.04X\t%-50.50s\n",cfg->vendorID,
  1952.          get_vendor_name(cfg->vendorID)) ;
  1953.       printf("Device:\t%4.04X\t%-50.50s\n",
  1954.          cfg->deviceID,get_device_name(cfg->vendorID,cfg->deviceID)) ;
  1955.       printf("Class:\t  %2.02X\t%-20.20s\tRevision:\t%2.02X\n",
  1956.          cfg->classcode,class_name,cfg->revisionID) ;
  1957.       printf("SubClass: %2.02X\t%-20.20s\tProgramI/F:\t%2.02X\n",
  1958.          cfg->subclass,subclass_name,cfg->progIF) ;
  1959.       }
  1960.    printf("CommandReg:     %4.04X =",cfg->command_reg) ;
  1961.    WRITE_CMD_BITS(cfg->command_reg) ;
  1962.    printf("\n"
  1963.       "Status Reg:     %4.04X =",cfg->status_reg) ;
  1964.    WRITE_STAT_BITS(cfg->status_reg) ;
  1965.    printf(" (%s)\n",select_timing[(cfg->status_reg & 0x0600) >> 9]) ;
  1966.    printf("CacheLine:       %2.02X\tLatency:\t%2.02X\tBIST:\t     %2.02X\n",
  1967.       cfg->cacheline_size,cfg->latency,cfg->BIST) ;
  1968.    switch(cfg->header_type & 0x7F)
  1969.       {
  1970.       case 0x00:  // non-bridge
  1971.      printf("SubsysVendor:    %4.04X\tSubsysDevice: %4.04X\n",
  1972.         cfg->nonbridge.subsystem_vendorID,
  1973.         cfg->nonbridge.subsystem_deviceID) ;
  1974.      dump_base_addresses(bus,device,func,
  1975.                  cfg->nonbridge.base_address0,
  1976.                  cfg->nonbridge.base_address1,
  1977.                  cfg->nonbridge.base_address2,
  1978.                  cfg->nonbridge.base_address3,
  1979.                  cfg->nonbridge.base_address4,
  1980.                  cfg->nonbridge.base_address5) ;
  1981.      printf("CardBus:     %8.08lX\tExpansionROM: %8.08lX ",
  1982.         cfg->nonbridge.CardBus_CIS,cfg->nonbridge.expansion_ROM) ;
  1983.      determine_ROM_size(bus,device,func,0x30) ;
  1984.      printf("\n") ;
  1985.      printf("INTline:\t   %2.02X\tINTpin:       %2.02X\n",
  1986.         cfg->nonbridge.interrupt_line,cfg->nonbridge.interrupt_pin) ;
  1987.      printf("MinGrant:\t   %2.02X\tMaxLatency:   %2.02X\n",
  1988.         cfg->nonbridge.min_grant,cfg->nonbridge.max_latency) ;
  1989.      printf("Device-Specific Data:\n 40:") ;
  1990.      for (i = 0 ; i < 48 ; i++)
  1991.         {
  1992.         printf(" %8.08lX ",cfg->nonbridge.device_specific[i]) ;
  1993.         if (i % 6 == 5 && i < 47)
  1994.            printf("\n %2.02X:",4*(i+17)) ;
  1995.         }
  1996.      putchar('\n') ;
  1997.      if (cfg->status_reg & CAPLIST_BIT)
  1998.         dump_capabilities_list(cfg->nonbridge.cap_ptr,(char*)cfg) ;
  1999.      break ;
  2000.       case 0x01:  // bridge
  2001.      printf("PrimaryBus:\t   %2.02X\tSecondaryBus:    %2.02X\tSubordinBus: %2.02X\n",
  2002.         cfg->bridge.primary_bus,cfg->bridge.secondary_bus,
  2003.         cfg->bridge.subordinate_bus) ;
  2004.      printf("SecLatency:\t   %2.02X\tExpansion ROM: %8.08lX ",
  2005.         cfg->bridge.secondary_latency,cfg->bridge.expansion_ROM) ;
  2006.      determine_ROM_size(bus,device,func,0x38) ;
  2007.      printf("\n") ;
  2008.      printf("SecStatus:\t %4.04X =",cfg->bridge.secondary_status) ;
  2009.      WRITE_STAT_BITS(cfg->bridge.secondary_status) ;
  2010.      printf(" (%s)\n",select_timing[(cfg->bridge.secondary_status & 0x0600) >> 9]) ;
  2011.      printf("BridgeCntrl:\t %4.04X =",
  2012.         cfg->bridge.bridge_control) ;
  2013.      WRITE_BCTRL_BITS(cfg->bridge.bridge_control) ;
  2014.      printf("\n") ;
  2015.      write_mem_base_limit("MemBase/Limit: ",cfg->bridge.memory_base_low,0,
  2016.                   cfg->bridge.memory_limit_low,0) ;
  2017.      printf("\t") ;
  2018.          write_IO_base_limit("IObase/limit: ",cfg->bridge.IO_base_low,
  2019.                              cfg->bridge.IO_base_high) ;
  2020.          write_IO_base_limit("/",cfg->bridge.IO_limit_low,
  2021.                              cfg->bridge.IO_limit_high) ;
  2022.      printf("\n") ;
  2023.      write_mem_base_limit("PrefBase/Limit:",cfg->bridge.prefetch_base_low,
  2024.                   cfg->bridge.prefetch_base_high,
  2025.                   cfg->bridge.prefetch_limit_low,
  2026.                   cfg->bridge.prefetch_limit_high) ;
  2027.      printf("\tINTline:  %2.02X\tINTpin:  %2.02X\n",
  2028.         cfg->bridge.interrupt_line,cfg->bridge.interrupt_pin) ;
  2029.      dump_base_addresses(bus,device,func,
  2030.                  cfg->bridge.base_address0,
  2031.                  cfg->bridge.base_address1,0,0,0,0) ;
  2032.      printf("Device-Specific Data:\n 40:") ;
  2033.       for (i = 0 ; i < 48 ; i++)
  2034.         {
  2035.         printf(" %8.08lX ",cfg->bridge.device_specific[i]) ;
  2036.         if (i % 6 == 5 && i < 47)
  2037.            printf("\n %2.02X:",4*(i+17)) ;
  2038.         }
  2039.      putchar('\n') ;
  2040.      break    ;
  2041.       case 0x02:
  2042.      printf("SubsysVendor: %4.04X\tSubsysDevice: %4.04X\n",
  2043.         cfg->cardbus.subsystem_vendorID,
  2044.         cfg->cardbus.subsystem_deviceID) ;
  2045.      printf("PCI bus: %2.02X\tCardBus bus: %2.02X\tSubordBus: %2.02X\tLatency: %2.02X\n",
  2046.         cfg->cardbus.PCI_bus, cfg->cardbus.CardBus_bus,
  2047.         cfg->cardbus.subordinate_bus, cfg->cardbus.latency_timer) ;
  2048.      printf("Memory0: %8.08lX bytes at %8.08lX\n",
  2049.         cfg->cardbus.memory_limit0, cfg->cardbus.memory_base0) ;
  2050.      printf("Memory1: %8.08lX bytes at %8.08lX\n",
  2051.         cfg->cardbus.memory_limit1, cfg->cardbus.memory_base1) ;
  2052.      printf("I/O range 0: %4.04X ports at %4.04X\n",
  2053.         cfg->cardbus.IOlimit_0low, cfg->cardbus.IObase_0low) ;
  2054.      printf("I/O range 1: %4.04X ports at %4.04X\n",
  2055.         cfg->cardbus.IOlimit_1low, cfg->cardbus.IObase_1low) ;
  2056.      printf("INTline:  %2.02X\tINTpin:  %2.02X\tBridgeCntrl: %4.04X\n",
  2057.         cfg->cardbus.interrupt_line,cfg->cardbus.interrupt_pin,
  2058.         cfg->cardbus.bridge_control) ;
  2059.      printf("Legacy Mode base address: %8.08lX\n",
  2060.         cfg->cardbus.legacy_baseaddr) ;
  2061.      printf("Device-Specific Data:\n 80:") ;
  2062.      for (i = 0 ; i < 32 ; i++)
  2063.         {
  2064.         printf(" %8.08lX ",cfg->cardbus.vendor_specific[i]) ;
  2065.         if (i % 6 == 5 && i < 47)
  2066.            printf("\n %2.02X:",4*(i+33)) ;
  2067.         }
  2068.      putchar('\n') ;
  2069.      if (cfg->status_reg & CAPLIST_BIT)
  2070.         dump_capabilities_list(cfg->cardbus.cap_ptr,(char*)cfg) ;
  2071.      break ;
  2072.       default:
  2073.      printf("Unknown header format %2.02X!\n",cfg->header_type & 0x7F) ;
  2074.      break ;
  2075.       }
  2076.    if (verbose)
  2077.       dump_device_specific_data(cfg->vendorID,cfg->deviceID,(char*)cfg) ;
  2078.    if (!report_missing)
  2079.       putchar('\n') ;
  2080.    return is_multifunc ;
  2081. }
  2082.  
  2083. //----------------------------------------------------------------------
  2084.  
  2085. static int read_device_ID(FILE *fp, char *&ID_data, int maxsize,
  2086.               int pcicfg_format)
  2087. {
  2088.    char line[MAX_LINE] ;
  2089.    long startpos = ftell(fp) ;
  2090.    if (!read_nonblank_line(line,sizeof(line),fp,pcicfg_format))
  2091.       return FALSE ;
  2092.    char *data_end = ID_data + maxsize - (MAX_DEVICE_NAME + 5) ;
  2093.    const char *l = line ;
  2094.    int is_vendor_line ;
  2095.    if (pcicfg_format)
  2096.       {
  2097.       l = skip_whitespace(l) ;
  2098.       is_vendor_line = strncmp(l,"Vendor",6) == 0 ;
  2099.       if (is_vendor_line)
  2100.      l = skip_whitespace(l+6) ;    // skip to vendor ID
  2101.       }
  2102.    else
  2103.       {
  2104.       is_vendor_line = isxdigit(*l) ;
  2105.       }
  2106.    if (is_vendor_line)
  2107.       {
  2108.       *((char**)ID_data) = 0 ;        // pointer to next vendor ID
  2109.       ID_data += sizeof(char*) ;
  2110.       WORD *length = (WORD*)ID_data ;
  2111.       *((WORD*)ID_data) = 0 ;        // length of data for vendor
  2112.       ID_data += sizeof(WORD) ;
  2113.       WORD ID = hextoint(l) ;        // get the vendor's ID
  2114.       *((WORD*)ID_data) = ID ;
  2115.       ID_data += sizeof(WORD) ;
  2116.       l = skip_whitespace(l) ;        // skip to vendor name
  2117.       int count = 0 ;
  2118.       // copy the vendor name
  2119.       while (*l && *l != '\n' && count++ < MAX_VENDOR_NAME)
  2120.      *ID_data++ = *l++ ;
  2121.       *ID_data++ = '\0' ;        // ensure termination
  2122.       do {
  2123.      startpos = ftell(fp) ;
  2124.      if (!read_nonblank_line(line,sizeof(line),fp,pcicfg_format))
  2125.         break ;
  2126.      l = line ;
  2127.      int is_device_line ;
  2128.      if (pcicfg_format)
  2129.         {
  2130.         l = skip_whitespace(l) ;
  2131.         is_vendor_line = strncmp(l,"Vendor",6) == 0 ;
  2132.         is_device_line = isxdigit(*l) ;
  2133.         }
  2134.      else
  2135.         {
  2136.         is_vendor_line = isxdigit(*l) ;
  2137.         is_device_line = FALSE ;
  2138.         if (!is_vendor_line)
  2139.            {
  2140.            l = skip_whitespace(l) ;
  2141.            is_device_line = isxdigit(*l) ;
  2142.            }
  2143.         }
  2144.      if (is_device_line)
  2145.         {
  2146.         ID = hextoint(l) ;        // convert device ID
  2147.         if (ID != 0xFFFF)
  2148.            {
  2149.            *((WORD*)ID_data) = ID ;
  2150.            ID_data += sizeof(WORD) ;
  2151.            l = skip_whitespace(l) ; // skip to device name
  2152.            // copy the device name
  2153.            count = 0 ;
  2154.            while (*l && *l != '\n' && count++ < MAX_DEVICE_NAME)
  2155.           *ID_data++ = *l++ ;
  2156.            *ID_data++ = '\0' ;    // ensure termination
  2157.            if (ID_data >= data_end)
  2158.           {
  2159.           fprintf(stderr,"Too much information for a single vendor!\n") ;
  2160.           return TRUE ;
  2161.           }
  2162.            }
  2163.         }
  2164.      } while (!is_vendor_line) ;
  2165.       *length = (ID_data - (char*)length) - sizeof(*length) ;
  2166.       // back up to start of Vendor line
  2167.       (void)fseek(fp,startpos,SEEK_SET) ;
  2168.       return TRUE ;
  2169.       }
  2170.    else // !is_vendor_line
  2171.       {
  2172.       fprintf(stderr,"non-empty line found, but it is not a vendor ID line!\n");
  2173.       return FALSE ;
  2174.       }
  2175. }
  2176.  
  2177. //----------------------------------------------------------------------
  2178.  
  2179. static int check_PCICFG_DAT_signature(FILE *fp, int complain = FALSE)
  2180. {
  2181.    char signature[SIGNATURE_LENGTH] ;
  2182.    (void)fseek(fp,0L,SEEK_SET) ;
  2183.    signature[0] = '\0' ;
  2184.    if (fread(signature,sizeof(char),sizeof(signature),fp) < sizeof(signature))
  2185.       return FALSE ;
  2186.    int present = strncmp(signature,SIGNATURE,SIGNATURE_LENGTH) == 0 ;
  2187.    if (present)
  2188.       {
  2189.       // skip the rest of the first line
  2190.       int c ;
  2191.       while ((c = fgetc(fp)) != EOF && c != '\n')
  2192.      ;
  2193.       }
  2194.    else
  2195.       {
  2196.       (void)fseek(fp,0L,SEEK_SET) ;
  2197.       if (complain)
  2198.      {
  2199.      fprintf(stderr,"Invalid PCICFG.DAT\n") ;
  2200.      if (verbose)
  2201.         fprintf(stderr,"File Signature: \"%6.6s\"\n",signature) ;
  2202.      }
  2203.       }
  2204.    return present ;
  2205. }
  2206.  
  2207. //----------------------------------------------------------------------
  2208.  
  2209. static int load_device_IDs()
  2210. {
  2211.    FILE *fp = open_PCICFG_DAT("r") ;
  2212.    if (fp)
  2213.       {
  2214.       int pcicfg_format = check_PCICFG_DAT_signature(fp,TRUE) ;
  2215.       char *prev_ID_data = 0 ;
  2216.       while (!feof(fp))
  2217.      {
  2218.      char *vendor_ID_data = (char*)malloc(MAX_VENDOR_DATA) ;
  2219.      if (!vendor_ID_data)
  2220.         {
  2221.         fprintf(stderr,"Insufficient memory for PCICFG.DAT contents\n"
  2222.                    "Some vendors/devices will not be shown by name\n") ;
  2223.         return FALSE ;
  2224.         }
  2225.      char *ID_data = vendor_ID_data ;
  2226.      if (!read_device_ID(fp,ID_data,MAX_VENDOR_DATA,pcicfg_format))
  2227.         break ;
  2228.      ID_data = (char*)realloc(vendor_ID_data, ID_data - vendor_ID_data) ;
  2229.      if (ID_data)
  2230.         vendor_ID_data = ID_data ;
  2231.      if (prev_ID_data)
  2232.         *((char**)prev_ID_data) = vendor_ID_data ;
  2233.      else
  2234.         device_ID_data = vendor_ID_data ;
  2235.      prev_ID_data = vendor_ID_data ;
  2236.      }
  2237.       return TRUE ;
  2238.       }
  2239.    return FALSE ;   
  2240. }
  2241.  
  2242. //----------------------------------------------------------------------
  2243.  
  2244. static int write_PCICFG_DAT_header(FILE *outfp)
  2245. {
  2246.    fputs("PCICFG ;<<-- signature - DO NOT CHANGE\n",outfp) ;
  2247.    return TRUE ;
  2248. }
  2249.  
  2250. //----------------------------------------------------------------------
  2251.  
  2252. static int copy_initial_comments(FILE *outfp, FILE *datfp)
  2253. {
  2254.    char line[MAX_LINE] ;
  2255.    int is_comment ;
  2256.    long startpos ;
  2257.    if (verbose)
  2258.       printf("copying initial comments:\n") ;
  2259.    do {
  2260.       line[0] = '\0' ;
  2261.       startpos = ftell(datfp) ;
  2262.       if (!fgets(line,sizeof(line),datfp))
  2263.      return FALSE ;
  2264.       is_comment = is_comment_line(line) ;
  2265.       if (is_comment)
  2266.      {
  2267.      fputs(line,outfp) ;
  2268.      if (verbose)
  2269.         printf("\t%s",line) ;
  2270.      }
  2271.       } while (is_comment) ;
  2272.    fseek(datfp,startpos,SEEK_SET) ;
  2273.    return TRUE ;
  2274. }
  2275.  
  2276. //----------------------------------------------------------------------
  2277.  
  2278. static char *skip_string(char *s, char *end)
  2279. {
  2280.    while (s < end && *s)
  2281.       s++ ;
  2282.    if (s < end)
  2283.       s++ ;                // skip terminating NUL
  2284.    return s ;
  2285. }
  2286.  
  2287. //----------------------------------------------------------------------
  2288.  
  2289. static int write_vendor_data(FILE *outfp, WORD ID, char *data, char *end)
  2290. {
  2291.    if (!outfp || !data || data >= end)
  2292.       return FALSE ;
  2293.    // output the vendor's name and ID
  2294.    fprintf(outfp,"Vendor %4.04X %s\n",ID,data) ;
  2295.    data = skip_string(data,end) ;
  2296.    // output all of the devices listed under the vendor
  2297.    while (data < end)
  2298.       {
  2299.       ID = *((WORD*)data) ;
  2300.       data += sizeof(WORD) ;
  2301.       fprintf(outfp,"  %4.04X %s\n",ID,data) ;
  2302.       data = skip_string(data,end) ;
  2303.       }
  2304.    return TRUE ;
  2305. }
  2306.  
  2307. //----------------------------------------------------------------------
  2308.  
  2309. static int merge_vendor_data(FILE *outfp, char *data1, char *data2)
  2310. {
  2311.    data1 += sizeof(char*) ;        // skip the 'next' field
  2312.    WORD length1 = *((WORD*)data1) ;    // get length of data
  2313.    data1 += sizeof(WORD) ;
  2314.    char *end1 = data1 + length1 ;
  2315.    WORD ID1 = *((WORD*)data1) ;        // get vendor ID
  2316.    data1 += sizeof(WORD) ;
  2317.    data2 += sizeof(char*) ;        // skip the 'next' field
  2318.    WORD length2 = *((WORD*)data2) ;    // get length of data
  2319.    data2 += sizeof(WORD) ;
  2320.    char *end2 = data2 + length2 ;
  2321.    WORD ID2 = *((WORD*)data2) ;        // get vendor ID
  2322.    data2 += sizeof(WORD) ;
  2323.    if (ID1 == ID2)
  2324.       {
  2325.       fprintf(outfp,"Vendor %4.04X %s\n",ID1,data1) ;
  2326.       data1 = skip_string(data1,end1) ;
  2327.       data2 = skip_string(data2,end2) ;
  2328.       ID1 = *((WORD*)data1) ;
  2329.       data1 += sizeof(WORD) ;
  2330.       ID2 = *((WORD*)data2) ;
  2331.       data2 += sizeof(WORD) ;
  2332.       while (data1 < end1 && data2 < end2)
  2333.      {
  2334.      if (ID1 <= ID2)
  2335.         {
  2336.         fprintf(outfp,"  %4.04X %s\n",ID1,data1) ;
  2337.         if (ID1 == ID2)
  2338.            {
  2339.            data2 = skip_string(data2,end2) ;
  2340.            ID2 = *((WORD*)data2) ;
  2341.            data2 += sizeof(WORD) ;
  2342.            }
  2343.         data1 = skip_string(data1,end1) ;
  2344.         ID1 = *((WORD*)data1) ;
  2345.         data1 += sizeof(WORD) ;
  2346.         }
  2347.      else // if (ID1 > ID2)
  2348.         {
  2349.         fprintf(outfp,"  %4.04X %s\n",ID2,data2) ;
  2350.         data2 = skip_string(data2,end2) ;
  2351.         ID2 = *((WORD*)data2) ;
  2352.         data2 += sizeof(WORD) ;
  2353.         }
  2354.      }
  2355.       while (data1 < end1)
  2356.      {
  2357.      // copy the remainder of the first file's device IDs
  2358.      fprintf(outfp,"  %4.04X %s\n",ID1,data1) ;
  2359.      data1 = skip_string(data1,end1) ;
  2360.      ID1 = *((WORD*)data1) ;
  2361.      data1 += sizeof(WORD) ;
  2362.      }
  2363.       while (data2 < end2)
  2364.      {
  2365.      // copy the remainder of the second file's device IDs
  2366.      fprintf(outfp,"  %4.04X %s\n",ID2,data2) ;
  2367.      data2 = skip_string(data2,end2) ;
  2368.      ID2 = *((WORD*)data2) ;
  2369.      data2 += sizeof(WORD) ;
  2370.      }
  2371.       return 0 ;
  2372.       }
  2373.    else if (ID1 < ID2)
  2374.       {
  2375.       write_vendor_data(outfp,ID1,data1,end1) ;
  2376.       return -1 ;
  2377.       }
  2378.    else // ID1 > ID2
  2379.       {
  2380.       write_vendor_data(outfp,ID2,data2,end2) ;
  2381.       return +1 ;
  2382.       }
  2383. }
  2384.  
  2385. //----------------------------------------------------------------------
  2386.  
  2387. static int merge_info(FILE *outfp, FILE *datfp, FILE *newfp)
  2388. {
  2389.    if (!outfp || !datfp || !newfp)
  2390.       return FALSE ;
  2391.    if (!check_PCICFG_DAT_signature(datfp,TRUE))
  2392.       {
  2393.       fprintf(stderr,"invalid signature in PCICFG.DAT\n") ;
  2394.       return FALSE ;
  2395.       }
  2396.    if (!write_PCICFG_DAT_header(outfp) || !copy_initial_comments(outfp,datfp))
  2397.       {
  2398.       fprintf(stderr,"error writing new header\n") ;
  2399.       return FALSE ;
  2400.       }
  2401.    int pcicfg_format = check_PCICFG_DAT_signature(newfp,FALSE) ;
  2402.    if (verbose)
  2403.       printf("new data file is in %s format\n",
  2404.          pcicfg_format ? "PCICFG" : "Merlin's") ;
  2405.    if (!copy_initial_comments(outfp,newfp))
  2406.       {
  2407.       fprintf(stderr,"error copying initial comments\n") ;
  2408.       return FALSE ;
  2409.       }
  2410.    char *data1 = (char*)malloc(MAX_VENDOR_DATA) ;
  2411.    char *data2 = (char*)malloc(MAX_VENDOR_DATA) ;
  2412.    if (!data1 || !data2)
  2413.       {
  2414.       fprintf(stderr,"Insufficient memory to merge data!\n") ;
  2415.       if (data1)
  2416.      free(data1) ;
  2417.       return FALSE ;
  2418.       }
  2419.    char *dat1 = data1 ;
  2420.    char *dat2 = data2 ;
  2421.    // load up the first vendor from each file
  2422.    if (!read_device_ID(datfp,dat1,MAX_VENDOR_DATA,TRUE) ||
  2423.        !read_device_ID(newfp,dat2,MAX_VENDOR_DATA,pcicfg_format))
  2424.       {
  2425.       free(data1) ;
  2426.       free(data2) ;
  2427.       fprintf(stderr,"empty data file!\n") ;
  2428.       return FALSE ;
  2429.       }
  2430.    int done1 = FALSE ;
  2431.    int done2 = FALSE ;
  2432.    do {
  2433.       int merge = merge_vendor_data(outfp,data1,data2) ;
  2434.       switch (merge)
  2435.      {
  2436.      case -1:
  2437.         dat1 = data1 ;
  2438.         if (!read_device_ID(datfp,dat1,MAX_VENDOR_DATA,TRUE))
  2439.            done1 = TRUE ;
  2440.         break ;
  2441.      case 0:
  2442.         dat1 = data1 ;
  2443.         if (!read_device_ID(datfp,dat1,MAX_VENDOR_DATA,TRUE))
  2444.            done1 = TRUE ;
  2445.         // fall through to +1
  2446.      case +1:
  2447.         dat2 = data2 ;
  2448.         if (!read_device_ID(newfp,dat2,MAX_VENDOR_DATA,pcicfg_format))
  2449.            done2 = TRUE ;
  2450.         break ;
  2451.      default:
  2452.         fprintf(stderr,"Missed case in switch()!\n") ;
  2453.         return FALSE ;
  2454.      }
  2455.       } while (!done1 && !done2) ;
  2456.    if (!done1)
  2457.       {
  2458.       // copy any remaining items from first file (we can't possibly have any
  2459.       // left over from the second file, since PCICFG.DAT goes up to FFFFh)
  2460.       do {
  2461.      dat1 = data1 + sizeof(char*) ;    // reset, but skip the 'next' field
  2462.      WORD length1 = *((WORD*)dat1) ;
  2463.      dat1 += sizeof(WORD) ;
  2464.      char *end1 = data1 + length1 ;
  2465.      WORD ID1 = *((WORD*)dat1) ;    // get vendor ID
  2466.      dat1 += sizeof(WORD) ;
  2467.      write_vendor_data(outfp,ID1,dat1,end1) ;
  2468.      dat1 = data1 ;
  2469.      } while (read_device_ID(datfp,dat1,MAX_VENDOR_DATA,TRUE)) ;
  2470.       }
  2471.    free(data1) ;
  2472.    free(data2) ;
  2473.    return TRUE ;
  2474. }
  2475.  
  2476. //----------------------------------------------------------------------
  2477.  
  2478. static int merge_new_info(const char *filename)
  2479. {
  2480.    if (!filename || !*filename)
  2481.       return FALSE ;
  2482.    FILE *fp = fopen(filename,"r") ;
  2483.    if (fp)
  2484.       {
  2485.       static char tempfile[] = "pcicfg.$$$" ;
  2486.       FILE *datfp = open_PCICFG_DAT("r") ;
  2487.       FILE *merged = fopen(tempfile,"w") ;
  2488.       if (!datfp)
  2489.      return FALSE ;
  2490.       if (!merged)
  2491.      {
  2492.      fprintf(stderr,"Unable to open temporary file for merge\n") ;
  2493.      return FALSE ;
  2494.      }
  2495.       int success = merge_info(merged,datfp,fp) ;
  2496.       (void) fclose(datfp) ;
  2497.       (void) fclose(fp) ;
  2498.       (void) fclose(merged) ;
  2499.       if (success)
  2500.      {
  2501.      // copy the temporary file over PCICFG.DAT
  2502.      merged = fopen(tempfile,"r") ;
  2503.      fp = open_PCICFG_DAT("w") ;
  2504.      char buffer[BUFSIZ] ;
  2505.      int count ;
  2506.      while ((count = fread(buffer,sizeof(char),sizeof(buffer),merged)) > 0)
  2507.         {
  2508.         if (fwrite(buffer,sizeof(char),count,fp) < count)
  2509.            {
  2510.            fprintf(stderr,"Error copying temporary file to PCICFG.DAT!!\n") ;
  2511.            break ;
  2512.            }
  2513.         }
  2514.      (void) fclose(fp) ;
  2515.      (void) fclose(merged) ;
  2516.      }
  2517.       else
  2518.      fprintf(stderr,"Unable to merge new data!\n") ;
  2519.       unlink(tempfile) ;
  2520.       return success ;
  2521.       }
  2522.    return FALSE ;
  2523. }
  2524.  
  2525. //----------------------------------------------------------------------
  2526.  
  2527. static int merge_new_info(int argc, char **argv)
  2528. {
  2529.     if (!backup_PCICFG_DAT())
  2530.        {
  2531.        fprintf(stderr,"Unable to backup PCICFG.DAT\n") ;
  2532.        return 1 ;
  2533.        }
  2534.     while (argc > 0 && *argv)
  2535.        {
  2536.        if (!merge_new_info(argv[0]))
  2537.       return 2 ;
  2538.        argc-- ;
  2539.        argv++ ;
  2540.        }
  2541.     return 0 ;
  2542. }
  2543.  
  2544. //----------------------------------------------------------------------
  2545.  
  2546. int main(int argc, char **argv)
  2547. {
  2548.    fprintf(stderr,"PCICFG v" VERSION " (c) Copyright 1997,1998 Ralf Brown\n") ;
  2549.    get_exe_directory(argv[0]) ;
  2550.    while (argc > 1 && argv[1][0] == '-')
  2551.       {
  2552.       switch (argv[1][1])
  2553.      {
  2554.      case 'b':
  2555.         bypass_BIOS = TRUE ;
  2556.         if (argv[1][2] == '1')
  2557.            cfg_mech = 1 ;
  2558.         else if (argv[1][2] == '2')
  2559.            cfg_mech = 2 ;
  2560.         else
  2561.            determine_cfg_mech() ;
  2562.         break ;
  2563.      case 'm':
  2564.         // merge new info into PCICFG.DAT
  2565.         return merge_new_info(argc-2,argv+2) ;
  2566.      case 't':
  2567.         terse = TRUE ;
  2568.         break ;
  2569.      case 'v':
  2570.         verbose = TRUE ;
  2571.         break ;
  2572.      default:
  2573.         fprintf(stderr,"unrecognized option '%s'\n",argv[1]) ;
  2574.         break ;
  2575.      }
  2576.       argv++ ;
  2577.       argc-- ;
  2578.       }
  2579.    int maxbus = check_PCI_BIOS() ;
  2580.    if (maxbus < 0)
  2581.       {
  2582.       if (!bypass_BIOS)
  2583.      {
  2584.      fprintf(stderr,"\nNo PCI BIOS detected\n") ;
  2585.      return 2 ;
  2586.      }
  2587.       else
  2588.      maxbus = 0xFF ;        // have to scan ALL possible buses
  2589.       }
  2590.    if (!load_device_IDs())
  2591.       {
  2592.       fprintf(stderr,
  2593.           "Unable to load the list of vendor and device IDs (PCICFG.DAT).\n"
  2594.           "Devices will not be identified by name.\n") ;
  2595.       }
  2596.    if (argc == 2 && argv[1][0] == '*')
  2597.       {
  2598.       for (int bus = 0 ; bus <= maxbus ; bus++)
  2599.      {
  2600.      for (int device = 0 ; device < 32 ; device++)
  2601.         {
  2602.         int multifunc = 0 ;
  2603.         for (int func = 0 ; func < 8 ; func++)
  2604.            {
  2605.            if (!dump_PCI_config(bus,device,func,0,multifunc))
  2606.           break ;
  2607.            }
  2608.         }
  2609.      }
  2610.       return 0 ;
  2611.       }
  2612.    if (argc < 4)
  2613.       {
  2614.       fprintf(stderr,
  2615.           "\nUsage:\tPCICFG [flag(s)] bus device func\n"
  2616.           "\tPCICFG [flag(s)] *         (to scan all devices)\n"
  2617.           "\tPCICFG -m file [file ...]  (to merge new info into PCICFG.DAT)\n"
  2618.           "\n"
  2619.           "Dumps info about the specified PCI device, or all devices\n"
  2620.           "Flags:\n"
  2621.           "\t-bN\tbypass BIOS -- talk directly to PCI hardware ports using\n"
  2622.           "\t\t access mechanism N (1 or 2) [using wrong one can reboot/hang!]\n"
  2623.           "\t-t\tterse -- output only device type and ID\n"
  2624.           "\t-v\tverbose output for known devices\n"
  2625.           "\n"
  2626.           "Use -v for more verbose output on devices specifically recognized by\n"
  2627.           "PCICFG.  Output is generally quite lengthy even without -v, so you\n"
  2628.           "should redirect output into a file or pipe it to MORE or LIST\n") ;
  2629.       return 1 ;
  2630.       }
  2631.    char *end = 0 ;
  2632.    int bus = (int)strtol(argv[1],&end,0) ;
  2633.    int device = (int)strtol(argv[2],&end,0) ;
  2634.    int func = (int)strtol(argv[3],&end,0) ;
  2635.    if (bus > maxbus)
  2636.       {
  2637.       fprintf(stderr,"\nRequested PCI bus does not exist\n") ;
  2638.       return 3 ;
  2639.       }
  2640.    else
  2641.       {
  2642.       int multifunc = 0 ;
  2643.       dump_PCI_config(bus,device,func,1,multifunc) ;
  2644.       }
  2645.    return 0 ;
  2646. }
  2647.  
  2648. // end of file pcicfg.cpp //
  2649.