/************************************************************************/
/*                                                                      */
/*     Copyright (c) 1992 Intel Corporation                             */
/*     All Rights Reserved                                              */
/*                                                                      */
/*     INTEL CORPORATION PROPRIETARY INFORMATION                        */
/*                                                                      */
/*     This software is supplied under the terms of a licence           */
/*     agreement with Intel Corporation and may not be copied nor       */
/*     disclosed except in accordance with the terms of that agreement. */
/*                                                                      */
/************************************************************************/

/*
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   HISTORY:

 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/

#include <windows.h>
//#include <windowsx.h>
#include <mmsystem.h>
#include <dciddi.h>
#include "dcihdw.h"

// Constants
#define CURR_VERSION 1

// Macros
#define LogChipset(s) WritePrivateProfileString("dcisvga.dll", "chipset", s, "indeo.ini")

// defined in VALIDBMP.BPP
COLORSUPPORT ValidateBMP(HDC);

// Global data
GLOBALDATA g;

// Local data
typedef WORD (FAR CDECL *CHKHDW) (WORD);
static CHKHDW CheckHardware;

/* local functions 	*/
void _far _pascal SETSELLIMIT(UINT sel, DWORD limit);

//---------------------------------------------------------------------------//
//                                                                           //
//                           HARDWARE FUNCTIONS                              //
//                                                                           //
//---------------------------------------------------------------------------//


/******************************************************************************
   FUNCTION:       VidGetHdwType (void)

   Determine the hardware type. Eliminate known problem cards first
   because sometimes the checking done for other cards can be intrusive
   enough to foul up the unsupported card. (eg: WD90C23)
******************************************************************************/
LPVOID LOCAL VidGetHdwType ()
{
   // ATI 68800
   // Typical cards:  ATI Graphics Ultra Plus, ATI Graphics Ultra Pro
   CheckHardware = (CHKHDW) DispatchATI68800;
   if (CheckHardware (VDSP_IDENTIFY) != 0
       && CheckHardware (VDSP_VERSION) == CURR_VERSION) {
      LogChipset ("ATI 68800");
      return (LPVOID) CheckHardware;
   }

   // the adapter hardware is not supported
   LogChipset ("Unsupported");
   CheckHardware = 0;                     // avoid WEP cleanup
   return 0;
}


/******************************************************************************
   FUNCTION:       VidInitialize (void)

   Multi-vendor hardware support DLL load-time initializations

   Returns:  TRUE   Hardware supported
             FALSE  Hardware NOT supported
******************************************************************************/
BOOL VidInitialize ()
{
   // Get display characteristics
   HDC hdc = CreateDC ("DISPLAY", 0, 0, 0); // allocate display context
   if (hdc == 0)                            // fail if CreateDC failed
      return FALSE;
   g.iBitsPerPixel = GetDeviceCaps (hdc, BITSPIXEL);
   g.iBytesPerPixel = g.iBitsPerPixel / 8;
   g.iPlanes = GetDeviceCaps (hdc, PLANES);
   g.wVertRes = GetDeviceCaps (hdc, VERTRES);
   if ((GetDeviceCaps (hdc, RASTERCAPS) & RC_PALETTE) != 0)
      g.iSizePalette = GetDeviceCaps (hdc, SIZEPALETTE);
   g.Color = ValidateBMP (hdc);
   DeleteDC (hdc);

   // Check hardware type and get pointer to entry point if supported
   g.lpvHdwDisp = VidGetHdwType ();

   // If the hardware is supported directly, get full disclosure
   if (g.lpvHdwDisp != 0)
   {
      g.wScanLineWidth = CheckHardware (VDSP_SCANWIDTH);
      g.fBanked = CheckHardware (VDSP_QUERYBANK);
      g.dwLastPixelOffset = g.wVertRes * (DWORD) g.wScanLineWidth -
                            g.iBytesPerPixel;
      // Successful return
      return TRUE;
   }

   // Unsuccessful return
   return FALSE;
}


