|
|
/******************************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()
|