/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = EDDESRES                                       */
/*                                                                    */
/*   Description     = Display Device Driver internal functions to    */
/*                     set the mode if the user selected mode in      */
/*                     os2.ini is an available mode.                  */
/*                                                                    */
/*   Function        =                                                */
/*                                                                    */
/*   Reference       = Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_WINSHELLDATA
#define INCL_DOSDEVICES
#include <eddinclt.h>
#include <edddtypt.h>
#include <eddetypt.h>
#include <eddeextf.h>

#include <eddqsres.h>
#include <eddesres.h>
#include <cacheman.h>

#include <plasma.h>
#include <memman.h>

#ifdef DBCS                                                 
#define DBCS_ADJUST_RESOLUTION
extern BOOL            flDrvMode1040;
#endif // DBCS

extern DDTType         DDT;
#ifndef   _8514
extern HFILE           ring0_handle;
#endif

#ifndef   _8514

typedef struct _VIOMODEINFO {   /* viomi */
        USHORT cb;
        UCHAR  fbType;
        UCHAR  color;
        USHORT col;
        USHORT row;
        USHORT hres;
        USHORT vres;
        UCHAR  fmt_ID;
        UCHAR  attrib;
        ULONG  buf_addr;
        ULONG  buf_length;
        ULONG  full_length;
        ULONG  partial_length;
        PCH    ext_data_addr;
        } VIOMODEINFO;
extern VIOMODEINFO     VioModeInfo;

#endif

USHORT usNumScreenResolutions = NUM_SCREEN_RESOLUTIONS;

#define SLOT_USEABLE(pas,ms) ( ((pas).primary_adapter_slot ==                \
                                              NO_PRIMARY_ADAPTER_OVERRIDE) ||\
                         ((pas).primary_adapter_slot == (ms).bSlot) )


/**********************************************************************/
/* Table of all possible screen modes that we support. This is ordered*/
/* so that we will always use the nearest entry to the first that is  */
/* obtainable by default.  The last entry is always the entry used    */
/* on the P75 plasma screen (lores 4bpp).                             */
/*                                                                    */
/* We chose high res in preference to low res.                        */
/* We chose more rather than less bpp.                                */
/*                                                                    */
/* Low res, 4bpp is always avaliable, so to guard against an error    */
/* which somehow means we dont mark any modes as avaliable, we        */
/* will hardcode this mode to always be avaliable.                    */
/**********************************************************************/
#define ASR_SIZE NUM_SCREEN_RESOLUTIONS*2
SCREENRESOLUTION asr[ASR_SIZE] = {
    #ifndef   _8514
    HI_RES_WIDTH, HI_RES_HEIGHT, NUM_8BPP_COLOURS,  NUM_PLANES, 0,
    HI_RES_WIDTH, HI_RES_HEIGHT, NUM_4BPP_COLOURS,  NUM_PLANES, 0,
    LO_RES_WIDTH, LO_RES_HEIGHT, NUM_16BPP_COLOURS, NUM_PLANES, 0,
    LO_RES_WIDTH, LO_RES_HEIGHT, NUM_8BPP_COLOURS,  NUM_PLANES, 0,
/******  BUGBUG JOECELI - Temp      below! ***********************/
//  LO_RES_WIDTH, LO_RES_HEIGHT, NUM_4BPP_COLOURS,  NUM_PLANES, DSP_RESOLUTION_OBTAINABLE
    LO_RES_WIDTH, LO_RES_HEIGHT, NUM_4BPP_COLOURS,  NUM_PLANES, 0
    #else
    #ifndef S3
    HI_RES_WIDTH,   HI_RES_HEIGHT,   NUM_8BPP_COLOURS,  NUM_PLANES, DSP_RESOLUTION_DEFAULT | DSP_RESOLUTION_OBTAINABLE,
    #else   S3
    LO_RES_WIDTH,   LO_RES_HEIGHT,   NUM_8BPP_COLOURS,  NUM_PLANES, DSP_RESOLUTION_OBTAINABLE | DSP_RESOLUTION_DEFAULT,
    RES_800_WIDTH,  RES_800_HEIGHT,  NUM_8BPP_COLOURS,  NUM_PLANES, 0,
    HI_RES_WIDTH,   HI_RES_HEIGHT,   NUM_8BPP_COLOURS,  NUM_PLANES, 0,
    RES_1280_WIDTH, RES_1280_HEIGHT, NUM_8BPP_COLOURS,  NUM_PLANES, 0,
    LO_RES_WIDTH,   LO_RES_HEIGHT,   NUM_16BPP_COLOURS, NUM_PLANES, 0,
    RES_800_WIDTH,  RES_800_HEIGHT,  NUM_16BPP_COLOURS, NUM_PLANES, 0,
    HI_RES_WIDTH,   HI_RES_HEIGHT,   NUM_16BPP_COLOURS, NUM_PLANES, 0,
    #ifdef BPP24
    LO_RES_WIDTH,   LO_RES_HEIGHT,   NUM_24BPP_COLOURS, NUM_PLANES, 0,
    #endif
    #endif
    #endif
/******  BUGBUG JOECELI - Temp      above! ***********************/
};

