video.c

/*--------------------------------------------------------------------\
|       Marcus W. Johnson 1990.                                       |
|                                                                     |
|       Code to identify video display adaptors and display devices   |
|                                                                     |
|       Adapted from:  Programmer's Guide to PC and PS/2 Video Systems|
|                      Richard Wilton                                 |
|                      Microsoft Press                                |
|                      Redmond, Washington                            |
\--------------------------------------------------------------------*/

#include       <dos.h>
#include       "video.h"

enum    boolean
       {
       NO,
       YES
       };

#define N_SYSTEMS    (2)

static struct video  Device[ N_SYSTEMS ];

/*---------------------------------------------------------------------\
|       Detects whether or not a given I/O address is that of a CRT    |
|       Controller; the Cursor Location Low register of the alleged    |
|       CRTC is written with an arbitrary value (I used the one Wilton |
|       uses in his Find6845 procedure), we wait an arbitrary period of|
|       time (I waited a millisecond), and we see if the value is still|
|       there, then this is probably the CRTC.                         |
\---------------------------------------------------------------------*/

static int      FindCRTC(int Port)
       {
       unsigned char  CursorLow;
       unsigned char  NewCursorLow;
       
       outportb(Port++, 0x0F);
       CursorLow = inportb(Port);
       outportb(Port, 0x66);
       delay(1);
       NewCursorLow = inportb(Port);
       outportb(Port, CursorLow);
       return (NewCursorLow == 0x66);
       }

/*---------------------------------------------------------------------\
|       Places the specified adaptor and monitor data in the next      |
|       unused element of the Device array.                            |
\---------------------------------------------------------------------*/

static void      FoundDevice(enum adaptor AType, enum monitor MType)
       {
       if (Device[ 0 ].VideoAdaptor == UnknownAdaptor)
              {
              Device[ 0 ].VideoAdaptor = AType;
              Device[ 0 ].VideoMonitor = MType;
              }
       else
              {
              Device[ 1 ].VideoAdaptor = AType;
              Device[ 1 ].VideoMonitor = MType;
              }
       }

/*---------------------------------------------------------------------\
|       Attempt to find a monochrome adaptor; attempts to detect a CRTC|
|       at I/O address at 0x3B4. If this is successful, we read the    |
|       vertical sync bit, and wait a while to see a transition; if it |
|       occurs, it's a plain monochrome display adaptor, otherwise it's|
|       a Hercules card of some sort. What type is decided by bits 4-6 |
|       of the CRTC port.                                              |
\---------------------------------------------------------------------*/

static void  DetectMono(void)
      {
      if {FindCRTC{0x3B4))
            {
            auto unsigned char    VSync;
            auto unsigned int     k;
            auto enum boolean     FoundIt;
            
            VSync = inportb(0x3BA)& 0x80;
            FoundIt = NO;
            for (k = 0; k < 0x8000; k++)
                  {
                  if (VSync != (inportb(0x3BA) a 0x80))
                        {
                        switch (inportb(0x3BA) & 0x70)
                              {
                              case 0x10:
                                  FoundDevice(HGCPlus, MDA);
                                  break;
                              case 0x50:
                                  FoundDevice(HerculesInColor,
                                        EGAColor);
                                  break;
                              default:
                                  FoundDevice(HGC, MDA);
                                  break;
                              }
                        FoundIt = YES;
                        break;
                        }
                  }
            if (FoundIt == NO)
                  FoundDevice(MDA, MDAMonochrome);
            }
      }

/*---------------------------------------------------------------------\
|       Attempt to find a CGA adaptor; if a CRTC is detected at I/O    |
|       address 3D4, must be CGA...                                    |
\---------------------------------------------------------------------*/

static void     DetectCGA(void)
       {
       if (FindCRTC(0x3D4))
              FoundDevice(CGA, CGAColor);
       }

/*---------------------------------------------------------------------\
|       Fills in the Device array and returns its address to the       |
|       caller, who can then examine its contents.                     |
\---------------------------------------------------------------------*/

