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.
 
 
 
 
 
 

2158 lines
74 KiB

/******************************Module*Header***********************************\
*
* *******************
* * GDI SAMPLE CODE *
* *******************
*
* Module Name: enable.c
*
* This module contains the functions that enable and disable the
* driver, the pdev, and the surface.
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
\******************************************************************************/
#include "precomp.h"
#include "directx.h"
#include "gdi.h"
#include "text.h"
#include "heap.h"
#include "dd.h"
#define ALLOC_TAG ALLOC_TAG_NE2P
PVOID pCounterBlock; // some macros need this
#define SYSTM_LOGFONT {16,7,0,0,700,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,\
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,\
VARIABLE_PITCH | FF_DONTCARE,L"System"}
#define HELVE_LOGFONT {12,9,0,0,400,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,\
CLIP_STROKE_PRECIS,PROOF_QUALITY,\
VARIABLE_PITCH | FF_DONTCARE,L"MS Sans Serif"}
#define COURI_LOGFONT {12,9,0,0,400,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,\
CLIP_STROKE_PRECIS,PROOF_QUALITY,\
FIXED_PITCH | FF_DONTCARE, L"Courier"}
//----------------------------Public*Structure---------------------------------
//
// GDIINFO ggdiDefault
//
// This contains the default GDIINFO fields that are passed back to GDI
// during DrvEnablePDEV.
//
// NOTE: This structure defaults to values for an 8bpp palette device.
// Some fields are overwritten for different colour depths.
//
//-----------------------------------------------------------------------------
GDIINFO ggdiDefault =
{
0x5000, // Major OS Ver 5, Minor Ver 0, Driver Ver 0
DT_RASDISPLAY, // ulTechnology
0, // ulHorzSize (filled in later)
0, // ulVertSize (filled in later)
0, // ulHorzRes (filled in later)
0, // ulVertRes (filled in later)
0, // cBitsPixel (filled in later)
0, // cPlanes (filled in later)
20, // ulNumColors (palette managed)
0, // flRaster (DDI reserved field)
0, // ulLogPixelsX (filled in later)
0, // ulLogPixelsY (filled in later)
TC_RA_ABLE, // flTextCaps
0, // ulDACRed (filled in later)
0, // ulDACGreen (filled in later)
0, // ulDACBlue (filled in later)
0x0024, // ulAspectX
0x0024, // ulAspectY
0x0033, // ulAspectXY (one-to-one aspect ratio)
1, // xStyleStep
1, // yStyleSte;
3, // denStyleStep -- Styles have a one-to-one aspect
// ratio, and every 'dot' is 3 pixels long
{ 0, 0 }, // ptlPhysOffset
{ 0, 0 }, // szlPhysSize
256, // ulNumPalReg
// These fields are for halftone initialization. The actual values are
// a bit magic, but seem to work well on our display.
{ // ciDevice
{ 6700, 3300, 0 }, // Red
{ 2100, 7100, 0 }, // Green
{ 1400, 800, 0 }, // Blue
{ 1750, 3950, 0 }, // Cyan
{ 4050, 2050, 0 }, // Magenta
{ 4400, 5200, 0 }, // Yellow
{ 3127, 3290, 0 }, // AlignmentWhite
20000, // RedGamma
20000, // GreenGamma
20000, // BlueGamma
0, 0, 0, 0, 0, 0 // No dye correction for raster displays
},
0, // ulDevicePelsDPI (for printers only)
PRIMARY_ORDER_CBA, // ulPrimaryOrder
HT_PATSIZE_4x4_M, // ulHTPatternSize
HT_FORMAT_8BPP, // ulHTOutputFormat
HT_FLAG_ADDITIVE_PRIMS, // flHTFlags
0, // ulVRefresh
0, // ulPanningHorzRes
0, // ulPanningVertRes
0, // ulBltAlignment
};// GDIINFO ggdiDefault
//-----------------------------Public*Structure--------------------------------
//
// DEVINFO gdevinfoDefault
//
// This contains the default DEVINFO fields that are passed back to GDI
// during DrvEnablePDEV.
//
// NOTE: This structure defaults to values for an 8bpp palette device.
// Some fields are overwritten for different colour depths.
//
//-----------------------------------------------------------------------------
DEVINFO gdevinfoDefault =
{
(GCAPS_OPAQUERECT |
GCAPS_DITHERONREALIZE |
GCAPS_PALMANAGED |
GCAPS_ALTERNATEFILL |
GCAPS_WINDINGFILL |
GCAPS_MONO_DITHER |
GCAPS_DIRECTDRAW |
GCAPS_GRAY16 | // we handle anti-aliased text
GCAPS_COLOR_DITHER),
// flGraphicsFlags
SYSTM_LOGFONT, // lfDefaultFont
HELVE_LOGFONT, // lfAnsiVarFont
COURI_LOGFONT, // lfAnsiFixFont
0, // cFonts
BMF_8BPP, // iDitherFormat
8, // cxDither
8, // cyDither
0, // hpalDefault (filled in later)
GCAPS2_SYNCTIMER |
GCAPS2_SYNCFLUSH
}; // DEVINFO gdevinfoDefault
//-----------------------------Public*Structure--------------------------------
//
// DFVFN gadrvfn[]
//
// Build the driver function table gadrvfn with function index/address
// pairs. This table tells GDI which DDI calls we support, and their
// location (GDI does an indirect call through this table to call us).
//
// Why haven't we implemented DrvSaveScreenBits? To save code.
//
// When the driver doesn't hook DrvSaveScreenBits, USER simulates on-
// the-fly by creating a temporary device-format-bitmap, and explicitly
// calling DrvCopyBits to save/restore the bits. Since we already hook
// DrvCreateDeviceBitmap, we'll end up using off-screen memory to store
// the bits anyway (which would have been the main reason for implementing
// DrvSaveScreenBits). So we may as well save some working set.
//
//-----------------------------------------------------------------------------
DRVFN gadrvfnOne[] =
{
{ INDEX_DrvAssertMode, (PFN) DrvAssertMode },
{ INDEX_DrvCompletePDEV, (PFN) DrvCompletePDEV },
{ INDEX_DrvCreateDeviceBitmap, (PFN) DrvCreateDeviceBitmap },
{ INDEX_DrvDeleteDeviceBitmap, (PFN) DrvDeleteDeviceBitmap },
{ INDEX_DrvDeriveSurface, (PFN) DrvDeriveSurface },
{ INDEX_DrvDestroyFont, (PFN) DrvDestroyFont },
{ INDEX_DrvDisableDirectDraw, (PFN) DrvDisableDirectDraw },
{ INDEX_DrvDisablePDEV, (PFN) DrvDisablePDEV },
{ INDEX_DrvDisableDriver, (PFN) DrvDisableDriver },
{ INDEX_DrvDisableSurface, (PFN) DrvDisableSurface },
{ INDEX_DrvEnableDirectDraw, (PFN) DrvEnableDirectDraw },
{ INDEX_DrvEnablePDEV, (PFN) DrvEnablePDEV },
{ INDEX_DrvEnableSurface, (PFN) DrvEnableSurface },
{ INDEX_DrvEscape, (PFN) DrvEscape },
{ INDEX_DrvGetDirectDrawInfo, (PFN) DrvGetDirectDrawInfo },
{ INDEX_DrvGetModes, (PFN) DrvGetModes },
{ INDEX_DrvIcmSetDeviceGammaRamp, (PFN) DrvIcmSetDeviceGammaRamp },
{ INDEX_DrvMovePointer, (PFN) DrvMovePointer },
{ INDEX_DrvNotify, (PFN) DrvNotify },
{ INDEX_DrvRealizeBrush, (PFN) DrvRealizeBrush },
{ INDEX_DrvResetPDEV, (PFN) DrvResetPDEV },
{ INDEX_DrvSetPalette, (PFN) DrvSetPalette },
{ INDEX_DrvSetPointerShape, (PFN) DrvSetPointerShape },
{ INDEX_DrvStretchBlt, (PFN) DrvStretchBlt },
{ INDEX_DrvSynchronizeSurface, (PFN) DrvSynchronizeSurface },
#if THUNK_LAYER
{ INDEX_DrvAlphaBlend, (PFN) xDrvAlphaBlend },
{ INDEX_DrvBitBlt, (PFN) xDrvBitBlt },
{ INDEX_DrvCopyBits, (PFN) xDrvCopyBits },
{ INDEX_DrvFillPath, (PFN) xDrvFillPath },
{ INDEX_DrvGradientFill, (PFN) xDrvGradientFill },
{ INDEX_DrvLineTo, (PFN) xDrvLineTo },
{ INDEX_DrvStrokePath, (PFN) xDrvStrokePath },
{ INDEX_DrvTextOut, (PFN) xDrvTextOut },
{ INDEX_DrvTransparentBlt, (PFN) xDrvTransparentBlt },
#else
{ INDEX_DrvAlphaBlend, (PFN) DrvAlphaBlend },
{ INDEX_DrvBitBlt, (PFN) DrvBitBlt },
{ INDEX_DrvCopyBits, (PFN) DrvCopyBits },
{ INDEX_DrvFillPath, (PFN) DrvFillPath },
{ INDEX_DrvGradientFill, (PFN) DrvGradientFill },
{ INDEX_DrvLineTo, (PFN) DrvLineTo },
{ INDEX_DrvStrokePath, (PFN) DrvStrokePath },
{ INDEX_DrvTextOut, (PFN) DrvTextOut },
{ INDEX_DrvTransparentBlt, (PFN) DrvTransparentBlt },
#endif
{ INDEX_DrvResetDevice, (PFN) DrvResetDevice },
};// DRVFN gadrvfnOne[]
// Number of driver callbacks for after NT5.
#define NON_NT5_FUNCTIONS 1
//
// Driver Function array we use when running on NT40. Notice the INDEX_Drv
// calls which we have commneted out implying we dont support these
// calls on NT4.0
DRVFN gadrvfnOne40[] =
{
{ INDEX_DrvAssertMode, (PFN) DrvAssertMode },
{ INDEX_DrvCompletePDEV, (PFN) DrvCompletePDEV },
{ INDEX_DrvCreateDeviceBitmap, (PFN) DrvCreateDeviceBitmap },
{ INDEX_DrvDeleteDeviceBitmap, (PFN) DrvDeleteDeviceBitmap },
// { INDEX_DrvDeriveSurface, (PFN) DrvDeriveSurface },
{ INDEX_DrvDisableDirectDraw, (PFN) DrvDisableDirectDraw },
{ INDEX_DrvDisablePDEV, (PFN) DrvDisablePDEV },
{ INDEX_DrvDisableDriver, (PFN) DrvDisableDriver },
{ INDEX_DrvDisableSurface, (PFN) DrvDisableSurface },
{ INDEX_DrvEnableDirectDraw, (PFN) DrvEnableDirectDraw },
{ INDEX_DrvEnablePDEV, (PFN) DrvEnablePDEV },
{ INDEX_DrvEnableSurface, (PFN) DrvEnableSurface },
{ INDEX_DrvEscape, (PFN) DrvEscape },
{ INDEX_DrvGetDirectDrawInfo, (PFN) DrvGetDirectDrawInfo },
{ INDEX_DrvGetModes, (PFN) DrvGetModes },
{ INDEX_DrvMovePointer, (PFN) DrvMovePointer },
{ INDEX_DrvRealizeBrush, (PFN) DrvRealizeBrush },
{ INDEX_DrvSetPalette, (PFN) DrvSetPalette },
{ INDEX_DrvSetPointerShape, (PFN) DrvSetPointerShape },
// { INDEX_DrvIcmSetDeviceGammaRamp, (PFN) DrvIcmSetDeviceGammaRamp },
// { INDEX_DrvNotify, (PFN) DrvNotify },
// { INDEX_DrvSynchronizeSurface, (PFN) DrvSynchronizeSurface },
#if THUNK_LAYER
{ INDEX_DrvBitBlt, (PFN) xDrvBitBlt },
{ INDEX_DrvCopyBits, (PFN) xDrvCopyBits },
{ INDEX_DrvTextOut, (PFN) xDrvTextOut },
// { INDEX_DrvAlphaBlend, (PFN) xDrvAlphaBlend },
// { INDEX_DrvGradientFill, (PFN) xDrvGradientFill },
// { INDEX_DrvTransparentBlt, (PFN) xDrvTransparentBlt },
{ INDEX_DrvLineTo, (PFN) xDrvLineTo },
{ INDEX_DrvFillPath, (PFN) xDrvFillPath },
{ INDEX_DrvStrokePath, (PFN) xDrvStrokePath },
#else
{ INDEX_DrvBitBlt, (PFN) DrvBitBlt },
{ INDEX_DrvCopyBits, (PFN) DrvCopyBits },
{ INDEX_DrvTextOut, (PFN) DrvTextOut },
// { INDEX_DrvAlphaBlend, (PFN) DrvAlphaBlend },
// { INDEX_DrvGradientFill, (PFN) DrvGradientFill },
// { INDEX_DrvTransparentBlt, (PFN) DrvTransparentBlt },
{ INDEX_DrvLineTo, (PFN) DrvLineTo },
{ INDEX_DrvFillPath, (PFN) DrvFillPath },
{ INDEX_DrvStrokePath, (PFN) DrvStrokePath },
#endif
};// DRVFN gadrvfnOne40[]
ULONG gcdrvfnOne = sizeof(gadrvfnOne) / sizeof(DRVFN);
//
// Special setup for NT4.0 runtime behaviour
//
ULONG gcdrvfnOne40 = sizeof(gadrvfnOne40) / sizeof(DRVFN);
//
// We initialize this to TRUE and set it to FALSE in
// DrvEnablePDEV when on NT5.0. We do this using the iEngineVersion passed on
// to us in that call.
//
BOOL g_bOnNT40 = TRUE;
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
HSEMAPHORE gLock = NULL;
ULONG gLockCount = 0;
#endif
//@@END_DDKSPLIT
//
// Local prototypes
//
BOOL bAssertModeHardware(PDev* ppdev, BOOL bEnable);
BOOL bEnableHardware(PDev* ppdev);
BOOL bInitializeModeFields(PDev* ppdev, GDIINFO* pgdi,
DEVINFO* pdi, DEVMODEW* pdm);
DWORD getAvailableModes(HANDLE hDriver,
PVIDEO_MODE_INFORMATION* modeInformation,
DWORD* cbModeSize);
VOID vDisableHardware(PDev* ppdev);
#define SETUP_LOG_LEVEL 2
//-------------------------------Public*Routine--------------------------------
//
// BOOL DrvEnableDriver
//
// DrvEnableDriver is the initial driver entry point exported by the driver
// DLL. It fills a DRVENABLEDATA structure with the driver version number and
// calling addresses of functions supported by the driver
//
// Parameters:
// iEngineVersion--Identifies the version of GDI that is currently running.
// cj--------------Specifies the size in bytes of the DRVENABLEDATA structure.
// If the structure is larger than expected, extra members
// should be left unmodified.
// pded------------Points to a DRVENABLEDATA structure. GDI zero-initializes
// cj bytes before the call. The driver fills in its own data.
//
// Return Value
// The return value is TRUE if the specified driver is enabled. Otherwise, it
// is FALSE, and an error code is logged.
//
//-----------------------------------------------------------------------------
BOOL
DrvEnableDriver(ULONG iEngineVersion,
ULONG cj,
DRVENABLEDATA* pded)
{
ULONG gcdrvfn;
DRVFN* gadrvfn;
ULONG DriverVersion;
DBG_GDI((SETUP_LOG_LEVEL, "DrvEnableDriver: iEngineVersion = 0x%lx\n",
iEngineVersion, cj, pded));
// Set up g_bOnNT40 based on the value in iEngineVersion
if(iEngineVersion >= DDI_DRIVER_VERSION_NT5)
g_bOnNT40 = FALSE;
if(g_bOnNT40 == FALSE)
{
// Since this driver is backwards compatible,
// report highest driver version this was built
// against that the Engine will also recognize.
// Ordered list of supported DDI versions
ULONG SupportedVersions[] = {
DDI_DRIVER_VERSION_NT5,
DDI_DRIVER_VERSION_NT5_01,
};
LONG i = sizeof(SupportedVersions)/sizeof(SupportedVersions[0]);
// Look for highest version also supported by engine
while (--i >= 0)
{
if (SupportedVersions[i] <= iEngineVersion) break;
}
// Fail if there isn't common support
if (i < 0) return FALSE;
DriverVersion = SupportedVersions[i];
gadrvfn = gadrvfnOne;
gcdrvfn = gcdrvfnOne;
if (iEngineVersion < DDI_DRIVER_VERSION_NT5_01)
{
// Trim new DDI hooks since NT5.0
gcdrvfn -= NON_NT5_FUNCTIONS;
}
if(!bEnableThunks())
{
ASSERTDD(0,"DrvEnableDriver: bEnableThunks Failed\n");
return FALSE;
}
}
else
{
DriverVersion = DDI_DRIVER_VERSION_NT4;
gadrvfn = gadrvfnOne40;
gcdrvfn = gcdrvfnOne40;
}
//
// Engine Version is passed down so future drivers can support previous
// engine versions. A next generation driver can support both the old
// and new engine conventions if told what version of engine it is
// working with. For the first version the driver does nothing with it.
// Fill in as much as we can.
//
if ( cj >= (sizeof(ULONG) * 3) )
{
pded->pdrvfn = gadrvfn;
}
//
// Tell GDI what are the functions this driver can do
//
if ( cj >= (sizeof(ULONG) * 2) )
{
pded->c = gcdrvfn;
}
//
// DDI version this driver was targeted for is passed back to engine.
// Future graphic's engine may break calls down to old driver format.
//
if ( cj >= sizeof(ULONG) )
{
DBG_GDI((SETUP_LOG_LEVEL, "DrvEnableDriver: iDriverVersion = 0x%lx",
DriverVersion));
pded->iDriverVersion = DriverVersion;
}
//
// add instance to memory tracker if enabled
//
MEMTRACKERADDINSTANCE();
return(TRUE);
}// DrvEnableDriver()
//-------------------------------Public*Routine--------------------------------
//
// VOID DrvDisableDriver
//
// This function is used by GDI to notify a driver that it no longer requires
// the driver and is ready to unload it.
//
// Comments
// The driver should free all allocated resources and return the device to the
// state it was in before the driver loaded.
//
// DrvDisableDriver is required for graphics drivers.
//
//-----------------------------------------------------------------------------
VOID
DrvDisableDriver(VOID)
{
//
// Do nothing
//
//
// except cleanup memory tracker, if enabled.
// also show memory usage
//
MEMTRACKERDEBUGCHK();
MEMTRACKERREMINSTANCE();
return;
}// DrvDisableDriver()
//-------------------------------Public*Routine--------------------------------
//
// DHPDEV DrvEnablePDEV
//
// This function returns a description of the physical device's characteristics
// to GDI.
//
// It initializes a bunch of fields for GDI, based on the mode we've been asked
// to do. This is the first thing called after DrvEnableDriver, when GDI wants
// to get some information about the driver.
//
// Parameters
//
// pdm-------------Points to a DEVMODEW structure that contains driver data.
//
// pwszLogAddress--Will always be null and can be ignored
//
// cPat------------No longer used by GDI and can be ignored
//
// phsurfPatterns--No longer used by GDI and can be ignored
//
// cjCaps----------Specifies the size of the buffer pointed to by pdevcaps.
// The driver must not access memory beyond the end of the
// buffer.
//
// pdevcaps--------Points to a GDIINFO structure that will be used to describe
// device capabilities. GDI zero-initializes this structure
// calling DrvEnablePDEV.
//
// cjDevInfo-------Specifies the number of bytes in the DEVINFO structure
// pointed to by pdi. The driver should modify no more than
// this number of bytes in the DEVINFO.
//
// pdi-------------Points to the DEVINFO structure, which describes the driver
// and the physical device. The driver should only alter the
// members it understands. GDI fills this structure with zeros
// before a call to DrvEnablePDEV.
//
// hdev------------Is a GDI-supplied handle to the display driver device that
// is being enabled. The device is in the process of being
// created and thus can not be used for Eng calls thus making
// this paramter practially useless. The one exception to this
// rule is the use of hdev for calls to EngGetDriverName. No
// other Eng calls are gaurenteed to work.
//
// pwszDeviceName--Device driver file name stored as a zero terminated ASCII
// string
//
// hDriver---------Identifies the kernel-mode driver that supports the device.
// We will use this to make EngDeviceIoControl calls to our
// corresponding mini-port driver.
//
// Returns upon success a handle to the driver-defined device instance
// information upon success. Otherwise it returns NULL.
//
//-----------------------------------------------------------------------------
DHPDEV
DrvEnablePDEV(DEVMODEW* pdm,
PWSTR pwszLogAddr,
ULONG cPat,
HSURF* phsurfPatterns,
ULONG cjCaps,
ULONG* pdevcaps,
ULONG cjDevInfo,
DEVINFO* pdi,
HDEV hdev,
PWSTR pwszDeviceName,
HANDLE hDriver)
{
PDev* ppdev = NULL;
GDIINFO gdiinfo;
DEVINFO devinfo;
DBG_GDI((SETUP_LOG_LEVEL, "DrvEnablePDEV(...)"));
//
// Invalidate input parameters
// Note: here we use "<" to check the size of the structure is to ensure
// that the driver can be used in the future version of NT, in which case
// that the structure size might go larger
//
// GDIINFO and DEVINFO are larger on NT50. On NT40 they are smaller.
// To make NT50 built driver binary work on NT40, we use temporary copies of
// GDIINFO and DEVINFO and only copy what cjCaps and cjDevInfo indicate
// into these structures.
RtlZeroMemory(&gdiinfo, sizeof(GDIINFO));
RtlCopyMemory(&gdiinfo, pdevcaps, __min(cjCaps, sizeof(GDIINFO)));
RtlZeroMemory(&devinfo, sizeof(DEVINFO));
RtlCopyMemory(&devinfo, pdi, __min(cjDevInfo, sizeof(DEVINFO)));
//
// Allocate a physical device structure. Note that we definitely
// rely on the zero initialization:
//
ppdev = (PDev*)ENGALLOCMEM(FL_ZERO_MEMORY, sizeof(PDev), ALLOC_TAG);
if ( ppdev == NULL )
{
DBG_GDI((0, "DrvEnablePDEV: failed memory allocation"));
goto errExit;
}
ppdev->hDriver = hDriver;
//
// Initialize status field.
//
ppdev->flStatus = ENABLE_BRUSH_CACHE;
// NT50 -> NT40 compat:
// We dont do Device Bitamps on NT40.
//
if(!g_bOnNT40)
ppdev->flStatus |= STAT_DEV_BITMAPS;
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
ppdev->hsemLock = EngCreateSemaphore();
if(ppdev->hsemLock == NULL)
{
DBG_GDI((0, "DrvEnablePDEV: failed to create semaphore"));
goto errExit;
}
#endif
//@@END_DDKSPLIT
//
// We haven't initialized the pointer yet
//
ppdev->bPointerInitialized = FALSE;
//
// Get the current screen mode information. Set up device caps and devinfo
//
if ( !bInitializeModeFields(ppdev, &gdiinfo, &devinfo, pdm) )
{
goto errExit;
}
RtlCopyMemory(pdevcaps, &gdiinfo, cjCaps);
RtlCopyMemory(pdi, &devinfo, cjDevInfo);
//
// Initialize palette information.
//
if ( !bInitializePalette(ppdev, pdi) )
{
goto errExit;
}
DBG_GDI((SETUP_LOG_LEVEL, "DrvEnablePDEV(...) returning %lx", ppdev));
return((DHPDEV)ppdev);
errExit:
if( ppdev != NULL )
{
DrvDisablePDEV((DHPDEV)ppdev);
}
DBG_GDI((0, "Failed DrvEnablePDEV"));
return(0);
}// DrvEnablePDEV()
//-------------------------------Public*Routine--------------------------------
//
// DrvDisablePDEV
//
// This function is used by GDI to notify a driver that the specified PDEV is
// no longer needed
//
// Parameters
// dhpdev------Pointer to the PDEV that describes the physical device to be
// disabled. This value is the handle returned by DrvEnablePDEV.
//
// Comments
// If the physical device has an enabled surface, GDI calls DrvDisablePDEV
// after calling DrvDisableSurface. The driver should free any memory and
// resources used by the PDEV.
//
// DrvDisablePDEV is required for graphics drivers.
//
// Note: In an error, we may call this before DrvEnablePDEV is done.
//
//-----------------------------------------------------------------------------
VOID
DrvDisablePDEV(DHPDEV dhpdev)
{
PDev* ppdev = (PDev*)dhpdev;
DBG_GDI((SETUP_LOG_LEVEL, "DrvDisablePDEV(%lx)", ppdev));
vUninitializePalette(ppdev);
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
if( ppdev->hsemLock != NULL)
{
EngDeleteSemaphore(ppdev->hsemLock);
ppdev->hsemLock = NULL;
}
#endif
//@@END_DDKSPLIT
ENGFREEMEM(ppdev);
}// DrvDisablePDEV()
//-------------------------------Public*Routine--------------------------------
//
// DrvResetPDEV
//
// This function is used by GDI to allow a driver to pass state information
// from one driver instance to the next.
//
// Parameters
// dhpdevOld---Pointer to the PDEV that describes the physical device to be
// disabled. This value is the handle returned by DrvEnablePDEV.
// dhpdevNew---Pointer to the PDEV that describes the physical device to be
// enabled. This value is the handle returned by DrvEnablePDEV.
//
//
// Return Value
// TRUE if successful, FALSE otherwise.
//
//-----------------------------------------------------------------------------
BOOL
DrvResetPDEV(DHPDEV dhpdevOld,
DHPDEV dhpdevNew)
{
PDev* ppdevOld = (PDev*)dhpdevOld;
PDev* ppdevNew = (PDev*)dhpdevNew;
BOOL bResult = TRUE;
DBG_GDI((SETUP_LOG_LEVEL, "DrvResetPDEV(%lx,%lx)", ppdevOld, ppdevNew));
// pass state information here:
// sometimes the new ppdev has already some DeviceBitmaps assigned...
if (ppdevOld->bDdExclusiveMode)
{
bResult = bDemoteAll(ppdevNew);
}
// pass information if DirectDraw is in exclusive mode
// to next active PDEV
if(bResult)
{
ppdevNew->bDdExclusiveMode=ppdevOld->bDdExclusiveMode;
}
return bResult;
}// DrvResetPDEV()
//-------------------------------Public*Routine--------------------------------
//
// VOID DrvCompletePDEV
//
// This function stores the GDI handle (hdev) of the physical device in dhpdev.
// The driver should retain this handle for use when calling GDI services.
//
// Parameters
// dhpdev------Identifies the physical device by its handle, which was
// returned to GDI when it called DrvEnablePDEV.
// hdev--------Identifies the physical device that has been installed. This is
// the GDI handle for the physical device being created. The
// driver should use this handle when calling GDI functions.
//
// Comments
// DrvCompletePDEV is called by GDI when its installation of the physical
// device is complete. It also provides the driver with a handle to the PDEV
// to be used when requesting GDI services for the device. This function is
// required for graphics drivers; when GDI calls DrvCompletePDEV, it cannot
// fail.
//
//-----------------------------------------------------------------------------
VOID
DrvCompletePDEV(DHPDEV dhpdev,
HDEV hdev)
{
PDev* ppdev = (PDev*)dhpdev;
DBG_GDI((SETUP_LOG_LEVEL, "DrvCompletePDEV(%lx, %lx)", dhpdev, hdev));
ppdev->hdevEng = hdev;
if(!g_bOnNT40)
{
//
// Retrieve acceleration level before the surface is enabled.
//
EngQueryDeviceAttribute(hdev,
QDA_ACCELERATION_LEVEL,
NULL,
0,
(PVOID)&ppdev->dwAccelLevel,
sizeof(ppdev->dwAccelLevel));
}
DBG_GDI((6, "acceleration level %d", ppdev->dwAccelLevel));
}// DrvCompletePDEV()
//-------------------------------Public*Routine--------------------------------
//
// HSURF DrvEnableSurface
//
// This function sets up a surface to be drawn on and associates it with a
// given PDEV and initializes the hardware. This is called after DrvEnablePDEV
// and performs the final device initialization.
//
// Parameters
// dhpdev------Identifies a handle to a PDEV. This value is the return value
// of DrvEnablePDEV. The PDEV describes the physical device for
// which a surface is to be created.
//
// Return Value
// The return value is a handle that identifies the newly created surface.
// Otherwise, it is zero, and an error code is logged.
//
// Comments
// Depending on the device and circumstances, the driver can do any of the
// following to enable the surface:
//
// If the driver manages its own surface, the driver can call
// EngCreateDeviceSurface to get a handle for the surface.
// GDI can manage the surface completely if the device has a surface that
// resembles a standard-format bitmap. The driver can obtain a bitmap handle
// for the surface by calling EngCreateBitmap with a pointer to the buffer for
// the bitmap.
// GDI can collect the graphics directly onto a GDI bitmap. The driver should
// call EngCreateBitmap, allowing GDI to allocate memory for the bitmap. This
// function is generally used only by printer devices.
// Any existing GDI bitmap handle is a valid surface handle.
//
// Before defining and returning a surface, a graphics driver must associate
// the surface with the physical device using EngAssociateSurface. This GDI
// function allows the driver to specify which graphics output routines are
// supported for standard-format bitmaps. A call to this function can only be
// made when no surface exists for the given physical device.
//
//-----------------------------------------------------------------------------
HSURF
DrvEnableSurface(DHPDEV dhpdev)
{
PDev* ppdev;
HSURF hsurf;
SIZEL sizl;
Surf* psurf;
VOID* pvTmpBuffer;
BYTE* pjScreen;
LONG lDelta;
FLONG flHooks;
ULONG DIBHooks;
DBG_GDI((SETUP_LOG_LEVEL, "DrvEnableSurface(%lx)", dhpdev));
ppdev = (PDev*)dhpdev;
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
if(ppdev->ulLockCount)
{
DBG_GDI((MT_LOG_LEVEL, "DrvEnableSurface: re-entry! %d", ppdev->ulLockCount));
}
EngAcquireSemaphore(ppdev->hsemLock);
ppdev->ulLockCount++;
#endif
//@@END_DDKSPLIT
if ( !bEnableHardware(ppdev) )
{
goto errExit;
}
//
// Initializes the off-screen heap
//
if ( !bEnableOffscreenHeap(ppdev) )
{
goto errExit;
}
//
// The DSURF for the screen is special.
//
// It is custom built here as opposed to being allocated via the
// heap management calls.
//
// NOTE: The video memory for the screen is reserved up front starting
// at zero and thus we do not need to allocate this memory from the
// video memory heap.
//
// NOTE: The DSURF will not be among the list of all of the other DSURFs
// which are allocated dynamically.
//
// NIT: remove the dynamic allocation of the DSURF. Instead, just
// declare pdsurfScreen as a DSURF instead of a DSURF*.
//
psurf = (Surf*)ENGALLOCMEM(FL_ZERO_MEMORY, sizeof(Surf), ALLOC_TAG);
if ( psurf == NULL )
{
DBG_GDI((0, "DrvEnableSurface: failed pdsurf memory allocation"));
goto errExit;
}
ppdev->pdsurfScreen = psurf;
psurf->flags = SF_VM;
psurf->ppdev = ppdev;
psurf->ulByteOffset= 0;
psurf->ulPixOffset = 0;
psurf->lDelta = ppdev->lDelta;
psurf->ulPixDelta = ppdev->lDelta >> ppdev->cPelSize;
vCalcPackedPP(ppdev->lDelta >> ppdev->cPelSize, NULL, &psurf->ulPackedPP);
//
// Create screen SURFOBJ.
//
sizl.cx = ppdev->cxScreen;
sizl.cy = ppdev->cyScreen;
//
// On NT4.0 we create a GDI managed bitmap as the primay surface. But
// on NT5.0 we create a device managed primary.
//
// On NT4.0 we still use our driver's accleration capabilities by
// doing a trick with EngLockSurface on the GDI managed primary.
//
if(g_bOnNT40)
{
hsurf = (HSURF) EngCreateBitmap(sizl,
ppdev->lDelta,
ppdev->iBitmapFormat,
(ppdev->lDelta > 0) ? BMF_TOPDOWN : 0,
(PVOID)(ppdev->pjScreen));
}
else
{
hsurf = (HSURF)EngCreateDeviceSurface((DHSURF)psurf, sizl,
ppdev->iBitmapFormat);
}
if ( hsurf == 0 )
{
DBG_GDI((0, "DrvEnableSurface: failed EngCreateDeviceBitmap"));
goto errExit;
}
//
// On NT5.0 we call EngModifSurface to expose our device surface to
// GDI. We cant do this on NT4.0 hence we call EngAssociateSurface.
//
if(g_bOnNT40)
{
//
// We have to associate the surface we just created with our physical
// device so that GDI can get information related to the PDEV when
// it's drawing to the surface (such as, for example, the length of
// styles on the device when simulating styled lines).
//
//
// On NT4.0 we dont want to be called to Synchronize Access
//
SURFOBJ *psoScreen;
LONG myflHooks = ppdev->flHooks;
myflHooks &= ~HOOK_SYNCHRONIZE;
if (!EngAssociateSurface(hsurf, ppdev->hdevEng, myflHooks))
{
DBG_GDI((0, "DrvEnableSurface: failed EngAssociateSurface"));
goto errExit;
}
//
// Jam in the value of dhsurf into screen SURFOBJ. We do this to
// make sure the driver acclerates Drv calls we hook and not
// punt them back to GDI as the SURFOBJ's dhsurf = 0.
//
ppdev->psoScreen = EngLockSurface(hsurf);
if(ppdev->psoScreen == 0)
{
DBG_GDI((0, "DrvEnableSurface: failed EngLockSurface"));
goto errExit;
}
ppdev->psoScreen->dhsurf = (DHSURF)psurf;
}
else
{
//
// Tell GDI about the screen surface. This will enable GDI to render
// directly to the screen.
//
if ( !EngModifySurface(hsurf,
ppdev->hdevEng,
ppdev->flHooks,
MS_NOTSYSTEMMEMORY,
(DHSURF)psurf,
ppdev->pjScreen,
ppdev->lDelta,
NULL))
{
DBG_GDI((0, "DrvEnableSurface: failed EngModifySurface"));
goto errExit;
}
}
if(MAKE_BITMAPS_OPAQUE)
{
SURFOBJ* surfobj = EngLockSurface(hsurf);
ASSERTDD(surfobj->iType == STYPE_BITMAP,
"expected STYPE_BITMAP");
surfobj->iType = STYPE_DEVBITMAP;
EngUnlockSurface(surfobj);
}
ppdev->hsurfScreen = hsurf; // Remember it for clean-up
ppdev->bEnabled = TRUE; // We'll soon be in graphics mode
//
// Allocate some pageable memory for temp space. This will save
// us from having to allocate and free the temp space inside high
// frequency calls.
//
pvTmpBuffer = ENGALLOCMEM(0, TMP_BUFFER_SIZE, ALLOC_TAG);
if ( pvTmpBuffer == NULL )
{
DBG_GDI((0, "DrvEnableSurface: failed TmpBuffer allocation"));
goto errExit;
}
ppdev->pvTmpBuffer = pvTmpBuffer;
//
// Now enable all the subcomponents.
//
// Note that the order in which these 'Enable' functions are called
// may be significant in low off-screen memory conditions, because
// the off-screen heap manager may fail some of the later
// allocations...
//
if ( !bInitializeHW(ppdev) )
{
goto errExit;
}
//
// On NT5.0 bEnablePointer call is made in DrvNotify. On NT4.0 we wont
// get called with DrvNotify and hence we have to call bInitializePointer
// now.
//
if(g_bOnNT40)
{
if ( !bEnablePointer(ppdev) )
{
goto errExit;
}
}
if ( !bEnablePalette(ppdev) )
{
goto errExit;
}
if (!bEnableText(ppdev))
{
goto errExit;
}
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
ppdev->ulLockCount--;
EngReleaseSemaphore(ppdev->hsemLock);
#endif
//@@END_DDKSPLIT
DBG_GDI((7, "DrvEnableSurface: done with hsurf=%x", hsurf));
DBG_GDI((6, "DrvEnableSurface: done with dhpdev = %lx", dhpdev));
DBG_GDI((SETUP_LOG_LEVEL, "DrvEnableSurface(..) return hsurf = %lx", hsurf));
return(hsurf);
errExit:
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
ppdev->ulLockCount--;
EngReleaseSemaphore(ppdev->hsemLock);
#endif
//@@END_DDKSPLIT
DrvDisableSurface((DHPDEV) ppdev);
DBG_GDI((0, "DrvEnableSurface: failed"));
return(0);
}// DrvEnableSurface()
//-------------------------------Public*Routine--------------------------------
//
// VOID DrvDisableSurface
//
// This function is used by GDI to notify a driver that the surface created
// by DrvEnableSurface for the current device is no longer needed
//
// Parameters
// dhpdev------Handle to the PDEV that describes the physical device whose
// surface is to be released.
//
// Comments
// The driver should free any memory and resources used by the surface
// associated with the PDEV as soon as the physical device is disabled.
//
// If the driver has been disabled by a call to DrvAssertMode, the driver
// cannot access the hardware during DrvDisablePDEV because another active
// PDEV might be in use. Any necessary hardware changes should have been
// performed during the call to DrvAssertMode. A driver should keep track of
// whether or not it has been disabled by DrvAssertMode so that it can perform
// proper cleanup operations in DrvDisablePDEV.
//
// If the physical device has an enabled surface, GDI calls DrvDisableSurface
// before calling DrvDisablePDEV.
//
// DrvDisableSurface is required for graphics drivers
//
// Note: In an error case, we may call this before DrvEnableSurface is
// completely done.
//
//-----------------------------------------------------------------------------
VOID
DrvDisableSurface(DHPDEV dhpdev)
{
PDev* ppdev = (PDev*)dhpdev;
Surf* psurf = ppdev->pdsurfScreen;
DBG_GDI((SETUP_LOG_LEVEL, "DrvDisableSurface(%lx)", ppdev));
//
// Note: In an error case, some of the following relies on the
// fact that the PDEV is zero-initialized, so fields like
// 'hsurfScreen' will be zero unless the surface has been
// sucessfully initialized, and makes the assumption that
// EngDeleteSurface can take '0' as a parameter.
//
vDisableText(ppdev);
vDisableHW(ppdev);
vDisableOffscreenHeap(ppdev);
vDisableHardware(ppdev);
ENGFREEMEM(ppdev->pvTmpBuffer);
if(g_bOnNT40)
EngUnlockSurface(ppdev->psoScreen);
EngDeleteSurface(ppdev->hsurfScreen);
ppdev->hsurfScreen = NULL;
ENGFREEMEM(psurf);
}// DrvDisableSurface()
//-------------------------------Public*Routine--------------------------------
//
// BOOL DrvAssertMode
//
// This function sets the mode of the specified physical device to either the
// mode specified when the PDEV was initialized or to the default mode of the
// hardware.
//
// Parameters
//
// dhpdev------Identifies the PDEV describing the hardware mode that should be
// set.
// bEnable-----Specifies the mode to which the hardware is to be set. If this
// parameter is TRUE, then the hardware is set to the original
// mode specified by the initialized PDEV. Otherwise, the hardware
// is set to its default mode so the video miniport driver can
// assume control.
//
// Comments
// GDI calls DrvAssertMode when it is required to switch among multiple
// desktops on a single display surface. To switch from one PDEV to another,
// GDI calls DrvAssertMode with the bEnable parameter set to FALSE for one
// PDEV, and TRUE for the other. To revert to the original PDEV, DrvAssertMode
// is called with bEnable set to FALSE, followed by another call to
// DrvAssertMode, with bEnable set to TRUE and dhpdev set to the original PDEV
//
// If the physical device is palette-managed, GDI should call DrvSetPalette to
// reset the device's palette. The driver does not then need to keep track of
// the current pointer state because the Window Manager selects the correct
// pointer shape and moves it to the current position. The Console Manager
// ensures that desktops are properly redrawn.
//
// DrvAssertMode is required for display drivers
//
//-----------------------------------------------------------------------------
BOOL
DrvAssertMode(DHPDEV dhpdev,
BOOL bEnable)
{
PDev* ppdev = (PDev*)dhpdev;
BOOL bRet = FALSE;
DBG_GDI((SETUP_LOG_LEVEL, "DrvAssertMode(%lx, %lx)", dhpdev, bEnable));
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
if(ppdev->ulLockCount)
{
DBG_GDI((MT_LOG_LEVEL, "DrvAssertMode: re-entered! %d", ppdev->ulLockCount));
}
EngAcquireSemaphore(ppdev->hsemLock);
ppdev->ulLockCount++;
#endif
//@@END_DDKSPLIT
if ( !bEnable )
{
//
// bEnable == FALSE. The hardware is set to its default mode so the
// video miniport driver can assume control.
//
vAssertModeBrushCache(ppdev, FALSE);
vAssertModePointer(ppdev, FALSE);
vAssertModeText(ppdev, FALSE);
if ( bAssertModeOffscreenHeap(ppdev, FALSE) )
{
vAssertModeHW(ppdev, FALSE);
if ( bAssertModeHardware(ppdev, FALSE) )
{
ppdev->bEnabled = FALSE;
bRet = TRUE;
goto done;
}
//
// We failed to switch to full-screen. So undo everything:
//
vAssertModeHW(ppdev, TRUE);
} // return code with TRUE
bEnablePointer(ppdev);
vAssertModeText(ppdev, TRUE);
vAssertModeBrushCache(ppdev, TRUE);
}// if ( !bEnable )
else
{
//
// bEnable == TRUE means the hardware is set to the original mode
// specified by the initialized PDEV
//
// Switch back to graphics mode
//
// We have to enable every subcomponent in the reverse order
// in which it was disabled:
//
// NOTE: We defer the enabling of the brush and pointer cache
// to DrvNotify. The direct draw heap is not valid
// at this point.
//
if ( bAssertModeHardware(ppdev, TRUE) )
{
vAssertModeHW(ppdev, TRUE);
vAssertModeText(ppdev, TRUE);
ppdev->bEnabled = TRUE;
bRet = TRUE;
}
}// bEnable == TRUE
done:
//@@BEGIN_DDKSPLIT
#if MULTITHREADED
ppdev->ulLockCount--;
EngReleaseSemaphore(ppdev->hsemLock);
#endif
//@@END_DDKSPLIT
return(bRet);
}// DrvAssertMode()
//-------------------------------Public*Routine--------------------------------
//
// ULONG DrvGetModes
//
// This function lists the modes supported by the device.
//
// Parameters:
//
// hDriver-----Specifies the handle to the kernel driver for which the modes
// must be enumerated. This is the handle that is passed in the
// hDriver parameter of the DrvEnablePDEV function.
// cjSize------Specifies the size, in bytes, of the buffer pointed to by pdm.
// pdm---------Points to the buffer in which DEVMODEW structures will be
// written.
//
// Return Value
// The return value is the count of bytes written to the buffer, or, if pdm is
// null, the number of bytes required to hold all mode data. If an error
// occurs, the return value is zero, and an error code is logged
//
//-----------------------------------------------------------------------------
ULONG
DrvGetModes(HANDLE hDriver,
ULONG cjSize,
DEVMODEW* pdm)
{
DWORD cModes;
DWORD cbOutputSize;
PVIDEO_MODE_INFORMATION pVideoModeInformation;
PVIDEO_MODE_INFORMATION pVideoTemp;
//
// How many MODEs the caller wants us to fill
//
DWORD cOutputModes = cjSize
/ (sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
DWORD cbModeSize;
DBG_GDI((7, "DrvGetModes"));
cModes = getAvailableModes(hDriver,
(PVIDEO_MODE_INFORMATION*)&pVideoModeInformation,
&cbModeSize);
if ( cModes == 0 )
{
DBG_GDI((0, "DrvGetModes: failed to get mode information"));
return(0);
}
if ( pdm == NULL )
{
//
// GDI only wants to know the number of bytes required to hold all
// mode data at this moment
//
cbOutputSize = cModes * (sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
}
else
{
//
// Now copy the information for the supported modes back into the
// output buffer
//
cbOutputSize = 0;
pVideoTemp = pVideoModeInformation;
do
{
if ( pVideoTemp->Length != 0 )
{
//
// If the caller's buffer is filled up, we should quit now
//
if ( cOutputModes == 0 )
{
break;
}
//
// Zero the entire structure to start off with.
//
memset(pdm, 0, sizeof(DEVMODEW));
//
// Set the name of the device to the name of the DLL.
//
memcpy(pdm->dmDeviceName, DLL_NAME, sizeof(DLL_NAME));
pdm->dmSpecVersion = DM_SPECVERSION;
pdm->dmDriverVersion = DM_SPECVERSION;
//
// We currently do not support Extra information in the driver
//
pdm->dmDriverExtra = DRIVER_EXTRA_SIZE;
pdm->dmSize = sizeof(DEVMODEW);
pdm->dmBitsPerPel = pVideoTemp->NumberOfPlanes
* pVideoTemp->BitsPerPlane;
pdm->dmPelsWidth = pVideoTemp->VisScreenWidth;
pdm->dmPelsHeight = pVideoTemp->VisScreenHeight;
pdm->dmDisplayFrequency = pVideoTemp->Frequency;
pdm->dmDisplayFlags = 0;
pdm->dmPanningWidth = pdm->dmPelsWidth;
pdm->dmPanningHeight = pdm->dmPelsHeight;
pdm->dmFields = DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFREQUENCY
| DM_DISPLAYFLAGS;
//
// Go to the next DEVMODE entry in the buffer.
//
cOutputModes--;
pdm = (LPDEVMODEW)(((UINT_PTR)pdm) + sizeof(DEVMODEW)
+ DRIVER_EXTRA_SIZE);
cbOutputSize += (sizeof(DEVMODEW) + DRIVER_EXTRA_SIZE);
}// if ( pVideoTemp->Length != 0 )
pVideoTemp = (PVIDEO_MODE_INFORMATION)
(((PUCHAR)pVideoTemp) + cbModeSize);
} while (--cModes);
}// pbm != NULL
ENGFREEMEM(pVideoModeInformation);
return(cbOutputSize);
}// DrvGetModes()
//-----------------------------------------------------------------------------
//
// BOOL bAssertModeHardware
//
// Sets the appropriate hardware state for graphics mode or full-screen.
//
//-----------------------------------------------------------------------------
BOOL
bAssertModeHardware(PDev* ppdev, BOOL bEnable)
{
DWORD dLength;
ULONG ulReturn;
VIDEO_MODE_INFORMATION VideoModeInfo;
PERMEDIA_DECL;
DBG_GDI((6, "bAssertModeHardware: bEnable = %d", bEnable));
if ( bEnable )
{
//
// Call the miniport via an IOCTL to set the graphics mode.
//
if ( EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_SET_CURRENT_MODE,
&ppdev->ulMode, // input buffer
sizeof(DWORD),
NULL,
0,
&dLength) )
{
DBG_GDI((0, "bAssertModeHardware: failed VIDEO_SET_CURRENT_MODE"));
goto errExit;
}
if ( EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_QUERY_CURRENT_MODE,
NULL,
0,
&VideoModeInfo,
sizeof(VideoModeInfo),
&dLength) )
{
DBG_GDI((0,"bAssertModeHardware: failed VIDEO_QUERY_CURRENT_MODE"));
goto errExit;
}
//
// The following variables are determined only after the initial
// modeset
// Note: here lVidMemWidth and lVidMemHeight are in "pixel" unit, not
// bytes
//
ppdev->cxMemory = VideoModeInfo.VideoMemoryBitmapWidth;
ppdev->cyMemory = VideoModeInfo.VideoMemoryBitmapHeight;
ppdev->lVidMemWidth = VideoModeInfo.VideoMemoryBitmapWidth;
ppdev->lVidMemHeight = VideoModeInfo.VideoMemoryBitmapHeight;
ppdev->lDelta = VideoModeInfo.ScreenStride;
ppdev->flCaps = VideoModeInfo.DriverSpecificAttributeFlags;
DBG_GDI((7, "bAssertModeHardware: Got flCaps 0x%x", ppdev->flCaps));
DBG_GDI((7, "bAssertModeHardware: using %s pointer",
(ppdev->flCaps & CAPS_SW_POINTER) ?
"GDI Software Cursor":
(ppdev->flCaps & CAPS_TVP4020_POINTER) ?
"TI TVP4020" :
(ppdev->flCaps & CAPS_P2RD_POINTER) ?
"3Dlabs P2RD" : "unknown"));
}
else
{
//
// Call the kernel driver to reset the device to a known state.
// NTVDM will take things from there:
//
if ( EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_RESET_DEVICE,
NULL,
0,
NULL,
0,
&ulReturn) )
{
DBG_GDI((0, "bAssertModeHardware: failed reset IOCTL"));
goto errExit;
}
}
return(TRUE);
errExit:
DBG_GDI((0, "bAssertModeHardware: failed"));
return(FALSE);
}// bAssertModeHardware()
//-----------------------------------------------------------------------------
//
// BOOL bEnableHardware
//
// Puts the hardware in the requested mode and initializes it.
//
// Note: This function Should be called before any access is done to the
// hardware from the display driver
//
//-----------------------------------------------------------------------------
BOOL
bEnableHardware(PDev* ppdev)
{
VIDEO_MEMORY VideoMemory;
VIDEO_MEMORY_INFORMATION VideoMemoryInfo;
DWORD dLength;
VIDEO_PUBLIC_ACCESS_RANGES VideoAccessRange[3];
DBG_GDI((7, "bEnableHardware"));
//
// Map control registers into virtual memory:
//
VideoMemory.RequestedVirtualAddress = NULL;
if ( EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES,
&VideoMemory, // input buffer
sizeof(VIDEO_MEMORY),
&VideoAccessRange[0], // output buffer
sizeof (VideoAccessRange),
&dLength) )
{
DBG_GDI((0,"bEnableHardware: query failed"));
goto errExit;
}
ppdev->pulCtrlBase[0] = (ULONG*)VideoAccessRange[0].VirtualAddress;
ppdev->pulCtrlBase[1] = (ULONG*)VideoAccessRange[1].VirtualAddress;
ppdev->pulDenseCtrlBase = (ULONG*)VideoAccessRange[2].VirtualAddress;
ppdev->pulInputDmaCount = ppdev->pulCtrlBase[0] + (PREG_INDMACOUNT>>2);
ppdev->pulInputDmaAddress = ppdev->pulCtrlBase[0] + (PREG_INDMAADDRESS>>2);
ppdev->pulFifo = ppdev->pulCtrlBase[0] + (PREG_FIFOINTERFACE>>2);
ppdev->pulOutputFifoCount = ppdev->pulCtrlBase[0] + (PREG_OUTFIFOWORDS>>2);
ppdev->pulInputFifoCount = ppdev->pulCtrlBase[0] + (PREG_INFIFOSPACE>>2);
DBG_GDI((7, "bEnableHardware: mapped control registers[0] at 0x%x",
ppdev->pulCtrlBase[0]));
DBG_GDI((7, " mapped registers[1] at 0x%x",
ppdev->pulCtrlBase[1]));
DBG_GDI((7, " mapped dense control registers at 0x%x",
ppdev->pulDenseCtrlBase));
//
// Get the linear memory address range.
//
VideoMemory.RequestedVirtualAddress = NULL;
if ( EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_MAP_VIDEO_MEMORY,
&VideoMemory, // input buffer
sizeof(VIDEO_MEMORY),
&VideoMemoryInfo, // output buffer
sizeof(VideoMemoryInfo),
&dLength) )
{
DBG_GDI((0, "bEnableHardware: error mapping buffer address"));
goto errExit;
}
DBG_GDI((7, "bEnableHardware: frameBufferBase addr = %lx",
VideoMemoryInfo.FrameBufferBase));
DBG_GDI((7, " frameBufferLength = %l",
VideoMemoryInfo.FrameBufferLength));
DBG_GDI((7, " videoRamBase addr = %lx",
VideoMemoryInfo.VideoRamBase));
DBG_GDI((7, " videoRamLength = %l",
VideoMemoryInfo.VideoRamLength));
//
// Record the Frame Buffer Linear Address.
//
ppdev->pjScreen = (BYTE*)VideoMemoryInfo.FrameBufferBase;
ppdev->FrameBufferLength = VideoMemoryInfo.FrameBufferLength;
//
// Set hardware states, like ppdev->lVidMemWidth, lVidMemHeight, cxMemory,
// cyMemory etc
//
if ( !bAssertModeHardware(ppdev, TRUE) )
{
goto errExit;
}
DBG_GDI((7, "bEnableHardware: width = %li height = %li",
ppdev->cxMemory, ppdev->cyMemory));
DBG_GDI((7, "bEnableHardware: stride = %li flCaps = 0x%lx",
ppdev->lDelta, ppdev->flCaps));
return (TRUE);
errExit:
DBG_GDI((0, "bEnableHardware: failed"));
return (FALSE);
}// bEnableHardware()
//-----------------------------------------------------------------------------
//
// VOID vDisableHardware
//
// Undoes anything done in bEnableHardware.
//
// Note: In an error case, we may call this before bEnableHardware is
// completely done.
//
//-----------------------------------------------------------------------------
VOID
vDisableHardware(PDev* ppdev)
{
DWORD ReturnedDataLength;
VIDEO_MEMORY VideoMemory[3];
DBG_GDI((6, "vDisableHardware"));
if (ppdev->pjScreen)
{
VideoMemory[0].RequestedVirtualAddress = ppdev->pjScreen;
if ( EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_UNMAP_VIDEO_MEMORY,
&VideoMemory[0],
sizeof(VIDEO_MEMORY),
NULL,
0,
&ReturnedDataLength))
{
DBG_GDI((0, "vDisableHardware: failed IOCTL_VIDEO_UNMAP_VIDEO"));
}
}
VideoMemory[0].RequestedVirtualAddress = ppdev->pulCtrlBase[0];
VideoMemory[1].RequestedVirtualAddress = ppdev->pulCtrlBase[1];
VideoMemory[2].RequestedVirtualAddress = ppdev->pulDenseCtrlBase;
if ( EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES,
&VideoMemory[0],
sizeof(VideoMemory),
NULL,
0,
&ReturnedDataLength) )
{
DBG_GDI((0, "vDisableHardware: failed IOCTL_VIDEO_FREE_PUBLIC_ACCESS"));
}
}// vDisableHardware()
//-----------------------------------------------------------------------------
//
// ULONG ulLog2(ULONG ulVal)
//
// Returns the log base 2 of the given value. The ulVal must be a power of
// two otherwise the return value is undefined. If ulVal is zero the return
// value is undefined.
//
//-----------------------------------------------------------------------------
ULONG
ulLog2(ULONG ulVal)
{
ULONG ulLog2 = 0;
ULONG ulTemp = ulVal >> 1;
while( ulTemp )
{
ulTemp >>= 1;
ulLog2++;
}
ASSERTDD(ulVal == (1UL << ulLog2), "ulLog2: bad value given");
return ulLog2;
}// ulLog2()
//-----------------------------------------------------------------------------
//
// BOOL bInitializeModeFields
//
// Initializes a bunch of fields in the pdev, devcaps (aka gdiinfo), and
// devinfo based on the requested mode.
//
//-----------------------------------------------------------------------------
BOOL
bInitializeModeFields(PDev* ppdev,
GDIINFO* pgdi,
DEVINFO* pdi,
DEVMODEW* pdm)
{
ULONG cModes;
PVIDEO_MODE_INFORMATION pVideoBuffer;
PVIDEO_MODE_INFORMATION pVideoModeSelected;
PVIDEO_MODE_INFORMATION pVideoTemp;
VIDEO_MODE_INFORMATION vmi;
ULONG cbModeSize;
BOOL bSelectDefault; // Used for NT4.0 compat only
DBG_GDI((6, "bInitializeModeFields"));
//
// Call the miniport to get mode information, result will be in
// "pVideoBuffer"
//
// Note: the lower level function allocates memory for us in "pVideoBuffer"
// so we should take care of this later
//
cModes = getAvailableModes(ppdev->hDriver, &pVideoBuffer, &cbModeSize);
if ( cModes == 0 )
{
goto errExit;
}
//
// Now see if the requested mode has a match in that table.
//
pVideoModeSelected = NULL;
pVideoTemp = pVideoBuffer;
if(g_bOnNT40)
{
if ( (pdm->dmPelsWidth == 0)
&&(pdm->dmPelsHeight == 0)
&&(pdm->dmBitsPerPel == 0)
&&(pdm->dmDisplayFrequency == 0) )
{
DBG_GDI((2, "bInitializeModeFields: default mode requested"));
bSelectDefault = TRUE;
}
else
{
DBG_GDI((2, "bInitializeModeFields: Request width = %li height = %li",
pdm->dmPelsWidth, pdm->dmPelsHeight));
DBG_GDI((2, " bpp = %li frequency = %li",
pdm->dmBitsPerPel, pdm->dmDisplayFrequency));
bSelectDefault = FALSE;
}
}
else
{
//
// On NT5.0 we should never get an old sytle default mode request.
//
ASSERTDD(pdm->dmPelsWidth != 0 &&
pdm->dmPelsHeight != 0 &&
pdm->dmBitsPerPel != 0 &&
pdm->dmDisplayFrequency != 0,
"bInitializeModeFields: old style default mode request");
}
while ( cModes-- )
{
if ( pVideoTemp->Length != 0 )
{
DBG_GDI((7, "bInitializeModeFields: check width = %li height = %li",
pVideoTemp->VisScreenWidth,
pVideoTemp->VisScreenHeight));
DBG_GDI((7, " bpp = %li freq = %li",
pVideoTemp->BitsPerPlane * pVideoTemp->NumberOfPlanes,
pVideoTemp->Frequency));
//
// Handle old style default mode case only on NT4.0
//
if(g_bOnNT40 && bSelectDefault)
{
pVideoModeSelected = pVideoTemp;
DBG_GDI((7, "bInitializeModeFields: found a mode match(default)"));
break;
}
if ( (pVideoTemp->VisScreenWidth == pdm->dmPelsWidth)
&& (pVideoTemp->VisScreenHeight == pdm->dmPelsHeight)
&& (pVideoTemp->BitsPerPlane * pVideoTemp->NumberOfPlanes
== pdm->dmBitsPerPel)
&& (pVideoTemp->Frequency == pdm->dmDisplayFrequency) )
{
pVideoModeSelected = pVideoTemp;
DBG_GDI((7, "bInitializeModeFields: found a mode match!"));
break;
}
}// if the video mode info structure buffer is not empty
//
// Move on to next video mode structure
//
pVideoTemp = (PVIDEO_MODE_INFORMATION)(((PUCHAR)pVideoTemp)
+ cbModeSize);
}// while ( cModes-- )
//
// If no mode has been found, return an error
//
if ( pVideoModeSelected == NULL )
{
DBG_GDI((0, "bInitializeModeFields: couldn't find a mode match!"));
ENGFREEMEM(pVideoBuffer);
goto errExit;
}
//
// We have chosen the one we want. Save it in a stack buffer and
// get rid of allocated memory before we forget to free it.
//
vmi = *pVideoModeSelected;
ENGFREEMEM(pVideoBuffer);
//
// Set up screen information from the mini-port:
//
ppdev->ulMode = vmi.ModeIndex;
ppdev->cxScreen = vmi.VisScreenWidth;
ppdev->cyScreen = vmi.VisScreenHeight;
ppdev->cBitsPerPel = vmi.BitsPerPlane;
DBG_GDI((7, "bInitializeModeFields: screenStride = %li", vmi.ScreenStride));
ppdev->flHooks = HOOK_SYNCHRONIZE
| HOOK_FILLPATH
| HOOK_STROKEPATH
| HOOK_LINETO
| HOOK_TEXTOUT
| HOOK_BITBLT
| HOOK_COPYBITS;
if(!g_bOnNT40)
ppdev->flHooks |= HOOK_TRANSPARENTBLT |
HOOK_ALPHABLEND |
HOOK_STRETCHBLT |
HOOK_GRADIENTFILL;
//
// Fill in the GDIINFO data structure with the default 8bpp values:
//
*pgdi = ggdiDefault;
//
// Now overwrite the defaults with the relevant information returned
// from the kernel driver:
//
pgdi->ulHorzSize = vmi.XMillimeter;
pgdi->ulVertSize = vmi.YMillimeter;
pgdi->ulHorzRes = vmi.VisScreenWidth;
pgdi->ulVertRes = vmi.VisScreenHeight;
pgdi->ulPanningHorzRes = vmi.VisScreenWidth;
pgdi->ulPanningVertRes = vmi.VisScreenHeight;
pgdi->cBitsPixel = vmi.BitsPerPlane;
pgdi->cPlanes = vmi.NumberOfPlanes;
pgdi->ulVRefresh = vmi.Frequency;
pgdi->ulDACRed = vmi.NumberRedBits;
pgdi->ulDACGreen = vmi.NumberGreenBits;
pgdi->ulDACBlue = vmi.NumberBlueBits;
pgdi->ulLogPixelsX = pdm->dmLogPixels;
pgdi->ulLogPixelsY = pdm->dmLogPixels;
//
// Fill in the devinfo structure with the default 8bpp values:
//
*pdi = gdevinfoDefault;
//
// Bytes per pel 4/2/1 for 32/16/8 bpp
//
ppdev->cjPelSize = vmi.BitsPerPlane >> 3;
//
// Bytes per pel log 2
//
ppdev->cPelSize = ulLog2(ppdev->cjPelSize);
//
// = 2,1,0 for 32,16,8 depth. Shifts needed to calculate bytes/pixel
//
ppdev->bPixShift = (BYTE) ppdev->cPelSize;
//
// = 0,1,2 for 32/16/8.
//
ppdev->bBppShift = 2 - ppdev->bPixShift;
//
// = 3,1,0 for 8,16,32 bpp
//
ppdev->dwBppMask = 3 >> ppdev->bPixShift;
switch ( vmi.BitsPerPlane )
{
case 8:
ppdev->iBitmapFormat = BMF_8BPP;
ASSERTDD(vmi.AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN,
"bInitializeModeFields: unexpected non-palette 8bpp mode");
ppdev->ulWhite = 0xff;
ppdev->ulPermFormat = PERMEDIA_8BIT_PALETTEINDEX;
ppdev->ulPermFormatEx = PERMEDIA_8BIT_PALETTEINDEX_EXTENSION;
if(g_bOnNT40)
pdi->flGraphicsCaps &= ~GCAPS_COLOR_DITHER;
// No AntiAliased text support in 8bpp mode.
pdi->flGraphicsCaps &= ~GCAPS_GRAY16;
break;
case 16:
ppdev->iBitmapFormat = BMF_16BPP;
ppdev->flRed = vmi.RedMask;
ppdev->flGreen = vmi.GreenMask;
ppdev->flBlue = vmi.BlueMask;
pgdi->ulNumColors = (ULONG)-1;
pgdi->ulNumPalReg = 0;
pgdi->ulHTOutputFormat = HT_FORMAT_16BPP;
pdi->iDitherFormat = BMF_16BPP;
pdi->flGraphicsCaps &= ~(GCAPS_PALMANAGED | GCAPS_COLOR_DITHER);
// support gamma ramp changes
pdi->flGraphicsCaps2 |= GCAPS2_CHANGEGAMMARAMP;
ppdev->ulWhite = vmi.RedMask
| vmi.GreenMask
| vmi.BlueMask;
ppdev->ulPermFormat = PERMEDIA_565_RGB;
ppdev->ulPermFormatEx = PERMEDIA_565_RGB_EXTENSION;
break;
case 32:
ppdev->iBitmapFormat = BMF_32BPP;
ppdev->flRed = vmi.RedMask;
ppdev->flGreen = vmi.GreenMask;
ppdev->flBlue = vmi.BlueMask;
pgdi->ulNumColors = (ULONG)-1;
pgdi->ulNumPalReg = 0;
pgdi->ulHTOutputFormat = HT_FORMAT_32BPP;
pdi->iDitherFormat = BMF_32BPP;
pdi->flGraphicsCaps &= ~(GCAPS_PALMANAGED | GCAPS_COLOR_DITHER);
//
// Support gamma ramp changes
//
pdi->flGraphicsCaps2 |= GCAPS2_CHANGEGAMMARAMP;
ppdev->ulWhite = vmi.RedMask
| vmi.GreenMask
| vmi.BlueMask;
ppdev->ulPermFormat = PERMEDIA_888_RGB;
ppdev->ulPermFormatEx = PERMEDIA_888_RGB_EXTENSION;
break;
default:
ASSERTDD(0, "bInitializeModeFields: bit depth not supported");
goto errExit;
}// switch on clor depth
return(TRUE);
errExit:
DBG_GDI((0, "bInitializeModeFields: failed"));
return(FALSE);
}// bInitializeModeFields()
//-----------------------------------------------------------------------------
//
// DWORD getAvailableModes
//
// Calls the miniport to get the list of modes supported by the kernel driver.
// Prunes the list to only those modes supported by this driver.
//
// Returns the number of entries supported and returned in the
// modeInformation array. If the return value is non-zero, then
// modeInformation was set to point to a valid mode information array. It is
// the responsibility of the caller to free this array when it is no longer
// needed.
//
//-----------------------------------------------------------------------------
DWORD
getAvailableModes(HANDLE hDriver,
PVIDEO_MODE_INFORMATION* modeInformation,
DWORD* cbModeSize)
{
ULONG ulTemp;
VIDEO_NUM_MODES modes;
PVIDEO_MODE_INFORMATION pVideoTemp;
//
// Get the number of modes supported by the mini-port
//
if ( EngDeviceIoControl(hDriver,
IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES,
NULL,
0,
&modes,
sizeof(VIDEO_NUM_MODES),
&ulTemp) )
{
DBG_GDI((0, "getAvailableModes: failed VIDEO_QUERY_NUM_AVAIL_MODES"));
return(0);
}
*cbModeSize = modes.ModeInformationLength;
//
// Allocate the buffer for the mini-port to write the modes in.
//
*modeInformation = (VIDEO_MODE_INFORMATION*)ENGALLOCMEM(FL_ZERO_MEMORY,
modes.NumModes * modes.ModeInformationLength,
ALLOC_TAG);
if ( *modeInformation == (PVIDEO_MODE_INFORMATION)NULL )
{
DBG_GDI((0, "getAvailableModes: fFailed memory allocation"));
return 0;
}
//
// Ask the mini-port to fill in the available modes.
//
if ( EngDeviceIoControl(hDriver,
IOCTL_VIDEO_QUERY_AVAIL_MODES,
NULL,
0,
*modeInformation,
modes.NumModes * modes.ModeInformationLength,
&ulTemp) )
{
DBG_GDI((0, "getAvailableModes: failed VIDEO_QUERY_AVAIL_MODES"));
ENGFREEMEM(*modeInformation);
*modeInformation = (PVIDEO_MODE_INFORMATION)NULL;
return (0);
}
//
// Now see which of these modes are supported by the display driver.
// A non-supported mode is invalidated by setting the length to 0.
//
ulTemp = modes.NumModes;
pVideoTemp = *modeInformation;
//
// Mode is rejected if it is not one plane, or not graphics, or is not
// one of 8, 16 or 32 bits per pel.
//
while ( ulTemp-- )
{
if ( (pVideoTemp->NumberOfPlanes != 1 )
||!(pVideoTemp->AttributeFlags & VIDEO_MODE_GRAPHICS)
||( (pVideoTemp->BitsPerPlane != 8)
&&(pVideoTemp->BitsPerPlane != 16)
&&(pVideoTemp->BitsPerPlane != 32))
|| (pVideoTemp->VisScreenWidth > 2000)
|| (pVideoTemp->VisScreenHeight > 2000) )
{
DBG_GDI((2, "getAvailableModes: rejecting miniport mode"));
DBG_GDI((2, " width = %li height = %li",
pVideoTemp->VisScreenWidth,
pVideoTemp->VisScreenHeight));
DBG_GDI((2, " bpp = %li freq = %li",
pVideoTemp->BitsPerPlane * pVideoTemp->NumberOfPlanes,
pVideoTemp->Frequency));
pVideoTemp->Length = 0;
}
pVideoTemp = (PVIDEO_MODE_INFORMATION)
(((PUCHAR)pVideoTemp) + modes.ModeInformationLength);
}
return (modes.NumModes);
}// getAvailableModes()
//-----------------------------Public*Routine----------------------------------
//
// BOOL DrvNotify
//
//-----------------------------------------------------------------------------
VOID
DrvNotify(SURFOBJ* pso,
ULONG iType,
PVOID pvData)
{
PPDev ppdev = (PPDev) pso->dhpdev;
switch( iType )
{
case DN_DEVICE_ORIGIN:
{
ppdev->ptlOrigin = *((POINTL*) pvData);
DBG_GDI((6,"DrvNotify: origin at %ld, %ld",
ppdev->ptlOrigin.x, ppdev->ptlOrigin.y));
}
break;
case DN_DRAWING_BEGIN:
{
bEnablePointer(ppdev);
bEnableBrushCache(ppdev);
}
break;
default:
// do nothing
break;
}
}// DrvNotify()
//-----------------------------Public*Routine----------------------------------
//
// ULONG DrvResetDevice
//
// This function is used by GDI to request that the specified device be
// reset to an operational state. Safe steps should be taken to keep
// data loss at a minimum. It may be called anytime between DrvEnablePDEV
// and DrvDisablePDEV.
//
// Parameters
// dhpdev------Identifies a handle to a PDEV. This value is the return value
// of DrvEnablePDEV. The PDEV describes the physical device for
// which a reset is requested.
//
// Upon successful reset of the device DRD_SUCCESS should be returned.
// Otherwise return DRD_ERROR.
//
//-----------------------------------------------------------------------------
ULONG
DrvResetDevice(
DHPDEV dhpdev,
PVOID Reserved
)
{
DBG_GDI((0, "DrvResetDevice called."));
// TODO: Place code to reset device here.
return DRD_ERROR;
}// DrvResetDevice()