PSCREENRESOLUTION asrScreenResolution = asr;

#ifndef _8514
/**********************************************************************/
/* This is used to query the graphics modes available when calling    */
/* the ring0.                                                         */
/**********************************************************************/
MODEDATAINFO DMQSModesInfo;


BOOL ModesMatch(PSCREENRESOLUTION pscrres,
                PMODEDATA         pmd)

/**********************************************************************/
/* Returns TRUE if the resolution specified for pscrres matches that  */
/* in the DMQS data, pmd, FALSE otherwise.                            */
/**********************************************************************/

{
  return ( (pscrres->width == pmd->usXPels) &&
           (pscrres->height == pmd->usYPels) &&
           (pscrres->colors <= (ULONG)(1 << pmd->bBitsPerPel)) );

} /* ModesMatch */


BOOL BetterResolution(PSCREENRESOLUTION pscrres,
                      PSCREENRESOLUTION pscrresDefault)

/**********************************************************************/
/* If the resolution specified by pscrres is better than that of      */
/* pscrresDefault then return TRUE, otherwise return FALSE.           */
/* Choice is based on width then height then number of colours.       */
/**********************************************************************/

{
#ifdef DBCS                                                 
  if (pscrres->width == EX_RES_WIDTH)  /* 1040 cannot be default      */
    {                                  /*   so consider it worst      */
      return FALSE;                    /*                             */
    }                                  /* end of if:                  */

#endif 
  if ( pscrres->width >= pscrresDefault->width )
  {
    if ( pscrres->width == pscrresDefault->width )
    {
      if ( pscrres->height >= pscrresDefault->height )
      {
        if ( pscrres->height == pscrresDefault->height )
        {
          if ( pscrres->colors > pscrresDefault->colors )
          {
            return TRUE;
          }
        }
        else /* better height */
        {
          return TRUE;
        }
      }
    }
    else /* better width */
    {
      return TRUE;
    }
  }

  return FALSE;

} /* BetterResolution */


/**********************************************************************/
/* Adds the resolution in pmd to the screen resolution table. If the  */
/* new mode is the best found then pusDefaultChoice is updated.       */
/**********************************************************************/
VOID add_resolution(PMODEDATA pmd, PUSHORT pusDefaultChoice)
{
#ifdef DBCS                                                 
  if ((!flDrvMode1040) &&              /* if 1040 mode is not req'd   */
      (pmd->usXPels == EX_RES_WIDTH))  /* and this is 1040x768,       */
    {                                  /*                             */
      return;                          /* do not add this to list     */
    }                                  /* end of if:                  */

#endif 
  asrScreenResolution[usNumScreenResolutions].width = pmd->usXPels;
  asrScreenResolution[usNumScreenResolutions].height = pmd->usYPels;
  asrScreenResolution[usNumScreenResolutions].colors =
                                                   1<<pmd->bBitsPerPel;
  asrScreenResolution[usNumScreenResolutions].planes =
                                                   NUM_PLANES;
  /**********************************************************/
  /* The presence of a mode in the DMQS mode info means     */
  /* that it is available.                                  */
  /**********************************************************/
  if ( SLOT_USEABLE(DMQSModesInfo, *pmd) )
  {
    asrScreenResolution[usNumScreenResolutions].floptions =
                                      DSP_RESOLUTION_OBTAINABLE;

    if ( BetterResolution(
                   &asrScreenResolution[usNumScreenResolutions],
                   &asrScreenResolution[*pusDefaultChoice]) )
    {
      *pusDefaultChoice = usNumScreenResolutions;
    }
  }
  else
  {
    asrScreenResolution[usNumScreenResolutions].floptions = 0;
  }

  usNumScreenResolutions++;

} /* add_resolution */


