home *** CD-ROM | disk | FTP | other *** search
/ Shareware Supreme Volume 6 #1 / swsii.zip / swsii / 168 / VGAMOVE.ZIP / VGAPOS.C < prev   
Encoding:
C/C++ Source or Header  |  1991-05-09  |  22.7 KB  |  669 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <dos.h>
  4. #include <stdlib.h>
  5. #include <conio.h>
  6.  
  7. /* vgapos.c - version 1.0 Copyright (c) May 8, 1991 by
  8.     Robert W. Babcock and WSS Division of DDC
  9.     4 Reeves Road
  10.     Bedford, MA  01730
  11.     USA
  12.     617-275-1183
  13.  
  14.     Display screens in various modes and accept input to change VGA CRTC
  15.     registers which control centering and other aspects of the display.
  16.     Print a table of values to be stuffed into the VGA registers by a
  17.     memory resident routine such as the accompanying VGAMOVE.ASM.  This
  18.     program was specifically written for the ATI VGA Wonder card, but it
  19.     should be portable to other VGA cards with minor modifications.
  20.  
  21.     Warning: playing with VGA CRTC registers changes the timing signals sent
  22.     to your monitor.  Such changes could make your monitor very unhappy,
  23.     possibly even to the point of causing permanant hardware damage.  This
  24.     routine is supplied in source code form so that you can see exactly what
  25.     it does and make modifications to adapt it to your video board.  The
  26.     author specifically disclaims any responsibility for any harmful
  27.     consequences which may arise out of your use of this code.
  28.  */
  29.  
  30. /* Prototypes for local routines
  31.  */
  32. int add_reg(int incr, struct vga_regs *bios_value, struct vga_regs *old_value,
  33.                 int crt_reg);
  34. void bios_mode(int mode);
  35. void border_set(void);
  36. void enable_regs(void);
  37. void fill_screen(unsigned int segment);
  38. void help_print(int mode, struct vga_regs *bios_regs,
  39.                         struct vga_regs *current_regs);
  40. void poke_vga(int crt_reg, int data);
  41. int range_check(int old_value, int increment, int max_value);
  42. void set_mode(int mode, int mono, struct vga_regs *bios_value,
  43.                     struct vga_regs *new_value);
  44.  
  45. #define INPUT_STATUS_1            0x3da
  46. #define INPUT_STATUS_1_MONO    0x3ba
  47. #define ATTR_ADDRESS_WRITE        0x3c0
  48. #define ATTR_ADDRESS_READ        0x3c1
  49. #define INDEX_ATTR_PALBASE        0    /* palette registers 0-f */
  50. #define INDEX_ATTR_MCR            0x10    /* mode control register */
  51. #define INDEX_ATTR_OCR            0x11    /* overscan color register */
  52. #define INDEX_ATTR_CPE            0x12    /* color plane enable register */
  53. #define INDEX_ATTR_HPP            0x13    /* horizontal pixel panning register */
  54. #define INDEX_ATTR_CS            0x14    /* color select register */
  55.  
  56. #define SEQ_ADDRESS                0x3c4
  57. #define SEQ_DATA                    0x3c5
  58. #define INDEX_SEQ_RR                0    /* reset register */
  59. #define INDEX_SEQ_CM                1    /* clocking mode register */
  60. #define INDEX_SEQ_MAP            2    /* map mask register */
  61. #define INDEX_SEQ_CMS            3    /* character map select register */
  62. #define INDEX_SEQ_MEM            4        /* memory mode register */
  63.  
  64. #define CRTC_ADDRESS                0x3d4
  65. #define CRTC_ADDRESS_MONO        0x3b4
  66. #define CRTC_DATA                    0x3d5
  67. #define CRTC_DATA_MONO            0x3b5
  68. #define INDEX_CRTC_HT            0    /* horizontal total register */
  69. #define INDEX_CRTC_HDE            1    /* horizontal display end register */
  70. #define INDEX_CRTC_SHB            2    /* start horizontal blanking register */
  71. #define INDEX_CRTC_EHB            3    /* end horizontal blanking register */
  72. #define INDEX_CRTC_SHR            4    /* start horizontal retrace register */
  73. #define INDEX_CRTC_EHR            5    /* end horizontal retrace register */
  74. #define INDEX_CRTC_VT            6    /* vertical total register */
  75. #define INDEX_CRTC_OF            7    /* overflow register */
  76. #define INDEX_CRTC_PRS            8    /* preset row scan register */
  77. #define INDEX_CRTC_MSL            9    /* maximum scan line register */
  78. #define INDEX_CRTC_CS            0xa    /* cursor start register */
  79. #define INDEX_CRTC_CE            0xb    /* cursor end register */
  80. #define INDEX_CRTC_SAH            0xc    /* start address high register */
  81. #define INDEX_CRTC_SAL            0xd    /* start address low register */
  82. #define INDEX_CRTC_CLH            0xe    /* cursor location high register */
  83. #define INDEX_CRTC_CLL            0xf    /* cursor location low register */
  84. #define INDEX_CRTC_VRS            0x10    /* vertical retrace start register */
  85. #define INDEX_CRTC_EVR            0x11    /* vertical retrace end register */
  86. #define INDEX_CRTC_VDE            0x12    /* vertical display end register */
  87. #define INDEX_CRTC_OFF            0x13    /* offset register */
  88. #define INDEX_CRTC_UL            0x14    /* underline location register */
  89. #define INDEX_CRTC_VBS            0x15    /* start vertical blank register */
  90. #define INDEX_CRTC_VBE            0x16    /* end vertical blank register */
  91. #define INDEX_CRTC_MCR            0x17    /* mode control register */
  92. #define INDEX_CRTC_LCR            0x18    /* line compare register */
  93.  
  94. #define GCR_ADDRESS                0x3ce
  95. #define GCR_DATA                    0x3cf
  96. #define INDEX_GCR_SR                0    /* set/reset register */
  97. #define INDEX_GCR_ESR            1    /* enable set/reset register */
  98. #define INDEX_GCR_CC                2    /* color compare register */
  99. #define INDEX_GCR_DR                3    /* data rotate register */
  100. #define INDEX_GCR_RMS            4    /* read map select register */
  101. #define INDEX_GCR_MODE            5    /* mode register */
  102. #define INDEX_GCR_MR                6    /* miscellaneous register */
  103. #define INDEX_GCR_CDC            7    /* color don't care register */
  104. #define INDEX_GCR_BM                8    /* bit map register */
  105.  
  106. #define NMODES        25
  107.  
  108. int Crtc_address, Crtc_data, Input_status_1;
  109. struct vga_regs
  110.     {
  111.     int ht;            /* horizontal total */
  112.     int hde;            /* horizontal display end */
  113.     int shb;            /* start horizontal blanking */
  114.     int ehb;            /* end horizontal blanking, low 5 bits plus overflow to
  115.                             high bit of EHR, also display enable skew and
  116.                             compatible read */
  117.     int shr;            /* start horizontal retrace */
  118.     int ehr;            /* end horizontal retrace low 5 bits, also horizontal
  119.                             retrace delay and EHB overflow */
  120.     int vt;            /* vertical total, 2 additional bits in overflow
  121.                             register */
  122.     int overflow;    /* overflow of vrs, vde, vt, lc, vbs, vt */
  123.     int msl;            /* maximum scan line, also vbs overflow, lc overflow
  124.                             and 2T4 */
  125.     int vrs;            /* vertical retrace start */
  126.     int evr;            /* vertical retrace end low 4 bits, also protect registers
  127.                             0-7, and bandwidth */
  128.     int vde;            /* vertical display end, 2 high bits in overflow reg */
  129.     int vbs;            /* start vertical blank, 2 bits in overflow register and
  130.                             maximum scan line register */
  131.     int vbe;            /* end vertical blank */
  132.     };
  133.  
  134. void main(int argc, char **argv)
  135.     {
  136. /* These are the modes which the VGA board recognizes.  Non-standard modes
  137.     must be changed for different boards.  These are for the ATI VGA Wonder.
  138.  */
  139.     int modes[NMODES]={
  140.         0,            1,            2,            3,            4,            5,            6,         7,
  141.         0xd,        0xe,        0xf,        0x10,        0x11,        0x12,        0x13,        0x23,
  142.         0x27,        0x33,        0x37,        0x54,        0x61,        0x62,        0x63,        0x65,
  143.         0x67};
  144. /* These are the segments used by the various modes.  These need to be known
  145.     so that the program can stuff something into video memory to be displayed
  146.     on the sample screen
  147.  */
  148.     unsigned int segs[NMODES]={
  149.         0xb800,    0xb800,    0xb800,    0xb800,    0xb800,    0xb800,    0xb800,    0xb000,
  150.         0xa000,    0xa000,    0xa000,    0xa000,    0xa000,    0xa000,    0xa000,    0xb800,
  151.         0xb000,    0xb800,    0xb000,    0xa000,    0xa000,    0xa000,    0xa000,    0xa000,
  152.         0xa000};
  153. /* These are 0 for color modes, 1 for mono modes.  Some of the VGA registers
  154.     have different addresses for mono and color modes.
  155.  */
  156.     int mono_mode[NMODES]={
  157.         0,            0,            0,            0,            0,            0,            0,            1,
  158.         0,            0,            1,            0,            0,            0,            0,            0,
  159.         1,            0,            1,            0,            0,            0,            0,            0,
  160.         0};
  161.  
  162.     struct vga_regs bios_value[NMODES],new_value[NMODES];
  163.  
  164.     int crt_reg,i;
  165.     char *filename;
  166.     FILE *fpout;
  167.  
  168.     if(argc == 1)
  169.         filename = "REG.VGA";
  170.     else
  171.         filename=argv[1];
  172.  
  173.     if(NULL != (fpout = fopen(filename,"r")))
  174.         {
  175.         fclose(fpout);
  176.         printf("\n\nFile %s for register printout already exists, "
  177.                     "ok to overwrite? ",filename);
  178. /* don't want a macro version of toupper which might call getchar twice
  179.  */
  180. #ifdef toupper
  181. #undef toupper
  182. #endif
  183.         if('Y' != toupper(getchar()))
  184.             exit(1);
  185.         }
  186.  
  187.     if(NULL == (fpout = fopen(filename,"w")))
  188.         {
  189.         printf("\n\nUnable to open %s for register printout\n", filename);
  190.         exit(1);
  191.         }
  192.  
  193.     printf("This routine will display a screen in various modes (resolutions).\n"
  194.             "For each resolution, adjust the horizontal centering with the + and -\n"
  195.             "keys, or hit h to see what VGA registers you can select to fiddle with\n"
  196.             "by hitting a CAPITAL letter.  When done with a mode, hit enter.  The\n"
  197.             "actual screen contents may appear as garbage for graphics modes.  When\n"
  198.             "all modes have been displayed, 80x25 text mode is selected and a table\n"
  199.             "of results is printed to REG.VGA or to the first command line arg.\n\n"
  200.             "Warning: monitors can get very unhappy, even to the point of self\n"
  201.             "destruction, if you feed them strange sync signals.  Hitting the space\n"
  202.             "bar restores the BIOS defaults for the current mode, which is probably\n"
  203.             "the safest thing to do if you lose sync while fiddling with registers.\n\n"
  204.             "Hit ENTER to start...");
  205.  
  206.     getch();
  207.  
  208.     for(i=0; i<NMODES; i++)
  209.         {
  210.         set_mode(modes[i], mono_mode[i], &bios_value[i], &new_value[i]);
  211.         fill_screen(segs[i]);
  212.         enable_regs();
  213.  
  214. /* select start horizontal retrace register in CRT controller */
  215.         crt_reg=INDEX_CRTC_SHR;
  216.  
  217.         for(;;)
  218.             {
  219.             switch(getch())
  220.                 {
  221.                 case 'A':            /* horizontal total register */
  222.                     crt_reg=INDEX_CRTC_HT;
  223.                     continue;
  224.  
  225.                 case 'B':            /* horizontal display end register */
  226.                     crt_reg=INDEX_CRTC_HDE;
  227.                     continue;
  228.  
  229.                 case 'C':             /* start horizontal blanking register */
  230.                     crt_reg=INDEX_CRTC_SHB;
  231.                     continue;
  232.  
  233.                 case 'D':            /* end horizontal blanking register */
  234.                     crt_reg=INDEX_CRTC_EHB;
  235.                     continue;
  236.  
  237.                 case 'E':            /* start horizontal retrace register */
  238.                     crt_reg=INDEX_CRTC_SHR;
  239.                     continue;
  240.  
  241.                 case 'F':            /* end horizontal retrace register */
  242.                     crt_reg=INDEX_CRTC_EHR;
  243.                     continue;
  244.  
  245.                 case 'G':            /* vertical total register */
  246.                     crt_reg=INDEX_CRTC_VT;
  247.                     continue;
  248.  
  249.                 case 'H':            /* vertical retrace start register */
  250.                     crt_reg=INDEX_CRTC_VRS;
  251.                     continue;
  252.  
  253.                 case 'I':            /* vertical retrace end register */
  254.                     crt_reg=INDEX_CRTC_EVR;
  255.                     continue;
  256.  
  257.                 case 'J':            /* vertical display end register */
  258.                     crt_reg=INDEX_CRTC_VDE;
  259.                     continue;
  260.  
  261.                 case 'K':            /* start vertical blank register */
  262.                     crt_reg=INDEX_CRTC_VBS;
  263.                     continue;
  264.  
  265.                 case 'L':            /* end vertical blank register */
  266.                     crt_reg=INDEX_CRTC_VBE;
  267.                     continue;
  268.  
  269.                 case 'h':
  270.                     help_print(modes[i], &bios_value[i], &new_value[i]);
  271.                     fill_screen(segs[i]);
  272.                     continue;
  273.  
  274.                 case ' ':
  275.                     set_mode(modes[i], mono_mode[i], &bios_value[i], &new_value[i]);
  276.                     enable_regs();
  277.                     fill_screen(segs[i]);
  278.                     break;
  279.  
  280.                 case 'q':
  281.                     goto all_done;
  282.  
  283.                 case '+':
  284.                     add_reg(1, &bios_value[i], &new_value[i], crt_reg);
  285.                     break;
  286.  
  287.                 case '-':
  288.                     add_reg(-1, &bios_value[i], &new_value[i], crt_reg);
  289.                     break;
  290.  
  291.                 case '\r':
  292.                     goto mode_done;
  293.  
  294.                 default:
  295.                     printf("\a");
  296.                     break;
  297.                 }
  298.             }
  299. mode_done: ;
  300.         }
  301. all_done:
  302.     bios_mode(3);            /* select 80x25 color mode */
  303.  
  304.     for(i=0; i<NMODES; i++)
  305.         {
  306.         new_value[i].ehr = (new_value[i].ehr & 0x1f) | (bios_value[i].ehr & 0x60)
  307.                                  | ((new_value[i].ehb & 0x20) << 2);
  308.         new_value[i].ehb = (new_value[i].ehb & 0x1f) | (bios_value[i].ehb & 0xe0);
  309.         new_value[i].vt &= 0xff;
  310.         new_value[i].msl = ((new_value[i].vbs & 0x200) >> 4)
  311.                                  | (bios_value[i].msl & 0xdf);
  312.         new_value[i].vrs &= 0xff;
  313.         new_value[i].evr = (new_value[i].evr & 0xf) | (bios_value[i].evr & 0xf0);
  314.         new_value[i].vde &= 0xff;
  315.         new_value[i].vbs &= 0xff;
  316.  
  317.         fprintf(fpout, "Mode %xh\n\nRegister                 old    new  change (decimal)\n",
  318.                     modes[i]);
  319.         fprintf(fpout, "Horizontal total     %7x%7x%6d\n", bios_value[i].ht,
  320.                     new_value[i].ht, new_value[i].ht - bios_value[i].ht);
  321.         fprintf(fpout, "Horiz display end    %7x%7x%6d\n", bios_value[i].hde,
  322.                     new_value[i].hde, new_value[i].hde - bios_value[i].hde);
  323.         fprintf(fpout, "Start horiz blanking %7x%7x%6d\n",     bios_value[i].shb,
  324.                     new_value[i].shb, new_value[i].shb - bios_value[i].shb);
  325.         fprintf(fpout, "End horiz blanking   %7x%7x%6d\n", bios_value[i].ehb,
  326.                     new_value[i].ehb, new_value[i].ehb - bios_value[i].ehb);
  327.         fprintf(fpout, "Start horiz retrace  %7x%7x%6d\n", bios_value[i].shr,
  328.                     new_value[i].shr, new_value[i].shr - bios_value[i].shr);
  329.         fprintf(fpout, "End horiz retrace    %7x%7x%6d\n", bios_value[i].ehr,
  330.                     new_value[i].ehr, new_value[i].ehr - bios_value[i].ehr);
  331.         fprintf(fpout, "Vertical total       %7x%7x%6d\n", bios_value[i].vt,
  332.                     new_value[i].vt, new_value[i].vt - bios_value[i].vt);
  333.         fprintf(fpout, "Overflow             %7x%7x%6d\n", bios_value[i].overflow,
  334.             new_value[i].overflow, new_value[i].overflow - bios_value[i].overflow);
  335.         fprintf(fpout, "Maximum scan line    %7x%7x%6d\n", bios_value[i].msl,
  336.                     new_value[i].msl, new_value[i].msl - bios_value[i].msl);
  337.         fprintf(fpout, "Vert retrace start   %7x%7x%6d\n", bios_value[i].vrs,
  338.                     new_value[i].vrs, new_value[i].vrs - bios_value[i].vrs);
  339.         fprintf(fpout, "Vert retrace end     %7x%7x%6d\n", bios_value[i].evr,
  340.                     new_value[i].evr, new_value[i].evr - bios_value[i].evr);
  341.         fprintf(fpout, "Vert display end     %7x%7x%6d\n", bios_value[i].vde,
  342.                     new_value[i].vde, new_value[i].vde - bios_value[i].vde);
  343.         fprintf(fpout, "Vert blank start     %7x%7x%6d\n", bios_value[i].vbs,
  344.                     new_value[i].vbs, new_value[i].vbs - bios_value[i].vbs);
  345.         fprintf(fpout, "Vert blank end       %7x%7x%6d\n\n\n", bios_value[i].vbe,
  346.                     new_value[i].vbe, new_value[i].vbe - bios_value[i].vbe);
  347.         }
  348.     return;
  349.     }
  350.  
  351. /* add_reg - add an incr to a crtc register, checking for overflow.
  352.     return the new register value.
  353.  */
  354. int add_reg(int incr, struct vga_regs *bios_value, struct vga_regs *old_value,
  355.                 int crt_reg)
  356.     {
  357.     int new_value;
  358.  
  359.     switch(crt_reg)
  360.         {
  361.         case INDEX_CRTC_HT:            /* horizontal total register */
  362.             new_value = old_value->ht = range_check(old_value->ht, incr, 0xff);
  363.             poke_vga(crt_reg, new_value);
  364.             break;
  365.  
  366.         case INDEX_CRTC_HDE:            /* horizontal display end register */
  367.             new_value = old_value->hde = range_check(old_value->hde, incr, 0xff);
  368.             poke_vga(crt_reg, new_value);
  369.             break;
  370.  
  371.         case INDEX_CRTC_SHB:             /* start horizontal blanking register */
  372.             new_value = old_value->shb = range_check(old_value->shb, incr, 0xff);
  373.             poke_vga(crt_reg, new_value);
  374.             break;
  375.  
  376.         case INDEX_CRTC_EHB:            /* end horizontal blanking register */
  377.             new_value = old_value->ehb = range_check(old_value->ehb, incr, 0x3f);
  378.             poke_vga(crt_reg,
  379.                          (new_value & 0x1f) | (bios_value->ehb & 0x60) | 0x80);
  380.             new_value = ((new_value & 0x20) << 2) | (bios_value->ehr & 0x60)
  381.                             | old_value->ehr;
  382.             poke_vga(INDEX_CRTC_EHR, new_value);
  383.             break;
  384.  
  385.         case INDEX_CRTC_SHR:            /* start horizontal retrace register */
  386.             new_value = old_value->shr = range_check(old_value->shr, incr, 0xff);
  387.             poke_vga(crt_reg, new_value);
  388.             break;
  389.  
  390.         case INDEX_CRTC_EHR:            /* end horizontal retrace register */
  391.             new_value = old_value->ehr = range_check(old_value->ehr, incr, 0x1f);
  392.             poke_vga(crt_reg, new_value | (bios_value->ehr & 0x60)
  393.                                     | ((old_value->ehb & 0x20) << 2));
  394.             break;
  395.  
  396.         case INDEX_CRTC_VT:            /* vertical total register */
  397.             new_value = old_value->vt = range_check(old_value->vt, incr, 0x3ff);
  398.             poke_vga(crt_reg, new_value & 0xff);
  399.             new_value = (((new_value & 0x100) >> 8) | ((new_value & 0x200) >> 4)
  400.                             | (old_value->overflow & 0xde));
  401.             poke_vga(INDEX_CRTC_OF, new_value);
  402.             old_value->overflow = new_value;
  403.             break;
  404.  
  405.         case INDEX_CRTC_OF:
  406.             poke_vga(INDEX_CRTC_OF, old_value->overflow);
  407.             break;
  408.  
  409.         case INDEX_CRTC_MSL:
  410.             poke_vga(INDEX_CRTC_MSL,
  411.                         ((old_value->vbs & 0x200) >> 4) | (bios_value->msl & 0xdf));
  412.             break;
  413.  
  414.         case INDEX_CRTC_VRS:            /* vertical retrace start register */
  415.             new_value = old_value->vrs = range_check(old_value->vrs, incr, 0x3ff);
  416.             poke_vga(crt_reg,new_value & 0xff);
  417.             new_value = (((new_value & 0x100) >> 6) | ((new_value & 0x200) >> 2)
  418.                             | (old_value->overflow & 0x7b));
  419.             poke_vga(INDEX_CRTC_OF, new_value);
  420.             old_value->overflow = new_value;
  421.             break;
  422.  
  423.         case INDEX_CRTC_EVR:            /* vertical retrace end register */
  424.             new_value = old_value->evr = range_check(old_value->evr, incr, 0xf);
  425.             poke_vga(crt_reg, new_value | (bios_value->evr & 0x70));
  426.             break;
  427.  
  428.         case INDEX_CRTC_VDE:            /* vertical display end register */
  429.             new_value = old_value->vde = range_check(old_value->vde, incr, 0x3ff);
  430.             poke_vga(crt_reg, new_value & 0xff);
  431.             new_value = (((new_value & 0x100) >> 7) | ((new_value & 0x200) >> 3)
  432.                             | (old_value->overflow & 0xbd));
  433.             poke_vga(INDEX_CRTC_OF, new_value);
  434.             old_value->overflow = new_value;
  435.             break;
  436.  
  437.         case INDEX_CRTC_VBS:            /* start vertical blank register */
  438.             new_value = old_value->vbs = range_check(old_value->vbs, incr, 0x3ff);
  439.             poke_vga(crt_reg, new_value);
  440.             new_value = (((new_value & 0x100) >> 5) | (old_value->overflow & 0xf7));
  441.             poke_vga(INDEX_CRTC_OF, new_value);
  442.             old_value->overflow = new_value;
  443.             new_value = (((old_value->vbs & 0x200) >> 4) | (bios_value->msl & 0xdf));
  444.             poke_vga(INDEX_CRTC_MSL, new_value);
  445.             old_value->msl = new_value;
  446.             break;
  447.  
  448.         case INDEX_CRTC_VBE:            /* end vertical blank register */
  449.             new_value = old_value->vbe = range_check(old_value->vbe, incr, 0xff);
  450.             poke_vga(crt_reg, new_value);
  451.             break;
  452.         }
  453.     return(new_value);
  454.     }
  455.  
  456. /* bios_mode - call bios to select a video mode.  For many cards, this is done
  457.     by putting the mode in AL, setting AH=0 and issuing INT 10h.  Some boards,
  458.     such as the Vega VGA do it differently
  459.  */
  460. void bios_mode(int mode)
  461.     {
  462.     union REGS regs;
  463.  
  464.     regs.x.ax=mode;                /* select mode */
  465.     int86(0x10,®s,®s);
  466.     return;
  467.     }
  468.  
  469. /* border_set - set border color
  470.  */
  471. void border_set(void)
  472.     {
  473.     inportb(INPUT_STATUS_1);
  474.     outportb(ATTR_ADDRESS_WRITE, 0x31);
  475.     outportb(ATTR_ADDRESS_WRITE, 9);
  476.  
  477.     return;
  478.     }
  479.  
  480. /* enable_regs
  481.  */
  482. void enable_regs(void)
  483.     {
  484.     int temp;
  485.  
  486. /* enable access to lower 7 CRTC registers
  487.  */
  488.     outportb(Crtc_address, INDEX_CRTC_EVR);
  489.     temp=inportb(Crtc_data);
  490.     temp &= 0x7f;
  491.     outportb(Crtc_data, temp);
  492.  
  493. /* enable access to vertical retrace start/end registers
  494.  */
  495.     outportb(Crtc_address, INDEX_CRTC_EHB);
  496.     temp=inportb(Crtc_data);
  497.     temp |= 0x80;
  498.     outportb(Crtc_data, temp);
  499.  
  500.     return;
  501.     }
  502.  
  503. /* fill_screen - make sure something is displayed, also set border color
  504.  */
  505. void fill_screen(unsigned int segment)
  506.     {
  507.     long l,nfill;
  508.     char far *video_memory;
  509.  
  510.     video_memory=MK_FP(segment,0);    /* make sure something is displayed */
  511.     switch(segment)
  512.         {
  513.         case 0xa000:
  514.         case 0xb000:
  515.             nfill = 64L * 1024L;
  516.             break;
  517.  
  518.         default:
  519.         case 0xb800:
  520.             nfill = 32L * 1024L;
  521.             break;
  522.         }
  523.     for(l=0; l<nfill; l++)
  524.         *(video_memory++)='A' + (l % 26);
  525.  
  526.     border_set();
  527.  
  528.     return;
  529.     }
  530.  
  531. /* help_print - switch to test mode, print a help screen, switch back
  532.     to mode being set
  533.  */
  534. void help_print(int mode, struct vga_regs *bios_regs, struct vga_regs *current_regs)
  535.     {
  536.     int i;
  537.  
  538.     bios_mode(3);                    /* select 80x25 color mode */
  539.     border_set();
  540.  
  541.     fprintf(stderr,"To select a register, hit a CAPITAL letter:\n\n"
  542.         "A - horizontal total register (left/right centering within overscan)\n"
  543.         "B - horizontal display end register (# chars in line, don't change)\n"
  544.         "C - start horizontal blanking register (right side overscan size)\n"
  545.         "D - end horizontal blanking register (left side overscan size)\n"
  546.         "E - start horizontal retrace register (left/right centering)\n"
  547.         "F - end horizontal retrace register\n"
  548.         "G - vertical total register (height inside overscan region)\n"
  549.         "H - vertical retrace start register (up/down centering)\n"
  550.         "I - vertical retrace end register\n"
  551.         "J - vertical display end register (# scan lines, don't change)\n"
  552.         "K - start vertical blank register (bottom overscan, retrace blanking)\n"
  553.         "L - end vertical blank register (top overscan, retrace blanking)\n\n"
  554.         "+/- adjust value up/down, SPACE restores BIOS values\n"
  555.         "Return advances to the next mode\n\n"
  556.         "Current mode is %xh\n\n"
  557.         "Hit any key to return to sample screen...", mode);
  558.         getch();
  559.  
  560.     bios_mode(mode);                /* select mode */
  561.  
  562.     enable_regs();
  563.  
  564. /* restore any changes already made for this mode
  565.  */
  566.      for(i=INDEX_CRTC_HT; i<=INDEX_CRTC_VBE; i++)
  567.         add_reg(0, bios_regs, current_regs, i);
  568.  
  569.     return;
  570.     }
  571.  
  572. /* poke_vga - change a value in a VGA CRTC register
  573.  */
  574. void poke_vga(int crt_reg, int data)
  575.     {
  576.     outportb(Crtc_address, crt_reg);
  577.     outportb(Crtc_data, data);
  578.     return;
  579.     }
  580.  
  581. /* range_check - return old_value + increment if this is within the range
  582.     0 to max_value, otherwise beep and return unchanged old_value
  583.  */
  584. int range_check(int old_value, int increment, int max_value)
  585.     {
  586.     int new_value;
  587.  
  588.     new_value = old_value + increment;
  589.     if(new_value < 0 || new_value > max_value)
  590.         return(old_value);
  591.     else
  592.         return(new_value);
  593.     }
  594.  
  595. /* set a VGA mode, read out register values into bios_value and new_value
  596.  */
  597. void set_mode(int mode, int mono, struct vga_regs *bios_value,
  598.                     struct vga_regs *new_value)
  599.     {
  600.  
  601.     Crtc_address=mono ? CRTC_ADDRESS_MONO : CRTC_ADDRESS;
  602.     Crtc_data=mono ? CRTC_DATA_MONO : CRTC_DATA;
  603.     Input_status_1=mono ? INPUT_STATUS_1_MONO : INPUT_STATUS_1;
  604.  
  605.     bios_mode(mode);
  606.  
  607. /* read out needed VGA registers
  608.  */
  609.  
  610.     outportb(Crtc_address,INDEX_CRTC_HT);
  611.     bios_value->ht = new_value->ht = inportb(Crtc_data);
  612.  
  613.     outportb(Crtc_address,INDEX_CRTC_HDE);
  614.     bios_value->hde = new_value->hde = inportb(Crtc_data);
  615.  
  616.     outportb(Crtc_address,INDEX_CRTC_SHB);
  617.     bios_value->shb = new_value->shb = inportb(Crtc_data);
  618.  
  619.     outportb(Crtc_address,INDEX_CRTC_EHB);
  620.     bios_value->ehb = new_value->ehb = inportb(Crtc_data);
  621.  
  622.     outportb(Crtc_address,INDEX_CRTC_SHR);
  623.     bios_value->shr = new_value->shr = inportb(Crtc_data);
  624.  
  625.     outportb(Crtc_address,INDEX_CRTC_EHR);
  626.     bios_value->ehr = new_value->ehr = inportb(Crtc_data);
  627.  
  628.     outportb(Crtc_address,INDEX_CRTC_VT);
  629.     bios_value->vt = new_value->vt = inportb(Crtc_data);
  630.  
  631.     outportb(Crtc_address,INDEX_CRTC_OF);
  632.     bios_value->overflow = new_value->overflow = inportb(Crtc_data);
  633.  
  634.     outportb(Crtc_address,INDEX_CRTC_MSL);
  635.     bios_value->msl = new_value->msl = inportb(Crtc_data);
  636.  
  637.     outportb(Crtc_address,INDEX_CRTC_VRS);
  638.     bios_value->vrs = new_value->vrs = inportb(Crtc_data);
  639.  
  640.     outportb(Crtc_address,INDEX_CRTC_EVR);
  641.     bios_value->evr = new_value->evr = inportb(Crtc_data);
  642.  
  643.     outportb(Crtc_address,INDEX_CRTC_VDE);
  644.     bios_value->vde = new_value->vde = inportb(Crtc_data);
  645.  
  646.     outportb(Crtc_address,INDEX_CRTC_VBS);
  647.     bios_value->vbs = new_value->vbs = inportb(Crtc_data);
  648.  
  649.     outportb(Crtc_address,INDEX_CRTC_VBE);
  650.     bios_value->vbe = new_value->vbe = inportb(Crtc_data);
  651.  
  652. /* Generate actual values for things which use the overflow or other register
  653.  */
  654.  
  655.     new_value->ehb = ((bios_value->ehr & 0x80) >> 2) | (0x1f & bios_value->ehb);
  656.     new_value->ehr &= 0x1f;
  657.     new_value->vt = ((bios_value->overflow & 0x20) << 4)
  658.                          | ((bios_value->overflow & 1) << 8) | bios_value->vt;
  659.     new_value->vrs = ((bios_value->overflow & 0x80) << 2)
  660.                           | ((bios_value->overflow & 4) << 6) | bios_value->vrs;
  661.     new_value->evr &= 0xf;
  662.     new_value->vde = ((bios_value->overflow & 0x40) << 3)
  663.                           | ((bios_value->overflow & 2) << 7) | bios_value->vde;
  664.     new_value->vbs = ((bios_value->msl & 0x20) << 4)
  665.                           | ((bios_value->overflow & 8) << 5) | bios_value->vbs;
  666.  
  667.     return;
  668.     }
  669.