home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / SVGALIB / SVGALIB1.TAR / svgalib / src / tvga8900.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-11  |  11.3 KB  |  470 lines

  1. /* VGAlib version 1.2 - (c) 1993 Tommy Frandsen            */
  2. /*                                   */
  3. /* This library is free software; you can redistribute it and/or   */
  4. /* modify it without any restrictions. This library is distributed */
  5. /* in the hope that it will be useful, but without any warranty.   */
  6.  
  7. /* Multi-chipset support Copyright (C) 1993 Harm Hanemaayer */
  8. /* Modified by Hartmut Schirmer */
  9.  
  10. /* TVGA 8900c code taken from tvgalib by Toomas Losin */
  11.  
  12.  
  13. #include <stdio.h>
  14. #include "vga.h"
  15. #include "libvga.h"
  16. #include "driver.h"
  17.  
  18. #include "tvga8900.regs"
  19.  
  20. /* static int tvga_chiptype; */
  21. static int tvga8900_memory;    /* amount of video memory in K */
  22. static int tvga8900_nonint;    /* nonzero if non-interlaced jumper set */
  23.  
  24. static int tvga8900_init(int, int, int);
  25. static int tvga8900_interlaced( int mode );
  26.  
  27. static int reg_0c = 0xad;    /* value for 256k cards */
  28.  
  29.  
  30. /* Mode table */
  31. static ModeTable tvga_modes_1024[] = { /* 1Mb, non-interlace jumper set */
  32.         OneModeEntry(640x480x256),
  33.     OneModeEntry(800x600x256),
  34.     OneModeEntry(1024x768x256),
  35.     END_OF_MODE_TABLE
  36. };
  37.  
  38. #define INTERL(res,i) { G##res, g##res##i##_regs }
  39.  
  40. static ModeTable tvga_modes_1024i[] = { /* 1Mb, jumper set to interlaced */
  41.         INTERL(640x480x256,i),
  42.     INTERL(800x600x256,i),
  43.     INTERL(1024x768x256,i),
  44.     END_OF_MODE_TABLE
  45. };
  46.  
  47. static ModeTable tvga_modes_512[] = {    /* 512K */
  48.         INTERL(640x480x256,i),
  49.     INTERL(800x600x256,i1),
  50.     END_OF_MODE_TABLE
  51. };
  52.  
  53. static ModeTable *tvga_modes = NULL;
  54.  
  55.  
  56. /* Fill in chipset specific mode information */
  57.  
  58. static int tvga8900_getmodeinfo( int mode, vga_modeinfo *modeinfo ) {
  59.     if (modeinfo->bytesperpixel > 0)
  60.         modeinfo->maxpixels = tvga8900_memory * 1024 /
  61.             modeinfo->bytesperpixel;
  62.     else
  63.         modeinfo->maxpixels = tvga8900_memory * 1024; 
  64.     modeinfo->maxlogicalwidth = 2040;
  65.     modeinfo->startaddressrange = 0xfffff;
  66.     if (mode == G320x200x256) {
  67.         /* Special case: bank boundary may not fall within display. */
  68.         modeinfo->startaddressrange = 0xf0000;
  69.         /* Hack: disable page flipping capability for the moment. */
  70.         modeinfo->startaddressrange = 0xffff;
  71.         modeinfo->maxpixels = 65536;
  72.     }
  73.     modeinfo->haveblit = 0;
  74.  
  75.     if (tvga8900_interlaced(mode))
  76.       modeinfo->flags |= IS_INTERLACED;
  77.     modeinfo->flags &= ~HAVE_RWPAGE;
  78.  
  79.     return 0;
  80. }
  81.  
  82.  
  83. /* select the correct register table */
  84. static void setup_registers(void)
  85. {
  86.     if (tvga_modes == NULL) {
  87.       if (tvga8900_memory < 1024) 
  88.              tvga_modes = tvga_modes_512;
  89.       else
  90.       if (tvga8900_nonint)
  91.          tvga_modes = tvga_modes_1024;
  92.       else
  93.          tvga_modes = tvga_modes_1024i;
  94.         }
  95. }
  96.  
  97.  
  98. /* Read and store chipset-specific registers */
  99.  
  100. static int tvga8900_saveregs(unsigned char regs[])
  101. {
  102.     int i;
  103.  
  104.     /* save extended CRT registers */
  105.     for (i = 0; i < 7; i++) {
  106.      port_out(0x18 + i, CRT_I); 
  107.      regs[EXT + i] = port_in(CRT_D); 
  108.     }
  109.  
  110.     /* now do the sequencer mode regs */
  111.     port_out(0x0b, SEQ_I);        /* force old mode regs */
  112.     port_out(port_in(SEQ_D), SEQ_D);    /* by writing */
  113.  
  114.     /* outw(0x3C4, 0x820E); */        /* unlock conf. reg */
  115.     /* port_out(0x0c, SEQ_I); */        /* save conf. reg */
  116.     /* regs[EXT + 11] = port_in(SEQ_D); */
  117.  
  118.     port_out(0x0d, SEQ_I);        /* old reg 13 */
  119.     regs[EXT + 7] = port_in(SEQ_D);
  120.     port_out(0x0e, SEQ_I);        /* old reg 14 */
  121.     regs[EXT + 8] = port_in(SEQ_D);
  122.  
  123.     port_out(0x0b, SEQ_I);        /* now use new regs */
  124.     port_in(SEQ_D);
  125.     port_out(0x0d, SEQ_I);        /* new reg 13 */
  126.     regs[EXT + 9] = port_in(SEQ_D);
  127.     port_out(0x0e, SEQ_I);        /* new reg 14 */
  128.     regs[EXT + 10] = port_in(SEQ_D) ^ 0x02;
  129.  
  130.     /* we do the ^ 0x02 so that when the regs are restored */
  131.     /* later we don't have a special case; see trident.doc */
  132.  
  133.     return 12; /* tridents requires 12 additional registers */
  134. }
  135.  
  136.  
  137. /* Set chipset-specific registers */
  138.  
  139. static int tvga8900_setregs( const unsigned char regs[], int mode )
  140. {
  141.     int i;
  142.     int crtc31 = 0;
  143.     
  144.     /* 7 extended CRT registers */
  145.     /* 4 extended Sequencer registers (old and new) */
  146.     /* CRTC reg 0x1f is apparently dependent */
  147.     /* on the amount of memory installed. */
  148.  
  149.     switch (tvga8900_memory >> 8) {
  150.          case 1 : crtc31 = 0x94; reg_0c = 0xad; break;    /* 256K */
  151.           case 2 :
  152.          case 3 : crtc31 = 0x98; reg_0c = 0xcd; break;    /* 512/768K */
  153.           case 4 :                     /* 1024K */
  154.              crtc31 = 0x18;
  155.               reg_0c = 0xcd;
  156.              if (mode == G1024x768x256) {
  157.                  reg_0c = 0xed;
  158.                 crtc31 = 0x98;
  159.               }
  160.               else 
  161.                          if (mode == G640x480x256 || mode == G800x600x256)
  162.                  reg_0c = 0xed;
  163.              break;
  164.     }
  165.  
  166.     if (mode == TEXT) {
  167.         reg_0c = regs[EXT + 11];
  168.         crtc31 = regs[EXT + 12];
  169.     }
  170.  
  171.  
  172.     #ifdef REG_DEBUG
  173.     printf("Setting extended registers\n");
  174.     #endif
  175.  
  176.     /* write extended CRT registers */
  177.     for (i = 0; i < 7; i++) {
  178.      port_out(0x18 + i, CRT_I); 
  179.      port_out(regs[EXT + i], CRT_D); 
  180.     }
  181.  
  182.     /* update sequencer mode regs */
  183.     port_out(0x0b, SEQ_I);        /* select old regs */
  184.     port_out(port_in(SEQ_D), SEQ_D);
  185.     port_out(0x0d, SEQ_I);        /* old reg 13 */
  186.     port_out(regs[EXT + 7], SEQ_D);
  187.     port_out(0x0e, SEQ_I);        /* old reg 14 */
  188. #if 0
  189.     port_out(regs[EXT + 8], SEQ_D);
  190. #endif
  191.     port_out( ((port_in(SEQ_D) & 0x08) | (regs[EXT + 8] & 0xf7)), SEQ_D);
  192.     
  193.  
  194.     port_out(0x0b, SEQ_I);
  195.     port_in(SEQ_D);            /* select new regs */
  196.  
  197.         if (tvga8900_memory > 512) {
  198.         port_out(0x0e, SEQ_I);        /* set bit 7 of reg 14  */
  199.         port_out(0x80, SEQ_D);        /* to enable writing to */
  200.         port_out(0x0c, SEQ_I);        /* reg 12               */
  201.         port_out(reg_0c, SEQ_D);
  202.     }
  203.  
  204. /*    outw(0x3c4, 0x820e); */        /* unlock conf. reg */
  205. /*     port_out(0x0c, SEQ_I); */    /* reg 12 */
  206.  
  207.     port_out(0x0d, SEQ_I);        /* new reg 13 */
  208.     port_out(regs[EXT + 9], SEQ_D);
  209.     port_out(0x0e, SEQ_I);        /* new reg 14 */
  210.     port_out(regs[EXT + 10], SEQ_D);
  211.  
  212.     #ifdef REG_DEBUG
  213.     printf("Now setting last two extended registers.\n");
  214.     #endif
  215.  
  216.     /* update CRTC reg 1f */
  217.     port_out(0x1f, CRT_I);
  218.     port_out((port_in(CRT_D) & 0x03) | crtc31, CRT_D);
  219.  
  220.     return 0;
  221. }
  222.  
  223.  
  224. /* Return nonzero if mode is available */
  225.  
  226. static int tvga8900_modeavailable( int mode ) {
  227.     const unsigned char *regs;
  228.     struct info *info;
  229.  
  230.     regs = LOOKUPMODE(tvga_modes, mode);
  231.     if (regs == NULL || mode == GPLANE16)
  232.         return vga_driverspecs.modeavailable(mode);
  233.     if (regs==DISABLE_MODE || mode<=TEXT || mode>GLASTMODE)
  234.         return 0;
  235.  
  236.     info = &__svgalib_infotable[mode];
  237.     if (tvga8900_memory*1024 < info->ydim*info->xbytes)
  238.         return 0;
  239.  
  240.     return SVGADRV;
  241. }
  242.  
  243.  
  244. /* Check if mode is interlaced */
  245.  
  246. static int tvga8900_interlaced( int mode ) { 
  247.     const unsigned char *regs;
  248.  
  249.     setup_registers();
  250.     regs = LOOKUPMODE(tvga_modes, mode);
  251.     if (regs == NULL || regs == DISABLE_MODE)
  252.       return 0;
  253.     return tvga8900_nonint == 0;
  254. }
  255.  
  256.  
  257. /* Set a mode */
  258.  
  259. static int tvga8900_setmode( int mode, int prv_mode ) {
  260.     const unsigned char *regs;
  261.  
  262.     regs = LOOKUPMODE(tvga_modes, mode);
  263.     if (regs == NULL)
  264.         return (int)(vga_driverspecs.setmode(mode, prv_mode));
  265.     if (!tvga8900_modeavailable( mode))
  266.         return 1;
  267.     __vga_setregs(regs);
  268.     tvga8900_setregs(regs, mode);
  269.     return 0;
  270. }
  271.  
  272.  
  273. /* Unlock chipset-specific registers */
  274.  
  275. static int tvga8900_unlock() {
  276.     return 0;
  277. }
  278.  
  279.  
  280. /* Relock chipset-specific registers */
  281.  
  282. static int tvga8900_lock() {
  283.     return 0;
  284. }
  285.  
  286.  
  287. /* Indentify chipset; return non-zero if detected */
  288.  
  289. static int tvga8900_test()
  290. {
  291.     int origVal, newVal;
  292.     int save0b;
  293.     /* 
  294.             * Check first that we have a Trident card.
  295.             */
  296.            outb(0x3c4, 0x0b);
  297.            save0b = inb(0x3c5);
  298.     outw(0x3C4, 0x000B);    /* Switch to Old Mode */
  299.     inb(0x3C5);        /* Now to New Mode */
  300.           outb(0x3C4, 0x0E);
  301.           origVal = inb(0x3C5);
  302.           outb(0x3C5, 0x00);
  303.           newVal = inb(0x3C5) & 0x0F;
  304.           outb(0x3C5, (origVal ^ 0x02));
  305.  
  306.           if (newVal != 2) {
  307.               outb(0x3c5, origVal);
  308.               outb(0x3c4, 0x0b);
  309.               outb(0x3c5, save0b);
  310.               return 0;
  311.           }
  312.  
  313.     /* check version */
  314.     outw(0x3c4, 0x000b);
  315.     switch (inb(0x3c5)) {
  316.     case 0x02 :    /* 8800cs */
  317.     case 0x03 :    /* 8900b */
  318.     case 0x04 :    /* 8900c */
  319.     case 0x13 :
  320.     case 0x33 :    /* 8900cl */
  321.     case 0x23 :    /* 9000 */
  322.         break;
  323.     default :
  324.         return 0;
  325.     }
  326.  
  327.     tvga8900_init(0, 0, 0);
  328.     return 1;
  329. }
  330.  
  331.  
  332. /* Bank switching function - set 64K bank number */
  333.  
  334. static int tvga8900_setpage( int page ) {
  335.     port_out(0x0b, SEQ_I);
  336.     port_out(port_in(SEQ_D), SEQ_D);
  337.     port_in(SEQ_D);            /* select new mode regs */
  338.  
  339.     port_out(0x0e, SEQ_I);
  340.     port_out(page ^ 0x02, SEQ_D);    /* select the page */
  341.  
  342.     return 0;
  343. }
  344.  
  345. /* No read/write paging with TVGA8900 */
  346. static int tvga8900_setrdpage( int page ) {
  347.     return 0;
  348. }
  349. static int tvga8900_setwrpage( int page ) {
  350.     return 0;
  351. }
  352.  
  353.  
  354.  
  355. /* Set display start address (not for 16 color modes) */
  356. /* Trident supports any address in video memory (up to 1Mb) */
  357.  
  358. static int tvga8900_setdisplaystart( int address ) {
  359.     if (__svgalib_cur_mode == G320x200x256) {
  360.         outw(0x3d4, 0x0d + (address & 0x00ff) * 256);
  361.         outw(0x3d4, 0x0c + (address & 0xff00));
  362.         address <<= 2;    /* Adjust address so that extended bits */
  363.                 /* are correctly set later (too allow for */
  364.                 /* multi-page flipping in 320x200). */
  365.         goto setextendedbits;
  366.     }
  367.     if (tvga8900_memory == 1024) {
  368.         outw(0x3d4, 0x0d + ((address >> 3) & 0x00ff) * 256);    /* sa2-sa9 */
  369.         outw(0x3d4, 0x0c + ((address >> 3) & 0xff00));        /* sa10-sa17 */
  370.     }
  371.     else {
  372.         outw(0x3d4, 0x0d + ((address >> 2) & 0x00ff) * 256);    /* sa2-sa9 */
  373.         outw(0x3d4, 0x0c + ((address >> 2) & 0xff00));        /* sa10-sa17 */
  374.     }
  375.     if (__svgalib_cur_mode != G320x200x256) {
  376.         inb(0x3da);            /* set ATC to addressing mode */
  377.         outb(0x3c0, 0x13 + 0x20);    /* select ATC reg 0x13 */
  378.         if (tvga8900_memory == 1024) {
  379.             outb(0x3c0, (inb(0x3c1) & 0xf0) | (address & 7));
  380.                 /* write sa0-2 to bits 0-2 */
  381.             address >>= 1;
  382.         }
  383.         else
  384.             outb(0x3c0, (inb(0x3c1) & 0xf0) | ((address & 3) << 1));
  385.                 /* write sa0-1 to bits 1-2 */
  386.     }
  387.  
  388. setextendedbits:
  389.     outb(0x3d4, 0x1e);
  390.     outb(0x3d5, (inb(0x3d5) & 0x5f) | 0x80    /* set bit 7 */
  391.         | ((address & 0x40000) >> 13));    /* sa18: write to bit 5 */
  392.     outb(0x3c4, 0x0b); outb(0x3c5, 0);    /* select 'old mode' */
  393.     outb(0x3c4, 0x0e);
  394.     outb(0x3c5, (inb(0x3c5) & 0xfe)
  395.         | ((address & 0x80000) >> 19));    /* sa19: write to bit 0 */
  396.     outb(0x3c4, 0x0b);
  397.     inb(0x3c5);                /* return to 'new mode' */
  398.  
  399.     return 0;
  400. }
  401.  
  402.  
  403. /* Set logical scanline length (usually multiple of 8) */
  404. /* Trident supports multiples of 8 to 2040 */
  405.  
  406. static int tvga8900_setlogicalwidth( int width ) { 
  407.     outw(0x3d4, 0x13 + (width >> 3) * 256);    /* lw3-lw11 */
  408.  
  409.     return 0;
  410. }
  411.  
  412.  
  413. /* Function table */
  414.  
  415. DriverSpecs tvga8900_driverspecs = {
  416.     tvga8900_saveregs,
  417.     tvga8900_setregs,
  418.     tvga8900_unlock,
  419.     tvga8900_lock,
  420.     tvga8900_test,
  421.     tvga8900_init,
  422.     tvga8900_setpage,
  423.     tvga8900_setrdpage,
  424.     tvga8900_setwrpage,
  425.     tvga8900_setmode,
  426.     tvga8900_modeavailable,
  427.     tvga8900_setdisplaystart,
  428.     tvga8900_setlogicalwidth,
  429.     tvga8900_getmodeinfo,
  430.     0,    /* bitblt */
  431.     0,    /* imageblt */
  432.     0,    /* fillblt */
  433.     0,    /* hlinelistblt */
  434.     0,    /* bltwait */
  435.     0,    /* extset */
  436.     0,
  437.     0,    /* linear */
  438.     NULL    /* accelspecs */
  439. };
  440.  
  441.  
  442. /* Initialize chipset (called after detection) */
  443.  
  444. static int tvga8900_init( int force, int par1, int par2) {
  445.     if (force) {
  446.         #ifdef DEBUG
  447.         printf("Forcing memory to %dK\n", par1);
  448.         #endif
  449.         tvga8900_memory = par1;
  450.         tvga8900_nonint = par2;
  451.     }
  452.     else {
  453.            port_out(0x1f, CRT_I);
  454.             tvga8900_memory = (port_in(CRT_D) & 0x03) * 256 + 256;
  455.  
  456.             /* Now is the card running in interlace mode? */
  457.             port_out(0x0f, SEQ_I);
  458.            tvga8900_nonint = port_in(SEQ_D) & 0x04;
  459.     }
  460.  
  461.     if (__svgalib_driver_report) {
  462.         printf("Using Trident 8900/9000 driver (%dK, %sinterlaced).\n", 
  463.             tvga8900_memory, (tvga8900_nonint) ? "non-" : "");
  464.     }
  465.  
  466.     driverspecs = &tvga8900_driverspecs;
  467.     setup_registers();
  468.     return 0;
  469. }
  470.