/**********************************************************************/
/* Sets the options in the global array of screen resolutions. These  */
/* are DSP_RESOLUTION_OBTAINABLE if the resolution can be set with    */
/* the hardware configuration, DSP_RESOLUTION_DEFAULT if the          */
/* resolution is the default for the hardware configuration.          */
/**********************************************************************/
VOID SetObtainableModes(VOID)
{
    USHORT usMode;
    BYTE bDMQSMode;
    BOOL fAddMode;
    USHORT usDefaultChoice;

    /******************************************************************/
    /* usDefaultChoice is the ScreenResolution table entry to use as  */
    /* the default. Initialise to the worst case.                     */
    /******************************************************************/
    usDefaultChoice = NUM_SCREEN_RESOLUTIONS-1;

    /******************************************************************/
    /* First find out which modes are obtainable.                     */
    /******************************************************************/
    for (bDMQSMode = 0;
         bDMQSMode < DMQSModesInfo.bNumberOfModes;
         bDMQSMode++)
    {
        /**************************************************************/
        /* In the general case we must check to see which of the modes*/
        /* are supported by this adapter. BUT if the adapter is on    */
        /* the planar and the plasma is enabled then we can only      */
        /* support lores 4bpp so only check this mode. (Lores 4bpp is */
        /* our last choice of modes and so is last in the mode table).*/
        /**************************************************************/
        if (   (DMQSModesInfo.ModeData[bDMQSMode].bSlot == 0)
            && (plasma_status & PLASMA_ENABLED) )
        {
            /**********************************************************/
            /* This is the planar XGA and the plasma is enabled so we */
            /* are limitted to 4bpp lo res.                           */
            /**********************************************************/
            fAddMode = FALSE;
            usMode = NUM_SCREEN_RESOLUTIONS-1;
            if ( ModesMatch(&asrScreenResolution[usMode],
                            &DMQSModesInfo.ModeData[bDMQSMode]) &&
                 SLOT_USEABLE(DMQSModesInfo,
                              DMQSModesInfo.ModeData[bDMQSMode]) )

            {
                asrScreenResolution[usMode].floptions |=
                                              DSP_RESOLUTION_OBTAINABLE;
                if ( BetterResolution(&asrScreenResolution[usMode],
                                      &asrScreenResolution[usDefaultChoice]) )
                {
                    usDefaultChoice = usMode;
                }
            }
        }
        else
        {
            /**********************************************************/
            /* Search through all the modes that we know about to     */
            /* see if we can find a match.                            */
            /**********************************************************/
            fAddMode = TRUE;
            for (usMode = 0; usMode <  usNumScreenResolutions; usMode++)
            {
                if ( (ModesMatch(&asrScreenResolution[usMode],
                                 &DMQSModesInfo.ModeData[bDMQSMode])) &&

                     /*********************************************************/
                     /* BUGBUG JOECELI - 640 x 480 x 16 colors is causing     */
                     /* various problems. For r205 we are not going to allow  */
                     /* this mode. The         XGA driver does not support    */
                     /* this mode. This mode is needed for the plasma display.*/
                     /* Since we are not preloading on plasma display systems */
                     /* we can slime this mode out as a quick fix. We have    */
                     /* opened an r206 defect to remove this      and come up */
                     /* with a better solution. (8/12/92)                     */
                     /*********************************************************/

                     /**** WARNING      BELOW MUST BE REMOVED!!! **************/
                    ( (asrScreenResolution[usMode].width != LO_RES_WIDTH) ||
                      (asrScreenResolution[usMode].height != LO_RES_HEIGHT) ||
                      (asrScreenResolution[usMode].colors != NUM_4BPP_COLOURS) )
                     /**** WARNING      ABOVE MUST BE REMOVED!!! **************/

                   )
                {
                    if ( SLOT_USEABLE(DMQSModesInfo,
                                      DMQSModesInfo.ModeData[bDMQSMode]) )
                    {
                      asrScreenResolution[usMode].floptions |=
                                                  DSP_RESOLUTION_OBTAINABLE;
                      if ( BetterResolution(&asrScreenResolution[usMode],
                                    &asrScreenResolution[usDefaultChoice]) )
                      {
                          usDefaultChoice = usMode;
                      }

                      if (asrScreenResolution[usMode].colors ==
                          (ULONG)(1 <<
                             DMQSModesInfo.ModeData[bDMQSMode].bBitsPerPel))
                      {
                          fAddMode = FALSE;
                      }

                    }
                    else /* mode match  but slot not allowed */
                    {
                        fAddMode = FALSE;
                    }

                }
            }
        }

        /**************************************************************/
        /* If the mode does not exist in the table we currently have  */
        /* then add it.  There are a number of free slots in the      */
        /* standard table - if we use all of them then allocate some  */
        /* more memory.                                               */
        /**************************************************************/
        if ( fAddMode )
        {
            if ( usNumScreenResolutions < ASR_SIZE )
            {
                /******************************************************/
                /* Spare slot in the predefined table.                */
                /******************************************************/
                add_resolution(&DMQSModesInfo.ModeData[bDMQSMode],
                               &usDefaultChoice);
            }
            else
            {
                /******************************************************/
                /* Allocate a new, bigger table.                      */
                /******************************************************/
                PSCREENRESOLUTION psrNew;
                ULONG size_psrOld;

                size_psrOld = sizeof(SCREENRESOLUTION) *
                               usNumScreenResolutions;

                psrNew = AllocateMemory( (sizeof(SCREENRESOLUTION) *
                                           NUM_SCREEN_RESOLUTIONS) +
                                           size_psrOld,
                                         MT_SCREEN_RES_TABLE,
                                         MO_SHARED );
                if ( psrNew != NULL )
                {
                    memcpy(psrNew, asrScreenResolution, size_psrOld);
                    if ( usNumScreenResolutions > ASR_SIZE )
                    {
                        FreeMemory(asrScreenResolution);
                    }

                    asrScreenResolution = psrNew;
                    add_resolution(&DMQSModesInfo.ModeData[bDMQSMode],
                                   &usDefaultChoice);
                }
            }
        }
    }

    /******************************************************************/
    /* Mark the mode we decided was the best as the default.          */
    /******************************************************************/
    asrScreenResolution[usDefaultChoice].floptions |= DSP_RESOLUTION_DEFAULT;

} /* SetObtainableModes */
#endif // not _8514