/******************************************************************************
   FUNCTION:       VidWEP (void)

   Hardware WEP cleanup procedure

   This function must be in a fixed code segment.  All data it references
   must also be fixed, and DGROUP must be explicitly loaded to access g.??
******************************************************************************/
//extern "C" BOOL _loadds VidWEP ();
extern BOOL _loadds VidWEP ();
#pragma alloc_text(WEP_TEXT, VidWEP)
//extern "C" BOOL _loadds VidWEP ()
extern BOOL _loadds VidWEP ()
{
   // Clean up as required by the adapter
   if (CheckHardware != 0)                // if hardware initialized
      CheckHardware (VDSP_TERMINATE);     //  clean up

   // Successful return
   return TRUE;
}


/******************************************************************************
   FUNCTION:       VidGetDevMemAccess (DWORD, DWORD, LPWORD,
                        LPDWORD, LPDWORD, LPWORD);

   Get access to screen point x, y.

   Returns:  Values in parameters.
******************************************************************************/
void VidGetDevMemAccess (DWORD x, 
                         DWORD y, 
                         LPWORD lpwSel, 
                         LPDWORD lpdwStartOffset, 
                         LPDWORD lpdwEndOffset, 
                         LPWORD lpwStride
                        )
{
   // Compute offset of pixel in buffer
   DWORD dwOffset = y * g.wScanLineWidth + x * g.iBytesPerPixel;
      
   // Set hardware for target pixel
   SETTARG SetTarget = (SETTARG) g.lpvHdwDisp;
   // Hardware SetTarget functions currently return a 16:16 pointer in DX:AX.
   // This is OK since banked devices always work within a 64k segment, and
   // the linear routines use SetSelectorBase and return a StartOffset of 0.
   DWORD DXAX = SetTarget (VDSP_SETTARGET, dwOffset);

   // Fill return values
   *lpwSel = SELECTOROF (DXAX);
   *lpdwStartOffset = (DWORD) OFFSETOF (DXAX);
   if (g.fBanked)
      // Only write to the end of a 64k segment
      *lpdwEndOffset = 0xffff;
   else
      // Linear access limited to 1Mb from Windows LDT limitations.
      *lpdwEndOffset = *lpdwStartOffset +
                       min (0x000fffff, (g.dwLastPixelOffset - dwOffset));
   *lpwStride = g.wScanLineWidth;
}


/******************************************************************************
   FUNCTION:       VidStartDevMemAccess (BOOL)

   Start direct hardware access.

   Returns:  None
******************************************************************************/
void VidStartDevMemAccess (BOOL fHideCursor)
{
   SAVEBANK SaveBank = (SAVEBANK) g.lpvHdwDisp;

   SaveBank (VDSP_SAVECONTEXT, fHideCursor);
}


/******************************************************************************
   FUNCTION:       VidDoneDevMemAccess (BOOL)

   End direct hardware access.

   Returns:  None
******************************************************************************/
void VidDoneDevMemAccess (BOOL fShowCursor)
{
   RESTBANK RestBank = (RESTBANK) g.lpvHdwDisp;

   RestBank (VDSP_RESTCONTEXT, fShowCursor);
}


/******************************************************************************
   FUNCTION:       VidQueryColorSupport (void)

   Report available ColorSupport for current mode.

   Returns:  COLORSUPPORT
******************************************************************************/
COLORSUPPORT VidQueryColorSupport ()
{
   return g.Color;
}

/******************************************************************************
   FUNCTION:       SetSelLimit(UINT, DWORD)

   Setting selector limit for linearly addressed cards.  Code extracted
   from Todd Laney's @ Microsoft.

   Returns:  COLORSUPPORT
******************************************************************************/
void _far _pascal SETSELLIMIT(UINT sel, DWORD limit)
{
    if (limit >= 1024*1024l)
        limit = ((limit+4096) & ~4095) - 1;

    _asm
    {
        mov     ax,0008h            ; DPMI set limit
        mov     bx,sel
        mov     dx,word ptr limit[0]
        mov     cx,word ptr limit[2]
        int     31h
    }
}
