1784 lines
54 KiB
C
1784 lines
54 KiB
C
#include "precomp.h"
|
|
|
|
|
|
//
|
|
// OSI.C
|
|
// OS Isolation layer, display driver side
|
|
//
|
|
// Copyright(c) Microsoft 1997-
|
|
//
|
|
|
|
|
|
#include <version.h>
|
|
#include <ndcgver.h>
|
|
|
|
|
|
//
|
|
// These are the default 20 Windows colors, lifted from the base S3 driver.
|
|
//
|
|
// Global Table defining the 20 Window default colours. For 256 colour
|
|
// palettes the first 10 must be put at the beginning of the palette
|
|
// and the last 10 at the end of the palette.
|
|
const PALETTEENTRY s_aWinColors[20] =
|
|
{
|
|
{ 0, 0, 0, 0 }, // 0
|
|
{ 0x80,0, 0, 0 }, // 1
|
|
{ 0, 0x80,0, 0 }, // 2
|
|
{ 0x80,0x80,0, 0 }, // 3
|
|
{ 0, 0, 0x80,0 }, // 4
|
|
{ 0x80,0, 0x80,0 }, // 5
|
|
{ 0, 0x80,0x80,0 }, // 6
|
|
{ 0xC0,0xC0,0xC0,0 }, // 7
|
|
{ 192, 220, 192, 0 }, // 8
|
|
{ 166, 202, 240, 0 }, // 9
|
|
{ 255, 251, 240, 0 }, // 10
|
|
{ 160, 160, 164, 0 }, // 11
|
|
{ 0x80,0x80,0x80,0 }, // 12
|
|
{ 0xFF,0, 0 ,0 }, // 13
|
|
{ 0, 0xFF,0 ,0 }, // 14
|
|
{ 0xFF,0xFF,0 ,0 }, // 15
|
|
{ 0 ,0, 0xFF,0 }, // 16
|
|
{ 0xFF,0, 0xFF,0 }, // 17
|
|
{ 0, 0xFF,0xFF,0 }, // 18
|
|
{ 0xFF,0xFF,0xFF,0 }, // 19
|
|
};
|
|
|
|
|
|
|
|
//
|
|
// Functions supported by our Display Driver. Each entry is of the form:
|
|
//
|
|
// index - NT DDK defined index for the DDI function
|
|
//
|
|
// function - pointer to our intercept function
|
|
//
|
|
//
|
|
const DRVFN s_osiDriverFns[] =
|
|
{
|
|
//
|
|
// NT4 FUNCTIONS
|
|
//
|
|
{ INDEX_DrvEnablePDEV, (PFN)DrvEnablePDEV },
|
|
{ INDEX_DrvCompletePDEV, (PFN)DrvCompletePDEV },
|
|
{ INDEX_DrvDisablePDEV, (PFN)DrvDisablePDEV },
|
|
{ INDEX_DrvEnableSurface, (PFN)DrvEnableSurface },
|
|
{ INDEX_DrvDisableSurface, (PFN)DrvDisableSurface },
|
|
|
|
{ INDEX_DrvAssertMode, (PFN)DrvAssertMode },
|
|
{ INDEX_DrvResetPDEV, (PFN)DrvResetPDEV },
|
|
// INDEX_DrvCreateDeviceBitmap not used
|
|
// INDEX_DrvDeleteDeviceBitmap not used
|
|
{ INDEX_DrvRealizeBrush, (PFN)DrvRealizeBrush },
|
|
// INDEX_DrvDitherColor not used
|
|
{ INDEX_DrvStrokePath, (PFN)DrvStrokePath },
|
|
{ INDEX_DrvFillPath, (PFN)DrvFillPath },
|
|
|
|
{ INDEX_DrvStrokeAndFillPath, (PFN)DrvStrokeAndFillPath },
|
|
{ INDEX_DrvPaint, (PFN)DrvPaint },
|
|
{ INDEX_DrvBitBlt, (PFN)DrvBitBlt },
|
|
{ INDEX_DrvCopyBits, (PFN)DrvCopyBits },
|
|
{ INDEX_DrvStretchBlt, (PFN)DrvStretchBlt },
|
|
|
|
{ INDEX_DrvSetPalette, (PFN)DrvSetPalette },
|
|
{ INDEX_DrvTextOut, (PFN)DrvTextOut },
|
|
{ INDEX_DrvEscape, (PFN)DrvEscape },
|
|
// INDEX_DrvDrawEscape not used
|
|
// INDEX_DrvQueryFont not used
|
|
// INDEX_DrvQueryFontTree not used
|
|
// INDEX_DrvQueryFontData not used
|
|
{ INDEX_DrvSetPointerShape, (PFN)DrvSetPointerShape },
|
|
{ INDEX_DrvMovePointer, (PFN)DrvMovePointer },
|
|
|
|
{ INDEX_DrvLineTo, (PFN)DrvLineTo },
|
|
// INDEX_DrvSendPage not used
|
|
// INDEX_DrvStartPage not used
|
|
// INDEX_DrvEndDoc not used
|
|
// INDEX_DrvStartDoc not used
|
|
// INDEX_DrvGetGlyphMode not used
|
|
// INDEX_DrvSynchronize not used
|
|
{ INDEX_DrvSaveScreenBits, (PFN)DrvSaveScreenBits },
|
|
{ INDEX_DrvGetModes, (PFN)DrvGetModes },
|
|
// INDEX_DrvFree not used
|
|
// INDEX_DrvDestroyFont not used
|
|
// INDEX_DrvQueryFontCaps not used
|
|
// INDEX_DrvLoadFontFile not used
|
|
// INDEX_DrvUnloadFontFile not used
|
|
// INDEX_DrvFontManagement not used
|
|
// INDEX_DrvQueryTrueTypeTable not used
|
|
// INDEX_DrvQueryTrueTypeOutline not used
|
|
// INDEX_DrvGetTrueTypeFile not used
|
|
// INDEX_DrvQueryFontFile not used
|
|
// INDEX_DrvQueryAdvanceWidths not used
|
|
// INDEX_DrvSetPixelFormat not used
|
|
// INDEX_DrvDescribePixelFormat not used
|
|
// INDEX_DrvSwapBuffers not used
|
|
// INDEX_DrvStartBanding not used
|
|
// INDEX_DrvNextBand not used
|
|
// INDEX_DrvGetDirectDrawInfo not used
|
|
// INDEX_DrvEnableDirectDraw not used
|
|
// INDEX_DrvDisableDirectDraw not used
|
|
// INDEX_DrvQuerySpoolType not used
|
|
|
|
//
|
|
// NT5 FUNCTIONS - 5 of them currently. If you add to this list,
|
|
// update CFN_NT5 below.
|
|
//
|
|
// INDEX_DrvIcmCreateColorTransform not used
|
|
// INDEX_DrvIcmDeleteColorTransform not used
|
|
// INDEX_DrvIcmCheckBitmapBits not used
|
|
// INDEX_DrvIcmSetDeviceGammaRamp not used
|
|
{ INDEX_DrvGradientFill, (PFN)DrvGradientFill },
|
|
{ INDEX_DrvStretchBltROP, (PFN)DrvStretchBltROP },
|
|
|
|
{ INDEX_DrvPlgBlt, (PFN)DrvPlgBlt },
|
|
{ INDEX_DrvAlphaBlend, (PFN)DrvAlphaBlend },
|
|
// INDEX_DrvSynthesizeFont not used
|
|
// INDEX_DrvGetSynthesizedFontFiles not used
|
|
{ INDEX_DrvTransparentBlt, (PFN)DrvTransparentBlt },
|
|
// INDEX_DrvQueryPerBandInfo not used
|
|
// INDEX_DrvQueryDeviceSupport not used
|
|
// INDEX_DrvConnect not used
|
|
// INDEX_DrvDisconnect not used
|
|
// INDEX_DrvReconnect not used
|
|
// INDEX_DrvShadowConnect not used
|
|
// INDEX_DrvShadowDisconnect not used
|
|
// INDEX_DrvInvalidateRect not used
|
|
// INDEX_DrvSetPointerPos not used
|
|
// INDEX_DrvDisplayIOCtl not used
|
|
// INDEX_DrvDeriveSurface not used
|
|
// INDEX_DrvQueryGlyphAttrs not used
|
|
};
|
|
|
|
|
|
#define CFN_NT5 5
|
|
|
|
|
|
|
|
//
|
|
// s_osiDefaultGdi
|
|
//
|
|
// 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.
|
|
//
|
|
// It is expected that DDML ignores a lot of these parameters and
|
|
// uses the values from the primary driver instead
|
|
//
|
|
|
|
const GDIINFO s_osiDefaultGdi =
|
|
{
|
|
GDI_DRIVER_VERSION,
|
|
DT_RASDISPLAY, // ulTechnology
|
|
400, // ulHorzSize (display width: mm)
|
|
300, // ulVertSize (display height: mm)
|
|
0, // ulHorzRes (filled in later)
|
|
0, // ulVertRes (filled in later)
|
|
0, // cBitsPixel (filled in later)
|
|
1, // cPlanes
|
|
(ULONG)-1, // ulNumColors (palette managed)
|
|
0, // flRaster (DDI reserved field)
|
|
96, // ulLogPixelsX (filled in later)
|
|
96, // ulLogPixelsY (filled in later)
|
|
TC_RA_ABLE, // flTextCaps - If we had wanted console windows
|
|
// to scroll by repainting the entire window,
|
|
// instead of doing a screen-to-screen blt, we
|
|
// would have set TC_SCROLLBLT (yes, the flag
|
|
// is backwards).
|
|
|
|
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, // yStyleStep
|
|
3, // denStyleStep -- Styles have a one-to-one
|
|
// aspect ratio, and every dot is 3 pixels long
|
|
{ 0, 0 }, // ptlPhysOffset
|
|
{ 0, 0 }, // szlPhysSize
|
|
0, // ulNumPalReg
|
|
|
|
{
|
|
{ 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, // ulBltAlignment
|
|
0, // ulPanningHorzRes
|
|
0, // ulPanningVertRes
|
|
};
|
|
|
|
|
|
//
|
|
// s_osiDefaultDevInfo
|
|
//
|
|
// 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.
|
|
//
|
|
//
|
|
const DEVINFO s_osiDefaultDevInfo =
|
|
{
|
|
{
|
|
GCAPS_OPAQUERECT |
|
|
GCAPS_DITHERONREALIZE |
|
|
GCAPS_PALMANAGED |
|
|
GCAPS_MONO_DITHER |
|
|
GCAPS_COLOR_DITHER |
|
|
GCAPS_LAYERED
|
|
}, // NOTE: Only enable ASYNCMOVE if your code
|
|
// and hardware can handle DrvMovePointer
|
|
// calls at any time, even while another
|
|
// thread is in the middle of a drawing
|
|
// call such as DrvBitBlt.
|
|
|
|
// flGraphicsFlags
|
|
{ 16,7,0,0,700,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
|
|
VARIABLE_PITCH | FF_DONTCARE, L"System"
|
|
},
|
|
// lfDefaultFont
|
|
|
|
{
|
|
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"
|
|
},
|
|
// lfAnsiVarFont
|
|
|
|
{
|
|
12,9,0,0,400,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
|
|
CLIP_STROKE_PRECIS,PROOF_QUALITY,
|
|
FIXED_PITCH | FF_DONTCARE, L"Courier"
|
|
},
|
|
// lfAnsiFixFont
|
|
|
|
0, // cFonts
|
|
BMF_8BPP, // iDitherFormat
|
|
8, // cxDither
|
|
8, // cyDither
|
|
0 // hpalDefault (filled in later)
|
|
};
|
|
|
|
|
|
|
|
//
|
|
// DrvEnableDriver - see NT DDK documentation.
|
|
//
|
|
// This is the only directly exported entry point to the display driver.
|
|
// All other entry points are exported through the data returned from this
|
|
// function.
|
|
//
|
|
BOOL DrvEnableDriver
|
|
(
|
|
ULONG iEngineVersion,
|
|
ULONG cj,
|
|
DRVENABLEDATA* pded
|
|
)
|
|
{
|
|
DebugEntry(DrvEnableDriver);
|
|
|
|
INIT_OUT(("DrvEnableDriver(iEngineVersion = 0x%08x)", iEngineVersion));
|
|
|
|
//
|
|
// Check that the engine version is correct - we refuse to load on
|
|
// other versions because we will almost certainly not work.
|
|
//
|
|
if (iEngineVersion < DDI_DRIVER_VERSION_SP3)
|
|
{
|
|
INIT_OUT(("DrvEnableDriver: Not NT 4.0 SP-3 or NT 5.0; failing enable"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Fill in as much as we can. Start with the entry points.
|
|
//
|
|
if ( cj >= FIELD_OFFSET(DRVENABLEDATA, pdrvfn) +
|
|
FIELD_SIZE (DRVENABLEDATA, pdrvfn) )
|
|
{
|
|
pded->pdrvfn = (DRVFN *)s_osiDriverFns;
|
|
}
|
|
|
|
//
|
|
// Size of our entry point array.
|
|
//
|
|
if ( cj >= FIELD_OFFSET(DRVENABLEDATA, c) +
|
|
FIELD_SIZE (DRVENABLEDATA, c) )
|
|
{
|
|
//
|
|
// If this is NT4, return back a subset -- it doesn't like tables
|
|
// with unknown indeces
|
|
//
|
|
pded->c = sizeof(s_osiDriverFns) / sizeof(s_osiDriverFns[0]);
|
|
if (iEngineVersion < DDI_DRIVER_VERSION_NT5)
|
|
{
|
|
pded->c -= CFN_NT5;
|
|
}
|
|
INIT_OUT(("DrvEnableDriver: Returning driver function count %u", pded->c));
|
|
}
|
|
|
|
//
|
|
// DDI version this driver was targeted for is passed back to engine.
|
|
// Future graphics engines may break calls down to old driver format.
|
|
//
|
|
if ( cj >= FIELD_OFFSET(DRVENABLEDATA, iDriverVersion) +
|
|
FIELD_SIZE (DRVENABLEDATA, iDriverVersion) )
|
|
{
|
|
//
|
|
// Return back NT5 when we're on NT5. Hopefully this will work
|
|
// OK...
|
|
//
|
|
pded->iDriverVersion = iEngineVersion;
|
|
INIT_OUT(("DrvEnableDriver: Returning driver version 0x%08x", pded->iDriverVersion));
|
|
}
|
|
|
|
DebugExitVOID(DrvEnableDriver);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvDisableDriver - see NT DDK documentation.
|
|
//
|
|
VOID DrvDisableDriver(VOID)
|
|
{
|
|
DebugEntry(DrvDisableDriver);
|
|
|
|
DebugExitVOID(DrvDisableDriver);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvEnablePDEV - see NT DDK documentation.
|
|
//
|
|
// 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 us.
|
|
//
|
|
// (This function mostly returns back information; DrvEnableSurface is used
|
|
// for initializing the hardware and driver components.)
|
|
//
|
|
//
|
|
DHPDEV DrvEnablePDEV(DEVMODEW* pdm,
|
|
PWSTR pwszLogAddr,
|
|
ULONG cPat,
|
|
HSURF* phsurfPatterns,
|
|
ULONG cjCaps,
|
|
ULONG* pdevcaps,
|
|
ULONG cjDevInfo,
|
|
DEVINFO* pdi,
|
|
HDEV hdev,
|
|
PWSTR pwszDeviceName,
|
|
HANDLE hDriver)
|
|
{
|
|
DHPDEV rc = NULL;
|
|
LPOSI_PDEV ppdev = NULL;
|
|
GDIINFO gdiInfoNew;
|
|
|
|
DebugEntry(DrvEnablePDEV);
|
|
|
|
INIT_OUT(("DrvEnablePDEV: Parameters:"));
|
|
INIT_OUT((" PWSTR pdm->dmDeviceName %ws", pdm->dmDeviceName));
|
|
INIT_OUT((" HDEV hdev 0x%08x", hdev));
|
|
INIT_OUT((" PWSTR pwszDeviceName %ws", pwszDeviceName));
|
|
INIT_OUT((" HANDLE hDriver 0x%08x", hDriver));
|
|
|
|
//
|
|
// This function only sets up local data, so shared memory protection
|
|
// is not required.
|
|
//
|
|
|
|
//
|
|
// Make sure that we have large enough data to reference.
|
|
//
|
|
if ((cjCaps < sizeof(GDIINFO)) || (cjDevInfo < sizeof(DEVINFO)))
|
|
{
|
|
ERROR_OUT(( "Buffer size too small %lu %lu", cjCaps, cjDevInfo));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Allocate a physical device structure.
|
|
//
|
|
ppdev = EngAllocMem(FL_ZERO_MEMORY, sizeof(OSI_PDEV), OSI_ALLOC_TAG);
|
|
if (ppdev == NULL)
|
|
{
|
|
ERROR_OUT(( "DrvEnablePDEV - Failed EngAllocMem"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
ppdev->hDriver = hDriver;
|
|
|
|
//
|
|
// Set up the current screen mode information based upon the supplied
|
|
// mode settings.
|
|
//
|
|
if (!OSIInitializeMode((GDIINFO *)pdevcaps,
|
|
pdm,
|
|
ppdev,
|
|
&gdiInfoNew,
|
|
pdi))
|
|
{
|
|
ERROR_OUT(( "Failed to initialize mode"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
memcpy(pdevcaps, &gdiInfoNew, min(sizeof(GDIINFO), cjCaps));
|
|
|
|
INIT_OUT(("DrvEnablePDEV: Returning DEVINFO:"));
|
|
INIT_OUT((" FLONG flGraphicsCaps 0x%08x", pdi->flGraphicsCaps));
|
|
INIT_OUT((" ULONG iDitherFormat %d", pdi->iDitherFormat));
|
|
INIT_OUT((" HPALETTE hpalDefault 0x%08x", pdi->hpalDefault));
|
|
|
|
INIT_OUT(("DrvEnablePDEV: Returning GDIINFO (pdevcaps):"));
|
|
INIT_OUT((" ULONG ulVersion 0x%08x", gdiInfoNew.ulVersion));
|
|
INIT_OUT((" ULONG ulHorzSize %d", gdiInfoNew.ulHorzSize));
|
|
INIT_OUT((" ULONG ulVertSize %d", gdiInfoNew.ulVertSize));
|
|
INIT_OUT((" ULONG ulHorzRes %d", gdiInfoNew.ulHorzRes));
|
|
INIT_OUT((" ULONG ulVertRes %d", gdiInfoNew.ulVertRes));
|
|
INIT_OUT((" ULONG cBitsPixel %d", gdiInfoNew.cBitsPixel));
|
|
INIT_OUT((" ULONG cPlanes %d", gdiInfoNew.cPlanes));
|
|
INIT_OUT((" ULONG ulNumColors %d", gdiInfoNew.ulNumColors));
|
|
INIT_OUT((" ULONG ulDACRed 0x%08x", gdiInfoNew.ulDACRed));
|
|
INIT_OUT((" ULONG ulDACGreen 0x%08x", gdiInfoNew.ulDACGreen));
|
|
INIT_OUT((" ULONG ulDACBlue 0x%08x", gdiInfoNew.ulDACBlue));
|
|
INIT_OUT((" ULONG ulHTOutputFormat %d", gdiInfoNew.ulHTOutputFormat));
|
|
|
|
//
|
|
// We have successfully initialized - return the new PDEV.
|
|
//
|
|
rc = (DHPDEV)ppdev;
|
|
|
|
DC_EXIT_POINT:
|
|
//
|
|
// Release any resources if we failed to initialize.
|
|
//
|
|
if (rc == NULL)
|
|
{
|
|
ERROR_OUT(("DrvEnablePDEV failed; cleaning up by disabling"));
|
|
DrvDisablePDEV(NULL);
|
|
}
|
|
|
|
DebugExitPVOID(DrvEnablePDEV, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvDisablePDEV - see NT DDK documentation
|
|
//
|
|
// Release the resources allocated in DrvEnablePDEV. If a surface has been
|
|
// enabled DrvDisableSurface will have already been called.
|
|
//
|
|
// Note that this function will be called when previewing modes in the
|
|
// Display Applet, but not at system shutdown.
|
|
//
|
|
// Note: In an error, we may call this before DrvEnablePDEV is done.
|
|
//
|
|
//
|
|
VOID DrvDisablePDEV(DHPDEV dhpdev)
|
|
{
|
|
LPOSI_PDEV ppdev = (LPOSI_PDEV)dhpdev;
|
|
|
|
DebugEntry(DrvDisablePDEV);
|
|
|
|
INIT_OUT(("DrvDisablePDEV(dhpdev = 0x%08x)", dhpdev));
|
|
|
|
//
|
|
// Free the resources we allocated for the display.
|
|
//
|
|
if (ppdev != NULL)
|
|
{
|
|
if (ppdev->hpalCreated != NULL)
|
|
{
|
|
EngDeletePalette(ppdev->hpalCreated);
|
|
ppdev->hpalCreated = NULL;
|
|
}
|
|
|
|
if (ppdev->pPal != NULL)
|
|
{
|
|
EngFreeMem(ppdev->pPal);
|
|
ppdev->pPal = NULL;
|
|
}
|
|
|
|
EngFreeMem(ppdev);
|
|
}
|
|
|
|
DebugExitVOID(DrvDisablePDEV);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvCompletePDEV - see NT DDK documentation
|
|
//
|
|
// Stores the HPDEV, the engine's handle for this PDEV, in the DHPDEV.
|
|
//
|
|
VOID DrvCompletePDEV( DHPDEV dhpdev,
|
|
HDEV hdev )
|
|
{
|
|
DebugEntry(DrvCompletePDEV);
|
|
|
|
//
|
|
// Store the device handle for our display handle.
|
|
//
|
|
INIT_OUT(("DrvCompletePDEV(dhpdev = 0x%08x, hdev = 0x%08x)", dhpdev, hdev));
|
|
|
|
((LPOSI_PDEV)dhpdev)->hdevEng = hdev;
|
|
|
|
DebugExitVOID(DrvCompletePDEV);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvResetPDEV - see NT DDK documentation
|
|
//
|
|
// Allows us to reject dynamic screen changes if necessary ON NT4 ONLY
|
|
// This is NOT CALLED on NT5.
|
|
//
|
|
BOOL DrvResetPDEV
|
|
(
|
|
DHPDEV dhpdevOld,
|
|
DHPDEV dhpdevNew
|
|
)
|
|
{
|
|
BOOL rc = TRUE;
|
|
|
|
DebugEntry(DrvResetPDEV);
|
|
|
|
INIT_OUT(("DrvResetPDEV(dhpdevOld = 0x%08x, dhpdevNew = 0x%08x)", dhpdevOld,
|
|
dhpdevNew));
|
|
|
|
//
|
|
// We can only allow the display driver to change modes while DC-Share
|
|
// is not running.
|
|
//
|
|
if (g_shmMappedMemory != NULL)
|
|
{
|
|
//
|
|
// Deny the request.
|
|
//
|
|
rc = FALSE;
|
|
}
|
|
|
|
DebugExitDWORD(DrvResetPDEV, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvEnableSurface - see NT DDK documentation
|
|
//
|
|
// Creates the drawing surface and initializes driver components. This
|
|
// function is called after DrvEnablePDEV, and performs the final device
|
|
// initialization.
|
|
//
|
|
//
|
|
HSURF DrvEnableSurface(DHPDEV dhpdev)
|
|
{
|
|
LPOSI_PDEV ppdev = (LPOSI_PDEV)dhpdev;
|
|
HSURF hsurf;
|
|
SIZEL sizl;
|
|
LPOSI_DSURF pdsurf;
|
|
HSURF rc = 0;
|
|
|
|
DWORD returnedDataLength;
|
|
DWORD MaxWidth, MaxHeight;
|
|
VIDEO_MEMORY videoMemory;
|
|
VIDEO_MEMORY_INFORMATION videoMemoryInformation;
|
|
|
|
DebugEntry(DrvEnableSurface);
|
|
|
|
INIT_OUT(("DrvEnableSurface: Parameters:"));
|
|
INIT_OUT((" LPOSI_PDEV ppdev 0x%08x", ppdev));
|
|
INIT_OUT((" HDRIVER ->hDriver 0x%08x", ppdev->hDriver));
|
|
INIT_OUT((" INT ->cxScreen %d", ppdev->cxScreen));
|
|
INIT_OUT((" INT ->cyScreen %d", ppdev->cyScreen));
|
|
|
|
//
|
|
// Now create our private surface structure.
|
|
//
|
|
// Whenever we get a call to draw directly to the screen, we'll get
|
|
// passed a pointer to a SURFOBJ whose 'dhpdev' field will point
|
|
// to our PDEV structure, and whose 'dhsurf' field will point to the
|
|
// DSURF structure allocated below.
|
|
//
|
|
// Every device bitmap we create in DrvCreateDeviceBitmap will also
|
|
// have its own unique DSURF structure allocated (but will share the
|
|
// same PDEV). To make our code more polymorphic for handling drawing
|
|
// to either the screen or an off-screen bitmap, we have the same
|
|
// structure for both.
|
|
//
|
|
pdsurf = EngAllocMem(FL_ZERO_MEMORY, sizeof(OSI_DSURF), OSI_ALLOC_TAG);
|
|
if (pdsurf == NULL)
|
|
{
|
|
ERROR_OUT(( "DrvEnableSurface - Failed pdsurf EngAllocMem"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Store the screen surface details.
|
|
//
|
|
ppdev->pdsurfScreen = pdsurf;
|
|
pdsurf->sizl.cx = ppdev->cxScreen;
|
|
pdsurf->sizl.cy = ppdev->cyScreen;
|
|
pdsurf->ppdev = ppdev;
|
|
|
|
INIT_OUT(("DrvEnableSurface: Returning surface pointer 0x%08x", pdsurf));
|
|
|
|
//
|
|
// Only map the shared memory the first time we are called.
|
|
//
|
|
if (g_asSharedMemory == NULL)
|
|
{
|
|
//
|
|
// Map the pointer to the shared section in the miniport driver
|
|
//
|
|
videoMemory.RequestedVirtualAddress = NULL;
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_MAP_VIDEO_MEMORY,
|
|
&videoMemory,
|
|
sizeof(VIDEO_MEMORY),
|
|
&videoMemoryInformation,
|
|
sizeof(VIDEO_MEMORY_INFORMATION),
|
|
&returnedDataLength))
|
|
{
|
|
ERROR_OUT(( "Could not MAP miniport section"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
INIT_OUT(("DrvEnableSurface: Got video memory info from EngDeviceIoControl:"));
|
|
INIT_OUT((" FrameBufferBase 0x%08x", videoMemoryInformation.FrameBufferBase));
|
|
INIT_OUT((" FrameBufferLength 0x%08x", videoMemoryInformation.FrameBufferLength));
|
|
|
|
g_shmSharedMemorySize = videoMemoryInformation.FrameBufferLength;
|
|
|
|
// First block is shared memory header
|
|
g_asSharedMemory = (LPSHM_SHARED_MEMORY)
|
|
videoMemoryInformation.FrameBufferBase;
|
|
|
|
// Next are the two large OA_FAST_DATA blocks
|
|
g_poaData[0] = (LPOA_SHARED_DATA)(g_asSharedMemory + 1);
|
|
g_poaData[1] = (LPOA_SHARED_DATA)(g_poaData[0] + 1);
|
|
}
|
|
|
|
//
|
|
// Next, have GDI create the actual SURFOBJ.
|
|
//
|
|
// Our drawing surface is going to be 'device-managed', meaning that
|
|
// GDI cannot draw on the framebuffer bits directly, and as such we
|
|
// create the surface via EngCreateDeviceSurface. By doing this, we
|
|
// ensure that GDI will only ever access the bitmaps bits via the Drv
|
|
// calls that we've HOOKed.
|
|
//
|
|
sizl.cx = ppdev->cxScreen;
|
|
sizl.cy = ppdev->cyScreen;
|
|
|
|
//
|
|
// Otherwise the primary display driver has its own bitmap used by the
|
|
// physical hardware, so we do not need to do any drawing ourself.
|
|
//
|
|
INIT_OUT(("DrvEnableSurface: Calling EngCreateDeviceSurface with:"));
|
|
INIT_OUT((" Sizl.cx %d", sizl.cx));
|
|
INIT_OUT((" Sizl.cy %d", sizl.cy));
|
|
INIT_OUT((" BitmapFormat %d", ppdev->iBitmapFormat));
|
|
|
|
hsurf = EngCreateDeviceSurface( (DHSURF)pdsurf,
|
|
sizl,
|
|
ppdev->iBitmapFormat );
|
|
|
|
if (hsurf == 0)
|
|
{
|
|
ERROR_OUT(( "Could not allocate surface"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Store the screen surface handle.
|
|
//
|
|
ppdev->hsurfScreen = hsurf;
|
|
|
|
//
|
|
// Now associate the surface and the PDEV.
|
|
//
|
|
// 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).
|
|
//
|
|
if (!EngAssociateSurface(hsurf, ppdev->hdevEng,
|
|
HOOK_BITBLT |
|
|
HOOK_STRETCHBLT |
|
|
HOOK_PLGBLT |
|
|
HOOK_TEXTOUT |
|
|
HOOK_PAINT | // OBSOLETE
|
|
HOOK_STROKEPATH |
|
|
HOOK_FILLPATH |
|
|
HOOK_STROKEANDFILLPATH |
|
|
HOOK_LINETO |
|
|
HOOK_COPYBITS |
|
|
HOOK_STRETCHBLTROP |
|
|
HOOK_TRANSPARENTBLT |
|
|
HOOK_ALPHABLEND |
|
|
HOOK_GRADIENTFILL |
|
|
HOOK_SYNCHRONIZEACCESS)) // OBSOLETE
|
|
{
|
|
ERROR_OUT(( "DrvEnableSurface - Failed EngAssociateSurface"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// We have successfully associated the surface so return it to the GDI.
|
|
//
|
|
rc = hsurf;
|
|
|
|
DC_EXIT_POINT:
|
|
//
|
|
// Tidy up any resources if we failed.
|
|
//
|
|
if (rc == 0)
|
|
{
|
|
DrvDisableSurface((DHPDEV) ppdev);
|
|
}
|
|
|
|
DebugExitPVOID(DrvEnableSurface, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvDisableSurface - see NT DDK documentation
|
|
//
|
|
// Free resources allocated by DrvEnableSurface. Release the surface.
|
|
//
|
|
// Note that this function will be called when previewing modes in the
|
|
// Display Applet, but not at system shutdown. If you need to reset the
|
|
// hardware at shutdown, you can do it in the miniport by providing a
|
|
// 'HwResetHw' entry point in the VIDEO_HW_INITIALIZATION_DATA structure.
|
|
//
|
|
// Note: In an error case, we may call this before DrvEnableSurface is
|
|
// completely done.
|
|
//
|
|
VOID DrvDisableSurface(DHPDEV dhpdev)
|
|
{
|
|
LPOSI_PDEV ppdev = (LPOSI_PDEV)dhpdev;
|
|
|
|
DebugEntry(DrvDisableSurface);
|
|
|
|
INIT_OUT(("DrvDisableSurface(dhpdev = 0x%08x)", dhpdev));
|
|
|
|
if (ppdev->hsurfScreen != 0)
|
|
{
|
|
EngDeleteSurface(ppdev->hsurfScreen);
|
|
}
|
|
|
|
if (ppdev->pdsurfScreen != NULL)
|
|
{
|
|
EngFreeMem(ppdev->pdsurfScreen);
|
|
}
|
|
|
|
DebugExitVOID(DrvDisableSurface);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvEscape - see NT DDK documentation.
|
|
//
|
|
ULONG DrvEscape(SURFOBJ *pso,
|
|
ULONG iEsc,
|
|
ULONG cjIn,
|
|
PVOID pvIn,
|
|
ULONG cjOut,
|
|
PVOID pvOut)
|
|
{
|
|
ULONG rc = FALSE;
|
|
LPOSI_ESCAPE_HEADER pHeader;
|
|
|
|
DebugEntry(DrvEscape);
|
|
|
|
TRACE_OUT(("DrvEscape called with escape %d", iEsc));
|
|
|
|
//
|
|
// All functions we support use an identifier in the input data to make
|
|
// sure that we don't try to use another driver's escape functions. If
|
|
// the identifier is not present, we must not process the request.
|
|
//
|
|
// NOTE: This function is NOT protected for shared memory access
|
|
// because it is responsible for allocating / deallocating the shared
|
|
// memory.
|
|
//
|
|
|
|
//
|
|
// Check the data is long enough to store our standard escape header.
|
|
// If it is not big enough this must be an escape request for another
|
|
// driver.
|
|
//
|
|
if (cjIn < sizeof(OSI_ESCAPE_HEADER))
|
|
{
|
|
INIT_OUT(("DrvEscape ignoring; input size %04d too small", cjIn));
|
|
WARNING_OUT(("DrvEscape ignoring; input size %04d too small", cjIn));
|
|
DC_QUIT;
|
|
}
|
|
if (cjOut < sizeof(OSI_ESCAPE_HEADER))
|
|
{
|
|
INIT_OUT(("DrvEscape ignoring; output size %04d too small", cjOut));
|
|
WARNING_OUT(("DrvEscape ignoring; output size %04d too small", cjOut));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Check for our escape ID. If it is not our escape ID this must be an
|
|
// escape request for another driver.
|
|
//
|
|
pHeader = pvIn;
|
|
if (pHeader->identifier != OSI_ESCAPE_IDENTIFIER)
|
|
{
|
|
INIT_OUT(("DrvEscape ignoring; identifier 0x%08x is not for NetMtg", pHeader->identifier));
|
|
WARNING_OUT(("DrvEscape ignoring; identifier 0x%08x is not for NetMtg", pHeader->identifier));
|
|
DC_QUIT;
|
|
}
|
|
else if (pHeader->version != DCS_MAKE_VERSION())
|
|
{
|
|
INIT_OUT(("DrvEscape failing; version 0x%08x of NetMtg is not that of driver",
|
|
pHeader->version));
|
|
WARNING_OUT(("DrvEscape failing; version 0x%08x of NetMtg is not that of driver",
|
|
pHeader->version));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// If we haven't initialized yet, fail all other escapes.
|
|
//
|
|
if (g_shmMappedMemory == NULL)
|
|
{
|
|
if ((iEsc != OSI_ESC_CODE) || (pHeader->escapeFn != OSI_ESC_INIT))
|
|
{
|
|
WARNING_OUT(("DrvEscape failing; driver not initialized"));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Everything is tickety boo - process the request.
|
|
//
|
|
switch (iEsc)
|
|
{
|
|
case OSI_ESC_CODE:
|
|
{
|
|
//
|
|
// This is a request from the share core. Pass it on to the
|
|
// correct component.
|
|
//
|
|
TRACE_OUT(( "Function %ld", pHeader->escapeFn));
|
|
|
|
if( // (pHeader->escapeFn >= OSI_ESC_FIRST) && Always True
|
|
(pHeader->escapeFn <= OSI_ESC_LAST ) )
|
|
{
|
|
//
|
|
// OSI requests.
|
|
//
|
|
rc = OSI_DDProcessRequest(pso, cjIn, pvIn, cjOut, pvOut);
|
|
}
|
|
else if( (pHeader->escapeFn >= OSI_OE_ESC_FIRST) &&
|
|
(pHeader->escapeFn <= OSI_OE_ESC_LAST ) )
|
|
{
|
|
//
|
|
// Order Encoder requests.
|
|
//
|
|
rc = OE_DDProcessRequest(pso, cjIn, pvIn, cjOut, pvOut);
|
|
}
|
|
else if( (pHeader->escapeFn >= OSI_HET_ESC_FIRST) &&
|
|
(pHeader->escapeFn <= OSI_HET_ESC_LAST) )
|
|
{
|
|
//
|
|
// Non-locking (wnd tracking) HET requests
|
|
//
|
|
rc = HET_DDProcessRequest(pso, cjIn, pvIn, cjOut, pvOut);
|
|
}
|
|
else if( (pHeader->escapeFn >= OSI_SBC_ESC_FIRST) &&
|
|
(pHeader->escapeFn <= OSI_SBC_ESC_LAST ) )
|
|
{
|
|
//
|
|
// Send Bitmap Cache requests
|
|
//
|
|
rc = SBC_DDProcessRequest(pso, pHeader->escapeFn, pvIn, pvOut, cjOut);
|
|
}
|
|
else if( (pHeader->escapeFn >= OSI_SSI_ESC_FIRST) &&
|
|
(pHeader->escapeFn <= OSI_SSI_ESC_LAST ) )
|
|
{
|
|
//
|
|
// Save Screen Bits requests.
|
|
//
|
|
rc = SSI_DDProcessRequest(pHeader->escapeFn, pHeader, cjIn);
|
|
}
|
|
else if( (pHeader->escapeFn >= OSI_CM_ESC_FIRST) &&
|
|
(pHeader->escapeFn <= OSI_CM_ESC_LAST ) )
|
|
{
|
|
//
|
|
// Cursor Manager requests
|
|
//
|
|
rc = CM_DDProcessRequest(pso, cjIn, pvIn, cjOut, pvOut);
|
|
}
|
|
else if( (pHeader->escapeFn >= OSI_OA_ESC_FIRST) &&
|
|
(pHeader->escapeFn <= OSI_OA_ESC_LAST ) )
|
|
{
|
|
//
|
|
// Order Accumulator requests.
|
|
//
|
|
rc = OA_DDProcessRequest(pHeader->escapeFn, pHeader, cjIn);
|
|
}
|
|
else if( (pHeader->escapeFn >= OSI_BA_ESC_FIRST) &&
|
|
(pHeader->escapeFn <= OSI_BA_ESC_LAST ) )
|
|
{
|
|
//
|
|
// Bounds Accumulator requests.
|
|
//
|
|
rc = BA_DDProcessRequest(pHeader->escapeFn, pHeader, cjIn,
|
|
pvOut, cjOut);
|
|
}
|
|
else
|
|
{
|
|
WARNING_OUT(( "Unknown function", pHeader->escapeFn));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WNDOBJ_SETUP:
|
|
{
|
|
if ((pHeader->escapeFn >= OSI_HET_WO_ESC_FIRST) &&
|
|
(pHeader->escapeFn <= OSI_HET_WO_ESC_LAST))
|
|
{
|
|
TRACE_OUT(("WNDOBJ_SETUP Escape code - pass to HET"));
|
|
rc = HET_DDProcessRequest(pso, cjIn, pvIn, cjOut, pvOut);
|
|
}
|
|
else
|
|
{
|
|
INIT_OUT(("WNDOBJ_SETUP Escape is unrecognized, ignore"));
|
|
WARNING_OUT(("WNDOBJ_SETUP Escape is unrecognized, ignore"));
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ERROR_OUT(( "Unrecognised request %lu", iEsc));
|
|
}
|
|
break;
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitDWORD(DrvEscape, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvSetPalette - see NT DDK documentation.
|
|
//
|
|
BOOL DrvSetPalette(DHPDEV dhpdev,
|
|
PALOBJ* ppalo,
|
|
FLONG fl,
|
|
ULONG iStart,
|
|
ULONG cColors)
|
|
{
|
|
BOOL rc = FALSE;
|
|
LPOSI_PDEV ppdev = (LPOSI_PDEV)dhpdev;
|
|
|
|
DebugEntry(DrvSetPalette);
|
|
|
|
//
|
|
// Check that this doesn't hose our palette. Note that NT passes a
|
|
// zero indexed array element and a count, hence to fill a palette, the
|
|
// values are 'start at 0 with 256 colours'. Thus a total of 256 is
|
|
// the maximum for our 8-bit palette.
|
|
//
|
|
if (iStart + cColors > OSI_MAX_PALETTE)
|
|
{
|
|
ERROR_OUT(("Overflow: start %lu count %lu", iStart, cColors));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Fill in the palette
|
|
//
|
|
if (cColors != PALOBJ_cGetColors(ppalo,
|
|
iStart,
|
|
cColors,
|
|
(ULONG*)&ppdev->pPal[iStart]))
|
|
{
|
|
//
|
|
// Don't bother tracing the return code - it's always 0.
|
|
//
|
|
ERROR_OUT(("Failed to read palette"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// BOGUS LAURABU!
|
|
// For NT 5.0, do we need to turn around and reset the contents of
|
|
// our created palette object with these new color values? Real
|
|
// display drivers don't (S3 e.g.)
|
|
//
|
|
|
|
//
|
|
// Set the flag in the PDEV to indicate that the palette has changed
|
|
//
|
|
ppdev->paletteChanged = TRUE;
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(DrvSetPalette, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvGetModes - see NT DDK documentation
|
|
//
|
|
// Returns the list of available modes for the device.
|
|
// As a mirroring driver, we return 0. That will cause NT GRE to use
|
|
// whatever ChangeDisplaySettingsEx passed along.
|
|
//
|
|
ULONG DrvGetModes
|
|
(
|
|
HANDLE hDriver,
|
|
ULONG cjSize,
|
|
DEVMODEW* pdm
|
|
)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
//
|
|
// DrvAssertMode - see NT DDK documentation.
|
|
//
|
|
BOOL DrvAssertMode
|
|
(
|
|
DHPDEV dhpdev,
|
|
BOOL bEnable
|
|
)
|
|
{
|
|
LPOSI_PDEV ppdev = (LPOSI_PDEV)dhpdev;
|
|
|
|
DebugEntry(DrvAssertMode);
|
|
|
|
INIT_OUT(("DrvAssertMode(dhpdev = 0x%08x, bEnable = %d)", dhpdev, bEnable));
|
|
|
|
//
|
|
// Check for fullscreen switching.
|
|
//
|
|
if ((g_asSharedMemory != NULL) && (ppdev != NULL))
|
|
{
|
|
g_asSharedMemory->fullScreen = (BOOL)(!bEnable);
|
|
TRACE_OUT(("Fullscreen is now %d", g_asSharedMemory->fullScreen));
|
|
}
|
|
|
|
DebugExitVOID(DrvAssertMode);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Name: OSIInitializeMode
|
|
//
|
|
// Purpose:
|
|
//
|
|
// Initializes a bunch of fields in the pdev, devcaps (aka gdiinfo), and
|
|
// devinfo based on the requested mode.
|
|
//
|
|
// Returns:
|
|
//
|
|
// TRUE - Successfully initialized the data
|
|
// FALSE - Failed to set up mode data
|
|
//
|
|
// Params:
|
|
//
|
|
// pgdiRequested - GDI info from the primary display driver (empty in NT 5.0)
|
|
// pdmRequested - DEVMODE info with GDI's requested settings for our driver
|
|
// ppdev - Our driver's private copy of settings, values
|
|
// pgdiReturn - GDI info to return for our driver
|
|
// pdiReturn - DEVINFO to return for our driver
|
|
//
|
|
BOOL OSIInitializeMode
|
|
(
|
|
const GDIINFO* pgdiRequested,
|
|
const DEVMODEW* pdmRequested,
|
|
LPOSI_PDEV ppdev,
|
|
GDIINFO* pgdiReturn,
|
|
DEVINFO* pdiReturn
|
|
)
|
|
{
|
|
BOOL rc = FALSE;
|
|
HPALETTE hpal;
|
|
ULONG cColors;
|
|
ULONG iMode;
|
|
|
|
DebugEntry(OSIInitializeMode);
|
|
|
|
INIT_OUT(("DrvEnablePDEV: DEVMODEW requested contains:"));
|
|
INIT_OUT((" Screen width -- %li", pdmRequested->dmPelsWidth));
|
|
INIT_OUT((" Screen height -- %li", pdmRequested->dmPelsHeight));
|
|
INIT_OUT((" Bits per pel -- %li", pdmRequested->dmBitsPerPel));
|
|
INIT_OUT(("DrvEnablePDEV: DEVINFO parameter contains:"));
|
|
INIT_OUT((" flGraphicsCaps -- 0x%08x", pdiReturn->flGraphicsCaps));
|
|
INIT_OUT((" iDitherFormat -- 0x%08x", pdiReturn->iDitherFormat));
|
|
INIT_OUT((" hpalDefault -- 0x%08x", pdiReturn->hpalDefault));
|
|
INIT_OUT(("DrvEnablePDEV: GDIINFO (devcaps) parameter contains:"));
|
|
INIT_OUT((" ULONG ulVersion 0x%08x", pgdiRequested->ulVersion));
|
|
INIT_OUT((" ULONG ulHorzSize %d", pgdiRequested->ulHorzSize));
|
|
INIT_OUT((" ULONG ulVertSize %d", pgdiRequested->ulVertSize));
|
|
INIT_OUT((" ULONG ulHorzRes %d", pgdiRequested->ulHorzRes));
|
|
INIT_OUT((" ULONG ulVertRes %d", pgdiRequested->ulVertRes));
|
|
INIT_OUT((" ULONG cBitsPixel %d", pgdiRequested->cBitsPixel));
|
|
INIT_OUT((" ULONG cPlanes %d", pgdiRequested->cPlanes));
|
|
INIT_OUT((" ULONG ulNumColors %d", pgdiRequested->ulNumColors));
|
|
INIT_OUT((" ULONG ulDACRed 0x%08x", pgdiRequested->ulDACRed));
|
|
INIT_OUT((" ULONG ulDACGreen 0x%08x", pgdiRequested->ulDACGreen));
|
|
INIT_OUT((" ULONG ulDACBlue 0x%08x", pgdiRequested->ulDACBlue));
|
|
INIT_OUT((" ULONG ulHTOutputFormat %d", pgdiRequested->ulHTOutputFormat));
|
|
|
|
|
|
//
|
|
// Fill in the GDIINFO we're returning with the info for our driver.
|
|
// First, copy the default settings.
|
|
//
|
|
*pgdiReturn = s_osiDefaultGdi;
|
|
|
|
//
|
|
// Second, update the values that vary depending on the requested
|
|
// mode and color depth.
|
|
//
|
|
|
|
pgdiReturn->ulHorzRes = pdmRequested->dmPelsWidth;
|
|
pgdiReturn->ulVertRes = pdmRequested->dmPelsHeight;
|
|
pgdiReturn->ulVRefresh = pdmRequested->dmDisplayFrequency;
|
|
pgdiReturn->ulLogPixelsX = pdmRequested->dmLogPixels;
|
|
pgdiReturn->ulLogPixelsY = pdmRequested->dmLogPixels;
|
|
|
|
//
|
|
// If this is NT 4.0 SP-3, we get passed in the original GDIINFO of
|
|
// the real display. If not, we need to fake up one.
|
|
//
|
|
if (pgdiRequested->cPlanes != 0)
|
|
{
|
|
//
|
|
// Now overwrite the defaults with the relevant information returned
|
|
// from the kernel driver:
|
|
//
|
|
pgdiReturn->cBitsPixel = pgdiRequested->cBitsPixel;
|
|
pgdiReturn->cPlanes = pgdiRequested->cPlanes;
|
|
|
|
pgdiReturn->ulDACRed = pgdiRequested->ulDACRed;
|
|
pgdiReturn->ulDACGreen = pgdiRequested->ulDACGreen;
|
|
pgdiReturn->ulDACBlue = pgdiRequested->ulDACBlue;
|
|
}
|
|
else
|
|
{
|
|
pgdiReturn->cBitsPixel = pdmRequested->dmBitsPerPel;
|
|
pgdiReturn->cPlanes = 1;
|
|
|
|
switch (pgdiReturn->cBitsPixel)
|
|
{
|
|
case 8:
|
|
pgdiReturn->ulDACRed = pgdiReturn->ulDACGreen = pgdiReturn->ulDACBlue = 8;
|
|
break;
|
|
|
|
case 24:
|
|
pgdiReturn->ulDACRed = 0x00FF0000;
|
|
pgdiReturn->ulDACGreen = 0x0000FF00;
|
|
pgdiReturn->ulDACBlue = 0x000000FF;
|
|
break;
|
|
|
|
default:
|
|
ERROR_OUT(("Invalid color depth in NT 5.0 mirror driver"));
|
|
DC_QUIT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now save private copies of info we're returning to GDI
|
|
//
|
|
ppdev->cxScreen = pgdiReturn->ulHorzRes;
|
|
ppdev->cyScreen = pgdiReturn->ulVertRes;
|
|
ppdev->cBitsPerPel = pgdiReturn->cBitsPixel * pgdiReturn->cPlanes;
|
|
if (ppdev->cBitsPerPel == 15)
|
|
ppdev->cBitsPerPel = 16;
|
|
ppdev->flRed = pgdiReturn->ulDACRed;
|
|
ppdev->flGreen = pgdiReturn->ulDACGreen;
|
|
ppdev->flBlue = pgdiReturn->ulDACBlue;
|
|
|
|
//
|
|
// Fill in the devinfo structure with the default 8bpp values, taking
|
|
// care not to trash the supplied hpalDefault (which allows us to
|
|
// query information about the real display driver's color format).
|
|
//
|
|
// On NT 5.0, we don't get passed on the screen palette at all, we need
|
|
// to create our own.
|
|
//
|
|
hpal = pdiReturn->hpalDefault;
|
|
*pdiReturn = s_osiDefaultDevInfo;
|
|
|
|
switch (pgdiReturn->cBitsPixel * pgdiReturn->cPlanes)
|
|
{
|
|
case 4:
|
|
{
|
|
//
|
|
// NT 4.0 SP-3 ONLY
|
|
//
|
|
|
|
pgdiReturn->ulNumColors = 16;
|
|
pgdiReturn->ulNumPalReg = 0;
|
|
pgdiReturn->ulHTOutputFormat = HT_FORMAT_4BPP;
|
|
|
|
pdiReturn->flGraphicsCaps &= ~GCAPS_PALMANAGED;
|
|
pdiReturn->iDitherFormat = BMF_4BPP;
|
|
|
|
ppdev->iBitmapFormat = BMF_4BPP;
|
|
|
|
cColors = 16;
|
|
goto AllocPalEntries;
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
{
|
|
pgdiReturn->ulNumColors = 20;
|
|
pgdiReturn->ulNumPalReg = 256;
|
|
|
|
pdiReturn->iDitherFormat = BMF_8BPP;
|
|
|
|
ppdev->iBitmapFormat = BMF_8BPP;
|
|
|
|
cColors = 256;
|
|
AllocPalEntries:
|
|
//
|
|
// Alloc memory for the palette entries.
|
|
//
|
|
ppdev->pPal = EngAllocMem( FL_ZERO_MEMORY,
|
|
sizeof(PALETTEENTRY) * cColors,
|
|
OSI_ALLOC_TAG );
|
|
if (ppdev->pPal == NULL)
|
|
{
|
|
ERROR_OUT(("Failed to allocate palette memory"));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
{
|
|
//
|
|
// NT 4.0 SP-3 ONLY
|
|
//
|
|
pgdiReturn->ulHTOutputFormat = HT_FORMAT_16BPP;
|
|
|
|
pdiReturn->flGraphicsCaps &= ~(GCAPS_PALMANAGED | GCAPS_COLOR_DITHER);
|
|
pdiReturn->iDitherFormat = BMF_16BPP;
|
|
|
|
ppdev->iBitmapFormat = BMF_16BPP;
|
|
}
|
|
break;
|
|
|
|
case 24:
|
|
{
|
|
//
|
|
// DIB conversions will only work if we have a standard RGB
|
|
// surface for 24bpp.
|
|
//
|
|
pgdiReturn->ulHTOutputFormat = HT_FORMAT_24BPP;
|
|
|
|
pdiReturn->flGraphicsCaps &= ~(GCAPS_PALMANAGED | GCAPS_COLOR_DITHER);
|
|
pdiReturn->iDitherFormat = BMF_24BPP;
|
|
|
|
ppdev->iBitmapFormat = BMF_24BPP;
|
|
}
|
|
break;
|
|
|
|
case 32:
|
|
{
|
|
//
|
|
// NT 4.0 SP-3 ONLY
|
|
//
|
|
pgdiReturn->ulHTOutputFormat = HT_FORMAT_32BPP;
|
|
|
|
pdiReturn->flGraphicsCaps &= ~(GCAPS_PALMANAGED | GCAPS_COLOR_DITHER);
|
|
pdiReturn->iDitherFormat = BMF_32BPP;
|
|
|
|
ppdev->iBitmapFormat = BMF_32BPP;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
//
|
|
// Unsupported bpp - pretend we are 8 bpp.
|
|
//
|
|
ERROR_OUT(("Unsupported bpp value: %d",
|
|
pgdiReturn->cBitsPixel * pgdiReturn->cPlanes));
|
|
DC_QUIT;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
if (!hpal)
|
|
{
|
|
//
|
|
// This is NT 5.0. We need to create a palette, either an 8bpp
|
|
// indexed one, or a 24bpp bitfield one.
|
|
//
|
|
if (ppdev->iBitmapFormat == BMF_8BPP)
|
|
{
|
|
ULONG ulLoop;
|
|
|
|
//
|
|
// We have to initialize the fixed part (top 10 and bottom 10)
|
|
// of the palette entries.
|
|
//
|
|
for (ulLoop = 0; ulLoop < 10; ulLoop++)
|
|
{
|
|
// First 10
|
|
ppdev->pPal[ulLoop] = s_aWinColors[ulLoop];
|
|
|
|
// Last 10
|
|
ppdev->pPal[256 - 10 + ulLoop] = s_aWinColors[ulLoop + 10];
|
|
}
|
|
|
|
// Create the palette from the entries.
|
|
hpal = EngCreatePalette(PAL_INDEXED, 256, (ULONG*)ppdev->pPal,
|
|
0, 0, 0);
|
|
|
|
//
|
|
// Set the flag in the PDEV to indicate that the palette has
|
|
// changed.
|
|
//
|
|
ppdev->paletteChanged = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(ppdev->iBitmapFormat == BMF_24BPP);
|
|
|
|
hpal = EngCreatePalette(PAL_BITFIELDS, 0, NULL,
|
|
ppdev->flRed, ppdev->flGreen, ppdev->flBlue);
|
|
}
|
|
|
|
ppdev->hpalCreated = hpal;
|
|
if (!hpal)
|
|
{
|
|
ERROR_OUT(("DrvEnablePDEV: could not create DEVINFO palette"));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is NT 4.0 SP-3. Get the real bitmasks for > 8 bpp and
|
|
// the current palette colors for <= 8 bpp.
|
|
//
|
|
if (pgdiReturn->cBitsPixel <= 8)
|
|
{
|
|
if (ppdev->iBitmapFormat == BMF_4BPP)
|
|
{
|
|
ASSERT(cColors == 16);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(cColors == 256);
|
|
}
|
|
|
|
if (cColors != EngQueryPalette(hpal, &iMode, cColors,
|
|
(ULONG *)ppdev->pPal))
|
|
{
|
|
ERROR_OUT(("Failed to query current display palette"));
|
|
}
|
|
|
|
//
|
|
// Set the flag in the PDEV to indicate that the palette has
|
|
// changed.
|
|
//
|
|
ppdev->paletteChanged = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ULONG aulBitmasks[3];
|
|
|
|
//
|
|
// Query the true color bitmasks.
|
|
//
|
|
cColors = EngQueryPalette(hpal,
|
|
&iMode,
|
|
sizeof(aulBitmasks) / sizeof(aulBitmasks[0]),
|
|
&aulBitmasks[0] );
|
|
|
|
if (cColors == 0)
|
|
{
|
|
ERROR_OUT(("Failed to query real bitmasks"));
|
|
}
|
|
|
|
if (iMode == PAL_INDEXED)
|
|
{
|
|
ERROR_OUT(("Bitmask palette is indexed"));
|
|
}
|
|
|
|
//
|
|
// Get the real bitmasks for NT 4.0 SP-3 displays since we
|
|
// get the same info the real global display does, and we need
|
|
// to parse the bits in BitBlts, color tanslations, etc.
|
|
//
|
|
ppdev->flRed = aulBitmasks[0];
|
|
ppdev->flGreen = aulBitmasks[1];
|
|
ppdev->flBlue = aulBitmasks[2];
|
|
}
|
|
}
|
|
|
|
pdiReturn->hpalDefault = hpal;
|
|
|
|
rc = TRUE;
|
|
|
|
INIT_OUT(("DrvEnablePDEV: Returning bitmasks of:"));
|
|
INIT_OUT((" red %08x", ppdev->flRed));
|
|
INIT_OUT((" green %08x", ppdev->flGreen));
|
|
INIT_OUT((" blue %08x", ppdev->flBlue));
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(OSIInitializeMode, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// FUNCTION: OSI_DDProcessRequest
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
// Called by the display driver to process an OSI specific request
|
|
//
|
|
// PARAMETERS: pso - pointer to surface object
|
|
// cjIn - (IN) size of request block
|
|
// pvIn - (IN) pointer to request block
|
|
// cjOut - (IN) size of response block
|
|
// pvOut - (OUT) pointer to response block
|
|
//
|
|
// RETURNS: None
|
|
//
|
|
//
|
|
ULONG OSI_DDProcessRequest(SURFOBJ* pso,
|
|
UINT cjIn,
|
|
void * pvIn,
|
|
UINT cjOut,
|
|
void * pvOut)
|
|
{
|
|
ULONG rc;
|
|
LPOSI_ESCAPE_HEADER pHeader;
|
|
LPOSI_PDEV ppdev = (LPOSI_PDEV)pso->dhpdev;
|
|
|
|
DebugEntry(OSI_DDProcessRequest);
|
|
|
|
//
|
|
// Get the request number.
|
|
//
|
|
pHeader = pvIn;
|
|
switch (pHeader->escapeFn)
|
|
{
|
|
case OSI_ESC_INIT:
|
|
{
|
|
TRACE_OUT(("DrvEscape: OSI_ESC_INIT"));
|
|
ASSERT(cjOut == sizeof(OSI_INIT_REQUEST));
|
|
|
|
//
|
|
// Get shared memory block
|
|
//
|
|
OSI_DDInit(ppdev, (LPOSI_INIT_REQUEST)pvOut);
|
|
rc = TRUE;
|
|
}
|
|
break;
|
|
|
|
case OSI_ESC_TERM:
|
|
{
|
|
TRACE_OUT(("DrvEscape: OSI_ESC_TERM"));
|
|
ASSERT(cjIn == sizeof(OSI_TERM_REQUEST));
|
|
|
|
//
|
|
// Cleanup, NM is going away
|
|
//
|
|
OSI_DDTerm(ppdev);
|
|
rc = TRUE;
|
|
}
|
|
break;
|
|
|
|
case OSI_ESC_SYNC_NOW:
|
|
{
|
|
TRACE_OUT(("DrvEscape: OSI_ESC_SYNC_NOW"));
|
|
ASSERT(cjIn == sizeof(OSI_ESCAPE_HEADER));
|
|
|
|
//
|
|
// Resync with the 32-bit ring 3 core. This happens when
|
|
// somebody joins or leaves a share.
|
|
//
|
|
BA_ResetBounds();
|
|
OA_DDSyncUpdatesNow();
|
|
SBC_DDSyncUpdatesNow(ppdev);
|
|
rc = TRUE;
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
{
|
|
ERROR_OUT(("Unrecognised request %lu", pHeader->escapeFn));
|
|
rc = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
DebugExitBOOL(OSI_DDProcessRequest, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Function: OSI_DDInit
|
|
//
|
|
// Description: Map the shared memory into Kernel and User space
|
|
//
|
|
// Parameters: count - size of the buffer to return to user space
|
|
// pData - pointer to the buffer to be returned to user space
|
|
//
|
|
// Returns: (none)
|
|
//
|
|
void OSI_DDInit(LPOSI_PDEV ppdev, LPOSI_INIT_REQUEST pResult)
|
|
{
|
|
DWORD memRemaining;
|
|
LPBYTE pBuffer;
|
|
LPVOID shmMappedMemory;
|
|
|
|
VIDEO_SHARE_MEMORY ShareMemory;
|
|
VIDEO_SHARE_MEMORY_INFORMATION ShareMemoryInformation;
|
|
DWORD ReturnedDataLength;
|
|
|
|
DebugEntry(OSI_DDInit);
|
|
|
|
// Init to FALSE
|
|
pResult->result = FALSE;
|
|
|
|
// Initialize these to NULL
|
|
pResult->pSharedMemory = NULL;
|
|
pResult->poaData[0] = NULL;
|
|
pResult->poaData[1] = NULL;
|
|
pResult->sbcEnabled = FALSE;
|
|
|
|
//
|
|
// Check that the memory is available to the driver and that we are not
|
|
// in a race condition.
|
|
//
|
|
if (g_asSharedMemory == NULL)
|
|
{
|
|
ERROR_OUT(("No memory available"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
if (g_shmMappedMemory != NULL)
|
|
{
|
|
//
|
|
// We will never come in here with two copies of NetMeeting running.
|
|
// The UI code prevents the second instance from starting long
|
|
// before app sharing is in the picture. Therefore, these are the
|
|
// only possibilities:
|
|
//
|
|
// (1) Previous version is almost shutdown but hasn't called OSI_DDTerm
|
|
// yet and new version is starting up and calls OSI_DDInit
|
|
//
|
|
// (2) Previous version terminated abnormally and never called
|
|
// OSI_DDTerm(). This code handles the second case. The first one
|
|
// is handled by the same code in the UI that prevents two copies
|
|
// from starting around the same time.
|
|
//
|
|
WARNING_OUT(("OSI_DDInit: NetMeeting did not shutdown cleanly last time"));
|
|
OSI_DDTerm(ppdev);
|
|
}
|
|
|
|
//
|
|
// Map the shared section into the caller's process.
|
|
//
|
|
INIT_OUT(("OSI_DDInit: Mapping 0x%08x bytes of kernel memory at 0x%08x into caller process",
|
|
g_shmSharedMemorySize, g_asSharedMemory));
|
|
ShareMemory.ProcessHandle = LongToHandle(-1);
|
|
ShareMemory.ViewOffset = 0;
|
|
ShareMemory.ViewSize = g_shmSharedMemorySize;
|
|
ShareMemory.RequestedVirtualAddress = NULL;
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_SHARE_VIDEO_MEMORY,
|
|
&ShareMemory,
|
|
sizeof(VIDEO_SHARE_MEMORY),
|
|
&ShareMemoryInformation,
|
|
sizeof(VIDEO_SHARE_MEMORY_INFORMATION),
|
|
&ReturnedDataLength) != 0)
|
|
{
|
|
ERROR_OUT(("Failed to map shared memory into calling process"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// USER MODE pointer (not valid in kernel mode)
|
|
//
|
|
INIT_OUT(("OSI_DDInit: Mapped 0x%08x bytes of kernel memory to user memory 0x%08x",
|
|
g_shmSharedMemorySize, ShareMemoryInformation.VirtualAddress));
|
|
|
|
shmMappedMemory = ShareMemoryInformation.VirtualAddress;
|
|
pResult->pSharedMemory = shmMappedMemory;
|
|
pResult->poaData[0] = ((LPSHM_SHARED_MEMORY)pResult->pSharedMemory) + 1;
|
|
pResult->poaData[1] = ((LPOA_SHARED_DATA)pResult->poaData[0]) + 1;
|
|
|
|
TRACE_OUT(("Shared memory %08lx %08lx %08lx",
|
|
pResult->pSharedMemory, pResult->poaData[0], pResult->poaData[1]));
|
|
|
|
//
|
|
// Clear out the shared memory, so it's ready for immediate use.
|
|
// NOTE THAT THIS SETS ALL VALUES TO FALSE.
|
|
// NOTE ALSO THAT THIS CLEARS the two OA_SHARED_DATAs also
|
|
//
|
|
RtlFillMemory(g_asSharedMemory, SHM_SIZE_USED, 0);
|
|
g_asSharedMemory->displayToCore.indexCount = 0;
|
|
|
|
//
|
|
// Set up our pointer to the variable part of the shared memory i.e.
|
|
// the part which is not used for the SHM_SHARED_MEMORY structure
|
|
// We must skip past g_asSharedMemory, two CM_FAST_DATA structs, and
|
|
// two OA_SHARED_DATA structs.
|
|
//
|
|
pBuffer = (LPBYTE)g_asSharedMemory;
|
|
pBuffer += SHM_SIZE_USED;
|
|
memRemaining = g_shmSharedMemorySize - SHM_SIZE_USED;
|
|
|
|
//
|
|
// Initialise the other components required for DC-Share
|
|
//
|
|
|
|
//
|
|
// Bounds accumulation
|
|
//
|
|
BA_DDInit();
|
|
|
|
//
|
|
// Cursor
|
|
//
|
|
if (!CM_DDInit(ppdev))
|
|
{
|
|
ERROR_OUT(("CM failed to init"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Send Bitmap Cache
|
|
// NOTE that if it initializes OK but no caching allowed, we will continue.
|
|
//
|
|
// This will fill in the tile buffers & info. If no SBC caching allowed,
|
|
// the sbcEnabled field will be FALSE.
|
|
//
|
|
if (SBC_DDInit(ppdev, pBuffer, memRemaining, pResult))
|
|
{
|
|
pResult->sbcEnabled = TRUE;
|
|
}
|
|
|
|
//
|
|
// Mark memory as ready to use.
|
|
//
|
|
g_shmMappedMemory = shmMappedMemory;
|
|
pResult->result = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitVOID(OSI_DDInit);
|
|
}
|
|
|
|
|
|
//
|
|
// Function: OSI_DDTerm
|
|
//
|
|
// Description: Cleanup when NM shuts down
|
|
//
|
|
// Returns: (none)
|
|
//
|
|
void OSI_DDTerm(LPOSI_PDEV ppdev)
|
|
{
|
|
DebugEntry(OSI_DDTerm);
|
|
|
|
//
|
|
// Check for a valid address - must be non-NULL.
|
|
//
|
|
if (!g_asSharedMemory)
|
|
{
|
|
ERROR_OUT(("Invalid memory"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
|
|
//
|
|
// Terminate the dependent components.
|
|
//
|
|
|
|
//
|
|
// Hosted Entity Tracker
|
|
//
|
|
HET_DDTerm();
|
|
|
|
//
|
|
// Order Encoding
|
|
//
|
|
OE_DDTerm();
|
|
|
|
//
|
|
// Send Bitmap Cache
|
|
//
|
|
SBC_DDTerm();
|
|
|
|
//
|
|
// Cursor manager.
|
|
//
|
|
CM_DDTerm();
|
|
|
|
//
|
|
// The shared memory will be unmapped automatically in this process
|
|
// by OS cleanup, in both NT4 and NT5
|
|
//
|
|
g_shmMappedMemory = NULL;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitVOID(OSI_DDTerm);
|
|
}
|
|
|
|
|