home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 January / pcwk_01_1999.iso / Tajnepp / MCLK093 / DETECT.CPP < prev    next >
C/C++ Source or Header  |  1997-06-15  |  25KB  |  775 lines

  1. //    detect.cpp    v.093ß    06/15/97
  2. //
  3. //    0.81ß    added detection for Vision964/968
  4. //    0.83ß    added specific _868/_968 class chipset(s), GD-5434 separate
  5. //            if S3+ chipset (Trio/x68/TrioV) detect fails, default to _968
  6. //    0.84ß    added detection for GD-5436, distinguish GD-5430/40
  7. //    0.85ß    added several more Trident chipsets, thanks to VGADOC4B.ZIP
  8. //            I changed order of auto-detection, so TRIDENT is now LAST
  9. //            Restored w32p code, however it is NOT autodetected.
  10. //             The w32p code is only accessible with the "/F" option
  11. //    0.86ß    Fixed corrupted screen bug
  12. //    0.88ß    Added S3 Virge and Virge/VX detection
  13. //    0.89ß    Added Cirrus Logic GD-5446 detection
  14. //    0.90ß    Altered Trio64V+ detection routine, better S3 REV reporting
  15. //   0.92ß    Added Aurora64V+, Trio64UV+ (unsupported) detection
  16. //            cosmetic changes
  17. //    0.93α    Added Tseng Labs ET6000 support (untested)
  18. //            Added Cirrus Logic GD-546X support (untested)
  19. //            added rudimentary PCI-detection for certain chipsets
  20. //                all chipsets detected by detect_pci() include "PCI" f
  21. //                in the chipset-identification string (eg. "PCI TGUI9440")
  22. //
  23. //            detects ET4000/w32p, ET6000, Trident 9440 & 96XX, Cirrus
  24. //                GD-5462 & GD-5464, S3 Trio64V2 & Virge DX/GX
  25. //
  26. //    0.93ß    Added stub for Matrox Mystique (1064SG)
  27. //
  28. //    detects() installed svga hardware, tries to anyway!
  29. //    As of now, I hope it detects Cirrus, S3, and Trident video cards.
  30. //    As stated earlier, the W32p code has returned, but autodetection
  31. //    routine is inadequate, so to operate W32p-MCLK, you must invoke
  32. //    MCLK with "/F" option
  33.  
  34.  
  35. #include "vga.h"
  36. #include "s3.h"
  37. #include "cirrus.h"
  38. #include "trident.h"
  39. #include "tseng.h"
  40. #include "matrox.h"
  41. #include "pci.h"
  42. #include<string.h>
  43. #include<dos.h>
  44. #include<stdio.h>
  45. #include<stdlib.h>
  46.  
  47.  
  48. /* The following char-tables are used by the detection routine to list
  49.     available chipsets in each family.  I update the tables as I add
  50.     more chipsets.  The last entry is always "", which serves as an
  51.     endpoint marker...
  52.     DO NOT CHANGE THE ORDER OF THE ITEMS WITHIN EACH LIST!!!
  53. */
  54. const char table_cirrus[][30]={
  55.     "GD-5420/22",
  56.     "GD-5424/6/8/9",
  57.     "GD-5430/40/M30/M40",
  58.     "GD-5434",
  59.     "GD-5436",
  60.     "GD-5446",
  61.      "GD-5462",
  62.      "GD-5464",
  63.     ""};
  64.  
  65. const char table_s3[][30]={
  66.     "S3-801/805",
  67.     "S3-805i",
  68.     "S3-864",
  69.     "S3-964",    // added v0.86
  70.     "S3-732/764 (Trio)",
  71.     "S3-765 (Trio64V+)",
  72.     "S3-866/868",            // cosmetic change v0.93a
  73.     "S3-968",
  74.     "S3-325 (Virge)",        // added v0.88
  75.     "S3-988 (Virge/VX)",    // added v0.88, not yet tested
  76.     ""    };
  77.  
  78.  
  79. const char table_trident[][30]={
  80.     "Trident 9440/96xx",
  81.     ""
  82.     };
  83.  
  84. const char table_tseng[][30]={
  85.     "ET4000/W32p RevA",        // cosmetic change v0.93a
  86.     "ET4000/W32p RevB+",
  87.     "ET6000",
  88.      ""
  89.     };
  90.  
  91. const char table_matrox[][30]={    // added v0.93b
  92.      "1064SG (Mystique)",    // coming soon!
  93. //    "2064W  (Millenium)",    // don't know if I can support the Millenium
  94.      ""
  95.     };
  96.  
  97. // Help menu displays list(s) of either chipsets or families of chipsets.
  98. // if chipset == _AUTO, help-menu returns list of supported families
  99. // otherwise, help-menu returns list of chipsets indicated by chipset
  100. // has two parameters,
  101.  
  102. message
  103. detect::_help( int family )
  104. {
  105.     int i;    //    loop dummy variable
  106.     INITMSG( msg.text );
  107.  
  108.     if ( family == _AUTO )    {
  109.         msgout << "(F)orce manual selection of video-chipsets\n\n\t"
  110.             << _argv[ 0 ] << " /F %1\n\t\t(list available devices "
  111.             << "under family%1)"
  112.             << "\n\n\t" << _argv[ 0 ] << " /F %1 %2\n\t\t"
  113.             << "(select device%2 under family%1)\n\n"
  114.             << "Supported families\n------------------\n"
  115.             << "0 Generic VGA\n"
  116.             << (int)_FCIRRUS << " Cirrus Logic\n"
  117.             << (int)_FS3 << " S3, Inc.\n" << (int)_FTSENG
  118.             << " Tseng Labs\n"
  119.             << (int)_FTRIDENT << " Trident Microsystems\n"
  120.             << (int)_FMATROX << " Matrox Graphics, Inc.";
  121.     }    else
  122.         switch ( family )    {
  123.             case 0 :    msgout << "Generic VGA\n" << "0 VGA";
  124.                 break;
  125.             case _FTSENG :    msgout << "Tseng Labs\n";
  126.             for ( i = 0; table_tseng[ i ][ 0 ]; ++i )
  127.                 msgout << i << ' ' << table_tseng[ i ] << '\n' ;
  128.                 break;
  129.             case _FCIRRUS:    msgout << "Cirrus Logic\n";
  130.             for ( i = 0; table_cirrus[ i ][ 0 ]; ++i )
  131.                 msgout << i << ' ' << table_cirrus[ i ] << '\n' ;
  132.                 break;
  133.             case _FS3 :    msgout << "S3 accelerator\n";
  134.             for ( i = 0; table_s3[ i ][ 0 ]; ++i )
  135.                 msgout << i << ' ' << table_s3[ i ] << '\n' ;
  136.                 break;
  137.             case _FTRIDENT: msgout << "Trident Microsystems\n";
  138.             for ( i = 0; table_trident[ i ][ 0 ]; ++i )
  139.                 msgout << i << ' ' << table_trident[ i ] << '\n' ;
  140.                 break;
  141.             case _FMATROX: msgout << "Matrox Graphics, Inc.\n";
  142.             for ( i = 0; table_matrox[ i ][ 0 ]; ++i )
  143.                 msgout << i << ' ' << table_matrox[ i ] << '\n' ;
  144.                 break;
  145.             default:    msgout << family << " = unknown chipset ID";
  146.         }
  147.     msgout << ends;
  148.     return msg;
  149. }
  150.  
  151.  
  152. // detect will determine present video-hardware.  And initialize a new
  153. // object of type VGA.  Returns a pointer to that object.
  154. vga *
  155. detect::_find( int chipset, int family )
  156. {
  157.     if  ( hardware != NULL ) {
  158.         cerr << "\nInitialization error!";
  159.         exit (EXIT_FAILURE );
  160.     }
  161.     strcpy( id.make, "VGA" );
  162.  
  163.     switch ( family )    {
  164.         case 0 :
  165.             break;
  166.         case _FTSENG :    hardware = detect_tseng( chipset ); //    Force tseng
  167.             break;
  168.         case _FCIRRUS:    hardware = detect_cirrus( chipset ); //    force Cirrus
  169.             break;
  170.         case _FS3 :    hardware = detect_s3( chipset );    //    force S3
  171.             break;
  172.         case _FTRIDENT: hardware= detect_trident( chipset ); // force TVGA
  173.             break;
  174.         default:    //    Regular auto detection
  175.             family = _AUTO;
  176.     }
  177.  
  178.     if ( family == _AUTO )    {
  179.           hardware = detect_pci();        //    Check for PCI based adapters!
  180.           if ( hardware == NULL && id.make[ 0 ] == '?' )
  181.             hardware = detect_trident();
  182.             // Now check for Trident first!
  183.               // Reason is that Trident's registers are sensitive to the
  184.                // code of later detection routines!
  185.         if ( hardware == NULL && id.make[ 0 ] == '?' )
  186.             hardware = detect_tseng();    //    If not found, _trident()
  187.         if ( hardware == NULL && id.make[ 0 ] == '?' )
  188.             hardware = detect_s3();    //    If not found, _s3()
  189.         if ( hardware == NULL && id.make[ 0 ] == '?' )
  190.             hardware = detect_cirrus();    //    If not found, _trident()
  191.     }
  192.  
  193.     if ( !hardware )        // If hardware == NULL ... never set-up...
  194.         hardware = new vga( id );    //    Setup generic VGA hardware
  195.  
  196.     return hardware;
  197. }
  198.  
  199.  
  200. vga *    //    For debugging purposes only!
  201. detect::_debug( int mode )
  202. {
  203.     vga_info temp = { "S3", "Vision968", "??" };
  204.     if ( !hardware )
  205.         hardware = new _864( temp );
  206.     else
  207.         exit( EXIT_FAILURE );
  208.     return hardware;
  209. }
  210.  
  211.  
  212. vga *
  213. detect::detect_cirrus( int mode )
  214. {
  215. //    vga *hardware = NULL;
  216.     union REGS reg;
  217.     hardware->write_SR( 0x06, 0x12 );    // Unlock Cirrus SVGA registers
  218.  
  219.     uchar _CR28 = hardware->read_CR( 0x28 ) ;    // ClassID (5430/40)
  220.     uchar _CR27 = hardware->read_CR( 0x27 ) ;    // Read CL-GD ID register
  221.     _CR27 = ( _CR27 >> 2 ) & 0x3F;        //    1234 5678 -> 0012 3456
  222.  
  223.     reg.h.ah = 0x12;
  224.     reg.h.bl = 0x80;    //    Inquire VGA type
  225.     int86( 0x10, ®, ® );
  226.     if ( reg.h.bl != 0x80 )
  227.         sprintf( id.revision, "%02X", reg.h.bl );
  228.     else
  229.         strcpy( id.revision, "??" );
  230.  
  231.     strcpy( id.make, "Cirrus Logic" );    //    Let's assume it's a cirrus
  232.  
  233.     if ( mode == _AUTO )
  234.         switch ( _CR27 )    {
  235.             case 34:    strcpy( id.chipset, "GD-5420" );
  236.                 hardware = new _cirrus( id );            break;
  237.             case 35:    strcpy( id.chipset, "GD-5422" );
  238.                 hardware = new _cirrus( id );         break;
  239.             case 37:    strcpy( id.chipset, "GD-5424" );
  240.                 hardware = new _GD5424( id );            break;
  241.             case 36:    strcpy( id.chipset, "GD-5426" );
  242.                 hardware = new _GD5424( id );            break;
  243.             case 38:    strcpy( id.chipset, "GD-5428" );
  244.                 hardware = new _GD5424( id );            break;
  245.             case 39:    strcpy( id.chipset, "GD-5429" );
  246.                 hardware = new _GD5424( id );            break;
  247.             case 42:    strcpy( id.chipset, "GD-5434" );
  248.                 hardware = new _GD5434( id );            break;
  249.             case 41:    strcpy( id.chipset, "GD-5432 ??? " );
  250.                 hardware = new _GD543x( id );            break;
  251.             case 43:    strcpy( id.chipset, "GD-5436" );
  252.                 hardware = new _GD5436( id );            break;
  253.             case 46:    strcpy( id.chipset, "GD-5446" );
  254.                 hardware = new _GD5436( id );            break;
  255.             case 40:
  256.                 switch( _CR28 )    {    // Distinguish 5430/40
  257.                     case 0xFF:    strcpy( id.chipset, "GD-5430" );
  258.                         break;
  259.                     case 0x01:    strcpy( id.chipset, "GD-54M30" );
  260.                         break;
  261.                     case 0x03:    strcpy( id.chipset, "GD-5440" );
  262.                         break;
  263.                     case 0x07:    strcpy( id.chipset, "GD-54M40" );
  264.                         break;
  265.                     default:    strcpy( id.chipset, "?!?GD-5430/40" );
  266.                 }
  267.                 hardware = new _GD543x( id );            break;
  268.             default:        //  Couldn't identify Cirrus chipset
  269.                 strcpy( id.make, "? (tried Cirrus )" );
  270.                 strcpy( id.revision, "?" );
  271.                 sprintf( id.chipset, "? _CR27 = 0x%02X",
  272.                     hardware->read_CR( 0x27 ) );
  273.                 if ( mode == _FCIRRUS )    //    Forced Cirrus detection
  274.                     hardware = new _cirrus( id );
  275.         }    // Else, if user FORCES a video-chipset (manual selection)
  276.         else if ( mode != _AUTO )    {
  277.             strcpy( id.chipset, table_cirrus[ mode ] );
  278.             switch ( mode )    {
  279.                 case 0:   hardware = new _cirrus( id );
  280.                     break;
  281.                 case 1:    hardware = new _GD5424( id );
  282.                     break;
  283.                 case 2:    hardware = new _GD543x( id );
  284.                     break;
  285.                 case 3:    hardware = new _GD5434( id );
  286.                     break;
  287.                 case 4:    hardware = new _GD5436( id );
  288.                     break;
  289.                 case 5:    hardware = new _GD5436( id );
  290.                     break;
  291.                 case 6:    hardware = new _GD5462( id );
  292.                     break;
  293.                 case 7:    hardware = new _GD5464( id );
  294.                     break;
  295.                 default:
  296.                     cerr << "Unknown Cirrus Logic chipset.";
  297.                     exit( EXIT_FAILURE );
  298.             }
  299.         }
  300.  
  301.     return hardware;    //    Return whatever we found, even if nothing
  302. }
  303.  
  304.  
  305. vga *
  306. detect::detect_s3( int mode )
  307. {
  308. //    vga *hardware = NULL;
  309.     uchar _CR30, _CR2D, _CR2E, _CR2F, nibble, _DAC;
  310.         // _CR2E for all newer S3 chips...Trio on up
  311.         // _CR2F only needed to detect Trio64V+
  312.  
  313.     hardware->write_CR( 0x38, 0x48 );    // Unlock S3 VGA registers
  314.     hardware->write_CR( 0x39, 0xA0 );    // Unlock S3 registers
  315.  
  316.     _CR30= hardware->read_CR( 0x30 );    // Read _CR30 "S3 chip ID"
  317.     _CR2D= hardware->read_CR( 0x2D );    // Read _CR2D "S3 secondary ID"
  318.     _CR2E= hardware->read_CR( 0x2E );    // Read _CR2E "S3 secondary ID"
  319.     _CR2F= hardware->read_CR( 0x2F );    // If 4X, then we've got Trio64V+
  320.  
  321.     nibble = _CR30 & 0xF0;    //    Mask out revision status (lower 4bits)
  322.  
  323.     strcpy( id.make, "S3" );    //    Let's assume it's an S3 chip
  324.     sprintf( id.revision, "_CR30(3:0) = %02X", _CR30 & 0x0F );
  325.  
  326. if ( mode == _AUTO )
  327.     switch ( nibble )    {
  328.         case 0x80:    strcpy( id.chipset, "911/924 not supported" );
  329.             break;    //    Not supported
  330.         case 0x90:    strcpy ( id.chipset, "928 not supported" );
  331.             break;    //    Not supported
  332.         case 0xA0:  if ( _CR30 == 0xA8 )    {
  333.                     strcpy( id.chipset, "805i" );
  334.                     hardware = new _805i( id );    }
  335.             else    {    strcpy( id.chipset, "801/805" );
  336.                     hardware = new _S3( id );    }
  337.             break;
  338.         case 0xB0:    strcpy ( id.chipset, "928PCI not supported" );
  339.             break;    //    Not supported
  340.         case 0xC0:    strcpy( id.chipset, "864" );
  341.             hardware = new _864( id );            break;
  342.         case 0xD0:    strcpy( id.chipset, "964" );
  343.             hardware = new _964( id );            break;
  344.         case 0xE0:    //    0xE0, Trio/x68 or , newer S3chips
  345.             sprintf( id.revision,"_CR2F = %02X",hardware->read_CR( 0x2F ) );
  346.                 //    These newer chips have different REV register
  347.             switch( _CR2E )    {
  348.                 case 0x10:    strcpy( id.chipset, "732 (Trio32)" );
  349.                     hardware = new _Trio( id );    break;
  350.                 case 0x11:    // 0.90 changed 64V+ detection code
  351.                     if ( ( _CR2F >= 0x40 ) && ( _CR2F <= 0x5F ) ) {
  352.                         strcpy( id.chipset, "765 (Trio64V+)" );
  353.                         hardware = new _Triov( id );
  354.                     } else    {
  355.                         strcpy( id.chipset, "764 (Trio64)" );
  356.                         hardware = new _Trio( id );
  357.                     }
  358.                     break;
  359.                     case 0x12:    // 0.92 recognizes Aurora64V+ (UMA)
  360.                         strcpy( id.chipset, "Aurora64V+ (use Trio64V+)");
  361.                          hardware = new _Triov( id );    break;
  362.                     case 0x14:    // 0.92 recognizes Trio64UV+ (UMA)
  363.                         strcpy( id.chipset, "767 (Trio64UV+) not supported");
  364.                          break;    // UMA chipsets not supported
  365.                 case 0x31:    strcpy( id.chipset, "325 (Virge)" );
  366.                     hardware = new _Virge( id );    break;
  367.                 case 0x3D:    strcpy( id.chipset, "988 (VirgeVX)" );
  368.                     hardware = new _VirgeVX( id );    break;
  369.                 case 0x80:    strcpy( id.chipset, "866");
  370.                     hardware = new _868( id );    break;
  371.                 case 0x90:    strcpy( id.chipset, "868");
  372.                     hardware = new _868( id );    break;
  373.                 case 0xF0:    strcpy( id.chipset, "968");
  374.                     hardware = new _968( id );    break;
  375.                 default:    sprintf( id.chipset,    // UNKNOWN EXT
  376.                 "Unknown _CR30 = 0x%02X, _CR2D/_CR2E = 0x%02X/%02X",
  377.                     _CR30, _CR2D, _CR2E );
  378.                     hardware = new _968( id );
  379.             }
  380.             break;
  381.         default:    strcpy( id.make, "? (tried S3) " );
  382.             sprintf ( id.chipset, "? _CR30 = 0x%02X, _CR2D/_CR2E = 0x%02X/%02X",
  383.                 _CR30, _CR2D, _CR2E );
  384.             strcpy ( id.revision, "?" );
  385.             if ( mode == _FS3 )    //    Forced S3 detection
  386.                 hardware = new _S3( id );
  387.     }    // else, user-selected S3 chipset
  388.     else if ( mode != _AUTO )    {
  389.         strcpy( id.chipset, table_s3[ mode ] );
  390.         switch ( mode )    {
  391.             case 0:    hardware = new _S3( id );
  392.                 break;
  393.             case 1:    hardware = new _805i( id );
  394.                 break;
  395.             case 2:    hardware = new _864( id );
  396.                 break;
  397.             case 3:    hardware = new _964( id );    // added v0.86
  398.                 break;
  399.             case 4:    hardware = new _Trio( id );
  400.                 break;
  401.             case 5:    hardware = new _Triov( id );
  402.                 break;
  403.             case 6:    hardware = new _868( id );
  404.                 break;
  405.             case 7:    hardware = new _968( id );
  406.                 break;
  407.             case 8:    hardware = new _Virge( id );
  408.                 break;
  409.             case 9:    hardware = new _VirgeVX( id );
  410.                 break;
  411.             default:
  412.                 cerr << "Unknown S3 chipset.";
  413.                 exit( EXIT_FAILURE );
  414.         }
  415.     }
  416.  
  417.     return hardware;    //    Return whatever we found, even if nothing
  418. }
  419.  
  420.  
  421. vga *    //    Trident support not implemented
  422. detect::detect_trident( int mode )
  423. {
  424. //    vga *hardware = NULL ;
  425.     uchar _SR0B = 0, _SR0E;    //    Trident ID register
  426.     uchar old_mode;    // Preserve low/high bytes of mode-register
  427.     uchar temp;
  428. //    INITMSG( id.make );
  429. //    msgout << "Trident" << ends ;    // Let's assume it's a Trident
  430.  
  431.     strcpy( id.make, "Trident" );    //    Let's assume it's a Trident
  432.     strcpy( id.revision, "??" );
  433.  
  434. //    INITMSG( id.chipset );
  435.  
  436.     // Following code adapted from VGADOC4B.ZIP
  437.     hardware->write_SR( 0x0B, 0 );    //Write $00 to force new-mode
  438.     _SR0B = hardware->read_SR( 0x0B );    // this forces old mode
  439.     _SR0E = hardware->read_SR( 0x0E );
  440.     hardware->write_SR( 0x0E, _SR0E ^ 0x55 ); // xor $55
  441.     hardware->write_SR( 0x0E, _SR0E ^ 0x02 ); // xor $02
  442.  
  443. if ( mode == _AUTO )
  444.     switch ( _SR0B )    {
  445.         case 1 : case 2 :    strcpy( id.chipset, "8800" );
  446.             break;    //    Not supported
  447.         case 3: case 4: case 0x13: case 0x12: case 0x33:
  448.             strcpy( id.chipset, "8900 series" );
  449.             break;
  450.         case 0x23: case 0x43: strcpy( id.chipset, "9000 series" );
  451.             break;    //    Not supported
  452.         case 0x53:    strcpy( id.chipset, "9200CXr" );
  453.             break;    //    Not supported
  454.         case 0xC3: case 0x73:    strcpy( id.chipset, "GUI9420??" );
  455.             break;    //    Not supported
  456.         case 0x93:    strcpy( id.chipset, "GUI9400CXi" );
  457.             break;    //    Not supported
  458.         case 0xF3:    strcpy( id.chipset, "GUI9430??" );
  459.             break;
  460.         case 0xE3:    strcpy( id.chipset, "GUI9440" );
  461.             hardware = new _TR9440( id );
  462.             break;
  463.         case 0xD3:    strcpy( id.chipset, "GUI96xx" );
  464.             hardware = new _TR9440( id );
  465.             break;
  466.         case 0x63: case 0x83: case 0xA3:
  467.             strcpy( id.chipset, "A Trident LCD chipset" );
  468.             break;
  469.         default:
  470.             sprintf( id.chipset, "? Unknown _SR0B = 0x%02X", _SR0B );
  471.                 strcpy( id.make, "? (tried Trident)" );
  472.             strcpy( id.revision, "?" );
  473.             if ( mode == _FTRIDENT )    {
  474.                 cerr << "\nTRIDENT not supported yet.";
  475.                 exit( EXIT_FAILURE );
  476.             }
  477.     }
  478.     else if ( mode != _AUTO )    {
  479.         strcpy( id.chipset, table_trident[ mode ] );
  480.  
  481.         switch( mode )    {
  482.             case 0 :  hardware = new _TR9440( id );
  483.                 break;
  484.             default:
  485.                 cerr << "Unknown Trident chipset.";
  486.                 exit( EXIT_FAILURE );
  487.         }
  488.     }
  489. //}
  490.     return hardware;    //    Return whatever we found, even if nothing
  491. }
  492.  
  493.  
  494. //    v0.93...added ET6000 PCI/VL detection
  495. vga *
  496. detect::detect_tseng( int mode )
  497. {
  498. //    vga *hardware = NULL ;
  499.     dword creg;
  500.      int i;
  501.  
  502.     outportb( 0x3BF, 0x03 );    //    Unlock W32P "key"
  503.     outportb( 0x3D8, 0xA0 );    //    Unlock W32P "key"
  504.  
  505.      for ( i = 0; i < 4; ++ i )
  506.         outportb( 0xF100 + i, 0 );    // Activate VLbus-IO for ET6000
  507.  
  508.     strcpy( id.make, "? (tried Tseng Labs)" );
  509.     strcpy( id.chipset, "?" );
  510.     strcpy( id.revision, "?" );
  511.  
  512.     if ( mode == _AUTO )    {
  513.         creg.b.b0 = inportb( 0xF100 );
  514.         creg.b.b1 = inportb( 0xF101 );
  515.         creg.b.b2 = inportb( 0xF102 );
  516.         creg.b.b3 = inportb( 0xF103 );
  517.           // Test for Tesng Labs ET6000, vendor 0x100C, Device 0x3208
  518.           if ( creg.w.w0 == 0x100C && creg.w.w1 == 0x3208 )
  519.           {
  520.             sprintf( id.make, "Tseng Labs" );
  521.               sprintf( id.chipset, "ET6000VL" );
  522.             sprintf( id.revision, "%02X", inportb( 0xF100 + 8 ) );
  523.             hardware = new _et6000( id );
  524.           }
  525.     }
  526.     else if ( mode != _AUTO )    {
  527.         strcpy( id.chipset, table_tseng[ mode ] );
  528.         switch( mode )    {
  529.             case 0 :  hardware = new _w32p( id );
  530.                 break;
  531.             case 1 :    hardware = new _w32pb( id );
  532.                 break;
  533.                case 2 :     hardware = new _et6000( id );
  534.                    break;
  535.             default:
  536.                 cerr << "Unknown Tseng Labs chipset.";
  537.                 exit( EXIT_FAILURE );
  538.         }
  539.     }
  540.  
  541.     return hardware;
  542. }
  543.  
  544.  
  545. // Added PCI-detection for certain chipsets
  546. vga *
  547. detect::detect_pci( int mode )
  548. {
  549. //   pci_bios_type *pci_bios;
  550. //   pci_device_handle_type pci_vga;
  551.  
  552.     uchar rev;    // Revision ID
  553.     dword creg;    // Configuration test variable to test for VL-bus ET6000
  554.  
  555.     pci_bios=new pci_bios_type;    // Open PCI-bios routines, INT 0x1A
  556.  
  557.      // Note, the absence of BIOS-support for PCI does not automatically
  558.      // mean the host-bus isn't PCI.  It could mean an older system BIOS.
  559.      // Currently, MCLK requires BIOS-support for PCI-devices.
  560.  
  561.     if ( pci_bios->installation_check() == NULL )
  562.         return NULL;    // No PCI BIOS, no PCI-devices found!
  563.  
  564.     pci_vga.vendor=0x100C;    // Tseng Labs, Inc.
  565.     pci_vga.device=0x3208;    // ET-6000
  566.     pci_vga.index = 0;    // Only look for 1st installed ET6000
  567.  
  568.     // Look for PCI ET6000, if found, find_device() will store
  569.     // the host/bus# and dev/func# into our *pci_vga object
  570.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  571.     {
  572.          sprintf( id.chipset, "PCI ET6000" );
  573.         sprintf( id.make, "Tseng Labs" );
  574.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  575.           sprintf( id.revision, "%02X", rev );
  576.           hardware = new _et6000( id );
  577.           return hardware;
  578.      }
  579.  
  580.     pci_vga.vendor=0x100C;    // Tseng Labs, Inc.
  581.     pci_vga.device=0x3202;    // ET-4000/W32P
  582.     pci_vga.index = 0;    // Only look for 1st installed device
  583.  
  584.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  585.     {
  586.          sprintf( id.chipset, "PCI ET4000/W32P RevA" );
  587.         sprintf( id.make, "Tseng Labs" );
  588.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  589.           sprintf( id.revision, "%02X", rev );
  590.           hardware = new _w32p( id );
  591.           return hardware;
  592.      }
  593.  
  594.      pci_vga.vendor=0x100C;    // Tseng Labs, Inc.
  595.     pci_vga.device=0x3206;    // ET-4000/W32P
  596.     pci_vga.index = 0;    // Only look for 1st installed device
  597.  
  598.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  599.     {
  600.          sprintf( id.chipset, "PCI ET4000/W32P" );
  601.         sprintf( id.make, "Tseng Labs" );
  602.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  603.           sprintf( id.revision, "%02X", rev );
  604.           hardware = new _w32pb( id );
  605.           return hardware;
  606.      }
  607.  
  608.      pci_vga.vendor=0x100C;    // Tseng Labs, Inc.
  609.     pci_vga.device=0x3207;    // ET-4000/W32P
  610.     pci_vga.index = 0;    // Only look for 1st installed device
  611.  
  612.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  613.     {
  614.          sprintf( id.chipset, "PCI ET4000/W32P" );
  615.         sprintf( id.make, "Tseng Labs" );
  616.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  617.           sprintf( id.revision, "%02X", rev );
  618.           hardware = new _w32pb( id );
  619.           return hardware;
  620.      }
  621.  
  622.      pci_vga.vendor=0x1013;    // Cirrus Logic, Inc.
  623.     pci_vga.device=0xD0;    // Laguna GD-5462
  624.     pci_vga.index = 0;    // Only look for 1st installed device
  625.  
  626.      if ( pci_bios->find_device( &pci_vga ) == TRUE )
  627.     {
  628.          sprintf( id.chipset, "Cirrus Logic" );
  629.         sprintf( id.make, "PCI GD-5462" );
  630.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  631.           sprintf( id.revision, "%02X", rev );
  632.           hardware = new _GD5462( id );
  633.           return hardware;
  634.      }
  635.  
  636.  
  637.      pci_vga.vendor=0x1013;    // Cirrus Logic, Inc.
  638.     pci_vga.device=0xD4;    // Laguna GD-5464
  639.     pci_vga.index = 0;    // Only look for 1st installed device
  640.  
  641.      if ( pci_bios->find_device( &pci_vga ) == TRUE )
  642.     {
  643.          sprintf( id.chipset, "Cirrus Logic" );
  644.         sprintf( id.make, "PCI GD-5464" );
  645.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  646.           sprintf( id.revision, "%02X", rev );
  647.           hardware = new _GD5464( id );
  648.           return hardware;
  649.      }
  650.  
  651.  
  652.      pci_vga.vendor=0x1023;    // Trident Microsystems, Inc.
  653.     pci_vga.device=0x9440;    // TGUI 9440
  654.     pci_vga.index = 0;    // Only look for 1st installed device
  655.  
  656.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  657.     {
  658.          sprintf( id.chipset, "PCI TGUI9440" );
  659.         sprintf( id.make, "Trident Microsystems" );
  660.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  661.           sprintf( id.revision, "%02X", rev );
  662.           hardware = new _TR9440( id );
  663.           return hardware;
  664.      }
  665.  
  666.  
  667.      pci_vga.vendor=0x1023;    // Trident Microsystems, Inc.
  668.     pci_vga.device=0x9660;    // TGUI 96XX
  669.     pci_vga.index = 0;    // Only look for 1st installed device
  670.  
  671.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  672.     {
  673.          sprintf( id.chipset, "PCI TGUI96xx" );
  674.         sprintf( id.make, "Trident Microsystems" );
  675.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  676.           sprintf( id.revision, "%02X", rev );
  677.           hardware = new _TR9440( id );
  678.           return hardware;
  679.      }
  680.  
  681.  
  682.      pci_vga.vendor=0x5333;    // S3, Inc.
  683.     pci_vga.device=0x8A01;    // Virge DX/GX
  684.     pci_vga.index = 0;    // Only look for 1st installed device
  685.  
  686.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  687.     {
  688.          sprintf( id.chipset, "PCI Virge DX/GX" );
  689.         sprintf( id.make, "S3" );
  690.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  691.           sprintf( id.revision, "%02X", rev );
  692.           hardware = new _Virge( id );
  693.           return hardware;
  694.      }
  695.  
  696.  
  697.      pci_vga.vendor=0x5333;    // S3, Inc.
  698.     pci_vga.device=0x8901;    // Trio64V2
  699.     pci_vga.index = 0;    // Only look for 1st installed device
  700.  
  701.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  702.     {
  703.          sprintf( id.chipset, "PCI Trio64V2 (775)" );
  704.         sprintf( id.make, "S3" );
  705.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  706.           sprintf( id.revision, "%02X", rev );
  707.           hardware = new _Triov( id );
  708.           return hardware;
  709.      }
  710.  
  711.  
  712.      pci_vga.vendor=0x5333;    // S3, Inc.
  713.     pci_vga.device=0x5631;    // Virge (325)
  714.     pci_vga.index = 0;    // Only look for 1st installed device
  715.  
  716.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  717.     {
  718.          sprintf( id.chipset, "PCI Virge (325)" );
  719.         sprintf( id.make, "S3" );
  720.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  721.           sprintf( id.revision, "%02X", rev );
  722.           hardware = new _Virge( id );
  723.           return hardware;
  724.      }
  725.  
  726.  
  727.      pci_vga.vendor=0x5333;    // S3, Inc.
  728.     pci_vga.device=0x883D;    // Virge/VX
  729.     pci_vga.index = 0;    // Only look for 1st installed device
  730.  
  731.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  732.     {
  733.          sprintf( id.chipset, "PCI Virge/VX (988)" );
  734.         sprintf( id.make, "S3" );
  735.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  736.           sprintf( id.revision, "%02X", rev );
  737.           hardware = new _VirgeVX( id );
  738.           return hardware;
  739.      }
  740.  
  741.  
  742.      pci_vga.vendor=0x102B;    // Matrox Graphics, Inc.
  743.     pci_vga.device=0x051A;    // Matrox Mystique (1064SG)
  744.     pci_vga.index = 0;    // Only look for 1st installed device
  745.  
  746.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  747.     {
  748.          sprintf( id.chipset, "PCI Mystique (1064SG)" );
  749.         sprintf( id.make, "Matrox" );
  750.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  751.           sprintf( id.revision, "%02X", rev );
  752.           hardware = new _Mystique( id );
  753.           return hardware;
  754.      }
  755.  
  756.  
  757.     pci_vga.vendor=0x102B;    // Matrox Graphics, Inc.
  758.     pci_vga.device=0x0519;    // Matrox MGA Storm (2064W)
  759.     pci_vga.index = 0;    // Only look for 1st installed device
  760.  
  761.     if ( pci_bios->find_device( &pci_vga ) == TRUE )
  762.     {
  763.          sprintf( id.chipset, "PCI Millenium (2064W)" );
  764.         sprintf( id.make, "Matrox" );
  765.           pci_bios->read_cbyte( pci_vga, 0x8, &rev );
  766.           sprintf( id.revision, "%02X", rev );
  767.           hardware = NULL;    // Support coming soon!
  768.           return hardware;
  769.      }
  770.  
  771.  
  772.      sprintf( id.make, "?" );    // Didn't find anything
  773.      return hardware;
  774. }
  775.