#ifdef OLDS3
/**********************************************************************/
/* Sets the options in the global array of screen resolutions. These  */
/* are DSP_RESOLUTION_OBTAINABLE if the resolution can be set with    */
/* the hardware configuration.                                        */
/**********************************************************************/
VOID SetObtainableModes(VOID)
{
   BYTE   bMem;

    outp(0x03d4,0x36);
    bMem = (BYTE)inp(0x03d5);
    bMem &= 0xE0;


    switch ( bMem ) {
    case 0x00:
       ai8514Adapter.lMemorySize = FOUR_MEG_ADAPTER;
       break;
    case 0x40:
       ai8514Adapter.lMemorySize = THREE_MEG_ADAPTER;
       break;
    case 0x80:
       ai8514Adapter.lMemorySize = TWO_MEG_ADAPTER;
       break;
    case 0xC0:
       ai8514Adapter.lMemorySize = ONE_MEG_ADAPTER;
       break;
    case 0xE0:
       ai8514Adapter.lMemorySize = HALF_MEG_ADAPTER;
       break;
    }

    if ( bMem < 0xC0 ) {
       /******************************************************************/
       /* Mark the 1280 as obtainable.                                   */
       /******************************************************************/
       asrScreenResolution[1].floptions |= DSP_RESOLUTION_OBTAINABLE;
       asrScreenResolution[2].floptions |= DSP_RESOLUTION_OBTAINABLE;
       asrScreenResolution[3].floptions |= DSP_RESOLUTION_OBTAINABLE;
       asrScreenResolution[4].floptions |= DSP_RESOLUTION_OBTAINABLE;
       asrScreenResolution[6].floptions |= DSP_RESOLUTION_OBTAINABLE;
       //outp(0x03d4,0x30);
       //bMem = (BYTE)inp(0x03d5);
       //if ( bMem > 0x94 ) {
          asrScreenResolution[5].floptions |= DSP_RESOLUTION_OBTAINABLE;
       //}
    }

    else if ( bMem < 0xE0 ) {
       /******************************************************************/
       /* Mark the 1280 as obtainable.                                   */
       /******************************************************************/
       asrScreenResolution[1].floptions |= DSP_RESOLUTION_OBTAINABLE;
       asrScreenResolution[2].floptions |= DSP_RESOLUTION_OBTAINABLE;
       asrScreenResolution[4].floptions |= DSP_RESOLUTION_OBTAINABLE;
       //outp(0x03d4,0x30);
       //bMem = (BYTE)inp(0x03d5);
       //if ( bMem > 0x94 ) {
       //   asrScreenResolution[5].floptions |= DSP_RESOLUTION_OBTAINABLE;
       //}
    }

} /* SetObtainableModes */
#endif