struct video    *IdentifyVideo(void)
       {
       int             k;
       union REGS      r;
       
       for (k = 0; k < N_SYSTEMS; k++)
              {
              Device[ k ].VideoAdaptor = UnknownAdaptor;
              Device[ k ].VideoMonitor = UnknownMonitor;
              }
       
       /*------------------------------------------------------------\
       |      Attempt to detect PS/2-type systems by making a BIOS   |
       |      call to get the video display combination from the     |
       |      video BIOS. On return, the AL register is set to 1A,   |
       |      BL will contain the display code for the active display|
       |      and BH will contain the display code for the inactive  |
       |      display. The BL and BH registers are used to index     |
       |      arrays containing codes for the appropriate display and|
       |      display adaptor.                                       |
       \------------------------------------------------------------*/

r.x.ax = 0x1A00;
int86(0x10, &r, &r);
if (r.h.al == 0x1A)
       {
       static struct video     DeviceList[ ] =
              {
              {      UnknownAdaptor, UnknownMonitor  },
              {      MDA,            MDAMonochrome   },
              {      CGA,            CGAColor        },
              {      UnknownAdaptor, UnknownMonitor  },
              {      EGA,            EGAColor        },
              {      EGA,            MDAMonochrome   },
              {      UnknownAdaptor, UnknownMonitor  },
              {      VGA,            PS2Monochrome   },
              {      VGA,            PS2Color        },
              {      UnknownAdaptor, UnknownMonitor  },
              {      MCGA,           EGAColor        },
              {      MCGA,           PS2Monochrome   },
              {      MCGA,           PS2Color        },
              };
       if (r.h.bh != 0)
              {
              Device[ 1 ].VideoAdaptor =
                     DeviceList[ r.h.bh ].VideoAdaptor;
              Device[ 1 ].VideoMonitor =
                     DeviceList[ r.h.bh ].VideoMonitor;
              }
       Device[ 0 ].VideoAdaptor = DeviceList[ r.h.bl ].VideoAdaptor;
       Device[ 0 ].VideoMonitor = DeviceList[ r.h.bl ].VideoMonitor;
       if (Device[ 0 ].VideoAdaptor == MDA ||
              Device[ 1 ].VideoAdaptor == MDA)
              {
              
              /*----------------------------------------------\
              |       If either the active display or the     |
              |       inactive display is identified as MDA,  |
              |       we clear the system and display         |
              |       information for that display; we need   |
              |       to further identify the system as       |
              |       possibly a Hercules card.               |
              \----------------------------------------------*/
              
              if (Device[ 0 ].VideoAdaptor == MDA)
                     {
                     Device[ 0 ].VideoAdaptor = UnknownAdaptor;
                     Device[ 0 ].VideoMonitor = UnknownMonitor;
                     }
              else
                     {
                     Device[ 1 ].VideoAdaptor = UnknownAdaptor;
                     Device[ 1 ].VideoMonitor = UnknownMonitor;
                     }
              DetectMono();
              }
       }
else
       {
       /*------------------------------------------------------\
       |       detect an EGA card; make a call to the BIOS to  |
       |       get the video subsystem configuration. On       |
       |       return, BL will be set to 0, 1, 2 or 3 (which   |
       |       is the number of 64K blocks of RAM in addition  |
       |       to the default 64K block on the video card),    |
       |       and the least 4 bits of CL contain the          |
       |       configuration switch settings for the card.     |
       |       This includes information as to the display     |
       |       type.                                           |
       \------------------------------------------------------*/
       r.h.bl = 0x10;
       r.h.ah = 0x12;
       int86(0x10, &r, &r);
       if (r.h.bl != 0x10)
              {
              auto enum monitor    Display;
              static enum monitor  EGADisplay[ ] =
                     {
                     CGAColor,    EGAColor,      MDAMonochrome
                     };
              
              Display = EGADisplay[ (r.h.cl % 6) >> 1 ];
              FoundDevice(EGA, Display);
              
              /*-----------------------------------------------\
              |       If a monochrome display is found, any    |
              |       other system must be color, and          |
              |       vice-versa.                              |
              \-----------------------------------------------*/
              
              if (Display == MDAMonochrome)
                     DetectCGA();
              else
                     DetectMono();
              }
       else
              {
              DetectCGA();
              DetectMono();
              }
       }
/*---------------------------------------------------------------\
|       Resolve discrepancies between systems with multiple      |
|       display types and the current video state; not a         |
|       problem if only one type was found, or one of the types  |
|       found was MCGA or VGA. Basically, the active display,    |
|       which is in Device[ 0 ], should match the color          |
|       specification of the current video mode. Incidently,     |
|       the device swap is performed by the trick of using the   |
|       mathematical properties of the exclusive or operator to  |
|       avoid having to declare a temporary holding variable.    |
\---------------------------------------------------------------*/

if (Device[ 1 ].VideoAdaptor != UnknownAdaptor &&
       Device[ 0 ].VideoAdaptor != VGA &&
       Device[ 0 ].VideoAdaptor != MCGA &&
       Device[ 1 ].VideoAdaptor != VGA &&
       Device[ 1 ].VideoAdaptor != MCGA)
       {
       r.h.ah = 0x0F;
       int86(0x10, &r, &r);
       if ((r.h.al & 7) == 7)
              {
              if (Device[ 0 ].VideoMonitor != MDAMonochrome)
                     {
                     Device[ 0 ].VideoMonitor ^=
                            Device[ 1 ].VideoMonitor;
                     Device[ 1 ].VideoMonitor ^=
                            Device[ 0 ].VideoMonitor;
                     Device[ 0 ].VideoMonitor ^=
                            Device[ 1 ].VideoMonitor;
                     Device[ 0 ].VideoAdaptor ^=
                            Device[ 1 ].VideoAdaptor;
                     Device[ 1 ].VideoAdaptor ^=
                            Device[ 0 ].VideoAdaptor;
                     Device[ 0 ].VideoAdaptor ^=
                            Device[ 1 ].VideoAdaptor;
                     }
              }
       else
              {
              if (Device[ 0 ].VideoMonitor == MDAMonochrome)
                     {
                     Device[ 0 ].VideoMonitor ^=
                            Device[ 1 ].VideoMonitor;
                     Device[ 1 ].VideoMonitor ^=
                            Device[ 0 ].VideoMonitor;
                     Device[ 0 ].VideoMonitor ^=
                            Device[ 1 ].VideoMonitor;
                     Device[ 0 ].VideoAdaptor ^=
                            Device[ 1 ].VideoAdaptor;
                     Device[ 1 ].VideoAdaptor ^=
                            Device[ 0 ].VideoAdaptor;
                     Device[ 0 ].VideoAdaptor ^=
                            Device[ 1 ].VideoAdaptor;
                     }
              }
       }
return (Device);
}