Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2320 lines
83 KiB

/************************************************************************/
/* */
/* INIT_CX.C */
/* */
/* Nov 15 1993 (c) 1993, ATI Technologies Incorporated. */
/************************************************************************/
/********************** PolyTron RCS Utilities
$Revision: 1.42 $
$Date: 15 May 1996 16:34:38 $
$Author: RWolff $
$Log: S:/source/wnt/ms11/miniport/archive/init_cx.c_v $
*
* Rev 1.42 15 May 1996 16:34:38 RWolff
* Now reports failure of mode set, waits for idle after setting
* accelerator mode.
*
* Rev 1.41 01 May 1996 14:09:20 RWolff
* Calls new routine DenseOnAlpha() to determine dense space support rather
* than assuming all PCI cards support dense space.
*
* Rev 1.40 17 Apr 1996 13:09:04 RWolff
* Backed out Alpha LFB mapping as dense.
*
* Rev 1.39 11 Apr 1996 15:13:20 RWolff
* Now maps framebuffer as dense on DEC Alpha with PCI graphics card.
*
* Rev 1.38 20 Mar 1996 13:42:32 RWolff
* Removed debug print statements from RestoreMemSize_cx(), which must
* be nonpageable since it is called from ATIMPResetHw().
*
* Rev 1.37 01 Mar 1996 12:11:50 RWolff
* VGA Graphics Index and Graphics Data are now handled as separate
* registers rather than as offsets into the block of VGA registers.
*
* Rev 1.36 02 Feb 1996 17:16:40 RWolff
* Now uses VideoPortInt10() rather than our no-BIOS code to set "canned"
* modes on VGA-disabled cards.
*
* Rev 1.35 29 Jan 1996 16:55:02 RWolff
* Now uses VideoPortInt10() rather than no-BIOS code on PPC.
*
* Rev 1.34 23 Jan 1996 11:46:22 RWolff
* Added debug print statements.
*
* Rev 1.33 22 Dec 1995 14:53:30 RWolff
* Added support for Mach 64 GT internal DAC.
*
* Rev 1.32 23 Nov 1995 11:27:46 RWolff
* Fixes needed for initial run of VT chips (check if they're still needed
* on the final version), added support for multiple block-relocatable
* Mach 64 cards.
*
* Rev 1.31 28 Jul 1995 14:40:58 RWolff
* Added support for the Mach 64 VT (CT equivalent with video overlay).
*
* Rev 1.30 23 Jun 1995 16:01:46 RWOLFF
* In 8BPP and lower modes, SetPalette_cx() now uses the VGA palette
* registers rather than the accelerator palette registers. This is
* done so that a video capture card attached to the feature connector
* will know what colours the palette is set to.
*
* Rev 1.29 02 Jun 1995 14:26:48 RWOLFF
* Added debug print statements.
*
* Rev 1.28 31 Mar 1995 11:57:12 RWOLFF
* Changed from all-or-nothing debug print statements to thresholds
* depending on importance of the message.
*
* Rev 1.27 08 Mar 1995 11:33:54 ASHANMUG
* Fixed a bug if the banked aperture was enabled, the memory mapped register we
* getting moved if the memory sized was changed to support 4bpp
*
* Rev 1.26 27 Feb 1995 17:48:08 RWOLFF
* Now always reports 1M when mapping video memory for 4BPP, since we
* force the card to 1M, QueryPublicAccessRanges_cx() now returns
* the virtual address of the I/O register base rather than the
* beginning of I/O space.
*
* Rev 1.25 20 Feb 1995 18:01:18 RWOLFF
* Made test and workaround for screen tearing on 2M boundary DAC-independant,
* 1600x1200 16BPP added to modes that have this tearing.
*
* Rev 1.24 14 Feb 1995 15:45:36 RWOLFF
* Changed conditional compile that uses or fakes failure of
* VideoPortMapBankedMemory() to look for IOCTL_VIDEO_SHARE_VIDEO_MEMORY
* instead of the routine itself. Looking for the routine always failed,
* and since the routine is supplied in order to allow DCI to be used
* on systems without a linear framebuffer, it should be available on
* any DDK version that supports the IOCTL. If it isn't, a compile-time
* error will be generated (unresolved external reference).
*
* Rev 1.23 09 Feb 1995 14:57:36 RWOLFF
* Fix for GX-E IBM DAC screen tearing in 800x600 8BPP.
*
* Rev 1.22 07 Feb 1995 18:24:22 RWOLFF
* Fixed screen trash on return from 4BPP test on CT and 4M Xpression.
* These were the first cards I was able to obtain that switched aperture
* size between modes (GX uses 8M aperture only on 4M cards, which used
* to be made only with DAC that didn't support 4BPP, but CT uses 8M for
* 2M card and 4M when cut back to 1M).
*
* Rev 1.21 03 Feb 1995 15:15:12 RWOLFF
* Added support for DCI, fixed CT internal DAC 4BPP cursor problem,
* RestoreMemSize_cx() is no longer pageable, since it is called
* on a bugcheck.
*
* Rev 1.20 30 Jan 1995 11:56:24 RWOLFF
* Now supports CT internal DAC.
*
* Rev 1.19 11 Jan 1995 14:04:04 RWOLFF
* Added routine RestoreMemSize_cx() which sets the memory size register
* back to the value read by the BIOS query. This is used when returning
* from a test of 4BPP (code had been inlined there) or when shutting down
* from 4BPP (new) because 4BPP modes require that the memory size be
* set to 1M. On some platforms, the x86 emulation in the firmware does not
* reset the memory size to the true value, so a warm reboot from 4BPP left
* the card thinking that it only had 1M.
*
* Rev 1.18 23 Dec 1994 10:47:48 ASHANMUG
* ALPHA/Chrontel-DAC
*
* Rev 1.17 18 Nov 1994 11:40:00 RWOLFF
* Added support for Mach 64 without BIOS.
*
* Rev 1.16 14 Sep 1994 15:24:38 RWOLFF
* Now uses "most desirable supported colour ordering" field in query
* structure rather than DAC type to determine which colour ordering
* to use for 24 and 32BPP.
*
* Rev 1.15 31 Aug 1994 16:24:02 RWOLFF
* Added support for TVP3026 DAC, 1152x864, and BGRx colour ordering
* (used by TVP DAC), uses VideoPort[Read|Write]Register[Uchar|Ushort|Ulong]()
* instead of direct assignments when accessing structures stored in
* VGA text screen off-screen memory.
*
* Rev 1.14 19 Aug 1994 17:15:32 RWOLFF
* Added support for non-standard pixel clock generators.
*
* Rev 1.13 09 Aug 1994 11:52:30 RWOLFF
* Shifting of colours when setting up palette is now done in
* display driver.
*
* Rev 1.12 27 Jun 1994 16:27:38 RWOLFF
* Now reports all hardware default mode tables as noninterlaced to
* avoid confusing the display applet.
*
* Rev 1.11 15 Jun 1994 11:06:24 RWOLFF
* Now sets the cursor colour every time we enter graphics mode. This is a
* fix for the black cursor after testing 4BPP from 16BPP.
*
* Rev 1.10 12 May 1994 11:22:40 RWOLFF
* Added routine SetModeFromTable_cx() to allow the use of refresh rates not
* configured when card was installed, now reports refresh rate from mode table
* instead of only "use hardware default".
*
* Rev 1.9 04 May 1994 10:59:12 RWOLFF
* Now forces memory size to 1M on all 4BPP-capable DACs when using 4BPP,
* sets memory size back to true value when not using 4BPP.
*
* Rev 1.8 27 Apr 1994 13:59:38 RWOLFF
* Added support for paged aperture, fixed cursor colour for 4BPP.
*
* Rev 1.7 26 Apr 1994 12:38:32 RWOLFF
* Now uses a frame length of 128k when LFB is disabled.
*
* Rev 1.6 31 Mar 1994 15:02:42 RWOLFF
* Added SetPowerManagement_cx() function to implement DPMS handling,
* added 4BPP support.
*
* Rev 1.5 14 Mar 1994 16:30:58 RWOLFF
* XMillimeter field of mode information structure now set properly, added
* fix for 2M boundary tearing.
*
* Rev 1.4 03 Mar 1994 12:37:32 ASHANMUG
* Set palettized mode
*
* Rev 1.2 03 Feb 1994 16:44:26 RWOLFF
* Fixed "ceiling check" on right scissor register (documentation had
* maximum value wrong). Moved initialization of hardware cursor
* colours to after the switch into graphics mode. Colour initialization
* is ignored if it is done before the mode switch (undocumented), but
* this wasn't noticed earlier because most cards power up with the
* colours already set to the values we want.
*
* Rev 1.1 31 Jan 1994 16:24:38 RWOLFF
* Fixed setting of cursor colours on cards with 68860 DAC, now fills
* in Frequency and VideoMemoryBitmap[Width|Height] fields of mode
* information structure. Sets Number[Red|Green|Blue]Bits fields for
* palette modes to 6 (assumes VGA-compatible DAC) instead of 0 to allow
* Windows NT to set the palette colours to the best match for the
* colours to be displayed.
*
* Rev 1.0 31 Jan 1994 11:10:18 RWOLFF
* Initial revision.
*
* Rev 1.3 24 Jan 1994 18:03:52 RWOLFF
* Changes to accomodate 94/01/19 BIOS document.
*
* Rev 1.2 14 Jan 1994 15:20:48 RWOLFF
* Fixes required by BIOS version 0.13, added 1600x1200 support.
*
* Rev 1.1 15 Dec 1993 15:26:30 RWOLFF
* Clear screen only the first time we set the desired video mode.
*
* Rev 1.0 30 Nov 1993 18:32:22 RWOLFF
* Initial revision.
End of PolyTron RCS section *****************/
#ifdef DOC
INIT_CX.C - Highest-level card-dependent routines for miniport.
DESCRIPTION
This file contains initialization and packet handling routines
for Mach 64-compatible ATI accelerators. Routines in this module
are called only by routines in ATIMP.C, which is card-independent.
OTHER FILES
#endif
#include "dderror.h"
#include "miniport.h"
#include "ntddvdeo.h"
#include "video.h"
#include "stdtyp.h"
#include "amachcx.h"
#include "amach1.h"
#include "atimp.h"
#include "atint.h"
#define INCLUDE_INIT_CX
#include "init_cx.h"
#include "query_cx.h"
#include "services.h"
#include "setup_cx.h"
/*
* Prototypes for static functions.
*/
static void QuerySingleMode_cx(PVIDEO_MODE_INFORMATION ModeInformation, struct query_structure *QueryPtr, ULONG ModeIndex);
static VP_STATUS SetModeFromTable_cx(struct st_mode_table *ModeTable, VIDEO_X86_BIOS_ARGUMENTS Registers);
/*
* Allow miniport to be swapped out when not needed.
*/
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(PAGE_CX, Initialize_cx)
#pragma alloc_text(PAGE_CX, MapVideoMemory_cx)
#pragma alloc_text(PAGE_CX, QueryPublicAccessRanges_cx)
#pragma alloc_text(PAGE_CX, QueryCurrentMode_cx)
#pragma alloc_text(PAGE_CX, QueryAvailModes_cx)
#pragma alloc_text(PAGE_CX, QuerySingleMode_cx)
#pragma alloc_text(PAGE_CX, SetCurrentMode_cx)
#pragma alloc_text(PAGE_CX, SetPalette_cx)
#pragma alloc_text(PAGE_CX, IdentityMapPalette_cx)
#pragma alloc_text(PAGE_CX, ResetDevice_cx)
#pragma alloc_text(PAGE_CX, SetPowerManagement_cx)
#pragma alloc_text(PAGE_CX, GetPowerManagement_cx)
#pragma alloc_text(PAGE_CX, SetModeFromTable_cx)
/* RestoreMemSize_cx() can't be made pageable */
#pragma alloc_text(PAGE_CX, ShareVideoMemory_cx)
/* BankMap_cx() can't be made pageable */
#endif
/***************************************************************************
*
* void Initialize_cx(void);
*
* DESCRIPTION:
* This routine is the Mach 64-compatible hardware initialization routine
* for the miniport driver. It is called once an adapter has been found
* and all the required data structures for it have been created.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* ATIMPInitialize()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
void Initialize_cx(void)
{
DWORD Scratch; /* Temporary variable */
VIDEO_X86_BIOS_ARGUMENTS Registers; /* Used in VideoPortInt10() calls */
struct query_structure *Query; /* Information about the graphics card */
Query = (struct query_structure *) (phwDeviceExtension->CardInfo);
/*
* If the linear aperture is not configured, enable the VGA aperture.
*/
if (phwDeviceExtension->FrameLength == 0)
{
VideoDebugPrint((DEBUG_DETAIL, "Initialize_cx() switching to VGA aperture\n"));
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = BIOS_APERTURE;
Registers.Ecx = BIOS_VGA_APERTURE;
VideoPortInt10(phwDeviceExtension, &Registers);
}
/*
* Set the screen to start at the beginning of accelerator memory.
*/
Scratch = INPD(CRTC_OFF_PITCH) & ~CRTC_OFF_PITCH_Offset;
OUTPD(CRTC_OFF_PITCH, Scratch);
/*
* Disable the hardware cursor and set it up with the bitmap
* starting at the top left corner of the 64x64 block.
*/
Scratch = INPD(GEN_TEST_CNTL) & ~GEN_TEST_CNTL_CursorEna;
OUTPD(GEN_TEST_CNTL, Scratch);
OUTPD(CUR_HORZ_VERT_OFF, 0x00000000);
/*
* TVP3026 DAC requires special handling to disable
* the cursor.
*/
if (Query->q_DAC_type == DAC_TVP3026)
{
/*
* Access the indirect cursor control register.
*/
OUTP(DAC_CNTL, (BYTE)(INP(DAC_CNTL) & 0xFC));
OUTP(DAC_REGS, 6);
/*
* Write the "cursor disabled" value to the
* indexed data register.
*/
OUTP(DAC_CNTL, (BYTE)((INP(DAC_CNTL) & 0xFC) | 2));
OUTP_HBLW(DAC_REGS, 0);
/*
* Go back to using direct registers.
*/
OUTP(DAC_CNTL, (BYTE)(INP(DAC_CNTL) & 0xFC));
}
VideoDebugPrint((DEBUG_NORMAL, "Initialize_cx() complete\n"));
return;
} /* Initialize_cx() */
/**************************************************************************
*
* VP_STATUS MapVideoMemory_cx(RequestPacket, QueryPtr);
*
* PVIDEO_REQUEST_PACKET RequestPacket; Request packet with input and output buffers
* struct query_structure *QueryPtr; Query information for the card
*
* DESCRIPTION:
* Map the card's video memory into system memory and store the mapped
* address and size in OutputBuffer.
*
* RETURN VALUE:
* NO_ERROR if successful
* error code if failed
*
* GLOBALS CHANGED:
* FrameLength and PhysicalFrameAddress fields of phwDeviceExtension
* if linear framebuffer is not present.
*
* CALLED BY:
* IOCTL_VIDEO_MAP_VIDEO_MEMORY packet of ATIMPStartIO()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
VP_STATUS MapVideoMemory_cx(PVIDEO_REQUEST_PACKET RequestPacket, struct query_structure *QueryPtr)
{
PVIDEO_MEMORY_INFORMATION memoryInformation;
ULONG inIoSpace; /* Scratch variable used by VideoPortMapMemory() */
VP_STATUS status; /* Error code obtained from O/S calls */
UCHAR Scratch; /* Temporary variable */
ULONG FrameBufferLengthSave;
memoryInformation = RequestPacket->OutputBuffer;
memoryInformation->VideoRamBase = ((PVIDEO_MEMORY)
(RequestPacket->InputBuffer))->RequestedVirtualAddress;
/*
* The VideoRamLength field contains the amount of video memory
* on the card. The FrameBufferLength field contains the
* size of the aperture in bytes
*
* Initially assume that the linear aperture is available.
*
* In 4BPP, we always force the card to think it has 1M of memory.
*/
if (QueryPtr->q_pix_depth == 4)
memoryInformation->VideoRamLength = ONE_MEG;
else
memoryInformation->VideoRamLength = phwDeviceExtension->VideoRamSize;
Scratch = QueryPtr->q_aperture_cfg & CONFIG_CNTL_LinApMask;
if (Scratch == CONFIG_CNTL_LinAp4M)
{
memoryInformation->FrameBufferLength = 4 * ONE_MEG;
}
else if (Scratch == CONFIG_CNTL_LinAp8M)
{
memoryInformation->FrameBufferLength = 8 * ONE_MEG;
}
/*
* If the linear aperture is not available, map in the VGA aperture
* instead. Since the Mach 64 needs an aperture in order to use
* the drawing registers, ATIMPFindAdapter() will have already
* reported that it couldn't find a usable card if both the linear
* and VGA apertures are disabled.
*/
else if (Scratch == CONFIG_CNTL_LinApDisab)
{
phwDeviceExtension->FrameLength = 0x20000;
phwDeviceExtension->PhysicalFrameAddress.LowPart = 0x0A0000;
memoryInformation->FrameBufferLength = phwDeviceExtension->FrameLength;
}
inIoSpace = 0;
#if defined(ALPHA)
/*
* Use dense space if we can, otherwise use sparse space.
*/
if (DenseOnAlpha(QueryPtr) == TRUE)
{
VideoDebugPrint((DEBUG_DETAIL, "Using dense space for LFB\n"));
inIoSpace = 4;
}
#endif
FrameBufferLengthSave = memoryInformation->FrameBufferLength;
status = VideoPortMapMemory(phwDeviceExtension,
phwDeviceExtension->PhysicalFrameAddress,
&(memoryInformation->FrameBufferLength),
&inIoSpace,
&(memoryInformation->VideoRamBase));
#if defined (ALPHA)
/*
* VideoPortMapMemory() returns invalid FrameBufferLength
* on the Alpha.
*/
memoryInformation->FrameBufferLength = FrameBufferLengthSave;
#endif
memoryInformation->FrameBufferBase = memoryInformation->VideoRamBase;
VideoDebugPrint((DEBUG_DETAIL, "Frame buffer mapped base = 0x%X\n", memoryInformation->VideoRamBase));
/*
* On some DAC/memory combinations, some modes which require more
* than 2M of memory (1152x764 24BPP, 1280x1024 24BPP, and
* 1600x1200 16BPP) will have screen tearing at the 2M boundary.
*
* As a workaround, the display driver must start the framebuffer
* at an offset which will put the 2M boundary at the start of a
* scanline.
*
* Other DAC/memory combinations are unaffected, but since this
* fix is nearly harmless (only ill effect is to make DCI unusable
* in these modes), we can catch all future combinations which
* suffer from this problem by assuming that all DAC/memory
* combinations are affected.
*/
if ((QueryPtr->q_pix_depth == 24) &&
(QueryPtr->q_desire_x == 1280))
(PUCHAR)memoryInformation->FrameBufferBase += (0x40 * 8);
else if ((QueryPtr->q_pix_depth == 24) &&
(QueryPtr->q_desire_x == 1152))
(PUCHAR)memoryInformation->FrameBufferBase += (0x160 * 8);
else if ((QueryPtr->q_pix_depth == 16) &&
(QueryPtr->q_desire_x == 1600))
(PUCHAR)memoryInformation->FrameBufferBase += (0x90 * 8);
return status;
} /* MapVideoMemory_cx() */
/**************************************************************************
*
* VP_STATUS QueryPublicAccessRanges_cx(RequestPacket);
*
* PVIDEO_REQUEST_PACKET RequestPacket; Request packet with input and output buffers
*
* DESCRIPTION:
* Map and return information on the video card's public access ranges.
*
* RETURN VALUE:
* NO_ERROR if successful
* error code if failed
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES packet of ATIMPStartIO()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
VP_STATUS QueryPublicAccessRanges_cx(PVIDEO_REQUEST_PACKET RequestPacket)
{
PVIDEO_PUBLIC_ACCESS_RANGES portAccess;
PHYSICAL_ADDRESS physicalPortBase;
ULONG physicalPortLength;
if ( RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_PUBLIC_ACCESS_RANGES)) )
{
VideoDebugPrint((DEBUG_ERROR, "QueryPublicAccessRanges_cx() - buffer too small to handle query\n"));
return ERROR_INSUFFICIENT_BUFFER;
}
portAccess = RequestPacket->OutputBuffer;
portAccess->VirtualAddress = (PVOID) NULL; // Requested VA
portAccess->InIoSpace = 1; // In IO space
portAccess->MappedInIoSpace = portAccess->InIoSpace;
physicalPortBase.HighPart = 0x00000000;
physicalPortBase.LowPart = GetIOBase_cx();
// physicalPortLength = LINEDRAW+2 - physicalPortBase.LowPart;
/*
* If we are using packed (relocatable) I/O, all our I/O mapped
* registers are in a 1k block. If not, they are sparsely distributed
* in a 32k region.
*/
if (IsPackedIO_cx())
physicalPortLength = 0x400;
else
physicalPortLength = 0x8000;
// *SANITIZE* Should report MM registers instead
return VideoPortMapMemory(phwDeviceExtension,
physicalPortBase,
&physicalPortLength,
&(portAccess->MappedInIoSpace),
&(portAccess->VirtualAddress));
} /* QueryPublicAccessRanges_cx() */
/**************************************************************************
*
* VP_STATUS QueryCurrentMode_cx(RequestPacket, QueryPtr);
*
* PVIDEO_REQUEST_PACKET RequestPacket; Request packet with input and output buffers
* struct query_structure *QueryPtr; Query information for the card
*
* DESCRIPTION:
* Get screen information and colour masks for the current video mode.
*
* RETURN VALUE:
* NO_ERROR if successful
* error code if failed
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* IOCTL_VIDEO_QUERY_CURRENT_MODE packet of ATIMPStartIO()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
VP_STATUS QueryCurrentMode_cx(PVIDEO_REQUEST_PACKET RequestPacket, struct query_structure *QueryPtr)
{
PVIDEO_MODE_INFORMATION ModeInformation;
/*
* If the output buffer is too small to hold the information we need
* to put in it, return with the appropriate error code.
*/
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_MODE_INFORMATION)) )
{
VideoDebugPrint((DEBUG_ERROR, "QueryCurrentMode_cx() - buffer too small to handle query\n"));
return ERROR_INSUFFICIENT_BUFFER;
}
/*
* Fill in the mode information structure.
*/
ModeInformation = RequestPacket->OutputBuffer;
QuerySingleMode_cx(ModeInformation, QueryPtr, phwDeviceExtension->ModeIndex);
return NO_ERROR;
} /* QueryCurrentMode_cx() */
/**************************************************************************
*
* VP_STATUS QueryAvailModes_cx(RequestPacket, QueryPtr);
*
* PVIDEO_REQUEST_PACKET RequestPacket; Request packet with input and output buffers
* struct query_structure *QueryPtr; Query information for the card
*
* DESCRIPTION:
* Get screen information and colour masks for all available video modes.
*
* RETURN VALUE:
* NO_ERROR if successful
* error code if failed
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* IOCTL_VIDEO_QUERY_AVAIL_MODES packet of ATIMPStartIO()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
VP_STATUS QueryAvailModes_cx(PVIDEO_REQUEST_PACKET RequestPacket, struct query_structure *QueryPtr)
{
PVIDEO_MODE_INFORMATION ModeInformation;
ULONG CurrentMode;
/*
* If the output buffer is too small to hold the information we need
* to put in it, return with the appropriate error code.
*/
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
QueryPtr->q_number_modes * sizeof(VIDEO_MODE_INFORMATION)) )
{
VideoDebugPrint((DEBUG_ERROR, "QueryAvailModes_cx() - buffer too small to handle query\n"));
return ERROR_INSUFFICIENT_BUFFER;
}
/*
* Fill in the mode information structure.
*/
ModeInformation = RequestPacket->OutputBuffer;
/*
* For each mode supported by the card, store the mode characteristics
* in the output buffer.
*/
for (CurrentMode = 0; CurrentMode < QueryPtr->q_number_modes; CurrentMode++, ModeInformation++)
QuerySingleMode_cx(ModeInformation, QueryPtr, CurrentMode);
return NO_ERROR;
} /* QueryCurrentMode_cx() */
/**************************************************************************
*
* static void QuerySingleMode_cx(ModeInformation, QueryPtr, ModeIndex);
*
* PVIDEO_MODE_INFORMATION ModeInformation; Table to be filled in
* struct query_structure *QueryPtr; Query information for the card
* ULONG ModeIndex; Index of mode table to use
*
* DESCRIPTION:
* Fill in a single Windows NT mode information table using data from
* one of our CRT parameter tables.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* QueryCurrentMode_cx() and QueryAvailModes_cx()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
static void QuerySingleMode_cx(PVIDEO_MODE_INFORMATION ModeInformation,
struct query_structure *QueryPtr,
ULONG ModeIndex)
{
struct st_mode_table *CrtTable; /* Pointer to current mode table */
CrtTable = (struct st_mode_table *)QueryPtr;
((struct query_structure *)CrtTable)++;
CrtTable += ModeIndex;
ModeInformation->Length = sizeof(VIDEO_MODE_INFORMATION);
ModeInformation->ModeIndex = ModeIndex;
ModeInformation->VisScreenWidth = CrtTable->m_x_size;
ModeInformation->VisScreenHeight = CrtTable->m_y_size;
// * Bytes per line = ((pixels/line) * (bits/pixel)) / (bits/byte))
ModeInformation->ScreenStride = (CrtTable->m_screen_pitch * CrtTable->m_pixel_depth) / 8;
ModeInformation->NumberOfPlanes = 1;
ModeInformation->BitsPerPlane = (USHORT) CrtTable->m_pixel_depth;
ModeInformation->Frequency = CrtTable->Refresh;
/*
* Driver can't measure the screen size,
* so take reasonable values (16" diagonal).
*/
ModeInformation->XMillimeter = 320;
ModeInformation->YMillimeter = 240;
switch(ModeInformation->BitsPerPlane)
{
case 4:
/*
* Assume 6 bit DAC, since all VGA-compatible DACs support
* 6 bit mode. Future expansion (extensive testing needed):
* check DAC definition to see if 8 bit mode is supported,
* and use 8 bit mode if available.
*/
ModeInformation->RedMask = 0x00000000;
ModeInformation->GreenMask = 0x00000000;
ModeInformation->BlueMask = 0x00000000;
ModeInformation->NumberRedBits = 6;
ModeInformation->NumberGreenBits = 6;
ModeInformation->NumberBlueBits = 6;
CrtTable->ColourDepthInfo = BIOS_DEPTH_4BPP;
break;
case 16:
/*
* Assume that all DACs capable of 16BPP support 565.
*/
ModeInformation->RedMask = 0x0000f800;
ModeInformation->GreenMask = 0x000007e0;
ModeInformation->BlueMask = 0x0000001f;
ModeInformation->NumberRedBits = 5;
ModeInformation->NumberGreenBits = 6;
ModeInformation->NumberBlueBits = 5;
CrtTable->ColourDepthInfo = BIOS_DEPTH_16BPP_565;
break;
case 24:
/*
* Windows NT uses RGB as the standard 24BPP mode,
* so use this ordering unless this card only
* supports BGR.
*/
if (QueryPtr->q_HiColourSupport & RGB24_RGB)
{
ModeInformation->RedMask = 0x00ff0000;
ModeInformation->GreenMask = 0x0000ff00;
ModeInformation->BlueMask = 0x000000ff;
}
else{
ModeInformation->RedMask = 0x000000ff;
ModeInformation->GreenMask = 0x0000ff00;
ModeInformation->BlueMask = 0x00ff0000;
}
CrtTable->ColourDepthInfo = BIOS_DEPTH_24BPP;
ModeInformation->NumberRedBits = 8;
ModeInformation->NumberGreenBits = 8;
ModeInformation->NumberBlueBits = 8;
break;
case 32:
/*
* Windows NT uses RGBx as the standard 32BPP mode,
* so use this ordering if it's available. If it
* isn't, use the best available colour ordering.
*/
if (QueryPtr->q_HiColourSupport & RGB32_RGBx)
{
ModeInformation->RedMask = 0xff000000;
ModeInformation->GreenMask = 0x00ff0000;
ModeInformation->BlueMask = 0x0000ff00;
CrtTable->ColourDepthInfo = BIOS_DEPTH_32BPP_RGBx;
}
else if (QueryPtr->q_HiColourSupport & RGB32_xRGB)
{
ModeInformation->RedMask = 0x00ff0000;
ModeInformation->GreenMask = 0x0000ff00;
ModeInformation->BlueMask = 0x000000ff;
CrtTable->ColourDepthInfo = BIOS_DEPTH_32BPP_xRGB;
}
else if (QueryPtr->q_HiColourSupport & RGB32_BGRx)
{
ModeInformation->RedMask = 0x0000ff00;
ModeInformation->GreenMask = 0x00ff0000;
ModeInformation->BlueMask = 0xff000000;
CrtTable->ColourDepthInfo = BIOS_DEPTH_32BPP_BGRx;
}
else /* if (QueryPtr->q_HiColourSupport & RGB32_xBGR) */
{
ModeInformation->RedMask = 0x000000ff;
ModeInformation->GreenMask = 0x0000ff00;
ModeInformation->BlueMask = 0x00ff0000;
CrtTable->ColourDepthInfo = BIOS_DEPTH_32BPP_xBGR;
}
ModeInformation->NumberRedBits = 8;
ModeInformation->NumberGreenBits = 8;
ModeInformation->NumberBlueBits = 8;
break;
case 8:
default:
/*
* Assume 6 bit DAC, since all VGA-compatible DACs support
* 6 bit mode. Future expansion (extensive testing needed):
* check DAC definition to see if 8 bit mode is supported,
* and use 8 bit mode if available.
*/
ModeInformation->RedMask = 0x00000000;
ModeInformation->GreenMask = 0x00000000;
ModeInformation->BlueMask = 0x00000000;
ModeInformation->NumberRedBits = 6;
ModeInformation->NumberGreenBits = 6;
ModeInformation->NumberBlueBits = 6;
CrtTable->ColourDepthInfo = BIOS_DEPTH_8BPP;
break;
}
ModeInformation->AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS;
if (CrtTable->m_pixel_depth <= 8)
{
ModeInformation->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN |
VIDEO_MODE_MANAGED_PALETTE;
}
/*
* On "canned" mode tables,bit 4 of the m_disp_cntl field is set
* for interlaced modes and cleared for noninterlaced modes.
*
* The display applet gets confused if some of the "Use hardware
* default" modes are interlaced and some are noninterlaced
* (two "Use hardware default" entries are shown in the refresh
* rate list). To avoid this, report all mode tables stored in
* the EEPROM as noninterlaced, even if they are interlaced.
* "Canned" mode tables give true reports.
*
* If the display applet ever gets fixed, configured mode tables
* have (CrtTable->control & (CRTC_GEN_CNTL_Interlace << 8)) nonzero
* for interlaced and zero for noninterlaced.
*/
if (CrtTable->Refresh == DEFAULT_REFRESH)
{
ModeInformation->AttributeFlags &= ~VIDEO_MODE_INTERLACED;
}
else
{
if (CrtTable->m_disp_cntl & 0x010)
{
ModeInformation->AttributeFlags |= VIDEO_MODE_INTERLACED;
}
else
{
ModeInformation->AttributeFlags &= ~VIDEO_MODE_INTERLACED;
}
}
/*
* Fill in the video memory bitmap width and height fields.
* The descriptions are somewhat ambiguous - assume that
* "bitmap width" is the same as ScreenStride (bytes from
* start of one scanline to start of the next) and "bitmap
* height" refers to the number of complete scanlines which
* will fit into video memory.
*/
ModeInformation->VideoMemoryBitmapWidth = ModeInformation->ScreenStride;
ModeInformation->VideoMemoryBitmapHeight = (QueryPtr->q_memory_size * QUARTER_MEG) / ModeInformation->VideoMemoryBitmapWidth;
return;
} /* QuerySingleMode_m() */
VOID
EnableOldMach64MouseCursor(
PHW_DEVICE_EXTENSION pHwDeviceExtension
)
{
ULONG temp;
VideoDebugPrint((1, "Enabling the cursor\n"));
temp = INPD(GEN_TEST_CNTL);
temp |= GEN_TEST_CNTL_CursorEna;
OUTPD(GEN_TEST_CNTL, temp);
}
/**************************************************************************
*
* VP_STATUS SetCurrentMode_cx(QueryPtr, CrtTable);
*
* struct query_structure *QueryPtr; Query information for the card
* struct st_mode_table *CrtTable; CRT parameter table for desired mode
*
* DESCRIPTION:
* Switch into the specified video mode.
*
* RETURN VALUE:
* NO_ERROR if successful
* error code if failed
*
* NOTE:
* In the event of an error return by one of the services we call,
* there is no indication in our error return of which service failed,
* only the fact that one failed and the error code it returned. If
* a checked version of the miniport is being run under the kernel
* debugger, an indication will be printed to the debug terminal.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* IOCTL_VIDEO_SET_CURRENT_MODE packet of ATIMPStartIO()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
* 96 05 15 Now checks return values from INT 10 calls.
*
* TEST HISTORY:
*
***************************************************************************/
VP_STATUS SetCurrentMode_cx(struct query_structure *QueryPtr, struct st_mode_table *CrtTable)
{
VIDEO_X86_BIOS_ARGUMENTS Registers; /* Used in VideoPortInt10() calls */
ULONG WidthToClear; /* Screen width (in pixels) to clear */
ULONG ScreenPitch; /* Pitch in units of 8 pixels */
ULONG ScreenOffset = 0; /* Byte offset - varies with display mode */
ULONG PixelDepth; /* Colour depth of screen */
ULONG HorScissors; /* Horizontal scissor values */
ULONG Scratch; /* Temporary variable */
int CursorProgOffset; /* Offset of DAC register used to program the cursor */
VP_STATUS RetVal; /* Value returned by routines called */
/*
* Early versions of the Mach 64 BIOS have a bug where not all registers
* are set when initializing an accelerator mode. These registers are
* set when going into the 640x480 8BPP VGAWonder mode.
*
* All VGA disabled cards were built after this bug was fixed, so
* this mode switch is not necessary for them. On these cards, we
* must not do the mode switch, since it will affect the VGA enabled
* card rather than the card we are working on.
*/
if (phwDeviceExtension->BiosPrefix == BIOS_PREFIX_VGA_ENAB)
{
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = 0x62;
RetVal = VideoPortInt10(phwDeviceExtension, &Registers);
if (RetVal != NO_ERROR)
{
VideoDebugPrint((DEBUG_ERROR, "SetCurrentMode_cx() failed SVGA mode set\n"));
return RetVal;
}
}
/*
* Setting the linear aperture using the BIOS call will set
* a 4M aperture on 2M and lower cards, and an 8M aperture
* on 4M cards. Since we force the memory size to 1M in
* 4BPP modes (workaround for a hardware bug), this can
* result in writing to the wrong location for memory mapped
* registers if we switch between 4BPP and other depths
* (typically when testing a new mode) on a 4M card.
*
* To avoid this, set the memory size to its "honest" value
* before enabling the linear aperture. If we need to cut
* back to 1M, we will do this after the aperture is set.
* This will result in the aperture always being the same
* size, so the memory mapped registers will always be
* in the same place.
*
* When using the VGA aperture, we must set the "honest" value
* after enabling the aperture but before setting the mode.
* Otherwise, the system will hang when testing a mode that
* needs more than 1M of memory from a 4BPP mode.
*
* If the linear aperture is not configured, enable the VGA aperture.
*/
if (QueryPtr->q_aperture_cfg != 0)
{
RestoreMemSize_cx();
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = BIOS_APERTURE;
Registers.Ecx = BIOS_LINEAR_APERTURE;
RetVal = VideoPortInt10(phwDeviceExtension, &Registers);
if (RetVal != NO_ERROR)
{
VideoDebugPrint((DEBUG_ERROR, "SetCurrentMode_cx() failed to enable linear aperture\n"));
return RetVal;
}
}
else
{
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = BIOS_APERTURE;
Registers.Ecx = BIOS_VGA_APERTURE;
RetVal = VideoPortInt10(phwDeviceExtension, &Registers);
if (RetVal != NO_ERROR)
{
VideoDebugPrint((DEBUG_ERROR, "SetCurrentMode_cx() failed to enable VGA aperture\n"));
return RetVal;
}
OUTP(VGA_GRAX_IND, 6);
OUTP(VGA_GRAX_DATA, (BYTE)(INP(VGA_GRAX_DATA) & 0xF3));
}
/*
* Now we can set the accelerator mode.
*/
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = BIOS_LOAD_SET;
/*
* ECX register holds colour depth, gamma correction enable/disable
* (not used in NT miniport), pitch size, and resolution.
*/
Registers.Ecx = CrtTable->ColourDepthInfo;
/*
* Screen pitch differs from horizontal resolution only when using the
* VGA aperture and horizontal resolution is less than 1024.
*/
if ((CrtTable->m_screen_pitch == 1024) && (CrtTable->m_x_size < 1024))
Registers.Ecx |= BIOS_PITCH_1024;
else
Registers.Ecx |= BIOS_PITCH_HOR_RES;
/*
* On the 68860 DAC and ?T internal DACs, we must enable gamma
* correction for all pixel depths where the palette is not used.
*/
if (((QueryPtr->q_DAC_type == DAC_ATI_68860) ||
(QueryPtr->q_DAC_type == DAC_INTERNAL_CT) ||
(QueryPtr->q_DAC_type == DAC_INTERNAL_GT) ||
(QueryPtr->q_DAC_type == DAC_INTERNAL_VT)) &&
(QueryPtr->q_pix_depth > 8))
{
Registers.Ecx |= BIOS_ENABLE_GAMMA;
}
/*
* Fix 4bpp bugs by setting memory size to 1Meg. We do not
* need to switch back to the "honest" memory size for
* other pixel depths unless we are using the VGA aperture,
* since this was done for linear apertures before we enabled
* the aperture in order to ensure the same aperture size
* (and therefore the same locations for memory mapped
* registers) is used for all modes.
*/
else if (QueryPtr->q_pix_depth == 4)
{
OUTPD(MEM_CNTL, (INPD(MEM_CNTL) & ~MEM_CNTL_MemSizeMsk) | MEM_CNTL_MemSize1Mb);
}
else if (QueryPtr->q_aperture_cfg == 0)
{
RestoreMemSize_cx();
}
switch(CrtTable->m_x_size)
{
case 640:
Registers.Ecx |= BIOS_RES_640x480;
break;
case 800:
Registers.Ecx |= BIOS_RES_800x600;
break;
case 1024:
Registers.Ecx |= BIOS_RES_1024x768;
break;
case 1152:
/*
* Only "Other" mode that the config program will
* install for production cards.
*/
Registers.Ecx |= BIOS_RES_OEM;
break;
case 1280:
Registers.Ecx |= BIOS_RES_1280x1024;
break;
case 1600:
Registers.Ecx |= BIOS_RES_1600x1200;
break;
}
if (CrtTable->Refresh == DEFAULT_REFRESH)
{
RetVal = VideoPortInt10(phwDeviceExtension, &Registers);
if (RetVal != NO_ERROR)
{
VideoDebugPrint((DEBUG_ERROR, "SetCurrentMode_cx() failed mode set for default refresh\n"));
return RetVal;
}
if (phwDeviceExtension->BiosPrefix != BIOS_PREFIX_VGA_ENAB)
{
VideoDebugPrint((DEBUG_DETAIL, "Have set hardware default refresh on VGA-disabled card\n"));
/*
* On VGA-disabled cards, the INT 10 call will leave the
* DAC mask set to 0x00 (in palette modes, treat all pixels
* as if they are colour 0, regardless of what colour they
* really are). We must set it to 0xFF (in palette modes,
* use all bits of the value written to each pixel) in order
* to get the screen to display properly. This has no effect
* on non-palette (16BPP and higher) modes.
*/
OUTP_LBHW(DAC_REGS, 0xFF); /* DAC_MASK */
}
}
else
{
RetVal = SetModeFromTable_cx(CrtTable, Registers);
if (RetVal != NO_ERROR)
{
VideoDebugPrint((DEBUG_ERROR, "SetCurrentMode_cx() failed call to SetModeFromTable_cx()\n"));
return RetVal;
}
}
/*
* If the LFB is disabled, and we had to round up the pitch
* to 2048 (1152x864, 1280x1024, or 1600x1200), set the pitch
* registers manually, because there's no option in the
* INT 10 call to set them to anything other than 1024 or the
* screen width.
*/
if (CrtTable->m_screen_pitch == 2048)
{
OUTPD(CRTC_OFF_PITCH, ((INPD(CRTC_OFF_PITCH) & 0x000FFFFF) | ((2048/8) << 22)));
OUTPD(SRC_OFF_PITCH, ((INPD(SRC_OFF_PITCH) & 0x000FFFFF) | ((2048/8) << 22)));
OUTPD(DST_OFF_PITCH, ((INPD(DST_OFF_PITCH) & 0x000FFFFF) | ((2048/8) << 22)));
}
/*
* On 800x600, we must round the pitch up to a multiple of 64 to avoid
* screen warping on some DACs. Set the pitch registers to correspond
* to this.
*/
else if (CrtTable->m_screen_pitch == 832)
{
OUTPD(CRTC_OFF_PITCH, ((INPD(CRTC_OFF_PITCH) & 0x000FFFFF) | ((832/8) << 22)));
OUTPD(SRC_OFF_PITCH, ((INPD(SRC_OFF_PITCH) & 0x000FFFFF) | ((832/8) << 22)));
OUTPD(DST_OFF_PITCH, ((INPD(DST_OFF_PITCH) & 0x000FFFFF) | ((832/8) << 22)));
}
/*
* Set up the hardware cursor with colour 0 black and colour 1 white.
* Do this here rather than in Initialize_cx() because the cursor
* colours don't "take" unless we are in accelerator mode.
*
* On cards with 68860 DACs, the CUR_CLR0/1 registers don't set
* the cursor colours. Instead, the colours must be set using the
* DAC_CNTL and DAC_REGS registers. The cursor colour settings
* are independent of pixel depth because the 68860 doesn't
* support 4BPP, which is the only depth that requires a different
* setting for the cursor colours.
*
* Cursor colour initialization is done unconditionally, rather than
* only on the first graphics mode set, because otherwise testing a
* different pixel depth (most commonly testing 1024x768 4BPP when
* 1024x768 16BPP configured) may corrupt the cursor colours.
*/
if ((QueryPtr->q_DAC_type == DAC_ATI_68860) ||
(QueryPtr->q_DAC_type == DAC_TVP3026) ||
(QueryPtr->q_DAC_type == DAC_IBM514))
{
OUTP(DAC_CNTL, (BYTE)((INP(DAC_CNTL) & 0xFC) | 1));
/*
* On TVP3026 DAC, skip the OVERSCAN colour register.
*/
if (QueryPtr->q_DAC_type == DAC_TVP3026)
{
OUTP(DAC_REGS, 1);
CursorProgOffset = 1; /* DAC_DATA */
}
else if (QueryPtr->q_DAC_type == DAC_ATI_68860)
{
OUTP(DAC_REGS, 0);
CursorProgOffset = 1; /* DAC_DATA */
}
else /* if (QueryPtr->q_DAC_type == DAC_IBM514) */
{
OUTP_HBHW(DAC_REGS, 1); /* Auto-increment */
OUTP(DAC_REGS, 0x40);
OUTP_HBLW(DAC_REGS, 0);
CursorProgOffset = 2; /* DAC_MASK */
}
LioOutp(DAC_REGS, 0, CursorProgOffset); /* Colour 0 red */
LioOutp(DAC_REGS, 0, CursorProgOffset); /* Colour 0 green */
LioOutp(DAC_REGS, 0, CursorProgOffset); /* Colour 0 blue */
LioOutp(DAC_REGS, 0xFF, CursorProgOffset); /* Colour 1 red */
LioOutp(DAC_REGS, 0xFF, CursorProgOffset); /* Colour 1 green */
LioOutp(DAC_REGS, 0xFF, CursorProgOffset); /* Colour 1 blue */
OUTP(DAC_CNTL, (BYTE)((INP(DAC_CNTL) & 0xFC)));
}
else /* if (DAC not one of ATI68860, TVP3026, or IBM514) */
{
OUTPD(CUR_CLR0, 0x00000000);
/*
* On most Mach 64 cards, we must use only the lower 4 bits
* when setting up the white part of the cursor. On the
* ?T, however, we must set all 8 bits for each of the colour
* components.
*
* Verify that the VT/GT still need this after the final ASIC
* becomes available.
*/
if ((QueryPtr->q_pix_depth == 4) &&
(QueryPtr->q_DAC_type != DAC_INTERNAL_CT) &&
(QueryPtr->q_DAC_type != DAC_INTERNAL_GT) &&
(QueryPtr->q_DAC_type != DAC_INTERNAL_VT))
{
OUTPD(CUR_CLR1, 0x0F0F0F0F);
}
else
{
OUTPD(CUR_CLR1, 0xFFFFFFFF);
}
}
/*
* phwDeviceExtension->ReInitializing becomes TRUE in
* IOCTL_VIDEO_SET_COLOR_REGISTERS packet of ATIMPStartIO().
*
* If this is the first time we are going into graphics mode,
* Turn on the graphics engine. Otherwise, set the palette
* to the last set of colours that was selected while in
* accelerator mode.
*/
if (phwDeviceExtension->ReInitializing)
{
SetPalette_cx(phwDeviceExtension->Clut,
phwDeviceExtension->FirstEntry,
phwDeviceExtension->NumEntries);
}
else
{
/*
* Turn on the graphics engine.
*/
OUTPD(GEN_TEST_CNTL, (INPD(GEN_TEST_CNTL) | GEN_TEST_CNTL_GuiEna));
}
/*
* If we are using a 68860 DAC or ?T internal DAC in a non-palette
* mode, identity map the palette.
*/
if (((QueryPtr->q_DAC_type == DAC_ATI_68860) ||
(QueryPtr->q_DAC_type == DAC_INTERNAL_CT) ||
(QueryPtr->q_DAC_type == DAC_INTERNAL_GT) ||
(QueryPtr->q_DAC_type == DAC_INTERNAL_VT)) &&
(QueryPtr->q_pix_depth > 8))
IdentityMapPalette_cx();
/*
* Clear the screen regardless of whether or not this is the
* first time we are going into graphics mode. This is done
* because in 3.50 and later releases of Windows NT, the
* screen will be filled with garbage if we don't clear it.
*
* 24BPP is not a legal setting for DP_DST_PIX_WID@DP_PIX_WID.
* Instead, use 8BPP, but tell the engine that the screen is
* 3 times as wide as it actually is.
*/
if (CrtTable->ColourDepthInfo == BIOS_DEPTH_24BPP)
{
WidthToClear = CrtTable->m_x_size * 3;
ScreenPitch = (CrtTable->m_screen_pitch * 3) / 8;
PixelDepth = BIOS_DEPTH_8BPP;
/*
* Horizontal scissors are only valid in the range
* -4096 to +4095. If the horizontal resolution
* is high enough to put the scissor outside this
* range, clamp the scissors to the maximum
* permitted value.
*/
HorScissors = QueryPtr->q_desire_x * 3;
if (HorScissors > 4095)
HorScissors = 4095;
HorScissors <<= 16;
}
else
{
WidthToClear = CrtTable->m_x_size;
ScreenPitch = CrtTable->m_screen_pitch / 8;
PixelDepth = CrtTable->ColourDepthInfo;
HorScissors = (QueryPtr->q_desire_x) << 16;
}
/*
* On some DAC/memory combinations, some modes which require more
* than 2M of memory (1152x764 24BPP, 1280x1024 24BPP, and
* 1600x1200 16BPP) will have screen tearing at the 2M boundary.
*
* As a workaround, the offset field of all 3 CRTC/SRC/DST_OFF_PITCH
* registers must be set to put the 2M boundary at the start
* of a scanline.
*
* Other DAC/memory combinations are unaffected, but since this
* fix is nearly harmless (only ill effect is to make DCI unusable
* in these modes), we can catch all future combinations which
* suffer from this problem by assuming that all DAC/memory
* combinations are affected.
*/
if ((QueryPtr->q_pix_depth == 24) &&
(QueryPtr->q_desire_x == 1280))
{
ScreenOffset = 0x40;
}
else if ((QueryPtr->q_pix_depth == 24) &&
(QueryPtr->q_desire_x == 1152))
{
ScreenOffset = 0x160;
}
else if ((QueryPtr->q_pix_depth == 16) &&
(QueryPtr->q_desire_x == 1600))
{
ScreenOffset = 0x90;
}
else /* all other DAC/resolution/pixel depth combinations */
{
ScreenOffset = 0;
}
CheckFIFOSpace_cx(TWO_WORDS);
Scratch = INPD(CRTC_OFF_PITCH) & ~CRTC_OFF_PITCH_Offset;
Scratch |= ScreenOffset;
OUTPD(CRTC_OFF_PITCH, Scratch);
Scratch = INPD(SRC_OFF_PITCH) & ~SRC_OFF_PITCH_Offset;
Scratch |= ScreenOffset;
OUTPD(SRC_OFF_PITCH, Scratch);
/*
* The pixel widths for destination,
* source, and host must be the same.
*/
PixelDepth |= ((PixelDepth << 8) | (PixelDepth << 16));
CheckFIFOSpace_cx(ELEVEN_WORDS);
OUTPD(DP_WRITE_MASK, 0xFFFFFFFF);
OUTPD(DST_OFF_PITCH, (ScreenPitch << 22) | ScreenOffset);
OUTPD(DST_CNTL, (DST_CNTL_XDir | DST_CNTL_YDir));
OUTPD(DP_PIX_WIDTH, PixelDepth);
OUTPD(DP_SRC, (DP_FRGD_SRC_FG | DP_BKGD_SRC_BG | DP_MONO_SRC_ONE));
OUTPD(DP_MIX, ((MIX_FN_PAINT << 16) | MIX_FN_PAINT));
OUTPD(DP_FRGD_CLR, 0x0);
OUTPD(SC_LEFT_RIGHT, HorScissors);
OUTPD(SC_TOP_BOTTOM, (CrtTable->m_y_size) << 16);
OUTPD(DST_Y_X, 0);
OUTPD(DST_HEIGHT_WIDTH, (WidthToClear << 16) | CrtTable->m_y_size);
if (WaitForIdle_cx() == FALSE)
{
VideoDebugPrint((DEBUG_ERROR, "SetCurrentMode_cx() failed WaitForIdle_cx()\n"));
return ERROR_INSUFFICIENT_BUFFER;
}
return NO_ERROR;
} /* SetCurrentMode_cx() */
/***************************************************************************
*
* void SetPalette_cx(lpPalette, StartIndex, Count);
*
* PPALETTEENTRY lpPalette; Colour values to plug into palette
* USHORT StartIndex; First palette entry to set
* USHORT Count; Number of palette entries to set
*
* DESCRIPTION:
* Set the desired number of palette entries to the specified colours,
* starting at the specified index. Colour values are stored in
* doublewords, in the order (low byte to high byte) RGBx.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* SetCurrentMode_cx() and IOCTL_VIDEO_SET_COLOR_REGISTERS packet
* of ATIMPStartIO()
*
* AUTHOR:
* unknown
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
void SetPalette_cx(PULONG lpPalette, USHORT StartIndex, USHORT Count)
{
int i;
BYTE *pPal=(BYTE *)lpPalette;
struct query_structure *Query; /* Information about the graphics card */
Query = (struct query_structure *) (phwDeviceExtension->CardInfo);
/*
* In the current rev of the 88800GX, the memory mapped access
* to the DAC_REGS register is broken but the I/O mapped access
* works properly. Force the use of the I/O mapped access.
*/
phwDeviceExtension->aVideoAddressMM[DAC_REGS] = 0;
/*
* If a video capture card is hooked up to the feature connector,
* it will only "see" the palette being set if we use the VGA
* palette registers. This applies only in 4 and 8BPP, and is
* not necessary for when we identity map the palette (needed
* on certain DACs in 16BPP and above).
*
* In a multi-headed setup, only the card with the VGA enabled is
* able to be programmed using the VGA registers. All others must
* be programmed using the accelerator registers. Since this is
* the only card where we can hook up a video capture card to the
* feature connector, we don't lose "snooping" capability by
* programming VGA-disabled cards through the accelerator registers.
*/
if ((Query->q_pix_depth <= 8) && (phwDeviceExtension->BiosPrefix == BIOS_PREFIX_VGA_ENAB))
{
VideoDebugPrint((DEBUG_DETAIL, "Setting palette via VGA registers\n"));
/*
* DAC_W_INDEX is 8 bytes into second block of VGA registers.
* We do not have a separate OUTP()able register for this one.
*/
LioOutp(VGA_END_BREAK_PORT, (BYTE)StartIndex, 8);
for (i=0; i<Count; i++) /* this is number of colours to update */
{
/*
* DAC_DATA is 9 bytes into second block of VGA registers.
* We do not have a separate OUTP()able register for this one.
*/
LioOutp(VGA_END_BREAK_PORT, *pPal++, 9); /* red */
LioOutp(VGA_END_BREAK_PORT, *pPal++, 9); /* green */
LioOutp(VGA_END_BREAK_PORT, *pPal++, 9); /* blue */
pPal++;
}
}
else
{
VideoDebugPrint((DEBUG_DETAIL, "Setting palette via accelerator registers\n"));
OUTP(DAC_REGS,(BYTE)StartIndex); /* load DAC_W_INDEX@DAC_REGS with StartIndex */
for (i=0; i<Count; i++) /* this is number of colours to update */
{
/*
* DAC_DATA@DAC_REGS is high byte of low word.
*/
OUTP_HBLW(DAC_REGS, *pPal++); /* red */
OUTP_HBLW(DAC_REGS, *pPal++); /* green */
OUTP_HBLW(DAC_REGS, *pPal++); /* blue */
pPal++;
}
}
/*
* Victor Tango requires a few registers to be re-initialized after
* setting the palette.
*/
if (Query->q_DAC_type == DAC_INTERNAL_VT)
{
OUTP_LBHW(DAC_REGS, 0xFF); /* DAC_MASK */
OUTP(DAC_REGS, 0xFF); /* DAC_W_INDEX */
}
return;
} /* SetPalette_cx() */
/***************************************************************************
*
* void IdentityMapPalette_cx(void);
*
* DESCRIPTION:
* Set the entire palette to a grey scale whose intensity at each
* index is equal to the index value.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* SetCurrentMode_cx()
*
* AUTHOR:
* unknown
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
void IdentityMapPalette_cx(void)
{
unsigned long Index;
struct query_structure *Query; /* Information about the graphics card */
Query = (struct query_structure *) (phwDeviceExtension->CardInfo);
/*
* In the current rev of the 88800GX, the memory mapped access
* to the DAC_REGS register is broken but the I/O mapped access
* works properly. Force the use of the I/O mapped access.
*/
phwDeviceExtension->aVideoAddressMM[DAC_REGS] = 0;
OUTP(DAC_REGS, 0); // Start at first palette entry.
for (Index=0; Index<256; Index++) // Fill the whole palette.
{
/*
* DAC_DATA@DAC_REGS is high byte of low word.
*/
OUTP_HBLW(DAC_REGS,(BYTE)(Index)); // red
OUTP_HBLW(DAC_REGS,(BYTE)(Index)); // green
OUTP_HBLW(DAC_REGS,(BYTE)(Index)); // blue
}
/*
* Victor Tango requires a few registers to be re-initialized after
* setting the palette.
*/
if (Query->q_DAC_type == DAC_INTERNAL_VT)
{
OUTP_LBHW(DAC_REGS, 0xFF); /* DAC_MASK */
OUTP(DAC_REGS, 0xFF); /* DAC_W_INDEX */
}
return;
} /* IdentityMapPalette_cx() */
/**************************************************************************
*
* void ResetDevice_cx(void);
*
* DESCRIPTION:
* Switch back to VGA mode.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* IOCTL_VIDEO_RESET_DEVICE packet of ATIMPStartIO()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
void ResetDevice_cx(void)
{
VIDEO_X86_BIOS_ARGUMENTS Registers; /* Used in VideoPortInt10() calls */
ULONG Scratch;
VideoDebugPrint((DEBUG_NORMAL, "ResetDevice_cx() - entry\n"));
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = BIOS_SET_MODE;
Registers.Ecx = BIOS_MODE_VGA;
VideoPortInt10(phwDeviceExtension, &Registers);
VideoDebugPrint((DEBUG_DETAIL, "ResetDevice_cx() - VGA controls screen\n"));
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = 0x3;
VideoPortInt10(phwDeviceExtension, &Registers);
VideoDebugPrint((DEBUG_NORMAL, "ResetDevice_cx() - exit\n"));
return;
} /* ResetDevice_cx() */
/**************************************************************************
*
* DWORD GetPowerManagement_cx();
*
* DESCRIPTION:
* Determine our current DPMS state.
*
* RETURN VALUE:
* Current DPMS state (VIDEO_POWER_STATE enumeration)
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* ATIMPGetPower()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
DWORD GetPowerManagement_cx(PHW_DEVICE_EXTENSION phwDeviceExtension)
{
VIDEO_X86_BIOS_ARGUMENTS Registers; /* Used in VideoPortInt10() calls */
ASSERT(phwDeviceExtension != NULL);
/*
* Invoke the BIOS call to get the desired DPMS state. The BIOS call
* enumeration of DPMS states is in the same order as that in
* VIDEO_POWER_STATE, but it is zero-based instead of one-based.
*/
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = BIOS_GET_DPMS;
VideoPortInt10(phwDeviceExtension, &Registers);
return (Registers.Ecx + 1);
} /* GetPowerManagement_cx() */
/**************************************************************************
*
* VP_STATUS SetPowerManagement_cx(DpmsState);
*
* DWORD DpmsState; Desired DPMS state (VIDEO_POWER_STATE enumeration)
*
* DESCRIPTION:
* Switch into the desired DPMS state.
*
* RETURN VALUE:
* NO_ERROR if successful
* ERROR_INVALID_PARAMETER if invalid state requested.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* IOCTL_VIDEO_SET_POWER_MANAGEMENT packet of ATIMPStartIO()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
VP_STATUS SetPowerManagement_cx(DWORD DpmsState)
{
VIDEO_X86_BIOS_ARGUMENTS Registers; /* Used in VideoPortInt10() calls */
/*
* Only accept valid states.
*/
if ((DpmsState < VideoPowerOn) || (DpmsState > VideoPowerOff))
{
VideoDebugPrint((DEBUG_ERROR, "SetPowerManagement_cx - invalid DPMS state selected\n"));
return ERROR_INVALID_PARAMETER;
}
/*
* Invoke the BIOS call to set the desired DPMS state. The BIOS call
* enumeration of DPMS states is in the same order as that in
* VIDEO_POWER_STATE, but it is zero-based instead of one-based.
*/
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = BIOS_SET_DPMS;
Registers.Ecx = DpmsState - 1;
VideoPortInt10(phwDeviceExtension, &Registers);
return NO_ERROR;
} /* SetPowerManagement_cx() */
/**************************************************************************
*
* static VP_STATUS SetModeFromTable_cx(ModeTable, Registers);
*
* struct st_mode_table *ModeTable; Mode table to set up screen from
* VIDEO_X86_BIOS_ARGUMENTS Registers; Registers for INT 10 call
*
* DESCRIPTION:
* Switch into the graphics mode specified by ModeTable.
*
* RETURN VALUE:
* NO_ERROR if successful
* error code if failed
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* SetCurrentMode_cx()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
* 96 05 15 Now checks return values from INT 10 calls.
*
* TEST HISTORY:
*
***************************************************************************/
static VP_STATUS SetModeFromTable_cx(struct st_mode_table *ModeTable, VIDEO_X86_BIOS_ARGUMENTS Registers)
{
#define TBL_SET_BUFFER_SIZE 100
PUCHAR MappedBuffer; /* Pointer to buffer used for BIOS query */
struct cx_bios_set_from_table *CxTable; /* Mode table in Mach 64 BIOS format */
ULONG Scratch; /* Temporary variable */
struct query_structure *QueryPtr; /* Query information for the card */
VIDEO_X86_BIOS_ARGUMENTS TempRegs; /* Used in setting 640x480 8BPP to enable LFB */
BOOL FlippedPrimrary = FALSE; /* TRUE if we switched to VGA aperture on primrary card */
UCHAR SavedScreen[TBL_SET_BUFFER_SIZE]; /* Used to restore contents of primrary screen */
VP_STATUS RetVal; /* Value returned by routines called */
/*
* Get a formatted pointer into the query section of HwDeviceExtension.
* The CardInfo[] field is an unformatted buffer.
*/
QueryPtr = (struct query_structure *) (phwDeviceExtension->CardInfo);
/*
* To set the video mode from a table, we need to write the mode table
* to a buffer in physical memory below 1M. The nature of this block
* falls into one of two cases:
*
* Primrary (VGA enabled) card:
* We have already switched into video mode 0x62 (VGA 640x480 8BPP)
* to set up registers that under some circumstances are not set up
* by the accelerator mode set, so we have access to a 64k block
* starting at 0xA0000 which is backed by physical (video) memory
* and which we can write to without corrupting code and/or data
* being used by other processes.
*
* Secondary (VGA disabled) card:
* There is a VGA enabled card in the machine, which falls into
* one of five sub-cases:
*
* 1. VGA is in colour text mode
* We can use the offscreen portion of the buffer, and it doesn't
* matter whether or not the card is a Mach 64.
*
* 2. VGA is in mono text mode
* We can use the offscreen portion of the buffer, and it doesn't
* matter whether or not the card is a Mach 64.
*
* 3. VGA is in graphics mode
* We can use the beginning of the graphics screen, and it doesn't
* matter whether or not the card is a Mach 64.
*
* 4. VGA-enabled card is a Mach 64 in accelerator mode
* We can temporarily flip the primrary card's aperture status
* from LFB to VGA aperture, and use the start of the VGA
* aperture.
*
* 5. VGA-enabled card is another brand of accelerator, in accelerator mode
* This case should never occur, since NT should only run one video
* driver with VgaCompatible set to zero. If it is the ATI driver,
* a non-ATI card should not be in accelerator mode. If it is the
* driver for the non-ATI card, we will never receive a request
* to change into an accelerator mode on our card.
*
* We don't need to claim the whole block, but we should claim a bit
* more than the size of the mode table so the BIOS won't try to access
* unclaimed memory.
*/
if (phwDeviceExtension->BiosPrefix == BIOS_PREFIX_VGA_ENAB)
{
VideoDebugPrint((DEBUG_NORMAL, "Setting mode on primrary card\n"));
MappedBuffer = MapFramebuffer(0xA0000, TBL_SET_BUFFER_SIZE);
if (MappedBuffer == 0)
{
VideoDebugPrint((DEBUG_ERROR, "SetModeFromTable_cx() failed MapFramebuffer()\n"));
return ERROR_INSUFFICIENT_BUFFER;
}
/*
* Tell the BIOS to load the CRTC parameters from a table,
* rather than using the configured refresh rate for this
* resolution, and let it know where the table is.
*/
Registers.Eax = BIOS_LOAD_SET;
Registers.Edx = 0xA000;
Registers.Ebx = 0x0000;
Registers.Ecx &= ~BIOS_RES_MASK; /* Mask out code for configured resolution */
Registers.Ecx |= BIOS_RES_BUFFER;
}
else
{
/*
* This is a VGA disabled card. First try sub-cases 1 through 3.
*/
VideoDebugPrint((DEBUG_NORMAL, "Setting mode on secondary card\n"));
MappedBuffer = GetVgaBuffer(TBL_SET_BUFFER_SIZE, 0, &(Registers.Edx), SavedScreen);
/*
* If we were unable to map the buffer, assume we are dealing
* with sub-case 4. We can't distinguish between sub-cases
* 4 and 5, since the code to report an error if we issue an
* invalid BIOS call is in the ATI video BIOS, which won't
* be present in sub-case 5. Users in this sub-case are on
* their own.
*
* For sub-case 4 (VGA-enabled card is a Mach 64 in accelerator
* mode), temporarily flip from LFB mode to VGA aperture mode
* so we can use the VGA aperture without destroying the contents
* of the screen.
*/
if (MappedBuffer == 0)
{
FlippedPrimrary = TRUE;
VideoDebugPrint((DEBUG_DETAIL, "Temporary setting primrary card to VGA aperture\n"));
VideoPortZeroMemory(&TempRegs, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
TempRegs.Eax = BIOS_PREFIX_VGA_ENAB | BIOS_APERTURE_LB;
TempRegs.Ecx = BIOS_VGA_APERTURE;
RetVal = VideoPortInt10(phwDeviceExtension, &TempRegs);
if (RetVal != NO_ERROR)
{
VideoDebugPrint((DEBUG_ERROR, "SetModeFromTable_cx() failed VGA-enabled flip to VGA aperture\n"));
return RetVal;
}
MappedBuffer = MapFramebuffer(0xA0000, TBL_SET_BUFFER_SIZE);
if (MappedBuffer == 0)
{
VideoDebugPrint((DEBUG_ERROR, "SetModeFromTable_cx() failed to map buffer on VGA-enabled card\n"));
return ERROR_INSUFFICIENT_BUFFER;
}
Registers.Edx = 0xA000;
/*
* Save the contents of the buffer so that we can restore it
* after we finish the mode set.
*/
for (Scratch = 0; Scratch < TBL_SET_BUFFER_SIZE; Scratch++)
SavedScreen[Scratch] = VideoPortReadRegisterUchar(&(MappedBuffer[Scratch]));
}
/*
* Tell the BIOS to load the CRTC parameters from a table,
* rather than using the configured refresh rate for this
* resolution, and let it know where the table is.
*/
Registers.Eax = BIOS_LOAD_SET;
Registers.Ebx = 0x0000;
Registers.Ecx &= ~BIOS_RES_MASK; /* Mask out code for configured resolution */
Registers.Ecx |= BIOS_RES_BUFFER;
} /* end if (VGA disabled card) */
CxTable = (struct cx_bios_set_from_table *)MappedBuffer;
/*
* Copy the mode table into the Mach 64 format table. First handle
* the fields that only require shifting and masking.
*/
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_mode_select), (WORD)((Registers.Ecx & BIOS_RES_MASK) | CX_BS_MODE_SELECT_ACC));
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_h_tot_disp), (WORD)((ModeTable->m_h_disp << 8) | ModeTable->m_h_total));
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_h_sync_strt_wid), (WORD)((ModeTable->m_h_sync_wid << 8) | ModeTable->m_h_sync_strt));
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_v_sync_wid), (WORD)(ModeTable->m_v_sync_wid | CX_BS_V_SYNC_WID_CLK));
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_h_overscan), ModeTable->m_h_overscan);
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_v_overscan), ModeTable->m_v_overscan);
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_overscan_8b), ModeTable->m_overscan_8b);
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_overscan_gr), ModeTable->m_overscan_gr);
/*
* Next take care of fields which must be translated from our
* "canned" mode tables.
*
* The cx_crtc_gen_cntl field has only 3 bits that we use: interlace,
* MUX mode (all 1280x1024 noninterlaced modes), and force use of
* all parameters from the table (this bit is used by all the
* "canned" tables).
*/
if ((ModeTable->m_disp_cntl) & 0x10)
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_flags), CX_BS_FLAGS_INTERLACED | CX_BS_FLAGS_ALL_PARMS);
else if ((ModeTable->m_x_size > 1024) && (ModeTable->ClockFreq >= 100000000L))
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_flags), CX_BS_FLAGS_MUX | CX_BS_FLAGS_ALL_PARMS);
else
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_flags), CX_BS_FLAGS_ALL_PARMS);
/*
* Vertical parameters other than sync width are in skip-2 in
* the "canned" tables, but need to be in linear form for the Mach 64.
*/
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_v_total), (WORD)(((ModeTable->m_v_total >> 1) & 0x0FFFC) | (ModeTable->m_v_total & 0x03)));
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_v_disp), (WORD)(((ModeTable->m_v_disp >> 1) & 0x0FFFC) | (ModeTable->m_v_disp & 0x03)));
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_v_sync_strt), (WORD)(((ModeTable->m_v_sync_strt >> 1) & 0x0FFFC) | (ModeTable->m_v_sync_strt & 0x03)));
/*
* The cx_dot_clock field takes the pixel clock frequency in units
* of 10 kHz.
*/
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_dot_clock), (WORD)(ModeTable->ClockFreq / 10000L));
/*
* Now set up fields which have constant values.
*/
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_reserved_1), 0);
VideoPortWriteRegisterUshort(&(CxTable->cx_bs_reserved_2), 0);
/*
* Some Mach64 cards need to have an internal flag set up before
* they can switch into certain resolutions. Cards which have
* these resolutions configured using INSTALL.EXE don't need this
* flag set up, so we don't need to do it when switching to a
* hardware default mode. Since we don't know if the card needs
* this flag for the resolution we are using, set it for all
* "canned" mode tables.
*
* Unfortunately, this flag will disable automatic "kickdown"
* to a lower refresh rate for high pixel depths when "use
* hardware default refresh rate" is selected. To avoid this
* problem, save the contents of the scratchpad register, set
* the flag, then after we set the mode we want, restore the
* contents of the scratchpad register.
*/
Scratch = INPD(SCRATCH_REG1);
OUTPD(SCRATCH_REG1, Scratch | 0x00000200);
RetVal = VideoPortInt10(phwDeviceExtension, &Registers);
if (RetVal != NO_ERROR)
{
VideoDebugPrint((DEBUG_ERROR, "SetModeFromTable_cx() failed mode set\n"));
return RetVal;
}
/*
* If we are dealing with a VGA-disabled card (typically in a
* multiheaded setup, but under rare circumstances someone may
* be using a VGA-disabled Mach 64 with a separate VGA card),
* we must clean up after ourselves. First of all, the DAC_MASK
* register will have been left at zero by the BIOS call, which
* inhibits display of palette modes. Next, we must restore the
* contents of the buffer we used to store the CRT parameter table.
*
* Finally, if we obtained the buffer by setting a VGA-enabled
* Mach 64 in accelerator mode to use the VGA aperture, we must
* restore it to its previous aperture status. Since this will
* only happen in a multiheaded setup, and we only support PCI
* cards in such a setup (i.e. all cards have LFB available),
* we can safely assume that the VGA-enabled card was originally
* configured for LFB mode.
*/
if (phwDeviceExtension->BiosPrefix != BIOS_PREFIX_VGA_ENAB)
{
VideoDebugPrint((DEBUG_DETAIL, "Cleaning up after mode set on VGA-disabled card\n"));
OUTP_LBHW(DAC_REGS, 0xFF); /* DAC_MASK */
for (Scratch = 0; Scratch < TBL_SET_BUFFER_SIZE; Scratch++)
VideoPortWriteRegisterUchar(&(MappedBuffer[Scratch]), SavedScreen[Scratch]);
if (FlippedPrimrary == TRUE)
{
VideoDebugPrint((DEBUG_DETAIL, "Setting primrary card back to LFB mode\n"));
VideoPortZeroMemory(&TempRegs, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
TempRegs.Eax = BIOS_PREFIX_VGA_ENAB | BIOS_APERTURE_LB;
TempRegs.Ecx = BIOS_LINEAR_APERTURE;
RetVal = VideoPortInt10(phwDeviceExtension, &TempRegs);
if (RetVal != NO_ERROR)
{
VideoDebugPrint((DEBUG_ERROR, "SetModeFromTable_cx() failed VGA-enabled flip to linear aperture\n"));
return RetVal;
}
}
}
OUTPD(SCRATCH_REG1, Scratch);
VideoPortFreeDeviceBase(phwDeviceExtension, MappedBuffer);
return NO_ERROR;
} /* SetModeFromTable_cx() */
/**************************************************************************
*
* void RestoreMemSize_cx(void);
*
* DESCRIPTION:
* Restore the "memory size" register on the card when switching out
* of a mode which requires this register to be set to a specific value.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* SetCurrentMode_cx() and ATIMPResetHw()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
void RestoreMemSize_cx(void)
{
struct query_structure *QueryPtr; /* Query information for the card */
ULONG Scratch; /* Temporary variable */
/*
* Get a formatted pointer into the query section of HwDeviceExtension.
*/
QueryPtr = (struct query_structure *) (phwDeviceExtension->CardInfo);
Scratch = INPD(MEM_CNTL) & ~MEM_CNTL_MemSizeMsk;
switch(QueryPtr->q_memory_size)
{
case VRAM_512k:
Scratch |= MEM_CNTL_MemSize512k;
break;
case VRAM_1mb:
Scratch |= MEM_CNTL_MemSize1Mb;
break;
case VRAM_2mb:
Scratch |= MEM_CNTL_MemSize2Mb;
break;
case VRAM_4mb:
Scratch |= MEM_CNTL_MemSize4Mb;
break;
case VRAM_6mb:
Scratch |= MEM_CNTL_MemSize6Mb;
break;
case VRAM_8mb:
Scratch |= MEM_CNTL_MemSize8Mb;
break;
default:
break;
}
OUTPD(MEM_CNTL, Scratch);
return;
} /* RestoreMemSize_cx() */
/**************************************************************************
*
* VP_STATUS ShareVideoMemory_cx(RequestPacket, QueryPtr);
*
* PVIDEO_REQUEST_PACKET RequestPacket; Request packet with input and output buffers
* struct query_structure *QueryPtr; Query information for the card
*
* DESCRIPTION:
* Allow applications to do direct screen access through DCI.
*
* RETURN VALUE:
* NO_ERROR if successful
* error code if failed
*
* CALLED BY:
* IOCTL_VIDEO_SHARE_VIDEO_MEMORY packet of ATIMPStartIO()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
VP_STATUS ShareVideoMemory_cx(PVIDEO_REQUEST_PACKET RequestPacket, struct query_structure *QueryPtr)
{
PVIDEO_SHARE_MEMORY InputPtr; /* Pointer to input structure */
PVIDEO_SHARE_MEMORY_INFORMATION OutputPtr; /* Pointer to output structure */
PHYSICAL_ADDRESS ShareAddress; /* Physical address of video memory */
PVOID VirtualAddress; /* Virtual address to map video memory at */
ULONG SharedViewSize; /* Size of block to share */
ULONG SpaceType; /* Sparse or dense space? */
VP_STATUS Status; /* Status to return */
/*
* On some DAC/memory combinations, some modes which require more
* than 2M of memory (1152x764 24BPP, 1280x1024 24BPP, and
* 1600x1200 16BPP) will have screen tearing at the 2M boundary.
*
* As a workaround, the display driver must start the framebuffer
* at an offset which will put the 2M boundary at the start of a
* scanline.
*
* Other DAC/memory combinations are unaffected, but since this
* fix is nearly harmless (only ill effect is to make DCI unusable
* in these modes), we can catch all future combinations which
* suffer from this problem by assuming that all DAC/memory
* combinations are affected.
*
* Since this requires anyone making direct access to video memory
* to be aware of the workaround, we can't make the memory available
* through DCI.
*/
if (((QueryPtr->q_pix_depth == 24) && (QueryPtr->q_desire_x == 1280)) ||
((QueryPtr->q_pix_depth == 24) && (QueryPtr->q_desire_x == 1152)) ||
((QueryPtr->q_pix_depth == 16) && (QueryPtr->q_desire_x == 1600)))
return ERROR_INVALID_FUNCTION;
InputPtr = RequestPacket->InputBuffer;
if ((InputPtr->ViewOffset > phwDeviceExtension->VideoRamSize) ||
((InputPtr->ViewOffset + InputPtr->ViewSize) > phwDeviceExtension->VideoRamSize))
{
VideoDebugPrint((DEBUG_ERROR, "ShareVideoMemory_cx() - access beyond video memory\n"));
return ERROR_INVALID_PARAMETER;
}
RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
/*
* Beware: the input buffer and the output buffer are the same buffer,
* and therefore data should not be copied from one to the other.
*/
VirtualAddress = InputPtr->ProcessHandle;
SharedViewSize = InputPtr->ViewSize;
SpaceType = 0;
#if defined(_ALPHA_)
/*
* Use dense space mapping whenever we can, because that will
* allow us to support DCI and direct GDI access.
*
* Dense space is extremely slow with ISA cards on the newer Alphas,
* because any byte- or word-write requires a read/modify/write
* operation, and the ALpha can only ever do 64-bit reads when in
* dense mode. As a result, these operations would always require
* 4 reads and 2 writes on the ISA bus. Also, some older Alphas
* don't support dense space mapping.
*
* Any Alpha that supports PCI can support dense space mapping, and
* because the bus is wider and faster, the read/modify/write has
* less of an impact on performance.
*/
if (QueryPtr->q_bus_type == BUS_PCI)
SpaceType = 4;
#endif
/*
* NOTE: we are ignoring ViewOffset
*/
ShareAddress.QuadPart = phwDeviceExtension->PhysicalFrameAddress.QuadPart;
/*
* If the LFB is enabled, use ordinary mapping. If we have only
* the paged aperture, we must map to banked memory. Since the
* LFB is always aligned on a 4M boundary (8M boundary for 8M
* aperture), this check for the paged aperture will never falsely
* detect a LFB as paged.
*/
if (phwDeviceExtension->PhysicalFrameAddress.LowPart == 0x0A0000)
{
/*
* On some versions of the DDK, VideoPortMapBankedMemory() is
* not available. If this is the case, force an error.
* This routine should be available in all versions of
* the DDK which support DCI, since it is used for DCI
* support on cards with banked apertures.
*/
#if defined(IOCTL_VIDEO_SHARE_VIDEO_MEMORY)
Status = VideoPortMapBankedMemory(
phwDeviceExtension,
ShareAddress,
&SharedViewSize,
&SpaceType,
&VirtualAddress,
0x10000, /* Only first 64k of 128k aperture available */
FALSE, /* No separate read/write banks */
BankMap_cx, /* Our bank-mapping routine */
(PVOID) phwDeviceExtension);
#else
Status = ERROR_INVALID_FUNCTION;
#endif
}
else /* LFB */
{
Status = VideoPortMapMemory(phwDeviceExtension,
ShareAddress,
&SharedViewSize,
&SpaceType,
&VirtualAddress);
}
OutputPtr = RequestPacket->OutputBuffer;
OutputPtr->SharedViewOffset = InputPtr->ViewOffset;
OutputPtr->VirtualAddress = VirtualAddress;
OutputPtr->SharedViewSize = SharedViewSize;
return Status;
} /* ShareVideoMemory_cx() */
/**************************************************************************
*
* void BankMap_cx(BankRead, BankWrite, Context);
*
* ULONG BankRead; Bank to read
* ULONG BankWrite; Bank to write
* PVOID Context; Pointer to hardware-specific information
*
* DESCRIPTION:
* Map the selected bank of video memory into the 64k VGA aperture.
* We don't support separate read and write banks, so we use BankWrite
* to set the read/write bank, and ignore BankRead.
*
* CALLED BY:
* This is an entry point, rather than being called
* by other miniport functions.
*
* NOTE:
* This function is called directly by the memory manager during page
* fault handling, and so cannot be made pageable.
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
void BankMap_cx(ULONG BankRead, ULONG BankWrite, PVOID Context)
{
OUTPD(MEM_VGA_WP_SEL, (BankWrite*2) | (BankWrite*2 + 1) << 16);
OUTPD(MEM_VGA_RP_SEL, (BankWrite*2) | (BankWrite*2 + 1) << 16);
return;
} /* BankMap_cx() */