/**********************************************************************/
/* Returns TRUE if there is a user requested mode and a match was     */
/* found with the available modes and sets the pbUserMode to be the   */
/* number of the mode in the asrScreenResolution table.               */
/**********************************************************************/
BOOL Get_User_Mode(PUSHORT pusUserMode)
{
    SCREENRESOLUTION srUserRequestedResolution;
    LONG             lBufferSize;
    BOOL             fOK;
    USHORT           usMode;

    lBufferSize = sizeof(SCREENRESOLUTION);

    fOK = PrfQueryProfileData(HINI_PROFILE,
                              UMS_APPLICATION_NAME,
                              UMS_KEY,
                              &srUserRequestedResolution,
                              &lBufferSize);

    if (!fOK || (lBufferSize != sizeof(SCREENRESOLUTION)))
    {
        /**************************************************************/
        /* Getting hold of the use requested mode information failed. */
        /**************************************************************/
        return(FALSE);
    }


    /******************************************************************/
    /* We have the users requested resolution. Now search to see if   */
    /* we can find it.                                                */
    /* We match just the width, height and colors; and also ensure    */
    /* that it is obtainable.                                         */
    /******************************************************************/
    for (usMode = 0; usMode <  usNumScreenResolutions; usMode++)
    {
        if ( (asrScreenResolution[usMode].width ==
                                    srUserRequestedResolution.width)  &&
             (asrScreenResolution[usMode].height ==
                                    srUserRequestedResolution.height) &&
             (asrScreenResolution[usMode].colors ==
                                    srUserRequestedResolution.colors) &&
             (asrScreenResolution[usMode].floptions &
                                             DSP_RESOLUTION_OBTAINABLE))
        {
            *pusUserMode = usMode;
            return(TRUE);
        }
    }

    /******************************************************************/
    /* Could not find a match between the requested mode and the      */
    /* available modes.                                               */
    /******************************************************************/
    return(FALSE);

} /* Get_User_Mode */


VOID QueryAndSelectNativeMode(VOID)
{
    ULONG   fn_id;
    USHORT  usMode;
    BYTE   bMem;
    BYTE   bCnt;

#ifdef DBCS_ADJUST_RESOLUTION                               
    SHORT   sResError;
#endif 

    /******************************************************************/
    /* Find out which modes are available to us.                      */
    /******************************************************************/
    #ifndef   _8514
    fn_id = IO_GETMODEINFO;
    DosDevIOCtl(ring0_handle,
                XGA_CATEGORY,
                GEN_FUNCTION,
                (PVOID)&fn_id,
                sizeof(fn_id),       /* not passed to level 1 ring0 code */
                NULL,                /* not passed to level 1 ring0 code */
                (PVOID)&DMQSModesInfo,
                4,                   /* not passed to level 1 ring0 code */
                NULL );              /* not passed to level 1 ring0 code */

    /******************************************************************/
    /* At this point we must set the table of obtainable modes. Later */
    /* we will have selected one of the modes and so restricted our   */
    /* choice to the adapter we are using.                            */
    /******************************************************************/
    SetObtainableModes();

    /******************************************************************/
    /* Now we should choose a mode and select it.                     */
    /******************************************************************/
    if (!Get_User_Mode(&usMode))
    {
        /**************************************************************/
        /* We did not managed to find a mode which matches the users  */
        /* request (or the user has not made a request) so we must    */
        /* use the mode we decided would be the default.              */
        /**************************************************************/
        for (usMode = 0; usMode <  usNumScreenResolutions; usMode++)
        {
            if (asrScreenResolution[usMode].floptions & DSP_RESOLUTION_DEFAULT)
            {
                break;
            }
        }
    }

    /******************************************************************/
    /* We must call to a 16bit piece of code to do the VIOSetMode as  */
    /* this is not available in the 32bit API.                        */
    /* We must set up VioModeInfo fields dependent on the resolution  */
    /* table in this function as we cannot access the table in the    */
    /* 16-bit code (without a THUNK).                                 */
    /* Select the chosen mode.  (Note that we do not really care      */
    /* about most of the values because they will be set correctly    */
    /* later, but we must supply valid values here anyway).           */
    /******************************************************************/

    VioModeInfo.cb = 12;
    VioModeInfo.fbType = 0xB;
    VioModeInfo.col  = 40;
    VioModeInfo.row  = 25;
    VioModeInfo.hres = (USHORT)asrScreenResolution[usMode].width;
    VioModeInfo.vres = (USHORT)asrScreenResolution[usMode].height;

    switch (asrScreenResolution[usMode].colors)
    {
        case NUM_16BPP_COLOURS:
            VioModeInfo.color = 16;
            break;
        case NUM_8BPP_COLOURS:
            VioModeInfo.color = 8;
            break;
        case NUM_4BPP_COLOURS:
            VioModeInfo.color = 4;
            break;
    }

    SwitchToChosenMode();

    #else  // 8514



    #ifndef   S3
    usMode = 0;
    VioModeInfo.cb = 12;
    VioModeInfo.fbType = VGMT_MAKEITWORK | VGMT_OTHER | VGMT_GRAPHICS;
    VioModeInfo.col  = 85;
    VioModeInfo.row  = 38;
    VioModeInfo.hres = 1024;
    VioModeInfo.vres = 768;
    VioModeInfo.color = 8;
    #else

    #ifdef S3

    outp(0x03d4,0x36);
    bMem = (BYTE)inp(0x03d5);
    bMem &= 0xE0;

    // @DMS this is now redundant !!! c'mon MRC ???
    switch ( bMem ) {
    case 0x00:
       ai8514Adapter.lMemorySize = FOUR_MEG_ADAPTER;
       break;
    case 0x40:
       ai8514Adapter.lMemorySize = THREE_MEG_ADAPTER;
       break;
    case 0x80:
       ai8514Adapter.lMemorySize = TWO_MEG_ADAPTER;
       break;
    case 0xC0:
       ai8514Adapter.lMemorySize = ONE_MEG_ADAPTER;
       break;
    case 0xE0:
       ai8514Adapter.lMemorySize = HALF_MEG_ADAPTER;
       break;
    }

    // clear this flag before calling setobtainablemodes
    DDT.fScreenFlags = 0;
    #endif

    /******************************************************************/
    /* At this point we must set the table of obtainable modes. Later */
    /* we will have selected one of the modes and so restricted our   */
    /* choice to the adapter we are using.                            */
    /******************************************************************/
    SetObtainableModes();

    /******************************************************************/
    /* Now we should choose a mode and select it.                     */
    /******************************************************************/

    if (!Get_User_Mode(&usMode))
    {
        /**************************************************************/
        /* We did not managed to find a mode which matches the users  */
        /* request (or the user has not made a request) so we must    */
        /* use the mode we decided would be the default.              */
        /**************************************************************/
        for (usMode = 0; usMode <  usNumScreenResolutions; usMode++)
        {
            if (asrScreenResolution[usMode].floptions & DSP_RESOLUTION_DEFAULT)
            {
                break;
            }
        }
    }

    VioModeInfo.cb = 12;
    VioModeInfo.fbType = VGMT_MAKEITWORK | VGMT_OTHER | VGMT_GRAPHICS;
    VioModeInfo.hres = (USHORT)asrScreenResolution[usMode].width;
    VioModeInfo.vres = (USHORT)asrScreenResolution[usMode].height;

    switch (asrScreenResolution[usMode].width)
    {
        case HI_RES_WIDTH:
            VioModeInfo.col  = 128;
            VioModeInfo.row  = 48;
            break;
        case LO_RES_WIDTH:
            VioModeInfo.col  = 80;
            VioModeInfo.row  = 30;
            break;
        case RES_800_WIDTH:
            VioModeInfo.col  = 100;
            VioModeInfo.row  = 37;
            break;
        case RES_1280_WIDTH:
            VioModeInfo.col  = 160;
            VioModeInfo.row  = 64;
            break;
    }

    switch (asrScreenResolution[usMode].colors)
    {
        #ifdef BPP24
        case NUM_24BPP_COLOURS:
            VioModeInfo.color = 24;
            break;
        #endif
        case NUM_16BPP_COLOURS:
            VioModeInfo.color = 16;
            break;
        case NUM_8BPP_COLOURS:
            VioModeInfo.color = 8;
            break;
        case NUM_4BPP_COLOURS:
            VioModeInfo.color = 4;
            break;
    }
    #endif

    (VOID)DMS32CallBack( (PFN)SwitchToChosenMode );

#ifdef S3
    // @DMS this is in setmode.c I dont think we need it here!!!
    // if not rewrite it in C
    //--------------------------------------------------------------
    // Bill Bodin has asked us to ensure that Linear Addressing is
    // turned off immediately after setting the mode at startup.
    // @RCW
    //--------------------------------------------------------------
    _asm
    {
       push     ax
       push     dx

       mov      dx,03d4h
       mov      ax,058h         ;Linear Address Window Ctrl Reg.
       out      dx,al
       inc      dx
       in       al,dx
       and      al,0EFh         ;Turn off Linear Addressing.
       out      dx,al

       pop      dx
       pop      ax
    }

#endif

    (VOID)KlugeReset();

    #endif   //_8514

    /******************************************************************/
    /* Set up the values in the aiXGAAdapter and ai2XGAAdapter (these */
    /* values are set up after we have switched to a mode because     */
    /* they depend on the particular adapter instance which is used). */
    /******************************************************************/
    #ifndef   _8514
    QueryAdapter();
    #else
    #ifndef   S3
    ai8514Adapter.lMemorySize=0x100000; // 1Meg
    ai8514Adapter.usScreenWidth = 283;  // 1024;
    ai8514Adapter.usScreenHeight= 212;  //  768;
    #else
    // @DMS S3 this needs to change !!! NOW
    ai8514Adapter.usScreenWidth = 283;  // 1024;
    ai8514Adapter.usScreenHeight= 212;  //  768;
    #endif

    ai8514Adapter.usFlags=0;
    ai8514Adapter.usIORegBase= 0;
    ai8514Adapter.pMemRegBase= 0;
    ai8514Adapter.ulVRAMBase= 0xf0000000;   // use this to signify non zero
    #endif


    /******************************************************************/
    /* Finally we must fill in the values in the DDT which depend     */
    /* directly on the mode and adapter which have been selected.     */
    /******************************************************************/
    DDT.ScreenWidth  = (USHORT)asrScreenResolution[usMode].width;
    DDT.ScreenHeight = (USHORT)asrScreenResolution[usMode].height;

    /******************************************************************/
    /* The fScreenFlags field depends on the type of the display, the */
    /* resolution and the number of colors we are using.              */
    /******************************************************************/

    #ifndef _8514

    if ( MONO_DISPLAY(ai2XGAAdapter) )
    {
        DDT.fScreenFlags = DM_MONO;
    }
    else /* colour display */
    {
        DDT.fScreenFlags = 0;
    }
    #endif

    if ( asrScreenResolution[usMode].width <= LO_RES_WIDTH )
    {
        DDT.AlphaCellWidth  = LO_RES_ALPHA_CHAR_X;
        DDT.AlphaCellHeight = LO_RES_ALPHA_CHAR_Y;
    }
    else if ( asrScreenResolution[usMode].width <= RES_800_WIDTH )
    {
        DDT.AlphaCellWidth  = RES_800_ALPHA_CHAR_X;
        DDT.AlphaCellHeight = RES_800_ALPHA_CHAR_Y;
    }
    else
    {
        DDT.fScreenFlags |= DM_HI_RES;
        DDT.AlphaCellWidth  = HI_RES_ALPHA_CHAR_X;
        DDT.AlphaCellHeight = HI_RES_ALPHA_CHAR_Y;
    }

    /******************************************************************/

    /* Set the bitcount according to the number of colors used in     */
    /* this mode.                                                     */
    /******************************************************************/
    switch (asrScreenResolution[usMode].colors)
    {
        #ifdef BPP24
        case NUM_24BPP_COLOURS:
            DDT.BitCount = 24;
            DDT.fScreenFlags |= USE_24BPP;
            break;
        #endif
        case NUM_16BPP_COLOURS:
            DDT.BitCount = 16;
            DDT.fScreenFlags |= USE_16BPP;
            break;
        case NUM_8BPP_COLOURS:
            DDT.BitCount = 8;
            break;
        case NUM_4BPP_COLOURS:
            DDT.BitCount = 4;
            break;
    }


    /******************************************************************/
    /* Work out the resolution in pels per metre.  Note that the      */
    /* usScreenWidth field in ai2XGAAdapter is a measure in mm and    */
    /* the ScreenWidth field in the DDT is a measure in pels.         */
    /******************************************************************/
    #ifndef   _8514
    DDT.horizontal_resolution = (USHORT)
        (((ULONG)DDT.ScreenWidth) * 1000 / ai2XGAAdapter.usScreenWidth);
    DDT.vertical_resolution = (USHORT)
      (((ULONG)DDT.ScreenHeight) * 1000 / ai2XGAAdapter.usScreenHeight);
    #else
    DDT.horizontal_resolution = (USHORT)
        (((ULONG)DDT.ScreenWidth) * 1000 / ai8514Adapter.usScreenWidth);
    DDT.vertical_resolution = (USHORT)
      (((ULONG)DDT.ScreenHeight) * 1000 / ai8514Adapter.usScreenHeight);
    #endif

#ifdef DBCS_ADJUST_RESOLUTION                               
    /*================================================================*/
    /* I've found H-res is not same to V-res for, e.g., 8515 monitor. */
    /*  This is due to calculation error, and is not essential.       */
    /*  (less than 1% difference)  But for this difference, engine    */
    /*  tries to adjust coordinate when calling display driver.       */
    /*  (I.e. it passes not-unity xform matrix.)  Then driver need to */
    /*  call Convert routine.  All of this can be avoided by just     */
    /*  adjusting V-res to H-res, when the difference is small enough.*/
    /*                                          (9/28/92, Y.N.)       */
    /*================================================================*/
    sResError = (SHORT)(DDT.horizontal_resolution -
                        DDT.vertical_resolution);
    if ((sResError != 0) &&
        (abs(sResError) <= DDT.horizontal_resolution / 100))
      {                                /* if diff is small enough     */
        DDT.vertical_resolution = DDT.horizontal_resolution;
                                       /* will use same value         */
      }                                /* end of if:                  */
#endif 

    /******************************************************************/
    /* The graphics character width can only be one of three values   */
    /* (we only have three fonts to choose from) so use the           */
    /* resolution we just worked out as a guide to which font to use. */
    /******************************************************************/
    if (DDT.horizontal_resolution >=
                      (HI_8515_X_RESOLUTION + HI_8514_X_RESOLUTION) / 2)
    {
        DDT.graphics_char_width   = HI_RES_8515_GRAPHICS_CHAR_X;
        DDT.graphics_char_height  = HI_RES_8515_GRAPHICS_CHAR_Y;
    }
    else if (DDT.horizontal_resolution >=
                          (HI_8514_X_RESOLUTION + VGA_X_RESOLUTION) / 2)
    {
        DDT.graphics_char_width   = HI_RES_8514_GRAPHICS_CHAR_X;
        DDT.graphics_char_height  = HI_RES_8514_GRAPHICS_CHAR_Y;
    }
    else
    {
        DDT.graphics_char_width   = LO_RES_GRAPHICS_CHAR_X;
        DDT.graphics_char_height  = LO_RES_GRAPHICS_CHAR_Y;
    }

    #ifdef   _8514
    #ifdef   S3
    // Determine the availability to cache off screen
    // I should pack more info into this switch @DMS !!!
    switch (ai8514Adapter.lMemorySize)
    {
    case FOUR_MEG_ADAPTER:
    case THREE_MEG_ADAPTER:
    case TWO_MEG_ADAPTER:
       DDT.fCaching = TRUE;
       break;
    case ONE_MEG_ADAPTER:
       if ((DDT.ScreenWidth != LO_RES_WIDTH) && ( DDT.BitCount == 16 ))
          DDT.fCaching = FALSE;
       else
          DDT.fCaching = TRUE;
       break;

    case HALF_MEG_ADAPTER:
          DDT.fCaching = FALSE;
    }
    #else
    DDT.fCaching = TRUE;
    #endif
    #endif

    #ifdef _8514
    // initialize the HWResolution index here for the cache table

    for (bCnt = 0; bCnt <= MAX_HW_RESOLUTION_INDEX; bCnt++)
    {
       if(aResTable[bCnt].vis_width   == DDT.ScreenWidth  &&
          aResTable[bCnt].vis_height  == DDT.ScreenHeight &&
          (aResTable[bCnt].phys_memory & ai8514Adapter.lMemorySize) &&
          aResTable[bCnt].BitCount    == DDT.BitCount)
       {
          HWResolution = bCnt;
          break;
       }
    }

    // Setup Global Variables
    CacheManager(FALSE);

    #endif

} /* QueryAndSelectNativeMode */
